najm-auth 1.1.38 → 1.1.39

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
@@ -228,6 +228,229 @@ var authSchema3 = {
228
228
  rolePermissions: rolePermissionsTable3
229
229
  };
230
230
 
231
+ // src/auth/index.ts
232
+ var auth_exports = {};
233
+ __export(auth_exports, {
234
+ AUTH_MODULE: () => AUTH_MODULE,
235
+ AuthController: () => AuthController,
236
+ AuthGuard: () => AuthGuard,
237
+ AuthResolver: () => AuthResolver,
238
+ AuthService: () => AuthService,
239
+ CookieManager: () => CookieManager,
240
+ EncryptionService: () => EncryptionService,
241
+ isAuth: () => isAuth,
242
+ runAsUser: () => runAsUser
243
+ });
244
+
245
+ // src/auth/EncryptionService.ts
246
+ import { Inject, Injectable } from "najm-core";
247
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
248
+
249
+ // src/auth/password.ts
250
+ import bcrypt from "bcryptjs";
251
+ var getBunPassword = /* @__PURE__ */ __name(() => globalThis.Bun?.password, "getBunPassword");
252
+ async function hashPassword(password, rounds) {
253
+ if (!Number.isInteger(rounds) || rounds < 4 || rounds > 31) {
254
+ throw new Error("bcrypt rounds must be an integer between 4 and 31");
255
+ }
256
+ const bunPassword = getBunPassword();
257
+ if (bunPassword) {
258
+ return bunPassword.hash(password, { algorithm: "bcrypt", cost: rounds });
259
+ }
260
+ return bcrypt.hash(password, rounds);
261
+ }
262
+ __name(hashPassword, "hashPassword");
263
+ async function verifyPassword(password, hash) {
264
+ const bunPassword = getBunPassword();
265
+ if (bunPassword) {
266
+ return bunPassword.verify(password, hash);
267
+ }
268
+ return bcrypt.compare(password, hash);
269
+ }
270
+ __name(verifyPassword, "verifyPassword");
271
+
272
+ // src/auth/EncryptionService.ts
273
+ var __decorate = function(decorators, target, key, desc) {
274
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
275
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
276
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
277
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
278
+ };
279
+ var __metadata = function(k, v) {
280
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
281
+ };
282
+ var __param = function(paramIndex, decorator) {
283
+ return function(target, key) {
284
+ decorator(target, key, paramIndex);
285
+ };
286
+ };
287
+ var REQUIRED_KEY_BYTES = 32;
288
+ function decodeKey(raw) {
289
+ if (/^[0-9a-fA-F]{64}$/.test(raw)) {
290
+ return Buffer.from(raw, "hex");
291
+ }
292
+ if (/^[A-Za-z0-9+/]+=*$/.test(raw) || /^[A-Za-z0-9_-]+=*$/.test(raw)) {
293
+ const decoded = Buffer.from(raw, raw.includes("-") || raw.includes("_") ? "base64url" : "base64");
294
+ if (decoded.length === REQUIRED_KEY_BYTES)
295
+ return decoded;
296
+ }
297
+ if (Buffer.byteLength(raw, "utf8") === REQUIRED_KEY_BYTES) {
298
+ return Buffer.from(raw, "utf8");
299
+ }
300
+ throw new Error(`Encryption key must decode to ${REQUIRED_KEY_BYTES} bytes. Provide hex (64 chars) or base64 (32 bytes decoded).`);
301
+ }
302
+ __name(decodeKey, "decodeKey");
303
+ var EncryptionService = class EncryptionService2 {
304
+ static {
305
+ __name(this, "EncryptionService");
306
+ }
307
+ config;
308
+ encryptionKey;
309
+ constructor(encryptionKey) {
310
+ const raw = encryptionKey ?? process.env.NAJM_ENCRYPTION_KEY ?? "";
311
+ if (!raw) {
312
+ throw new Error("Encryption key missing. Set NAJM_ENCRYPTION_KEY (base64 or hex, 32 bytes) or pass auth({ encryptionKey })");
313
+ }
314
+ this.encryptionKey = decodeKey(raw);
315
+ }
316
+ async hashPassword(password) {
317
+ return hashPassword(password, this.config?.bcryptRounds ?? 10);
318
+ }
319
+ async comparePassword(password, hashedPassword) {
320
+ return verifyPassword(password, hashedPassword);
321
+ }
322
+ encrypt(plaintext) {
323
+ const iv = randomBytes(12);
324
+ const cipher = createCipheriv("aes-256-gcm", this.encryptionKey, iv);
325
+ const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
326
+ const tag = cipher.getAuthTag();
327
+ return Buffer.concat([iv, tag, encrypted]).toString("base64url");
328
+ }
329
+ decrypt(ciphertext) {
330
+ const raw = Buffer.from(ciphertext, "base64url");
331
+ const iv = raw.subarray(0, 12);
332
+ const tag = raw.subarray(12, 28);
333
+ const encrypted = raw.subarray(28);
334
+ const decipher = createDecipheriv("aes-256-gcm", this.encryptionKey, iv);
335
+ decipher.setAuthTag(tag);
336
+ return decipher.update(encrypted) + decipher.final("utf8");
337
+ }
338
+ };
339
+ __decorate([
340
+ Inject(AUTH_CONFIG),
341
+ __metadata("design:type", Object)
342
+ ], EncryptionService.prototype, "config", void 0);
343
+ EncryptionService = __decorate([
344
+ Injectable(),
345
+ __param(0, Inject(AUTH_ENCRYPTION_KEY)),
346
+ __metadata("design:paramtypes", [String])
347
+ ], EncryptionService);
348
+
349
+ // src/auth/CookieManager.ts
350
+ import { Service, Inject as Inject2 } from "najm-core";
351
+ import { CookieService } from "najm-cookies";
352
+ import timestring from "timestring";
353
+ var __decorate2 = function(decorators, target, key, desc) {
354
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
355
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
356
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
357
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
358
+ };
359
+ var __metadata2 = function(k, v) {
360
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
361
+ };
362
+ var _a;
363
+ var CookieManager = class CookieManager2 {
364
+ static {
365
+ __name(this, "CookieManager");
366
+ }
367
+ config;
368
+ cookieService;
369
+ get cookieName() {
370
+ return this.config.refreshCookieName || "refreshToken";
371
+ }
372
+ get sessionCookieName() {
373
+ return this.config.session.name;
374
+ }
375
+ get sessionMaxAge() {
376
+ return this.config.session.maxAge;
377
+ }
378
+ get sessionSecret() {
379
+ return this.config.session.secret || this.config.jwt.accessSecret;
380
+ }
381
+ // =========================================================================
382
+ // Refresh Token Cookie
383
+ // =========================================================================
384
+ setRefreshToken(refreshToken) {
385
+ const maxAge = timestring(this.config.jwt.refreshExpiresIn, "s");
386
+ this.cookieService.set(this.cookieName, refreshToken, { maxAge });
387
+ }
388
+ clearRefreshToken() {
389
+ this.cookieService.delete(this.cookieName);
390
+ }
391
+ getRefreshToken() {
392
+ return this.cookieService.get(this.cookieName);
393
+ }
394
+ hasRefreshToken() {
395
+ return this.cookieService.has(this.cookieName);
396
+ }
397
+ getCookieName() {
398
+ return this.cookieName;
399
+ }
400
+ // =========================================================================
401
+ // Session Cookie Cache (HMAC-signed, short-lived)
402
+ // =========================================================================
403
+ /**
404
+ * Write a signed session cookie containing user data, roles, and permissions.
405
+ * The cookie is HMAC-signed with the access secret so it is tamper-proof
406
+ * but readable without a database query. Short TTL (5 min) ensures freshness.
407
+ */
408
+ setSessionCookie(data) {
409
+ const payload = { ...data, iat: Date.now() };
410
+ this.cookieService.setSigned(this.sessionCookieName, JSON.stringify(payload), this.sessionSecret, {
411
+ maxAge: this.sessionMaxAge,
412
+ httpOnly: true,
413
+ sameSite: "Lax",
414
+ path: "/"
415
+ });
416
+ }
417
+ /**
418
+ * Read and verify the session cookie. Returns null if missing, expired,
419
+ * or signature verification fails.
420
+ */
421
+ getSessionCookie() {
422
+ const raw = this.cookieService.getSigned(this.sessionCookieName, this.sessionSecret);
423
+ if (!raw)
424
+ return null;
425
+ try {
426
+ const data = JSON.parse(raw);
427
+ const age = Date.now() - data.iat;
428
+ if (age > this.sessionMaxAge * 1e3)
429
+ return null;
430
+ return data;
431
+ } catch {
432
+ return null;
433
+ }
434
+ }
435
+ /**
436
+ * Clear the session cookie (on logout, password change, etc.)
437
+ */
438
+ clearSessionCookie() {
439
+ this.cookieService.delete(this.sessionCookieName);
440
+ }
441
+ };
442
+ __decorate2([
443
+ Inject2(AUTH_CONFIG),
444
+ __metadata2("design:type", Object)
445
+ ], CookieManager.prototype, "config", void 0);
446
+ __decorate2([
447
+ Inject2(CookieService),
448
+ __metadata2("design:type", typeof (_a = typeof CookieService !== "undefined" && CookieService) === "function" ? _a : Object)
449
+ ], CookieManager.prototype, "cookieService", void 0);
450
+ CookieManager = __decorate2([
451
+ Service()
452
+ ], CookieManager);
453
+
231
454
  // src/auth/AuthController.ts
232
455
  import { Controller } from "najm-core";
233
456
  import { Get, Post, ResMsg } from "najm-core";
@@ -236,17 +459,18 @@ import { Body, User as User2, Headers } from "najm-core";
236
459
  // src/auth/AuthService.ts
237
460
  import { Injectable as Injectable7, Inject as Inject8 } from "najm-core";
238
461
  import { Err as Err6, Log } from "najm-core";
239
- import { I18n as I18n4, I18nService as I18nService2 } from "najm-i18n";
462
+ import { I18n as I18n5, I18nService as I18nService2 } from "najm-i18n";
240
463
  import { EmailService, passwordResetTemplate } from "najm-email";
241
464
 
242
465
  // src/users/UserService.ts
243
- import { Injectable as Injectable5, Inject as Inject4 } from "najm-core";
466
+ import { Injectable as Injectable5, Inject as Inject5 } from "najm-core";
244
467
  import { Transaction } from "najm-database";
245
468
  import { I18nService } from "najm-i18n";
469
+ import { I18n as I18n3 } from "najm-i18n";
246
470
 
247
471
  // src/users/UserRepository.ts
248
- import { eq as eq2, ne } from "drizzle-orm";
249
- import { Repository, Inject } from "najm-core";
472
+ import { eq as eq2, ne, sql as sql4 } from "drizzle-orm";
473
+ import { Repository, Inject as Inject3 } from "najm-core";
250
474
  import { DB } from "najm-database";
251
475
 
252
476
  // src/shared/queries.ts
@@ -279,14 +503,22 @@ var AuthQueries = class {
279
503
  updatedAt: this.schema.users.updatedAt
280
504
  };
281
505
  }
506
+ async getUserWithPermissions(where2) {
507
+ const rows = await this.db.select({
508
+ ...this.userSelection(),
509
+ permissionName: this.schema.permissions.name
510
+ }).from(this.schema.users).leftJoin(this.schema.roles, eq(this.schema.users.roleId, this.schema.roles.id)).leftJoin(this.schema.rolePermissions, eq(this.schema.users.roleId, this.schema.rolePermissions.roleId)).leftJoin(this.schema.permissions, eq(this.schema.rolePermissions.permissionId, this.schema.permissions.id)).where(where2);
511
+ if (rows.length === 0)
512
+ return void 0;
513
+ const { permissionName: _permissionName, ...user } = rows[0];
514
+ const permissions = [...new Set(rows.map((row) => row.permissionName).filter(Boolean))];
515
+ return { ...user, permissions };
516
+ }
282
517
  /**
283
518
  * Get permissions for a user by their userId
284
519
  */
285
520
  async getUserPermissions(userId) {
286
- const [user] = await this.db.select({ roleId: this.schema.users.roleId }).from(this.schema.users).where(eq(this.schema.users.id, userId)).limit(1);
287
- if (!user?.roleId)
288
- return [];
289
- const perms = await this.db.select({ name: this.schema.permissions.name }).from(this.schema.rolePermissions).leftJoin(this.schema.permissions, eq(this.schema.rolePermissions.permissionId, this.schema.permissions.id)).where(eq(this.schema.rolePermissions.roleId, user.roleId));
521
+ const perms = await this.db.select({ name: this.schema.permissions.name }).from(this.schema.users).leftJoin(this.schema.rolePermissions, eq(this.schema.users.roleId, this.schema.rolePermissions.roleId)).leftJoin(this.schema.permissions, eq(this.schema.rolePermissions.permissionId, this.schema.permissions.id)).where(eq(this.schema.users.id, userId));
290
522
  return perms.map((p) => p.name).filter(Boolean);
291
523
  }
292
524
  /**
@@ -301,16 +533,13 @@ var AuthQueries = class {
301
533
  * Returns { roleName: string | null, permissions: string[] }
302
534
  */
303
535
  async getRoleAndPermissions(userId) {
304
- const [user] = await this.db.select({ roleId: this.schema.users.roleId }).from(this.schema.users).where(eq(this.schema.users.id, userId)).limit(1);
305
- if (!user?.roleId) {
306
- const [roleRow2] = await this.db.select({ roleName: this.schema.roles.name }).from(this.schema.users).leftJoin(this.schema.roles, eq(this.schema.users.roleId, this.schema.roles.id)).where(eq(this.schema.users.id, userId)).limit(1);
307
- return { roleName: roleRow2?.roleName ?? null, permissions: [] };
308
- }
309
- const [roleRow] = await this.db.select({ roleName: this.schema.roles.name }).from(this.schema.roles).where(eq(this.schema.roles.id, user.roleId)).limit(1);
310
- const perms = await this.db.select({ name: this.schema.permissions.name }).from(this.schema.rolePermissions).leftJoin(this.schema.permissions, eq(this.schema.rolePermissions.permissionId, this.schema.permissions.id)).where(eq(this.schema.rolePermissions.roleId, user.roleId));
536
+ const rows = await this.db.select({
537
+ roleName: this.schema.roles.name,
538
+ permissionName: this.schema.permissions.name
539
+ }).from(this.schema.users).leftJoin(this.schema.roles, eq(this.schema.users.roleId, this.schema.roles.id)).leftJoin(this.schema.rolePermissions, eq(this.schema.users.roleId, this.schema.rolePermissions.roleId)).leftJoin(this.schema.permissions, eq(this.schema.rolePermissions.permissionId, this.schema.permissions.id)).where(eq(this.schema.users.id, userId));
311
540
  return {
312
- roleName: roleRow?.roleName ?? null,
313
- permissions: perms.map((p) => p.name).filter(Boolean)
541
+ roleName: rows[0]?.roleName ?? null,
542
+ permissions: [...new Set(rows.map((row) => row.permissionName).filter(Boolean))]
314
543
  };
315
544
  }
316
545
  /**
@@ -343,13 +572,13 @@ var ROLE_GROUPS = {
343
572
  };
344
573
 
345
574
  // src/users/UserRepository.ts
346
- var __decorate = function(decorators, target, key, desc) {
575
+ var __decorate3 = function(decorators, target, key, desc) {
347
576
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
348
577
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
349
578
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
350
579
  return c > 3 && r && Object.defineProperty(target, key, r), r;
351
580
  };
352
- var __metadata = function(k, v) {
581
+ var __metadata3 = function(k, v) {
353
582
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
354
583
  };
355
584
  var UserRepository = class UserRepository2 {
@@ -365,11 +594,12 @@ var UserRepository = class UserRepository2 {
365
594
  return this.schema.roles;
366
595
  }
367
596
  /** Shared query helper */
597
+ queryHelper;
368
598
  get q() {
369
- return new AuthQueries(this.db, this.schema);
599
+ return this.queryHelper ??= new AuthQueries(this.db, this.schema);
370
600
  }
371
- async getAll() {
372
- const allUsers = await this.db.select(this.q.userSelection()).from(this.users).leftJoin(this.roles, eq2(this.users.roleId, this.roles.id));
601
+ async getAll(limit = 50, offset = 0) {
602
+ const allUsers = await this.db.select(this.q.userSelection()).from(this.users).leftJoin(this.roles, eq2(this.users.roleId, this.roles.id)).limit(limit).offset(offset);
373
603
  const permissionsByRole = await this.q.batchLoadPermissionsByRole();
374
604
  return allUsers.map((user) => ({
375
605
  ...user,
@@ -377,13 +607,11 @@ var UserRepository = class UserRepository2 {
377
607
  }));
378
608
  }
379
609
  async getById(id) {
380
- const [user] = await this.db.select(this.q.userSelection()).from(this.users).leftJoin(this.roles, eq2(this.users.roleId, this.roles.id)).where(eq2(this.users.id, id)).limit(1);
381
- if (!user)
382
- return user;
383
- return {
384
- ...user,
385
- permissions: await this.q.getUserPermissions(user.id)
386
- };
610
+ return this.q.getUserWithPermissions(eq2(this.users.id, id));
611
+ }
612
+ async existsById(id) {
613
+ const [user] = await this.db.select({ id: this.users.id }).from(this.users).where(eq2(this.users.id, id)).limit(1);
614
+ return Boolean(user);
387
615
  }
388
616
  async getRawById(id) {
389
617
  const [user] = await this.db.select().from(this.users).where(eq2(this.users.id, id)).limit(1);
@@ -411,8 +639,7 @@ var UserRepository = class UserRepository2 {
411
639
  return updatedUser;
412
640
  }
413
641
  async incrementFailedAttempts(id) {
414
- const user = await this.getRawById(id);
415
- const [updatedUser] = await this.db.update(this.users).set({ failedLoginAttempts: (user?.failedLoginAttempts ?? 0) + 1 }).where(eq2(this.users.id, id)).returning();
642
+ const [updatedUser] = await this.db.update(this.users).set({ failedLoginAttempts: sql4`coalesce(${this.users.failedLoginAttempts}, 0) + 1` }).where(eq2(this.users.id, id)).returning();
416
643
  return updatedUser;
417
644
  }
418
645
  async resetFailedAttempts(id) {
@@ -440,21 +667,7 @@ var UserRepository = class UserRepository2 {
440
667
  return this.q.getRoleName(userId);
441
668
  }
442
669
  async findByPhone(phone) {
443
- const [user] = await this.db.select(this.q.userSelection()).from(this.users).leftJoin(this.roles, eq2(this.users.roleId, this.roles.id)).where(eq2(this.users.phone, phone)).limit(1);
444
- if (!user)
445
- return void 0;
446
- return {
447
- ...user,
448
- permissions: await this.q.getUserPermissions(user.id)
449
- };
450
- }
451
- async getUserPassword(email2) {
452
- const [user] = await this.db.select({
453
- id: this.users.id,
454
- email: this.users.email,
455
- password: this.users.password
456
- }).from(this.users).where(eq2(this.users.email, email2)).limit(1);
457
- return user?.password;
670
+ return this.q.getUserWithPermissions(eq2(this.users.phone, phone));
458
671
  }
459
672
  async getUserPermissions(userId) {
460
673
  return this.q.getUserPermissions(userId);
@@ -464,15 +677,15 @@ var UserRepository = class UserRepository2 {
464
677
  return updatedUser;
465
678
  }
466
679
  };
467
- __decorate([
680
+ __decorate3([
468
681
  DB(),
469
- __metadata("design:type", Object)
682
+ __metadata3("design:type", Object)
470
683
  ], UserRepository.prototype, "db", void 0);
471
- __decorate([
472
- Inject(AUTH_SCHEMA),
473
- __metadata("design:type", Object)
684
+ __decorate3([
685
+ Inject3(AUTH_SCHEMA),
686
+ __metadata3("design:type", Object)
474
687
  ], UserRepository.prototype, "schema", void 0);
475
- UserRepository = __decorate([
688
+ UserRepository = __decorate3([
476
689
  Repository()
477
690
  ], UserRepository);
478
691
 
@@ -480,93 +693,16 @@ UserRepository = __decorate([
480
693
  import { Injectable as Injectable2 } from "najm-core";
481
694
  import { Err } from "najm-core";
482
695
  import { I18n } from "najm-i18n";
483
-
484
- // src/auth/EncryptionService.ts
485
- import { Inject as Inject2, Injectable } from "najm-core";
486
- import bcrypt from "bcryptjs";
487
- import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
488
- var __decorate2 = function(decorators, target, key, desc) {
489
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
490
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
491
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
492
- return c > 3 && r && Object.defineProperty(target, key, r), r;
493
- };
494
- var __metadata2 = function(k, v) {
495
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
496
- };
497
- var __param = function(paramIndex, decorator) {
498
- return function(target, key) {
499
- decorator(target, key, paramIndex);
500
- };
501
- };
502
- var REQUIRED_KEY_BYTES = 32;
503
- function decodeKey(raw) {
504
- if (/^[0-9a-fA-F]{64}$/.test(raw)) {
505
- return Buffer.from(raw, "hex");
506
- }
507
- if (/^[A-Za-z0-9+/]+=*$/.test(raw) || /^[A-Za-z0-9_-]+=*$/.test(raw)) {
508
- const decoded = Buffer.from(raw, raw.includes("-") || raw.includes("_") ? "base64url" : "base64");
509
- if (decoded.length === REQUIRED_KEY_BYTES)
510
- return decoded;
511
- }
512
- if (Buffer.byteLength(raw, "utf8") === REQUIRED_KEY_BYTES) {
513
- return Buffer.from(raw, "utf8");
514
- }
515
- throw new Error(`Encryption key must decode to ${REQUIRED_KEY_BYTES} bytes. Provide hex (64 chars) or base64 (32 bytes decoded).`);
516
- }
517
- __name(decodeKey, "decodeKey");
518
- var EncryptionService = class EncryptionService2 {
519
- static {
520
- __name(this, "EncryptionService");
521
- }
522
- encryptionKey;
523
- constructor(encryptionKey) {
524
- const raw = encryptionKey ?? process.env.NAJM_ENCRYPTION_KEY ?? "";
525
- if (!raw) {
526
- throw new Error("Encryption key missing. Set NAJM_ENCRYPTION_KEY (base64 or hex, 32 bytes) or pass auth({ encryptionKey })");
527
- }
528
- this.encryptionKey = decodeKey(raw);
529
- }
530
- async hashPassword(password) {
531
- return bcrypt.hash(password, 10);
532
- }
533
- async comparePassword(password, hashedPassword) {
534
- return bcrypt.compare(password, hashedPassword);
535
- }
536
- encrypt(plaintext) {
537
- const iv = randomBytes(12);
538
- const cipher = createCipheriv("aes-256-gcm", this.encryptionKey, iv);
539
- const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
540
- const tag = cipher.getAuthTag();
541
- return Buffer.concat([iv, tag, encrypted]).toString("base64url");
542
- }
543
- decrypt(ciphertext) {
544
- const raw = Buffer.from(ciphertext, "base64url");
545
- const iv = raw.subarray(0, 12);
546
- const tag = raw.subarray(12, 28);
547
- const encrypted = raw.subarray(28);
548
- const decipher = createDecipheriv("aes-256-gcm", this.encryptionKey, iv);
549
- decipher.setAuthTag(tag);
550
- return decipher.update(encrypted) + decipher.final("utf8");
551
- }
552
- };
553
- EncryptionService = __decorate2([
554
- Injectable(),
555
- __param(0, Inject2(AUTH_ENCRYPTION_KEY)),
556
- __metadata2("design:paramtypes", [String])
557
- ], EncryptionService);
558
-
559
- // src/users/UserValidator.ts
560
- var __decorate3 = function(decorators, target, key, desc) {
696
+ var __decorate4 = function(decorators, target, key, desc) {
561
697
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
562
698
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
563
699
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
564
700
  return c > 3 && r && Object.defineProperty(target, key, r), r;
565
701
  };
566
- var __metadata3 = function(k, v) {
702
+ var __metadata4 = function(k, v) {
567
703
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
568
704
  };
569
- var _a;
705
+ var _a2;
570
706
  var _b;
571
707
  var UserValidator = class UserValidator2 {
572
708
  static {
@@ -594,11 +730,11 @@ var UserValidator = class UserValidator2 {
594
730
  * Check if user exists by ID
595
731
  */
596
732
  async checkUserExists(id) {
597
- const user = await this.userRepository.getById(id);
598
- if (!user) {
733
+ const exists = await this.userRepository.existsById(id);
734
+ if (!exists) {
599
735
  Err(this.t("errors.notFound"), 404);
600
736
  }
601
- return user;
737
+ return true;
602
738
  }
603
739
  /**
604
740
  * Check if user exists by email
@@ -642,8 +778,7 @@ var UserValidator = class UserValidator2 {
642
778
  async checkUserIdIsUnique(id) {
643
779
  if (!id)
644
780
  return;
645
- const existingUser = await this.userRepository.getById(id);
646
- if (existingUser) {
781
+ if (await this.userRepository.existsById(id)) {
647
782
  Err(this.t("errors.idExists"), 409);
648
783
  }
649
784
  }
@@ -691,13 +826,13 @@ var UserValidator = class UserValidator2 {
691
826
  }
692
827
  }
693
828
  };
694
- __decorate3([
829
+ __decorate4([
695
830
  I18n("users"),
696
- __metadata3("design:type", Object)
831
+ __metadata4("design:type", Object)
697
832
  ], UserValidator.prototype, "t", void 0);
698
- UserValidator = __decorate3([
833
+ UserValidator = __decorate4([
699
834
  Injectable2(),
700
- __metadata3("design:paramtypes", [typeof (_a = typeof UserRepository !== "undefined" && UserRepository) === "function" ? _a : Object, typeof (_b = typeof EncryptionService !== "undefined" && EncryptionService) === "function" ? _b : Object])
835
+ __metadata4("design:paramtypes", [typeof (_a2 = typeof UserRepository !== "undefined" && UserRepository) === "function" ? _a2 : Object, typeof (_b = typeof EncryptionService !== "undefined" && EncryptionService) === "function" ? _b : Object])
701
836
  ], UserValidator);
702
837
 
703
838
  // src/roles/RoleService.ts
@@ -705,15 +840,15 @@ import { Injectable as Injectable4 } from "najm-core";
705
840
 
706
841
  // src/roles/RoleRepository.ts
707
842
  import { eq as eq3 } from "drizzle-orm";
708
- import { Repository as Repository2, Inject as Inject3 } from "najm-core";
843
+ import { Repository as Repository2, Inject as Inject4 } from "najm-core";
709
844
  import { DB as DB2 } from "najm-database";
710
- var __decorate4 = function(decorators, target, key, desc) {
845
+ var __decorate5 = function(decorators, target, key, desc) {
711
846
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
712
847
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
713
848
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
714
849
  return c > 3 && r && Object.defineProperty(target, key, r), r;
715
850
  };
716
- var __metadata4 = function(k, v) {
851
+ var __metadata5 = function(k, v) {
717
852
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
718
853
  };
719
854
  var RoleRepository = class RoleRepository2 {
@@ -749,15 +884,15 @@ var RoleRepository = class RoleRepository2 {
749
884
  return deletedRole;
750
885
  }
751
886
  };
752
- __decorate4([
887
+ __decorate5([
753
888
  DB2(),
754
- __metadata4("design:type", Object)
889
+ __metadata5("design:type", Object)
755
890
  ], RoleRepository.prototype, "db", void 0);
756
- __decorate4([
757
- Inject3(AUTH_SCHEMA),
758
- __metadata4("design:type", Object)
891
+ __decorate5([
892
+ Inject4(AUTH_SCHEMA),
893
+ __metadata5("design:type", Object)
759
894
  ], RoleRepository.prototype, "schema", void 0);
760
- RoleRepository = __decorate4([
895
+ RoleRepository = __decorate5([
761
896
  Repository2()
762
897
  ], RoleRepository);
763
898
 
@@ -765,16 +900,16 @@ RoleRepository = __decorate4([
765
900
  import { Injectable as Injectable3 } from "najm-core";
766
901
  import { I18n as I18n2 } from "najm-i18n";
767
902
  import { Err as Err2 } from "najm-core";
768
- var __decorate5 = function(decorators, target, key, desc) {
903
+ var __decorate6 = function(decorators, target, key, desc) {
769
904
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
770
905
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
771
906
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
772
907
  return c > 3 && r && Object.defineProperty(target, key, r), r;
773
908
  };
774
- var __metadata5 = function(k, v) {
909
+ var __metadata6 = function(k, v) {
775
910
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
776
911
  };
777
- var _a2;
912
+ var _a3;
778
913
  var RoleValidator = class RoleValidator2 {
779
914
  static {
780
915
  __name(this, "RoleValidator");
@@ -833,26 +968,26 @@ var RoleValidator = class RoleValidator2 {
833
968
  return !!existingRole;
834
969
  }
835
970
  };
836
- __decorate5([
971
+ __decorate6([
837
972
  I18n2("roles"),
838
- __metadata5("design:type", Object)
973
+ __metadata6("design:type", Object)
839
974
  ], RoleValidator.prototype, "t", void 0);
840
- RoleValidator = __decorate5([
975
+ RoleValidator = __decorate6([
841
976
  Injectable3(),
842
- __metadata5("design:paramtypes", [typeof (_a2 = typeof RoleRepository !== "undefined" && RoleRepository) === "function" ? _a2 : Object])
977
+ __metadata6("design:paramtypes", [typeof (_a3 = typeof RoleRepository !== "undefined" && RoleRepository) === "function" ? _a3 : Object])
843
978
  ], RoleValidator);
844
979
 
845
980
  // src/roles/RoleService.ts
846
- var __decorate6 = function(decorators, target, key, desc) {
981
+ var __decorate7 = function(decorators, target, key, desc) {
847
982
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
848
983
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
849
984
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
850
985
  return c > 3 && r && Object.defineProperty(target, key, r), r;
851
986
  };
852
- var __metadata6 = function(k, v) {
987
+ var __metadata7 = function(k, v) {
853
988
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
854
989
  };
855
- var _a3;
990
+ var _a4;
856
991
  var _b2;
857
992
  var RoleService = class RoleService2 {
858
993
  static {
@@ -903,9 +1038,9 @@ var RoleService = class RoleService2 {
903
1038
  return role?.id;
904
1039
  }
905
1040
  };
906
- RoleService = __decorate6([
1041
+ RoleService = __decorate7([
907
1042
  Injectable4(),
908
- __metadata6("design:paramtypes", [typeof (_a3 = typeof RoleRepository !== "undefined" && RoleRepository) === "function" ? _a3 : Object, typeof (_b2 = typeof RoleValidator !== "undefined" && RoleValidator) === "function" ? _b2 : Object])
1043
+ __metadata7("design:paramtypes", [typeof (_a4 = typeof RoleRepository !== "undefined" && RoleRepository) === "function" ? _a4 : Object, typeof (_b2 = typeof RoleValidator !== "undefined" && RoleValidator) === "function" ? _b2 : Object])
909
1044
  ], RoleService);
910
1045
 
911
1046
  // src/users/UserService.ts
@@ -929,7 +1064,7 @@ var parseSchema = /* @__PURE__ */ __name(async (schema, data) => {
929
1064
  var clean = /* @__PURE__ */ __name((obj) => {
930
1065
  const cleaned = {};
931
1066
  for (const [key, value] of Object.entries(obj)) {
932
- if (value !== null && value !== void 0 && value !== "") {
1067
+ if (value !== void 0 && value !== "") {
933
1068
  cleaned[key] = value;
934
1069
  }
935
1070
  }
@@ -1010,13 +1145,13 @@ var isFile = /* @__PURE__ */ __name((img) => !!img && typeof img !== "string" &&
1010
1145
 
1011
1146
  // src/users/UserService.ts
1012
1147
  import { Err as Err4 } from "najm-core";
1013
- var __decorate7 = function(decorators, target, key, desc) {
1148
+ var __decorate8 = function(decorators, target, key, desc) {
1014
1149
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1015
1150
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1016
1151
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1017
1152
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1018
1153
  };
1019
- var __metadata7 = function(k, v) {
1154
+ var __metadata8 = function(k, v) {
1020
1155
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1021
1156
  };
1022
1157
  var __param2 = function(paramIndex, decorator) {
@@ -1024,7 +1159,7 @@ var __param2 = function(paramIndex, decorator) {
1024
1159
  decorator(target, key, paramIndex);
1025
1160
  };
1026
1161
  };
1027
- var _a4;
1162
+ var _a5;
1028
1163
  var _b3;
1029
1164
  var _c;
1030
1165
  var _d;
@@ -1043,6 +1178,7 @@ var UserService = class UserService2 {
1043
1178
  encryptionService;
1044
1179
  i18nService;
1045
1180
  authConfig;
1181
+ t;
1046
1182
  constructor(roleValidator, roleService, userRepository, userValidator, encryptionService, i18nService, authConfig) {
1047
1183
  this.roleValidator = roleValidator;
1048
1184
  this.roleService = roleService;
@@ -1061,6 +1197,12 @@ var UserService = class UserService2 {
1061
1197
  sanitizeUsers(users) {
1062
1198
  return users.map((user) => this.sanitizeUser(user)).filter(Boolean);
1063
1199
  }
1200
+ requireUser(user) {
1201
+ if (!user) {
1202
+ Err4(this.t("errors.notFound"), 404);
1203
+ }
1204
+ return user;
1205
+ }
1064
1206
  async resolveUserRole(roleId, roleName) {
1065
1207
  if (roleId) {
1066
1208
  await this.roleValidator.checkRoleExists(roleId);
@@ -1082,14 +1224,15 @@ var UserService = class UserService2 {
1082
1224
  }
1083
1225
  return null;
1084
1226
  }
1085
- async getAll() {
1086
- const users = await this.userRepository.getAll();
1227
+ async getAll(options = {}) {
1228
+ const limit = Math.min(Math.max(options.limit ?? 50, 1), 100);
1229
+ const offset = Math.max(options.offset ?? 0, 0);
1230
+ const users = await this.userRepository.getAll(limit, offset);
1087
1231
  return this.sanitizeUsers(users);
1088
1232
  }
1089
1233
  async getById(id) {
1090
- await this.userValidator.checkUserExists(id);
1091
1234
  const user = await this.userRepository.getById(id);
1092
- return this.sanitizeUser(user);
1235
+ return this.sanitizeUser(this.requireUser(user));
1093
1236
  }
1094
1237
  async getByEmail(email2) {
1095
1238
  const user = await this.userValidator.checkUserExistsByEmail(email2);
@@ -1111,9 +1254,9 @@ var UserService = class UserService2 {
1111
1254
  Err4("Password is required");
1112
1255
  }
1113
1256
  this.userValidator.validatePasswordStrength(password);
1114
- let userId = id || nanoid4(5);
1257
+ let userId = id || nanoid4(10);
1115
1258
  await this.userValidator.checkEmailUnique(data.email);
1116
- await this.userValidator.checkUserIdIsUnique(id);
1259
+ await this.userValidator.checkUserIdIsUnique(userId);
1117
1260
  const hashedPassword = await this.encryptionService.hashPassword(password);
1118
1261
  const resolvedRoleId = await this.resolveUserRole(roleId, role);
1119
1262
  const userDetails = {
@@ -1131,7 +1274,6 @@ var UserService = class UserService2 {
1131
1274
  }
1132
1275
  async update(id, data) {
1133
1276
  const { password, image } = data;
1134
- await this.userValidator.checkUserExists(id);
1135
1277
  await this.userValidator.checkEmailUnique(data.email, id);
1136
1278
  let hashedPassword;
1137
1279
  if (password) {
@@ -1145,12 +1287,11 @@ var UserService = class UserService2 {
1145
1287
  };
1146
1288
  const cleanedUpdateData = clean(updateData);
1147
1289
  const updatedUser = await this.userRepository.update(id, cleanedUpdateData);
1148
- return this.sanitizeUser(updatedUser);
1290
+ return this.sanitizeUser(this.requireUser(updatedUser));
1149
1291
  }
1150
1292
  async delete(id) {
1151
- await this.userValidator.checkUserExists(id);
1152
1293
  const user = await this.userRepository.delete(id);
1153
- return this.sanitizeUser(user);
1294
+ return this.sanitizeUser(this.requireUser(user));
1154
1295
  }
1155
1296
  async deleteAll() {
1156
1297
  const deletedUsers = await this.userRepository.deleteAll();
@@ -1160,12 +1301,7 @@ var UserService = class UserService2 {
1160
1301
  await this.userValidator.checkUserExists(id);
1161
1302
  return await this.userRepository.getRoleNameById(id);
1162
1303
  }
1163
- async getPassword(email2) {
1164
- await this.userValidator.checkUserExistsByEmail(email2);
1165
- return await this.userRepository.getUserPassword(email2);
1166
- }
1167
1304
  async updateLastLogin(id) {
1168
- await this.userValidator.checkUserExists(id);
1169
1305
  await this.userRepository.updateLastLogin(id);
1170
1306
  }
1171
1307
  async incrementFailedAttempts(id) {
@@ -1179,15 +1315,13 @@ var UserService = class UserService2 {
1179
1315
  await this.userRepository.setLockout(id, until);
1180
1316
  }
1181
1317
  async assignRole(id, roleId, roleName) {
1182
- await this.userValidator.checkUserExists(id);
1183
1318
  const resolvedRoleId = await this.resolveUserRole(roleId, roleName);
1184
1319
  const updatedUser = await this.userRepository.update(id, { roleId: resolvedRoleId });
1185
- return this.sanitizeUser(updatedUser);
1320
+ return this.sanitizeUser(this.requireUser(updatedUser));
1186
1321
  }
1187
1322
  async removeRole(id) {
1188
- await this.userValidator.checkUserExists(id);
1189
1323
  const updatedUser = await this.userRepository.update(id, { roleId: null });
1190
- return this.sanitizeUser(updatedUser);
1324
+ return this.sanitizeUser(this.requireUser(updatedUser));
1191
1325
  }
1192
1326
  async seedAdminUser(config) {
1193
1327
  if (!config?.email || !config?.password) {
@@ -1222,133 +1356,32 @@ var UserService = class UserService2 {
1222
1356
  return this.i18nService.getCurrentLanguage();
1223
1357
  }
1224
1358
  };
1225
- __decorate7([
1359
+ __decorate8([
1360
+ I18n3("users"),
1361
+ __metadata8("design:type", Object)
1362
+ ], UserService.prototype, "t", void 0);
1363
+ __decorate8([
1226
1364
  Transaction(),
1227
- __metadata7("design:type", Function),
1228
- __metadata7("design:paramtypes", [typeof (_g = typeof Record !== "undefined" && Record) === "function" ? _g : Object]),
1229
- __metadata7("design:returntype", typeof (_h = typeof Promise !== "undefined" && Promise) === "function" ? _h : Object)
1365
+ __metadata8("design:type", Function),
1366
+ __metadata8("design:paramtypes", [typeof (_g = typeof Record !== "undefined" && Record) === "function" ? _g : Object]),
1367
+ __metadata8("design:returntype", typeof (_h = typeof Promise !== "undefined" && Promise) === "function" ? _h : Object)
1230
1368
  ], UserService.prototype, "create", null);
1231
- UserService = __decorate7([
1369
+ UserService = __decorate8([
1232
1370
  Injectable5(),
1233
- __param2(6, Inject4(AUTH_CONFIG)),
1234
- __metadata7("design:paramtypes", [typeof (_a4 = typeof RoleValidator !== "undefined" && RoleValidator) === "function" ? _a4 : Object, typeof (_b3 = typeof RoleService !== "undefined" && RoleService) === "function" ? _b3 : Object, typeof (_c = typeof UserRepository !== "undefined" && UserRepository) === "function" ? _c : Object, typeof (_d = typeof UserValidator !== "undefined" && UserValidator) === "function" ? _d : Object, typeof (_e = typeof EncryptionService !== "undefined" && EncryptionService) === "function" ? _e : Object, typeof (_f = typeof I18nService !== "undefined" && I18nService) === "function" ? _f : Object, Object])
1371
+ __param2(6, Inject5(AUTH_CONFIG)),
1372
+ __metadata8("design:paramtypes", [typeof (_a5 = typeof RoleValidator !== "undefined" && RoleValidator) === "function" ? _a5 : Object, typeof (_b3 = typeof RoleService !== "undefined" && RoleService) === "function" ? _b3 : Object, typeof (_c = typeof UserRepository !== "undefined" && UserRepository) === "function" ? _c : Object, typeof (_d = typeof UserValidator !== "undefined" && UserValidator) === "function" ? _d : Object, typeof (_e = typeof EncryptionService !== "undefined" && EncryptionService) === "function" ? _e : Object, typeof (_f = typeof I18nService !== "undefined" && I18nService) === "function" ? _f : Object, Object])
1235
1373
  ], UserService);
1236
1374
 
1237
- // src/auth/CookieManager.ts
1238
- import { Service, Inject as Inject5 } from "najm-core";
1239
- import { CookieService } from "najm-cookies";
1240
- import timestring from "timestring";
1241
- var __decorate8 = function(decorators, target, key, desc) {
1242
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1243
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1244
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1245
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1246
- };
1247
- var __metadata8 = function(k, v) {
1248
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1249
- };
1250
- var _a5;
1251
- var CookieManager = class CookieManager2 {
1252
- static {
1253
- __name(this, "CookieManager");
1254
- }
1255
- config;
1256
- cookieService;
1257
- get cookieName() {
1258
- return this.config.refreshCookieName || "refreshToken";
1259
- }
1260
- get sessionCookieName() {
1261
- return this.config.session.name;
1262
- }
1263
- get sessionMaxAge() {
1264
- return this.config.session.maxAge;
1265
- }
1266
- get sessionSecret() {
1267
- return this.config.session.secret || this.config.jwt.accessSecret;
1268
- }
1269
- // =========================================================================
1270
- // Refresh Token Cookie
1271
- // =========================================================================
1272
- setRefreshToken(refreshToken) {
1273
- const maxAge = timestring(this.config.jwt.refreshExpiresIn, "s");
1274
- this.cookieService.set(this.cookieName, refreshToken, { maxAge });
1275
- }
1276
- clearRefreshToken() {
1277
- this.cookieService.delete(this.cookieName);
1278
- }
1279
- getRefreshToken() {
1280
- return this.cookieService.get(this.cookieName);
1281
- }
1282
- hasRefreshToken() {
1283
- return this.cookieService.has(this.cookieName);
1284
- }
1285
- getCookieName() {
1286
- return this.cookieName;
1287
- }
1288
- // =========================================================================
1289
- // Session Cookie Cache (HMAC-signed, short-lived)
1290
- // =========================================================================
1291
- /**
1292
- * Write a signed session cookie containing user data, roles, and permissions.
1293
- * The cookie is HMAC-signed with the access secret so it is tamper-proof
1294
- * but readable without a database query. Short TTL (5 min) ensures freshness.
1295
- */
1296
- setSessionCookie(data) {
1297
- const payload = { ...data, iat: Date.now() };
1298
- this.cookieService.setSigned(this.sessionCookieName, JSON.stringify(payload), this.sessionSecret, {
1299
- maxAge: this.sessionMaxAge,
1300
- httpOnly: true,
1301
- sameSite: "Lax",
1302
- path: "/"
1303
- });
1304
- }
1305
- /**
1306
- * Read and verify the session cookie. Returns null if missing, expired,
1307
- * or signature verification fails.
1308
- */
1309
- getSessionCookie() {
1310
- const raw = this.cookieService.getSigned(this.sessionCookieName, this.sessionSecret);
1311
- if (!raw)
1312
- return null;
1313
- try {
1314
- const data = JSON.parse(raw);
1315
- const age = Date.now() - data.iat;
1316
- if (age > this.sessionMaxAge * 1e3)
1317
- return null;
1318
- return data;
1319
- } catch {
1320
- return null;
1321
- }
1322
- }
1323
- /**
1324
- * Clear the session cookie (on logout, password change, etc.)
1325
- */
1326
- clearSessionCookie() {
1327
- this.cookieService.delete(this.sessionCookieName);
1328
- }
1329
- };
1330
- __decorate8([
1331
- Inject5(AUTH_CONFIG),
1332
- __metadata8("design:type", Object)
1333
- ], CookieManager.prototype, "config", void 0);
1334
- __decorate8([
1335
- Inject5(CookieService),
1336
- __metadata8("design:type", typeof (_a5 = typeof CookieService !== "undefined" && CookieService) === "function" ? _a5 : Object)
1337
- ], CookieManager.prototype, "cookieService", void 0);
1338
- CookieManager = __decorate8([
1339
- Service()
1340
- ], CookieManager);
1341
-
1342
1375
  // src/tokens/TokenService.ts
1343
1376
  import { Injectable as Injectable6, Inject as Inject7 } from "najm-core";
1344
- import { I18n as I18n3 } from "najm-i18n";
1377
+ import { I18n as I18n4 } from "najm-i18n";
1345
1378
  import { CacheService } from "najm-cache";
1346
1379
  import { createHash } from "crypto";
1347
1380
  import jwt from "jsonwebtoken";
1348
1381
  import { nanoid as nanoid5 } from "nanoid";
1349
1382
 
1350
1383
  // src/tokens/TokenRepository.ts
1351
- import { eq as eq4 } from "drizzle-orm";
1384
+ import { and, eq as eq4, isNull } from "drizzle-orm";
1352
1385
  import { Repository as Repository3, Inject as Inject6 } from "najm-core";
1353
1386
  import { DB as DB3 } from "najm-database";
1354
1387
  var __decorate9 = function(decorators, target, key, desc) {
@@ -1372,12 +1405,10 @@ var TokenRepository = class TokenRepository2 {
1372
1405
  get users() {
1373
1406
  return this.schema.users;
1374
1407
  }
1375
- get roles() {
1376
- return this.schema.roles;
1377
- }
1378
1408
  /** Shared query helper */
1409
+ queryHelper;
1379
1410
  get q() {
1380
- return new AuthQueries(this.db, this.schema);
1411
+ return this.queryHelper ??= new AuthQueries(this.db, this.schema);
1381
1412
  }
1382
1413
  async storeRefreshToken(tokenData) {
1383
1414
  return await this.db.insert(this.tokens).values(tokenData).onConflictDoUpdate({
@@ -1392,8 +1423,16 @@ var TokenRepository = class TokenRepository2 {
1392
1423
  }
1393
1424
  }).returning();
1394
1425
  }
1395
- async markPreviousUsed(userId) {
1396
- return await this.db.update(this.tokens).set({ previousUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(eq4(this.tokens.userId, userId)).returning();
1426
+ /**
1427
+ * Claim the previous-token grace slot. Conditional on BOTH the stored
1428
+ * previousHash still matching the presented token AND previousUsedAt being
1429
+ * NULL. Gating on the hash (not just the flag) closes the rotation race: the
1430
+ * winner's rotation rewrites previousHash via storeRefreshToken, so a loser
1431
+ * whose UPDATE lands after that rotation no longer matches and gets zero
1432
+ * rows — exactly one caller ever claims the slot.
1433
+ */
1434
+ async markPreviousUsed(userId, previousHash) {
1435
+ return await this.db.update(this.tokens).set({ previousUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and(eq4(this.tokens.userId, userId), eq4(this.tokens.previousHash, previousHash), isNull(this.tokens.previousUsedAt))).returning();
1397
1436
  }
1398
1437
  async getRefreshTokenWithFamily(userId) {
1399
1438
  const [token] = await this.db.select().from(this.tokens).where(eq4(this.tokens.userId, userId));
@@ -1420,13 +1459,7 @@ var TokenRepository = class TokenRepository2 {
1420
1459
  return this.q.getRoleAndPermissions(userId);
1421
1460
  }
1422
1461
  async getUser(userId) {
1423
- const [user] = await this.db.select(this.q.userSelection()).from(this.users).leftJoin(this.roles, eq4(this.users.roleId, this.roles.id)).where(eq4(this.users.id, userId)).limit(1);
1424
- if (!user)
1425
- return null;
1426
- return {
1427
- ...user,
1428
- permissions: await this.q.getUserPermissions(userId)
1429
- };
1462
+ return await this.q.getUserWithPermissions(eq4(this.users.id, userId)) ?? null;
1430
1463
  }
1431
1464
  };
1432
1465
  __decorate9([
@@ -1486,6 +1519,27 @@ var TokenService = class TokenService2 {
1486
1519
  get sessionVersionPrefix() {
1487
1520
  return "auth:session-version:";
1488
1521
  }
1522
+ sessionVersionKey(userId) {
1523
+ return `${this.sessionVersionPrefix}${userId}`;
1524
+ }
1525
+ accessTokenTtlMs() {
1526
+ return timestring2(this.config.jwt.accessExpiresIn, "ms");
1527
+ }
1528
+ expiresAt(expiresIn) {
1529
+ return Math.floor((Date.now() + timestring2(expiresIn, "ms")) / 1e3);
1530
+ }
1531
+ async getCacheValues(keys) {
1532
+ const cache2 = this.cache;
1533
+ if (cache2.getMany)
1534
+ return cache2.getMany(keys);
1535
+ return Promise.all(keys.map((key) => cache2.get(key)));
1536
+ }
1537
+ parseSessionVersion(raw) {
1538
+ if (!raw)
1539
+ return 0;
1540
+ const parsed = Number(raw);
1541
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
1542
+ }
1489
1543
  // ============ TOKEN VALIDATION ============
1490
1544
  extractAccessToken(authorization) {
1491
1545
  if (authorization?.startsWith("Bearer ")) {
@@ -1504,13 +1558,20 @@ var TokenService = class TokenService2 {
1504
1558
  } catch {
1505
1559
  Err5(this.t("errors.tokenVerificationFailed"));
1506
1560
  }
1561
+ const sessionKey = this.sessionVersionKey(payload.userId);
1562
+ let activeSessionVersion;
1507
1563
  if (payload.jti) {
1508
- const isBlacklisted = await this.isTokenBlacklisted(payload.jti);
1509
- if (isBlacklisted) {
1564
+ const [blacklisted, sessionVersion] = await this.getCacheValues([
1565
+ `${this.blacklistPrefix}${payload.jti}`,
1566
+ sessionKey
1567
+ ]);
1568
+ if (blacklisted !== null) {
1510
1569
  Err5(this.t("errors.tokenRevoked"));
1511
1570
  }
1571
+ activeSessionVersion = this.parseSessionVersion(sessionVersion);
1572
+ } else {
1573
+ activeSessionVersion = this.parseSessionVersion(await this.cache.get(sessionKey));
1512
1574
  }
1513
- const activeSessionVersion = await this.getUserSessionVersion(payload.userId);
1514
1575
  const tokenSessionVersion = payload.sessionVersion ?? 0;
1515
1576
  if (tokenSessionVersion !== activeSessionVersion) {
1516
1577
  Err5(this.t("errors.tokenRevoked"));
@@ -1529,38 +1590,16 @@ var TokenService = class TokenService2 {
1529
1590
  }
1530
1591
  }
1531
1592
  static PREVIOUS_GRACE_SECONDS = 120;
1532
- /**
1533
- * Validate a refresh token as an active session:
1534
- * 1. Verify JWT signature and type claim
1535
- * 2. Compare hash against current stored token
1536
- * 3. If mismatch, check previous hash within short grace window
1537
- * 4. Reject anything older or outside the grace window
1538
- */
1539
- async validateRefreshSession(refreshToken) {
1540
- const userId = this.verifyRefreshToken(refreshToken);
1541
- const stored = await this.tokenRepository.getRefreshTokenWithFamily(userId);
1542
- if (!stored) {
1543
- Err5(this.t("errors.refreshTokenInvalid"));
1544
- }
1545
- const presentedHash = this.hashToken(refreshToken);
1546
- if (presentedHash === stored.token) {
1547
- return { userId };
1548
- }
1549
- const canRecover = stored.previousHash && presentedHash === stored.previousHash && stored.previousValidUntil && new Date(stored.previousValidUntil).getTime() > Date.now() && !stored.previousUsedAt;
1550
- if (canRecover) {
1551
- await this.tokenRepository.markPreviousUsed(userId);
1552
- const tokens = await this.generateTokens(userId, stored.tokenFamily ?? void 0);
1553
- return {
1554
- userId,
1555
- rotatedTokens: { refreshToken: tokens.refreshToken, tokenFamily: stored.tokenFamily }
1556
- };
1557
- }
1558
- Err5(this.t("errors.refreshTokenInvalid"));
1559
- }
1560
1593
  /**
1561
1594
  * Read the refresh cookie and return the userId it belongs to.
1562
1595
  * Validates against current/previous token state with bounded recovery.
1563
1596
  * Throws if the cookie is missing, invalid, or outside the grace window.
1597
+ *
1598
+ * Intentionally side-effect-free: unlike refreshTokens(), a mismatch here
1599
+ * does NOT revoke the suspect family. This is a read path (e.g. GET
1600
+ * /auth/me) — a stray stale cookie on a read must not be able to destroy
1601
+ * the active session. Reuse detection and revocation belong to the
1602
+ * rotation path only.
1564
1603
  */
1565
1604
  async resolveUserFromCookie() {
1566
1605
  const refreshToken = this.cookieManager.getRefreshToken();
@@ -1588,14 +1627,19 @@ var TokenService = class TokenService2 {
1588
1627
  return null;
1589
1628
  const token = this.extractAccessToken(auth2);
1590
1629
  const { userId } = await this.verifyAccessToken(token);
1630
+ return this.getUserById(userId);
1631
+ }
1632
+ async getUserById(userId) {
1591
1633
  const cacheKey = `auth:user:${userId}`;
1634
+ if (typeof this.cache.getOrSet === "function") {
1635
+ return this.cache.getOrSet(cacheKey, () => this.tokenRepository.getUser(userId), 3e4);
1636
+ }
1592
1637
  const cached = await this.cache.get(cacheKey);
1593
1638
  if (cached)
1594
1639
  return JSON.parse(cached);
1595
1640
  const user = await this.tokenRepository.getUser(userId);
1596
- if (user) {
1641
+ if (user)
1597
1642
  await this.cache.set(cacheKey, JSON.stringify(user), 3e4);
1598
- }
1599
1643
  return user;
1600
1644
  }
1601
1645
  // ============ TOKEN GENERATION ============
@@ -1605,25 +1649,37 @@ var TokenService = class TokenService2 {
1605
1649
  getTokenExpire(token) {
1606
1650
  return jwt.decode(token)?.exp;
1607
1651
  }
1652
+ decodeAccessToken(token) {
1653
+ return jwt.decode(token);
1654
+ }
1655
+ async signAccessToken(data) {
1656
+ const jti = nanoid5(16);
1657
+ const sessionVersion = await this.getUserSessionVersion(data.userId);
1658
+ const expiresAt = this.expiresAt(this.config.jwt.accessExpiresIn);
1659
+ if (sessionVersion > 0) {
1660
+ await this.cache.set(this.sessionVersionKey(data.userId), String(sessionVersion), this.accessTokenTtlMs());
1661
+ }
1662
+ const token = jwt.sign({ ...data, jti, sessionVersion, exp: expiresAt }, this.config.jwt.accessSecret);
1663
+ return { token, expiresAt };
1664
+ }
1608
1665
  /**
1609
1666
  * Generate access token with unique jti for blacklist support.
1610
1667
  * Includes roles/permissions for client-side RBAC/PBAC.
1611
1668
  */
1612
1669
  async generateAccessToken(data) {
1613
- const jti = nanoid5(16);
1614
- const sessionVersion = await this.getUserSessionVersion(data.userId);
1615
- return jwt.sign({ ...data, jti, sessionVersion }, this.config.jwt.accessSecret, {
1616
- expiresIn: this.config.jwt.accessExpiresIn
1617
- });
1670
+ return (await this.signAccessToken(data)).token;
1618
1671
  }
1619
1672
  /**
1620
1673
  * Generate refresh token with unique jti
1621
1674
  */
1622
- generateRefreshToken(data) {
1675
+ signRefreshToken(data) {
1623
1676
  const jti = nanoid5(16);
1624
- return jwt.sign({ ...data, jti, type: "refresh" }, this.config.jwt.refreshSecret, {
1625
- expiresIn: this.config.jwt.refreshExpiresIn
1626
- });
1677
+ const expiresAt = this.expiresAt(this.config.jwt.refreshExpiresIn);
1678
+ const token = jwt.sign({ ...data, jti, type: "refresh", exp: expiresAt }, this.config.jwt.refreshSecret);
1679
+ return { token, expiresAt };
1680
+ }
1681
+ generateRefreshToken(data) {
1682
+ return this.signRefreshToken(data).token;
1627
1683
  }
1628
1684
  async generateTokens(userId, tokenFamily) {
1629
1685
  const family = tokenFamily ?? nanoid5(16);
@@ -1633,14 +1689,17 @@ var TokenService = class TokenService2 {
1633
1689
  roles: roleName ? [roleName] : [],
1634
1690
  permissions: permissions ?? []
1635
1691
  };
1636
- const accessToken = await this.generateAccessToken(accessTokenData);
1637
- const refreshToken = this.generateRefreshToken({ userId });
1638
- await this.storeRefreshToken(userId, refreshToken, family);
1692
+ const access = await this.signAccessToken(accessTokenData);
1693
+ const refresh = this.signRefreshToken({ userId });
1694
+ await this.storeRefreshToken(userId, refresh.token, family);
1639
1695
  return {
1640
- accessToken,
1641
- refreshToken,
1642
- accessTokenExpiresAt: this.getTokenExpire(accessToken),
1643
- refreshTokenExpiresAt: this.getTokenExpire(refreshToken)
1696
+ userId,
1697
+ roles: accessTokenData.roles,
1698
+ permissions: accessTokenData.permissions,
1699
+ accessToken: access.token,
1700
+ refreshToken: refresh.token,
1701
+ accessTokenExpiresAt: access.expiresAt,
1702
+ refreshTokenExpiresAt: refresh.expiresAt
1644
1703
  };
1645
1704
  }
1646
1705
  // ============ TOKEN BLACKLIST (Cache) ============
@@ -1666,7 +1725,7 @@ var TokenService = class TokenService2 {
1666
1725
  async blacklistCurrentToken(token) {
1667
1726
  try {
1668
1727
  const decoded = jwt.decode(token);
1669
- if (!decoded.jti) {
1728
+ if (!decoded?.jti) {
1670
1729
  return;
1671
1730
  }
1672
1731
  const now = Math.floor(Date.now() / 1e3);
@@ -1717,9 +1776,13 @@ var TokenService = class TokenService2 {
1717
1776
  }
1718
1777
  const canRecover = stored.previousHash && presentedHash === stored.previousHash && stored.previousValidUntil && new Date(stored.previousValidUntil).getTime() > Date.now() && !stored.previousUsedAt;
1719
1778
  if (canRecover) {
1720
- await this.tokenRepository.markPreviousUsed(userId);
1779
+ const claimed = await this.tokenRepository.markPreviousUsed(userId, presentedHash);
1780
+ if (!claimed?.length) {
1781
+ Err5(this.t("errors.refreshTokenInvalid"));
1782
+ }
1721
1783
  return this.generateTokens(userId, stored.tokenFamily ?? void 0);
1722
1784
  }
1785
+ await this.revokeSuspectRefreshFamily(userId, stored.tokenFamily ?? null);
1723
1786
  Err5(this.t("errors.refreshTokenInvalid"));
1724
1787
  }
1725
1788
  async revokeToken(userId) {
@@ -1727,10 +1790,26 @@ var TokenService = class TokenService2 {
1727
1790
  }
1728
1791
  async invalidateUserAccessTokens(userId) {
1729
1792
  const nextVersion = await this.getUserSessionVersion(userId) + 1;
1730
- await this.cache.set(`${this.sessionVersionPrefix}${userId}`, String(nextVersion));
1793
+ await this.cache.set(this.sessionVersionKey(userId), String(nextVersion), this.accessTokenTtlMs());
1731
1794
  await this.cache.del(`auth:user:${userId}`);
1732
1795
  return nextVersion;
1733
1796
  }
1797
+ async getUserFromCookie() {
1798
+ const userId = await this.resolveUserFromCookie();
1799
+ const user = await this.getUserById(userId);
1800
+ if (!user) {
1801
+ Err5(this.t("errors.refreshTokenInvalid"));
1802
+ }
1803
+ return user;
1804
+ }
1805
+ async revokeSuspectRefreshFamily(userId, tokenFamily) {
1806
+ await this.invalidateUserAccessTokens(userId);
1807
+ if (tokenFamily) {
1808
+ await this.tokenRepository.revokeByFamily(tokenFamily);
1809
+ return;
1810
+ }
1811
+ await this.revokeToken(userId);
1812
+ }
1734
1813
  /**
1735
1814
  * Logout user - blacklist access token and revoke refresh token
1736
1815
  */
@@ -1787,11 +1866,7 @@ var TokenService = class TokenService2 {
1787
1866
  return decoded.userId;
1788
1867
  }
1789
1868
  async getUserSessionVersion(userId) {
1790
- const raw = await this.cache.get(`${this.sessionVersionPrefix}${userId}`);
1791
- if (!raw)
1792
- return 0;
1793
- const parsed = Number(raw);
1794
- return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
1869
+ return this.parseSessionVersion(await this.cache.get(this.sessionVersionKey(userId)));
1795
1870
  }
1796
1871
  };
1797
1872
  __decorate10([
@@ -1799,7 +1874,7 @@ __decorate10([
1799
1874
  __metadata10("design:type", Object)
1800
1875
  ], TokenService.prototype, "config", void 0);
1801
1876
  __decorate10([
1802
- I18n3("auth"),
1877
+ I18n4("auth"),
1803
1878
  __metadata10("design:type", Object)
1804
1879
  ], TokenService.prototype, "t", void 0);
1805
1880
  TokenService = TokenService_1 = __decorate10([
@@ -1809,7 +1884,6 @@ TokenService = TokenService_1 = __decorate10([
1809
1884
 
1810
1885
  // src/auth/AuthService.ts
1811
1886
  import timestring3 from "timestring";
1812
- import jwt2 from "jsonwebtoken";
1813
1887
  var __decorate11 = function(decorators, target, key, desc) {
1814
1888
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1815
1889
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -1819,34 +1893,33 @@ var __decorate11 = function(decorators, target, key, desc) {
1819
1893
  var __metadata11 = function(k, v) {
1820
1894
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1821
1895
  };
1822
- var AuthService_1;
1823
1896
  var _a7;
1824
1897
  var _b5;
1825
1898
  var _c3;
1826
1899
  var _d2;
1827
1900
  var _e2;
1828
1901
  var _f2;
1902
+ var _g2;
1829
1903
  var AuthService = class AuthService2 {
1830
1904
  static {
1831
1905
  __name(this, "AuthService");
1832
1906
  }
1833
- static {
1834
- AuthService_1 = this;
1835
- }
1836
1907
  tokenService;
1837
1908
  userService;
1838
1909
  userValidator;
1910
+ encryptionService;
1839
1911
  cookieManager;
1840
1912
  i18nService;
1841
1913
  emailService;
1842
1914
  config;
1843
1915
  t;
1844
1916
  logger;
1845
- static DUMMY_HASH = "$2b$10$dummyhashfortimingatackprevention000000000000000";
1846
- constructor(tokenService, userService, userValidator, cookieManager, i18nService, emailService) {
1917
+ dummyHash;
1918
+ constructor(tokenService, userService, userValidator, encryptionService, cookieManager, i18nService, emailService) {
1847
1919
  this.tokenService = tokenService;
1848
1920
  this.userService = userService;
1849
1921
  this.userValidator = userValidator;
1922
+ this.encryptionService = encryptionService;
1850
1923
  this.cookieManager = cookieManager;
1851
1924
  this.i18nService = i18nService;
1852
1925
  this.emailService = emailService;
@@ -1860,20 +1933,12 @@ var AuthService = class AuthService2 {
1860
1933
  const durationMs = timestring3(this.config.lockout.duration, "ms");
1861
1934
  return new Date(Date.now() + durationMs).toISOString();
1862
1935
  }
1863
- /**
1864
- * Decode JWT payload without verification (token was just generated by us).
1865
- * Used to extract accurate roles/permissions for the session cookie cache.
1866
- */
1867
- decodeAccessToken(accessToken) {
1868
- try {
1869
- const decoded = jwt2.decode(accessToken);
1870
- return {
1871
- roles: decoded?.roles ?? [],
1872
- permissions: decoded?.permissions ?? []
1873
- };
1874
- } catch {
1875
- return { roles: [], permissions: [] };
1876
- }
1936
+ getDummyHash() {
1937
+ this.dummyHash ??= this.encryptionService.hashPassword("najm-auth-dummy-password");
1938
+ return this.dummyHash;
1939
+ }
1940
+ async warmupPasswordHash() {
1941
+ await this.getDummyHash();
1877
1942
  }
1878
1943
  async registerUser(body) {
1879
1944
  return await this.userService.create(body);
@@ -1889,7 +1954,7 @@ var AuthService = class AuthService2 {
1889
1954
  if (user && this.isLockoutActive(user.lockoutUntil)) {
1890
1955
  Err6(this.t("errors.accountLocked"), 423);
1891
1956
  }
1892
- const storedHash = user?.password ?? AuthService_1.DUMMY_HASH;
1957
+ const storedHash = user?.password ?? await this.getDummyHash();
1893
1958
  const isValid = await this.userValidator.comparePassword(password, storedHash);
1894
1959
  if (!user || !isValid) {
1895
1960
  if (user) {
@@ -1907,34 +1972,34 @@ var AuthService = class AuthService2 {
1907
1972
  if ((user.failedLoginAttempts ?? 0) > 0 || user.lockoutUntil) {
1908
1973
  await this.userService.resetFailedAttempts(user.id);
1909
1974
  }
1910
- const data = await this.tokenService.generateTokens(user.id);
1911
- this.cookieManager.setRefreshToken(data.refreshToken);
1975
+ const generated = await this.tokenService.generateTokens(user.id);
1976
+ this.cookieManager.setRefreshToken(generated.refreshToken);
1912
1977
  await this.userService.updateLastLogin(user.id);
1913
1978
  const { password: _, failedLoginAttempts: __, lockoutUntil: ___, ...sanitized } = user;
1914
- const { roles, permissions } = this.decodeAccessToken(data.accessToken);
1979
+ const { roles, permissions } = generated;
1915
1980
  this.cookieManager.setSessionCookie({
1916
- user: { id: sanitized.id, email: sanitized.email, name: sanitized.name, role: sanitized.role },
1981
+ user: { id: sanitized.id, email: sanitized.email, name: sanitized.name, role: sanitized.role, status: sanitized.status ?? void 0 },
1917
1982
  roles,
1918
1983
  permissions
1919
1984
  });
1920
- return { ...data, user: sanitized };
1985
+ const { userId: _userId, roles: _roles, permissions: _permissions, ...tokens } = generated;
1986
+ return { ...tokens, user: sanitized };
1921
1987
  }
1922
1988
  async refreshTokens() {
1923
- const data = await this.tokenService.refreshTokens();
1924
- this.cookieManager.setRefreshToken(data.refreshToken);
1925
- const user = await this.tokenService.getUser(`Bearer ${data.accessToken}`);
1989
+ const generated = await this.tokenService.refreshTokens();
1990
+ this.cookieManager.setRefreshToken(generated.refreshToken);
1991
+ const user = await this.tokenService.getUserById(generated.userId);
1926
1992
  if (user) {
1927
- const { roles, permissions } = this.decodeAccessToken(data.accessToken);
1928
1993
  this.cookieManager.setSessionCookie({
1929
- user: { id: user.id, email: user.email, name: user.name, role: user.role },
1930
- roles,
1931
- permissions
1994
+ user: { id: user.id, email: user.email, name: user.name, role: user.role, status: user.status ?? void 0 },
1995
+ roles: generated.roles,
1996
+ permissions: generated.permissions
1932
1997
  });
1933
1998
  }
1934
- return data;
1999
+ const { userId: _userId, roles: _roles, permissions: _permissions, ...tokens } = generated;
2000
+ return tokens;
1935
2001
  }
1936
2002
  async logoutUser(userId, authorization) {
1937
- await this.userValidator.checkUserExists(userId);
1938
2003
  await this.tokenService.logout(userId, authorization);
1939
2004
  this.cookieManager.clearRefreshToken();
1940
2005
  this.cookieManager.clearSessionCookie();
@@ -1948,8 +2013,7 @@ var AuthService = class AuthService2 {
1948
2013
  };
1949
2014
  }
1950
2015
  async getUserFromCookie() {
1951
- const userId = await this.tokenService.resolveUserFromCookie();
1952
- const user = await this.userService.getById(userId);
2016
+ const user = await this.tokenService.getUserFromCookie();
1953
2017
  const lang = this.i18nService.getCurrentLanguage();
1954
2018
  return { ...user, language: lang };
1955
2019
  }
@@ -1958,10 +2022,7 @@ var AuthService = class AuthService2 {
1958
2022
  * fall back to cookie when no Authorization header is present.
1959
2023
  *
1960
2024
  * Refreshes the session cookie cache only when authoritative roles/permissions
1961
- * are available (from the access token JWT). When called via the refresh-cookie
1962
- * fallback, we cannot reliably populate permissions without a DB round-trip,
1963
- * so we leave the existing cache alone — it will be refreshed by the next
1964
- * login/refresh cycle.
2025
+ * are available from the access token.
1965
2026
  */
1966
2027
  async getMe(authorization) {
1967
2028
  let result;
@@ -1971,8 +2032,8 @@ var AuthService = class AuthService2 {
1971
2032
  if (user) {
1972
2033
  const lang = this.i18nService.getCurrentLanguage();
1973
2034
  result = { ...user, language: lang };
1974
- const token = authorization.replace(/^Bearer\s+/i, "");
1975
- cachePayload = this.decodeAccessToken(token);
2035
+ const token = this.tokenService.decodeAccessToken(authorization.replace(/^Bearer\s+/i, ""));
2036
+ cachePayload = { roles: token?.roles ?? [], permissions: token?.permissions ?? [] };
1976
2037
  } else {
1977
2038
  result = await this.getUserFromCookie();
1978
2039
  }
@@ -1981,7 +2042,7 @@ var AuthService = class AuthService2 {
1981
2042
  }
1982
2043
  if (cachePayload) {
1983
2044
  this.cookieManager.setSessionCookie({
1984
- user: { id: result.id, email: result.email, name: result.name, role: result.role },
2045
+ user: { id: result.id, email: result.email, name: result.name, role: result.role, status: result.status ?? void 0 },
1985
2046
  roles: cachePayload.roles,
1986
2047
  permissions: cachePayload.permissions
1987
2048
  });
@@ -2037,16 +2098,16 @@ __decorate11([
2037
2098
  __metadata11("design:type", Object)
2038
2099
  ], AuthService.prototype, "config", void 0);
2039
2100
  __decorate11([
2040
- I18n4("auth"),
2101
+ I18n5("auth"),
2041
2102
  __metadata11("design:type", Object)
2042
2103
  ], AuthService.prototype, "t", void 0);
2043
2104
  __decorate11([
2044
2105
  Log(),
2045
2106
  __metadata11("design:type", Object)
2046
2107
  ], AuthService.prototype, "logger", void 0);
2047
- AuthService = AuthService_1 = __decorate11([
2108
+ AuthService = __decorate11([
2048
2109
  Injectable7(),
2049
- __metadata11("design:paramtypes", [typeof (_a7 = typeof TokenService !== "undefined" && TokenService) === "function" ? _a7 : Object, typeof (_b5 = typeof UserService !== "undefined" && UserService) === "function" ? _b5 : Object, typeof (_c3 = typeof UserValidator !== "undefined" && UserValidator) === "function" ? _c3 : Object, typeof (_d2 = typeof CookieManager !== "undefined" && CookieManager) === "function" ? _d2 : Object, typeof (_e2 = typeof I18nService2 !== "undefined" && I18nService2) === "function" ? _e2 : Object, typeof (_f2 = typeof EmailService !== "undefined" && EmailService) === "function" ? _f2 : Object])
2110
+ __metadata11("design:paramtypes", [typeof (_a7 = typeof TokenService !== "undefined" && TokenService) === "function" ? _a7 : Object, typeof (_b5 = typeof UserService !== "undefined" && UserService) === "function" ? _b5 : Object, typeof (_c3 = typeof UserValidator !== "undefined" && UserValidator) === "function" ? _c3 : Object, typeof (_d2 = typeof EncryptionService !== "undefined" && EncryptionService) === "function" ? _d2 : Object, typeof (_e2 = typeof CookieManager !== "undefined" && CookieManager) === "function" ? _e2 : Object, typeof (_f2 = typeof I18nService2 !== "undefined" && I18nService2) === "function" ? _f2 : Object, typeof (_g2 = typeof EmailService !== "undefined" && EmailService) === "function" ? _g2 : Object])
2050
2111
  ], AuthService);
2051
2112
 
2052
2113
  // src/auth/AuthGuard.ts
@@ -2088,6 +2149,7 @@ var isAuth = createGuard(AuthGuard);
2088
2149
  // src/auth/AuthController.ts
2089
2150
  import { Validate } from "najm-validation";
2090
2151
  import { RateLimit } from "najm-rate";
2152
+ import { createHash as createHash2 } from "crypto";
2091
2153
 
2092
2154
  // src/users/UserDto.ts
2093
2155
  import { z } from "zod";
@@ -2135,6 +2197,10 @@ var assignRoleParams = z.object({
2135
2197
  userId: z.string().min(1, "User ID is required"),
2136
2198
  roleId: z.string().min(1)
2137
2199
  });
2200
+ var userListQuery = z.object({
2201
+ limit: z.coerce.number().int().min(1).max(100).default(50),
2202
+ offset: z.coerce.number().int().min(0).default(0)
2203
+ });
2138
2204
 
2139
2205
  // src/auth/AuthController.ts
2140
2206
  var __decorate13 = function(decorators, target, key, desc) {
@@ -2152,25 +2218,22 @@ var __param4 = function(paramIndex, decorator) {
2152
2218
  };
2153
2219
  };
2154
2220
  var _a8;
2155
- var _configuredCookieName = "refreshToken";
2156
- var setConfiguredCookieName = /* @__PURE__ */ __name((name) => {
2157
- _configuredCookieName = name;
2158
- }, "setConfiguredCookieName");
2159
- var cookieFingerprint = /* @__PURE__ */ __name((cookieName) => (ctx) => {
2160
- const name = cookieName ?? _configuredCookieName;
2221
+ var hashKeyPart = /* @__PURE__ */ __name((value) => createHash2("sha256").update(value).digest("base64url").slice(0, 32), "hashKeyPart");
2222
+ var cookieFingerprint = /* @__PURE__ */ __name(() => (ctx) => {
2161
2223
  const ip = ctx.req.header("x-forwarded-for")?.split(",")[0]?.trim() ?? ctx.req.header("x-real-ip") ?? "unknown";
2162
- const cookie = ctx.req.raw.headers.get("cookie");
2163
- const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2164
- const match = cookie?.match(new RegExp(`${escaped}=([^;]+)`));
2165
- const fingerprint = match?.[1]?.slice(-8) ?? "none";
2224
+ const cookie = ctx.req.raw.headers.get("cookie") ?? "";
2225
+ const fingerprint = cookie ? hashKeyPart(cookie) : "none";
2166
2226
  return `${ip}:${fingerprint}`;
2167
2227
  }, "cookieFingerprint");
2168
2228
  var ipAndEmail = /* @__PURE__ */ __name(async (ctx) => {
2169
2229
  const ip = ctx.req.header("x-forwarded-for")?.split(",")[0]?.trim() ?? ctx.req.header("x-real-ip") ?? "unknown";
2170
2230
  try {
2171
2231
  const body = await ctx.req.json();
2172
- if (body?.email)
2173
- return `${ip}:${body.email}`;
2232
+ if (body?.email && typeof body.email === "string") {
2233
+ const normalizedEmail = body.email.trim().toLowerCase();
2234
+ if (normalizedEmail)
2235
+ return `${ip}:${hashKeyPart(normalizedEmail)}`;
2236
+ }
2174
2237
  } catch {
2175
2238
  }
2176
2239
  return ip;
@@ -2291,21 +2354,6 @@ AuthController = __decorate13([
2291
2354
  __metadata13("design:paramtypes", [typeof (_a8 = typeof AuthService !== "undefined" && AuthService) === "function" ? _a8 : Object])
2292
2355
  ], AuthController);
2293
2356
 
2294
- // src/auth/index.ts
2295
- var auth_exports = {};
2296
- __export(auth_exports, {
2297
- AUTH_MODULE: () => AUTH_MODULE,
2298
- AuthController: () => AuthController,
2299
- AuthGuard: () => AuthGuard,
2300
- AuthResolver: () => AuthResolver,
2301
- AuthService: () => AuthService,
2302
- CookieManager: () => CookieManager,
2303
- EncryptionService: () => EncryptionService,
2304
- isAuth: () => isAuth,
2305
- runAsUser: () => runAsUser,
2306
- setConfiguredCookieName: () => setConfiguredCookieName
2307
- });
2308
-
2309
2357
  // src/auth/AuthResolver.ts
2310
2358
  import { APP, Container, DI, Inject as Inject9, LOGGER, Meta, Service as Service3 } from "najm-core";
2311
2359
  import { USER, ROLE, PERMISSIONS } from "najm-guard";
@@ -2345,6 +2393,22 @@ var AuthResolver = class AuthResolver2 {
2345
2393
  return false;
2346
2394
  }
2347
2395
  }
2396
+ async resolveFromSessionCookie() {
2397
+ try {
2398
+ const cookieManager = await this.container.resolve(CookieManager);
2399
+ const session = cookieManager.getSessionCookie();
2400
+ if (!session)
2401
+ return false;
2402
+ return {
2403
+ user: { ...session.user, permissions: session.permissions },
2404
+ role: session.user.role ?? session.roles[0],
2405
+ permissions: session.permissions
2406
+ };
2407
+ } catch (error) {
2408
+ this.log.warn("Session cookie verification failed", error);
2409
+ return false;
2410
+ }
2411
+ }
2348
2412
  /**
2349
2413
  * Resolve the current user from the refresh cookie (cookie-only flow,
2350
2414
  * e.g. Next.js Server Components calling /auth/me with just the cookie).
@@ -2356,11 +2420,7 @@ var AuthResolver = class AuthResolver2 {
2356
2420
  async resolveFromCookie() {
2357
2421
  try {
2358
2422
  const tokenService = await this.container.resolve(TokenService);
2359
- const userId = await tokenService.resolveUserFromCookie();
2360
- if (!userId)
2361
- return false;
2362
- const userService = await this.container.resolve(UserService);
2363
- const user = await userService.getById(userId);
2423
+ const user = await tokenService.getUserFromCookie();
2364
2424
  if (!user)
2365
2425
  return false;
2366
2426
  return {
@@ -2377,7 +2437,7 @@ var AuthResolver = class AuthResolver2 {
2377
2437
  this.app.use("*", async (c, next) => {
2378
2438
  const raw = c.req.header("authorization") ?? "";
2379
2439
  const token = raw.replace(/^Bearer\s+/i, "").trim();
2380
- const result = token ? await this.resolve(token) || await this.resolveFromCookie() : await this.resolveFromCookie();
2440
+ const result = token ? await this.resolve(token) || await this.resolveFromCookie() : await this.resolveFromSessionCookie() || await this.resolveFromCookie();
2381
2441
  if (result) {
2382
2442
  if (this.container.isActive()) {
2383
2443
  this.container.set(USER, result.user);
@@ -2386,28 +2446,23 @@ var AuthResolver = class AuthResolver2 {
2386
2446
  if (result.permissions !== void 0)
2387
2447
  this.container.set(PERMISSIONS, result.permissions);
2388
2448
  } else {
2389
- const als = this.container.store?.als;
2390
- if (als && typeof als.getStore === "function") {
2391
- const previousStore = als.getStore();
2392
- const nextStore = new Map(previousStore);
2393
- nextStore.set(USER.key, result.user);
2394
- if (result.role !== void 0)
2395
- nextStore.set(ROLE.key, result.role);
2396
- if (result.permissions !== void 0)
2397
- nextStore.set(PERMISSIONS.key, result.permissions);
2398
- als.store = nextStore;
2399
- try {
2400
- await next();
2401
- return;
2402
- } finally {
2403
- als.store = previousStore;
2404
- }
2405
- }
2449
+ const store = {
2450
+ [USER.key]: result.user
2451
+ };
2452
+ if (result.role !== void 0)
2453
+ store[ROLE.key] = result.role;
2454
+ if (result.permissions !== void 0)
2455
+ store[PERMISSIONS.key] = result.permissions;
2456
+ return await this.container.run(store, next);
2406
2457
  }
2407
2458
  }
2408
2459
  await next();
2409
2460
  });
2410
2461
  }
2462
+ async onReady() {
2463
+ const authService = await this.container.resolve(AuthService);
2464
+ await authService.warmupPasswordHash();
2465
+ }
2411
2466
  };
2412
2467
  __decorate14([
2413
2468
  DI(),
@@ -2476,13 +2531,14 @@ __export(users_exports, {
2476
2531
  resetPasswordDto: () => resetPasswordDto,
2477
2532
  updateUserDto: () => updateUserDto,
2478
2533
  userIdInParam: () => userIdInParam,
2479
- userIdParam: () => userIdParam
2534
+ userIdParam: () => userIdParam,
2535
+ userListQuery: () => userListQuery
2480
2536
  });
2481
2537
 
2482
2538
  // src/users/UserController.ts
2483
2539
  import { Controller as Controller3 } from "najm-core";
2484
2540
  import { Get as Get3, Post as Post3, Put as Put2, Delete as Delete2, ResMsg as ResMsg3 } from "najm-core";
2485
- import { Params as Params2, Body as Body3 } from "najm-core";
2541
+ import { Params as Params2, Body as Body3, Query } from "najm-core";
2486
2542
 
2487
2543
  // src/roles/index.ts
2488
2544
  var roles_exports = {};
@@ -2734,8 +2790,8 @@ var UserController = class UserController2 {
2734
2790
  constructor(userService) {
2735
2791
  this.userService = userService;
2736
2792
  }
2737
- async getUsers() {
2738
- return this.userService.getAll();
2793
+ async getUsers(query) {
2794
+ return this.userService.getAll(userListQuery.parse(query ?? {}));
2739
2795
  }
2740
2796
  async getLang() {
2741
2797
  const language = await this.userService.getLang();
@@ -2775,9 +2831,11 @@ var UserController = class UserController2 {
2775
2831
  __decorate17([
2776
2832
  Get3(),
2777
2833
  isAdmin(),
2834
+ Validate3({ query: userListQuery }),
2778
2835
  ResMsg3("users.success.retrieved"),
2836
+ __param7(0, Query()),
2779
2837
  __metadata17("design:type", Function),
2780
- __metadata17("design:paramtypes", []),
2838
+ __metadata17("design:paramtypes", [Object]),
2781
2839
  __metadata17("design:returntype", Promise)
2782
2840
  ], UserController.prototype, "getUsers", null);
2783
2841
  __decorate17([
@@ -2912,7 +2970,7 @@ __export(permissions_exports, {
2912
2970
  });
2913
2971
 
2914
2972
  // src/permissions/PermissionRepository.ts
2915
- import { eq as eq5, and } from "drizzle-orm";
2973
+ import { eq as eq5, and as and2 } from "drizzle-orm";
2916
2974
  import { Repository as Repository4, Inject as Inject10 } from "najm-core";
2917
2975
  import { DB as DB4 } from "najm-database";
2918
2976
  var __decorate18 = function(decorators, target, key, desc) {
@@ -2986,11 +3044,11 @@ var PermissionRepository = class PermissionRepository2 {
2986
3044
  return newRolePermission;
2987
3045
  }
2988
3046
  async removePermissionFromRole(roleId, permissionId) {
2989
- const [deletedRolePermission] = await this.db.delete(this.rolePermissions).where(and(eq5(this.rolePermissions.roleId, roleId), eq5(this.rolePermissions.permissionId, permissionId))).returning();
3047
+ const [deletedRolePermission] = await this.db.delete(this.rolePermissions).where(and2(eq5(this.rolePermissions.roleId, roleId), eq5(this.rolePermissions.permissionId, permissionId))).returning();
2990
3048
  return deletedRolePermission;
2991
3049
  }
2992
3050
  async checkRoleHasPermission(roleId, permissionId) {
2993
- const [rolePermission] = await this.db.select().from(this.rolePermissions).where(and(eq5(this.rolePermissions.roleId, roleId), eq5(this.rolePermissions.permissionId, permissionId)));
3051
+ const [rolePermission] = await this.db.select().from(this.rolePermissions).where(and2(eq5(this.rolePermissions.roleId, roleId), eq5(this.rolePermissions.permissionId, permissionId)));
2994
3052
  return !!rolePermission;
2995
3053
  }
2996
3054
  async deleteAll() {
@@ -3080,7 +3138,7 @@ import { Injectable as Injectable10 } from "najm-core";
3080
3138
 
3081
3139
  // src/permissions/PermissionValidator.ts
3082
3140
  import { Injectable as Injectable9 } from "najm-core";
3083
- import { I18n as I18n5 } from "najm-i18n";
3141
+ import { I18n as I18n6 } from "najm-i18n";
3084
3142
  import { Err as Err7 } from "najm-core";
3085
3143
  var __decorate20 = function(decorators, target, key, desc) {
3086
3144
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -3160,7 +3218,7 @@ var PermissionValidator = class PermissionValidator2 {
3160
3218
  }
3161
3219
  };
3162
3220
  __decorate20([
3163
- I18n5("permissions"),
3221
+ I18n6("permissions"),
3164
3222
  __metadata20("design:type", Object)
3165
3223
  ], PermissionValidator.prototype, "t", void 0);
3166
3224
  PermissionValidator = __decorate20([
@@ -3519,7 +3577,7 @@ var revokeTokenDto = z4.object({
3519
3577
  });
3520
3578
 
3521
3579
  // src/ownership/scopedOwnership.ts
3522
- import { aliasedTable, eq as eq6, getTableColumns, sql as sql4 } from "drizzle-orm";
3580
+ import { aliasedTable, eq as eq6, getTableColumns, sql as sql5 } from "drizzle-orm";
3523
3581
  var DEFAULT_ADMIN_ROLES = ["admin"];
3524
3582
  var DRIZZLE_NAME = /* @__PURE__ */ Symbol.for("drizzle:Name");
3525
3583
  var DRIZZLE_BASE_NAME = /* @__PURE__ */ Symbol.for("drizzle:BaseName");
@@ -3656,7 +3714,7 @@ var OwnershipToken = class {
3656
3714
  return query;
3657
3715
  const rule = this._rules[role];
3658
3716
  if (!rule)
3659
- return query.where(sql4`1 = 0`);
3717
+ return query.where(sql5`1 = 0`);
3660
3718
  const { query: q, condition } = rule(uid, query);
3661
3719
  return q.where(condition);
3662
3720
  }
@@ -3671,7 +3729,7 @@ var OwnershipToken = class {
3671
3729
  return { query, condition: null };
3672
3730
  const rule = this._rules[role];
3673
3731
  if (!rule)
3674
- return { query, condition: sql4`1 = 0` };
3732
+ return { query, condition: sql5`1 = 0` };
3675
3733
  return rule(uid, query);
3676
3734
  }
3677
3735
  };
@@ -4030,7 +4088,7 @@ __name(Policy, "Policy");
4030
4088
 
4031
4089
  // src/ownership/OwnedDecorator.ts
4032
4090
  import "reflect-metadata";
4033
- import { sql as sql5, and as and2 } from "drizzle-orm";
4091
+ import { sql as sql6, and as and3 } from "drizzle-orm";
4034
4092
  import { Injectable as Injectable12, Inject as Inject12, DI as DI2, Container as Container2, REQUEST_ID } from "najm-core";
4035
4093
  import { USER as USER2 } from "najm-guard";
4036
4094
  var __decorate24 = function(decorators, target, key, desc) {
@@ -4100,7 +4158,7 @@ function Owned(token) {
4100
4158
  return null;
4101
4159
  if (filtered.length === 1)
4102
4160
  return filtered[0];
4103
- return and2(...filtered);
4161
+ return and3(...filtered);
4104
4162
  }
4105
4163
  __name(combineConditions, "combineConditions");
4106
4164
  function applyQueryOptions(query, opts = {}, whereCondition) {
@@ -4119,7 +4177,7 @@ function Owned(token) {
4119
4177
  return query;
4120
4178
  const user = getUser(this);
4121
4179
  if (!user)
4122
- return query.where(sql5`1 = 0`);
4180
+ return query.where(sql6`1 = 0`);
4123
4181
  return token.applyScope(user.id, user.role, query);
4124
4182
  };
4125
4183
  },
@@ -4265,6 +4323,10 @@ var DEFAULT_JWT = {
4265
4323
  refreshExpiresIn: process.env.REFRESH_EXPIRES_IN || "7d"
4266
4324
  };
4267
4325
  var mergeConfig = /* @__PURE__ */ __name((config) => {
4326
+ const bcryptRounds = config?.bcryptRounds ?? 10;
4327
+ if (!Number.isInteger(bcryptRounds) || bcryptRounds < 4 || bcryptRounds > 31) {
4328
+ throw new Error("auth.bcryptRounds must be an integer between 4 and 31");
4329
+ }
4268
4330
  const finalConfig = {
4269
4331
  jwt: {
4270
4332
  ...DEFAULT_JWT,
@@ -4280,6 +4342,7 @@ var mergeConfig = /* @__PURE__ */ __name((config) => {
4280
4342
  maxAttempts: config?.lockout?.maxAttempts ?? 5,
4281
4343
  duration: config?.lockout?.duration ?? "15m"
4282
4344
  },
4345
+ bcryptRounds,
4283
4346
  session: {
4284
4347
  name: config?.session?.name ?? "najm.session",
4285
4348
  maxAge: config?.session?.maxAge ?? 300,
@@ -4293,7 +4356,6 @@ var mergeConfig = /* @__PURE__ */ __name((config) => {
4293
4356
  if (!finalConfig.jwt.refreshSecret) {
4294
4357
  throw Err8.configRequired("auth", "JWT_REFRESH_SECRET");
4295
4358
  }
4296
- setConfiguredCookieName(finalConfig.refreshCookieName);
4297
4359
  return finalConfig;
4298
4360
  }, "mergeConfig");
4299
4361
  var selectSchema = /* @__PURE__ */ __name((config) => {
@@ -4313,7 +4375,6 @@ var selectSchema = /* @__PURE__ */ __name((config) => {
4313
4375
  var auth = /* @__PURE__ */ __name((config) => plugin("auth").version("1.0.0").depends(cache(), cookies(), i18n(), guards(), validation(config?.validation), rateLimit(config?.rateLimit), email()).requires("database").contributes(I18N_CONTRIBUTIONS, AUTH_LOCALES).services(auth_exports, users_exports, roles_exports, permissions_exports, tokens_exports, ScopeContext).config(AUTH_CONFIG, mergeConfig(config)).set(AUTH_SCHEMA, selectSchema(config)).set(AUTH_ENCRYPTION_KEY, config?.encryptionKey ?? null).build(), "auth");
4314
4376
 
4315
4377
  // src/seed.ts
4316
- import { hash } from "bcryptjs";
4317
4378
  var toSeedId = /* @__PURE__ */ __name((prefix, value) => {
4318
4379
  const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 48);
4319
4380
  return `${prefix}_${normalized || "item"}`;
@@ -4364,7 +4425,7 @@ var authSeed = /* @__PURE__ */ __name((config) => ({
4364
4425
  const users = [
4365
4426
  {
4366
4427
  email: config.adminEmail,
4367
- password: await hash(config.adminPass, 10),
4428
+ password: await hashPassword(config.adminPass, config.bcryptRounds ?? 10),
4368
4429
  roleId: adminRole.id,
4369
4430
  emailVerified: true,
4370
4431
  status: "active",
@@ -4384,7 +4445,7 @@ var authSeed = /* @__PURE__ */ __name((config) => ({
4384
4445
  }
4385
4446
  users.push({
4386
4447
  email: user.email,
4387
- password: await hash(user.password, 10),
4448
+ password: await hashPassword(user.password, config.bcryptRounds ?? 10),
4388
4449
  roleId: role.id,
4389
4450
  emailVerified: user.emailVerified ?? true,
4390
4451
  status: user.status ?? "active",
@@ -4415,6 +4476,7 @@ async function seedAuthData(config) {
4415
4476
  return await seeder.run(authSeed({
4416
4477
  adminEmail: config.adminEmail,
4417
4478
  adminPass: config.adminPassword,
4479
+ bcryptRounds: config.bcryptRounds,
4418
4480
  roles: config.roles,
4419
4481
  permissions: config.permissions,
4420
4482
  additionalUsers: config.users
@@ -4536,7 +4598,6 @@ export {
4536
4598
  rolesTable,
4537
4599
  runAsUser,
4538
4600
  seedAuthData,
4539
- setConfiguredCookieName,
4540
4601
  tokenIdParam,
4541
4602
  tokenStatusEnum,
4542
4603
  tokenTypeEnum,
@@ -4547,6 +4608,7 @@ export {
4547
4608
  updateUserDto,
4548
4609
  userIdInParam,
4549
4610
  userIdParam,
4611
+ userListQuery,
4550
4612
  userStatusEnum,
4551
4613
  usersTable,
4552
4614
  verifyTokenDto,