@mesob/auth-hono 0.4.6 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,23 +11,6 @@ import { deepmerge } from "deepmerge-ts";
11
11
  import { drizzle } from "drizzle-orm/node-postgres";
12
12
  import { Pool } from "pg";
13
13
 
14
- // src/db/relations.ts
15
- var relations_exports = {};
16
- __export(relations_exports, {
17
- accountChangesInIamRelations: () => accountChangesInIamRelations,
18
- accountsInIamRelations: () => accountsInIamRelations,
19
- domainsInIamRelations: () => domainsInIamRelations,
20
- permissionsInIamRelations: () => permissionsInIamRelations,
21
- rolePermissionsInIamRelations: () => rolePermissionsInIamRelations,
22
- rolesInIamRelations: () => rolesInIamRelations,
23
- sessionsInIamRelations: () => sessionsInIamRelations,
24
- tenantsInIamRelations: () => tenantsInIamRelations,
25
- userRolesInIamRelations: () => userRolesInIamRelations,
26
- usersInIamRelations: () => usersInIamRelations,
27
- verificationsInIamRelations: () => verificationsInIamRelations
28
- });
29
- import { relations } from "drizzle-orm/relations";
30
-
31
14
  // src/db/schema.ts
32
15
  var schema_exports = {};
33
16
  __export(schema_exports, {
@@ -333,117 +316,8 @@ var domainsInIam = iam.table("domains", {
333
316
  check("domains_status_check", sql`status = ANY (ARRAY['PENDING'::text, 'ACTIVE'::text, 'DISABLED'::text, 'DELETED'::text])`)
334
317
  ]);
335
318
 
336
- // src/db/relations.ts
337
- var verificationsInIamRelations = relations(verificationsInIam, ({ one }) => ({
338
- tenantsInIam: one(tenantsInIam, {
339
- fields: [verificationsInIam.tenantId],
340
- references: [tenantsInIam.id]
341
- }),
342
- usersInIam: one(usersInIam, {
343
- fields: [verificationsInIam.userId],
344
- references: [usersInIam.id]
345
- })
346
- }));
347
- var tenantsInIamRelations = relations(tenantsInIam, ({ many }) => ({
348
- verificationsInIam: many(verificationsInIam),
349
- sessionsInIam: many(sessionsInIam),
350
- accountChangesInIam: many(accountChangesInIam),
351
- rolePermissionsInIam: many(rolePermissionsInIam),
352
- accountsInIam: many(accountsInIam),
353
- usersInIam: many(usersInIam),
354
- rolesInIam: many(rolesInIam),
355
- userRolesInIam: many(userRolesInIam),
356
- domainsInIam: many(domainsInIam)
357
- }));
358
- var usersInIamRelations = relations(usersInIam, ({ one, many }) => ({
359
- verificationsInIam: many(verificationsInIam),
360
- sessionsInIam: many(sessionsInIam),
361
- accountChangesInIam: many(accountChangesInIam),
362
- accountsInIam: many(accountsInIam),
363
- tenantsInIam: one(tenantsInIam, {
364
- fields: [usersInIam.tenantId],
365
- references: [tenantsInIam.id]
366
- }),
367
- userRolesInIam: many(userRolesInIam)
368
- }));
369
- var sessionsInIamRelations = relations(sessionsInIam, ({ one }) => ({
370
- tenantsInIam: one(tenantsInIam, {
371
- fields: [sessionsInIam.tenantId],
372
- references: [tenantsInIam.id]
373
- }),
374
- usersInIam: one(usersInIam, {
375
- fields: [sessionsInIam.userId],
376
- references: [usersInIam.id]
377
- })
378
- }));
379
- var accountChangesInIamRelations = relations(accountChangesInIam, ({ one }) => ({
380
- tenantsInIam: one(tenantsInIam, {
381
- fields: [accountChangesInIam.tenantId],
382
- references: [tenantsInIam.id]
383
- }),
384
- usersInIam: one(usersInIam, {
385
- fields: [accountChangesInIam.userId],
386
- references: [usersInIam.id]
387
- })
388
- }));
389
- var rolePermissionsInIamRelations = relations(rolePermissionsInIam, ({ one }) => ({
390
- tenantsInIam: one(tenantsInIam, {
391
- fields: [rolePermissionsInIam.tenantId],
392
- references: [tenantsInIam.id]
393
- }),
394
- permissionsInIam: one(permissionsInIam, {
395
- fields: [rolePermissionsInIam.permissionId],
396
- references: [permissionsInIam.id]
397
- }),
398
- rolesInIam: one(rolesInIam, {
399
- fields: [rolePermissionsInIam.tenantId],
400
- references: [rolesInIam.tenantId]
401
- })
402
- }));
403
- var permissionsInIamRelations = relations(permissionsInIam, ({ many }) => ({
404
- rolePermissionsInIam: many(rolePermissionsInIam)
405
- }));
406
- var rolesInIamRelations = relations(rolesInIam, ({ one, many }) => ({
407
- rolePermissionsInIam: many(rolePermissionsInIam),
408
- tenantsInIam: one(tenantsInIam, {
409
- fields: [rolesInIam.tenantId],
410
- references: [tenantsInIam.id]
411
- }),
412
- userRolesInIam: many(userRolesInIam)
413
- }));
414
- var accountsInIamRelations = relations(accountsInIam, ({ one }) => ({
415
- tenantsInIam: one(tenantsInIam, {
416
- fields: [accountsInIam.tenantId],
417
- references: [tenantsInIam.id]
418
- }),
419
- usersInIam: one(usersInIam, {
420
- fields: [accountsInIam.userId],
421
- references: [usersInIam.id]
422
- })
423
- }));
424
- var userRolesInIamRelations = relations(userRolesInIam, ({ one }) => ({
425
- tenantsInIam: one(tenantsInIam, {
426
- fields: [userRolesInIam.tenantId],
427
- references: [tenantsInIam.id]
428
- }),
429
- usersInIam: one(usersInIam, {
430
- fields: [userRolesInIam.userId],
431
- references: [usersInIam.id]
432
- }),
433
- rolesInIam: one(rolesInIam, {
434
- fields: [userRolesInIam.tenantId],
435
- references: [rolesInIam.tenantId]
436
- })
437
- }));
438
- var domainsInIamRelations = relations(domainsInIam, ({ one }) => ({
439
- tenantsInIam: one(tenantsInIam, {
440
- fields: [domainsInIam.tenantId],
441
- references: [tenantsInIam.id]
442
- })
443
- }));
444
-
445
319
  // src/db/index.ts
446
- var schemaConfig = { schema: { ...schema_exports, ...relations_exports } };
320
+ var schemaConfig = { schema: { ...schema_exports } };
447
321
  var createDatabase = (connectionString) => {
448
322
  const pool = new Pool({ connectionString });
449
323
  return drizzle({ client: pool, ...schemaConfig });
@@ -612,6 +486,7 @@ var fetchUserWithRoles = async ({
612
486
  emailVerified: usersInIam.emailVerified,
613
487
  phoneVerified: usersInIam.phoneVerified,
614
488
  lastSignInAt: usersInIam.lastSignInAt,
489
+ bannedUntil: usersInIam.bannedUntil,
615
490
  ...getUserAuthSelect(tenantId)
616
491
  }).from(usersInIam).where(and4(eq4(usersInIam.id, userId), eq4(usersInIam.tenantId, tenantId))).limit(1);
617
492
  return userResult || null;
@@ -862,6 +737,7 @@ var userSchema = z.object({
862
737
  emailVerified: z.boolean(),
863
738
  phoneVerified: z.boolean(),
864
739
  lastSignInAt: z.string().datetime().nullable(),
740
+ bannedUntil: z.string().datetime().nullable().optional(),
865
741
  createdAt: z.string().datetime().nullable().optional(),
866
742
  userType: z.array(z.string()).optional(),
867
743
  roles: z.array(z.string()).nullable().optional(),
@@ -993,6 +869,8 @@ var checkAccountResponseSchema = z.object({
993
869
  verified: z.boolean(),
994
870
  hasPassword: z.boolean(),
995
871
  requiresPasswordSetup: z.boolean(),
872
+ needsVerification: z.boolean().optional(),
873
+ verificationId: z.string().uuid().optional(),
996
874
  account: authAccountSchema.nullable()
997
875
  });
998
876
  var updateProfileSchema = z.object({
@@ -1019,7 +897,7 @@ var pendingAccountChangeResponseSchema = z.object({
1019
897
  });
1020
898
 
1021
899
  // src/routes/auth/handler/check-account.ts
1022
- import { and as and5, eq as eq5, sql as sql4 } from "drizzle-orm";
900
+ import { and as and6, eq as eq6, sql as sql4 } from "drizzle-orm";
1023
901
 
1024
902
  // src/lib/tenant.ts
1025
903
  import { HTTPException as HTTPException2 } from "hono/http-exception";
@@ -1041,79 +919,9 @@ var ensureTenantId = (config, tenantId) => {
1041
919
  return config.tenant.tenantId;
1042
920
  };
1043
921
 
1044
- // src/routes/auth/handler/check-account.ts
1045
- var checkAccountHandler = async (c) => {
1046
- const body = c.req.valid("json");
1047
- const config = c.get("config");
1048
- const database = c.get("database");
1049
- const tenantId = c.get("tenantId");
1050
- const resolvedTenantId = ensureTenantId(config, tenantId);
1051
- const { username } = body;
1052
- const isEmail = username.includes("@");
1053
- const userTypeFilter = sql4`${usersInIam.userType} @> ARRAY[${config.userType}]::text[]`;
1054
- const whereClause = isEmail ? and5(
1055
- eq5(usersInIam.tenantId, resolvedTenantId),
1056
- userTypeFilter,
1057
- sql4`lower(${usersInIam.email}) = lower(${username})`
1058
- ) : and5(
1059
- eq5(usersInIam.tenantId, resolvedTenantId),
1060
- userTypeFilter,
1061
- eq5(usersInIam.phone, username)
1062
- );
1063
- const [result] = await database.select({
1064
- fullName: usersInIam.fullName,
1065
- email: usersInIam.email,
1066
- phone: usersInIam.phone,
1067
- verified: isEmail ? usersInIam.emailVerified : usersInIam.phoneVerified,
1068
- hasPassword: sql4`exists(
1069
- select 1
1070
- from ${accountsInIam}
1071
- where ${eq5(accountsInIam.tenantId, resolvedTenantId)}
1072
- and ${eq5(accountsInIam.userId, usersInIam.id)}
1073
- and ${eq5(accountsInIam.provider, "credentials")}
1074
- and ${sql4`${accountsInIam.password} is not null`}
1075
- )`
1076
- }).from(usersInIam).where(whereClause).limit(1);
1077
- const verified = result?.verified ?? false;
1078
- const hasPassword = result?.hasPassword ?? false;
1079
- return c.json(
1080
- {
1081
- exists: !!result,
1082
- verified,
1083
- hasPassword,
1084
- requiresPasswordSetup: !!result && verified && !hasPassword,
1085
- account: result ? {
1086
- fullName: result.fullName,
1087
- email: result.email,
1088
- phone: result.phone,
1089
- verified,
1090
- hasPassword,
1091
- requiresPasswordSetup: verified && !hasPassword
1092
- } : null
1093
- },
1094
- 200
1095
- );
1096
- };
1097
-
1098
- // src/routes/auth/handler/sign-in.ts
1099
- import { logger as logger2 } from "@mesob/common";
1100
- import { and as and9, eq as eq9 } from "drizzle-orm";
1101
-
1102
- // src/errors.ts
1103
- var AUTH_ERRORS = {
1104
- USER_NOT_FOUND: "USER_NOT_FOUND",
1105
- INVALID_PASSWORD: "INVALID_PASSWORD",
1106
- USER_EXISTS: "USER_EXISTS",
1107
- VERIFICATION_EXPIRED: "VERIFICATION_EXPIRED",
1108
- VERIFICATION_MISMATCH: "VERIFICATION_MISMATCH",
1109
- VERIFICATION_NOT_FOUND: "VERIFICATION_NOT_FOUND",
1110
- TOO_MANY_ATTEMPTS: "TOO_MANY_ATTEMPTS",
1111
- REQUIRES_VERIFICATION: "REQUIRES_VERIFICATION",
1112
- UNAUTHORIZED: "UNAUTHORIZED",
1113
- ACCESS_DENIED: "ACCESS_DENIED",
1114
- HAS_NO_PASSWORD: "HAS_NO_PASSWORD",
1115
- PASSWORD_ALREADY_SET: "PASSWORD_ALREADY_SET"
1116
- };
922
+ // src/routes/auth/helper/verification.ts
923
+ import { dayjs as dayjs2 } from "@mesob/common";
924
+ import { and as and5, desc, eq as eq5, gt as gt2 } from "drizzle-orm";
1117
925
 
1118
926
  // src/lib/normalize-auth-response.ts
1119
927
  var normalizeAuthUser = (user) => ({
@@ -1207,278 +1015,125 @@ var getRefreshedExpiresAt = ({
1207
1015
  return addDuration(duration);
1208
1016
  };
1209
1017
 
1210
- // src/routes/auth/helper/session.ts
1211
- import { and as and6, asc, eq as eq6, gt as gt2, inArray, sql as sql5 } from "drizzle-orm";
1212
- var createSessionRecord = async ({
1018
+ // src/routes/auth/helper/verification.ts
1019
+ var createVerification = async ({
1213
1020
  tx,
1214
1021
  tenantId,
1215
1022
  userId,
1216
- config,
1217
- userAgent,
1218
- ip,
1219
- action,
1220
- rememberMe,
1221
- expiresIn
1023
+ type,
1024
+ to,
1025
+ config
1222
1026
  }) => {
1223
- const sessionToken = generateToken();
1224
- const hashedToken = await hashToken(sessionToken, config.secret);
1225
- const sessionDuration = expiresIn || getSessionDuration({
1226
- sessionConfig: config.session,
1227
- rememberMe: rememberMe ?? true
1228
- });
1229
- const expiresAt = addDuration(sessionDuration);
1230
- const meta = { action };
1231
- if (rememberMe !== void 0) {
1232
- meta.rememberMe = rememberMe;
1233
- }
1234
- const [session] = await tx.insert(sessionsInIam).values({
1027
+ const isPhone = type === "phone-otp-sign-up";
1028
+ const code = generateOtpCode(
1029
+ isPhone ? config.phone.otpLength : config.email.otpLength
1030
+ );
1031
+ const hashedCode = await hashToken(code, config.secret);
1032
+ const expiresAt = addDuration(
1033
+ isPhone ? config.phone.expiresIn : config.email.expiresIn
1034
+ );
1035
+ const [verification] = await tx.insert(verificationsInIam).values({
1235
1036
  tenantId,
1236
1037
  userId,
1237
- token: hashedToken,
1038
+ type,
1039
+ code: hashedCode,
1238
1040
  expiresAt,
1239
- userAgent,
1240
- ip,
1241
- meta
1242
- }).returning({
1243
- id: sessionsInIam.id,
1244
- expiresAt: sessionsInIam.expiresAt,
1245
- createdAt: sessionsInIam.createdAt,
1246
- updatedAt: sessionsInIam.updatedAt,
1247
- userAgent: sessionsInIam.userAgent,
1248
- ip: sessionsInIam.ip
1249
- });
1250
- return { session, sessionToken, expiresAt };
1041
+ to,
1042
+ attempt: 0
1043
+ }).returning();
1044
+ return { verificationId: verification.id, code, hash: hashedCode };
1251
1045
  };
1252
- var createSession = async ({
1253
- tx,
1254
- tenantId,
1255
- userId,
1046
+ var sendVerification = async ({
1047
+ channel,
1048
+ to,
1049
+ code,
1256
1050
  config,
1257
- userAgent,
1258
- ip,
1259
- rememberMe = true
1051
+ hash,
1052
+ type
1260
1053
  }) => {
1261
- const { session, sessionToken, expiresAt } = await createSessionRecord({
1262
- tx,
1263
- tenantId,
1264
- userId,
1265
- config,
1266
- userAgent,
1267
- ip,
1268
- rememberMe,
1269
- action: "sign-up"
1270
- });
1271
- return { sessionId: session.id, sessionToken, expiresAt };
1054
+ if (channel === "phone" && config.phone.sendVerificationOTP) {
1055
+ await config.phone.sendVerificationOTP({
1056
+ phone: to,
1057
+ code,
1058
+ hash,
1059
+ type
1060
+ });
1061
+ } else if (config.email.sendVerificationOTP) {
1062
+ await config.email.sendVerificationOTP({
1063
+ email: to,
1064
+ code,
1065
+ hash,
1066
+ type
1067
+ });
1068
+ }
1272
1069
  };
1273
- var cleanupOldSessions = async ({
1070
+ var checkVerificationResend = async ({
1274
1071
  database,
1275
- userId,
1276
1072
  tenantId,
1277
- maxSessions
1073
+ userId,
1074
+ type,
1075
+ resendInterval
1278
1076
  }) => {
1279
- const [{ count }] = await database.select({ count: sql5`count(*)` }).from(sessionsInIam).where(
1280
- and6(
1281
- eq6(sessionsInIam.tenantId, tenantId),
1282
- eq6(sessionsInIam.userId, userId),
1283
- gt2(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1284
- )
1285
- );
1286
- if (count <= maxSessions) {
1287
- return;
1077
+ if (!resendInterval) {
1078
+ return { blocked: false };
1288
1079
  }
1289
- const toDeleteCount = count - maxSessions;
1290
- const idsToDelete = await database.select({ id: sessionsInIam.id }).from(sessionsInIam).where(
1291
- and6(
1292
- eq6(sessionsInIam.tenantId, tenantId),
1293
- eq6(sessionsInIam.userId, userId),
1294
- gt2(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1080
+ const [verification] = await database.select({
1081
+ id: verificationsInIam.id,
1082
+ createdAt: verificationsInIam.createdAt
1083
+ }).from(verificationsInIam).where(
1084
+ and5(
1085
+ eq5(verificationsInIam.tenantId, tenantId),
1086
+ eq5(verificationsInIam.userId, userId),
1087
+ eq5(verificationsInIam.type, type)
1295
1088
  )
1296
- ).orderBy(asc(sessionsInIam.createdAt)).limit(toDeleteCount);
1297
- if (!idsToDelete.length) {
1298
- return;
1089
+ ).orderBy(desc(verificationsInIam.createdAt)).limit(1);
1090
+ if (!verification) {
1091
+ return { blocked: false };
1299
1092
  }
1300
- await database.delete(sessionsInIam).where(
1301
- and6(
1302
- eq6(sessionsInIam.tenantId, tenantId),
1303
- eq6(sessionsInIam.userId, userId),
1304
- inArray(
1305
- sessionsInIam.id,
1306
- idsToDelete.map((s) => s.id)
1307
- )
1308
- )
1309
- );
1093
+ const cooldownSeconds = parseDuration(resendInterval);
1094
+ const createdAt = dayjs2(verification.createdAt);
1095
+ const blocked = dayjs2().diff(createdAt, "second") < cooldownSeconds;
1096
+ return { blocked, verificationId: verification.id };
1310
1097
  };
1311
-
1312
- // src/routes/auth/helper/user.ts
1313
- import { and as and7, eq as eq7, gt as gt3, sql as sql6 } from "drizzle-orm";
1314
- var checkExistingUserStatus = async ({
1315
- tx,
1316
- identifier,
1098
+ var ensureVerificationForCheckAccount = async ({
1099
+ database,
1317
1100
  tenantId,
1318
- isEmail
1101
+ userId,
1102
+ type,
1103
+ to,
1104
+ config
1319
1105
  }) => {
1320
- const whereClause = isEmail ? and7(
1321
- eq7(usersInIam.tenantId, tenantId),
1322
- sql6`lower(${usersInIam.email}) = lower(${identifier})`
1323
- ) : and7(eq7(usersInIam.tenantId, tenantId), eq7(usersInIam.phone, identifier));
1324
- const [existingUser] = await tx.select().from(usersInIam).where(whereClause).limit(1);
1325
- if (!existingUser) {
1326
- return { action: "proceed" };
1327
- }
1328
- const isVerified = isEmail ? existingUser.emailVerified : existingUser.phoneVerified;
1329
- if (isVerified) {
1330
- return { action: "error", code: AUTH_ERRORS.USER_EXISTS };
1331
- }
1332
- const [pendingVerification] = await tx.select().from(verificationsInIam).where(
1333
- and7(
1334
- eq7(verificationsInIam.userId, existingUser.id),
1335
- eq7(verificationsInIam.tenantId, tenantId),
1336
- gt3(verificationsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1106
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1107
+ const [existing] = await database.select({
1108
+ id: verificationsInIam.id,
1109
+ expiresAt: verificationsInIam.expiresAt
1110
+ }).from(verificationsInIam).where(
1111
+ and5(
1112
+ eq5(verificationsInIam.tenantId, tenantId),
1113
+ eq5(verificationsInIam.userId, userId),
1114
+ eq5(verificationsInIam.type, type),
1115
+ gt2(verificationsInIam.expiresAt, now)
1337
1116
  )
1338
- ).limit(1);
1339
- if (pendingVerification) {
1340
- return {
1341
- action: "pending",
1342
- verificationId: pendingVerification.id,
1343
- user: existingUser
1344
- };
1117
+ ).orderBy(desc(verificationsInIam.createdAt)).limit(1);
1118
+ if (existing) {
1119
+ return { verificationId: existing.id };
1345
1120
  }
1346
- await deleteUnverifiedUser({ tx, userId: existingUser.id, tenantId });
1347
- return { action: "proceed" };
1348
- };
1349
- var deleteUnverifiedUser = async ({
1350
- tx,
1351
- userId,
1352
- tenantId
1353
- }) => {
1354
- await tx.delete(verificationsInIam).where(
1355
- and7(
1356
- eq7(verificationsInIam.userId, userId),
1357
- eq7(verificationsInIam.tenantId, tenantId)
1121
+ await database.delete(verificationsInIam).where(
1122
+ and5(
1123
+ eq5(verificationsInIam.tenantId, tenantId),
1124
+ eq5(verificationsInIam.userId, userId),
1125
+ eq5(verificationsInIam.type, type)
1358
1126
  )
1359
1127
  );
1360
- await tx.delete(accountsInIam).where(
1361
- and7(
1362
- eq7(accountsInIam.userId, userId),
1363
- eq7(accountsInIam.tenantId, tenantId)
1364
- )
1365
- );
1366
- await tx.delete(usersInIam).where(and7(eq7(usersInIam.id, userId), eq7(usersInIam.tenantId, tenantId)));
1367
- };
1368
- var createUserWithAccount = async ({
1369
- tx,
1370
- tenantId,
1371
- email,
1372
- phone,
1373
- password,
1374
- fullName,
1375
- handle,
1376
- config
1377
- }) => {
1378
- const [user] = await tx.insert(usersInIam).values({
1379
- tenantId,
1380
- fullName,
1381
- handle,
1382
- email: email || null,
1383
- phone: phone || null,
1384
- emailVerified: email ? !config.email.required : false,
1385
- phoneVerified: phone ? !config.phone.required : false,
1386
- userType: [config.userType]
1387
- }).returning();
1388
- const passwordHash = await hashPassword(password);
1389
- await tx.insert(accountsInIam).values({
1390
- tenantId,
1391
- userId: user.id,
1392
- provider: "credentials",
1393
- providerAccountId: email || phone || user.id,
1394
- password: passwordHash
1395
- });
1396
- return user;
1397
- };
1398
- var fetchUserForLogin = async ({
1399
- database,
1400
- identifier,
1401
- tenantId,
1402
- isEmail,
1403
- userType
1404
- }) => {
1405
- const userTypeFilter = sql6`${usersInIam.userType} @> ARRAY[${userType}]::text[]`;
1406
- const whereClause = isEmail ? and7(
1407
- eq7(usersInIam.tenantId, tenantId),
1408
- userTypeFilter,
1409
- sql6`lower(${usersInIam.email}) = lower(${identifier})`
1410
- ) : and7(
1411
- eq7(usersInIam.tenantId, tenantId),
1412
- userTypeFilter,
1413
- eq7(usersInIam.phone, identifier)
1414
- );
1415
- const [row] = await database.select({
1416
- id: usersInIam.id,
1417
- tenantId: usersInIam.tenantId,
1418
- fullName: usersInIam.fullName,
1419
- email: usersInIam.email,
1420
- phone: usersInIam.phone,
1421
- handle: usersInIam.handle,
1422
- image: usersInIam.image,
1423
- emailVerified: usersInIam.emailVerified,
1424
- phoneVerified: usersInIam.phoneVerified,
1425
- lastSignInAt: usersInIam.lastSignInAt,
1426
- bannedUntil: usersInIam.bannedUntil,
1427
- loginAttempt: usersInIam.loginAttempt,
1428
- hasPassword: sql6`exists(
1429
- select 1
1430
- from ${accountsInIam}
1431
- where ${eq7(accountsInIam.tenantId, tenantId)}
1432
- and ${eq7(accountsInIam.userId, usersInIam.id)}
1433
- and ${eq7(accountsInIam.provider, "credentials")}
1434
- and ${sql6`${accountsInIam.password} is not null`}
1435
- )`
1436
- }).from(usersInIam).where(whereClause).limit(1);
1437
- return row || null;
1438
- };
1439
- var fetchUserByIdWithRoles = async ({
1440
- database,
1441
- userId,
1442
- tenantId
1443
- }) => {
1444
- const [result] = await database.select({
1445
- id: usersInIam.id,
1446
- tenantId: usersInIam.tenantId,
1447
- fullName: usersInIam.fullName,
1448
- email: usersInIam.email,
1449
- phone: usersInIam.phone,
1450
- handle: usersInIam.handle,
1451
- image: usersInIam.image,
1452
- emailVerified: usersInIam.emailVerified,
1453
- phoneVerified: usersInIam.phoneVerified,
1454
- lastSignInAt: usersInIam.lastSignInAt,
1455
- bannedUntil: usersInIam.bannedUntil,
1456
- loginAttempt: usersInIam.loginAttempt,
1457
- ...getUserAuthSelect(tenantId)
1458
- }).from(usersInIam).where(and7(eq7(usersInIam.id, userId), eq7(usersInIam.tenantId, tenantId))).limit(1);
1459
- return result || null;
1460
- };
1461
-
1462
- // src/routes/auth/helper/verification.ts
1463
- import { dayjs as dayjs2 } from "@mesob/common";
1464
- import { and as and8, desc, eq as eq8 } from "drizzle-orm";
1465
- var createVerification = async ({
1466
- tx,
1467
- tenantId,
1468
- userId,
1469
- type,
1470
- to,
1471
- config
1472
- }) => {
1473
- const isPhone = type === "phone-otp-sign-up";
1474
- const code = generateOtpCode(
1475
- isPhone ? config.phone.otpLength : config.email.otpLength
1128
+ const isPhone = type === "phone-otp";
1129
+ const code = generateOtpCode(
1130
+ isPhone ? config.phone.otpLength : config.email.otpLength
1476
1131
  );
1477
1132
  const hashedCode = await hashToken(code, config.secret);
1478
1133
  const expiresAt = addDuration(
1479
1134
  isPhone ? config.phone.expiresIn : config.email.expiresIn
1480
1135
  );
1481
- const [verification] = await tx.insert(verificationsInIam).values({
1136
+ const [verification] = await database.insert(verificationsInIam).values({
1482
1137
  tenantId,
1483
1138
  userId,
1484
1139
  type,
@@ -1487,59 +1142,22 @@ var createVerification = async ({
1487
1142
  to,
1488
1143
  attempt: 0
1489
1144
  }).returning();
1490
- return { verificationId: verification.id, code, hash: hashedCode };
1491
- };
1492
- var sendVerification = async ({
1493
- channel,
1494
- to,
1495
- code,
1496
- config,
1497
- hash,
1498
- type
1499
- }) => {
1500
- if (channel === "phone" && config.phone.sendVerificationOTP) {
1145
+ if (isPhone && config.phone.sendVerificationOTP) {
1501
1146
  await config.phone.sendVerificationOTP({
1502
1147
  phone: to,
1503
1148
  code,
1504
- hash,
1149
+ hash: hashedCode,
1505
1150
  type
1506
1151
  });
1507
- } else if (config.email.sendVerificationOTP) {
1152
+ } else if (!isPhone && config.email.sendVerificationOTP) {
1508
1153
  await config.email.sendVerificationOTP({
1509
1154
  email: to,
1510
1155
  code,
1511
- hash,
1156
+ hash: hashedCode,
1512
1157
  type
1513
1158
  });
1514
1159
  }
1515
- };
1516
- var checkVerificationResend = async ({
1517
- database,
1518
- tenantId,
1519
- userId,
1520
- type,
1521
- resendInterval
1522
- }) => {
1523
- if (!resendInterval) {
1524
- return { blocked: false };
1525
- }
1526
- const [verification] = await database.select({
1527
- id: verificationsInIam.id,
1528
- createdAt: verificationsInIam.createdAt
1529
- }).from(verificationsInIam).where(
1530
- and8(
1531
- eq8(verificationsInIam.tenantId, tenantId),
1532
- eq8(verificationsInIam.userId, userId),
1533
- eq8(verificationsInIam.type, type)
1534
- )
1535
- ).orderBy(desc(verificationsInIam.createdAt)).limit(1);
1536
- if (!verification) {
1537
- return { blocked: false };
1538
- }
1539
- const cooldownSeconds = parseDuration(resendInterval);
1540
- const createdAt = dayjs2(verification.createdAt);
1541
- const blocked = dayjs2().diff(createdAt, "second") < cooldownSeconds;
1542
- return { blocked, verificationId: verification.id };
1160
+ return { verificationId: verification.id };
1543
1161
  };
1544
1162
  var handleEmailVerification = async ({
1545
1163
  c,
@@ -1552,10 +1170,10 @@ var handleEmailVerification = async ({
1552
1170
  return c.json({ error: "User email not found" }, 401);
1553
1171
  }
1554
1172
  await database.delete(verificationsInIam).where(
1555
- and8(
1556
- eq8(verificationsInIam.tenantId, tenantId),
1557
- eq8(verificationsInIam.userId, user.id),
1558
- eq8(verificationsInIam.type, "email-verification")
1173
+ and5(
1174
+ eq5(verificationsInIam.tenantId, tenantId),
1175
+ eq5(verificationsInIam.userId, user.id),
1176
+ eq5(verificationsInIam.type, "email-verification")
1559
1177
  )
1560
1178
  );
1561
1179
  const code = generateOtpCode(config.email.otpLength);
@@ -1588,72 +1206,418 @@ var handleEmailVerification = async ({
1588
1206
  type: "email-verification"
1589
1207
  });
1590
1208
  }
1591
- return c.json(
1592
- {
1593
- user: normalizeAuthUser(user),
1594
- session: null,
1595
- verificationId: verification.id,
1596
- requiresVerification: true
1597
- },
1598
- 200
1599
- );
1209
+ return c.json(
1210
+ {
1211
+ user: normalizeAuthUser(user),
1212
+ session: null,
1213
+ verificationId: verification.id,
1214
+ requiresVerification: true
1215
+ },
1216
+ 200
1217
+ );
1218
+ };
1219
+ var handlePhoneVerification = async ({
1220
+ c,
1221
+ user,
1222
+ config,
1223
+ database,
1224
+ tenantId
1225
+ }) => {
1226
+ if (!user.phone) {
1227
+ return c.json({ error: "User phone not found" }, 401);
1228
+ }
1229
+ await database.delete(verificationsInIam).where(
1230
+ and5(
1231
+ eq5(verificationsInIam.tenantId, tenantId),
1232
+ eq5(verificationsInIam.userId, user.id),
1233
+ eq5(verificationsInIam.type, "phone-otp")
1234
+ )
1235
+ );
1236
+ const code = generateOtpCode(config.phone.otpLength);
1237
+ const hashedCode = await hashToken(code, config.secret);
1238
+ const expiresAt = addDuration(config.phone.expiresIn);
1239
+ const [verification] = await database.insert(verificationsInIam).values({
1240
+ tenantId,
1241
+ userId: user.id,
1242
+ type: "phone-otp",
1243
+ code: hashedCode,
1244
+ expiresAt,
1245
+ to: user.phone,
1246
+ attempt: 0
1247
+ }).returning({
1248
+ id: verificationsInIam.id,
1249
+ tenantId: verificationsInIam.tenantId,
1250
+ userId: verificationsInIam.userId,
1251
+ type: verificationsInIam.type,
1252
+ code: verificationsInIam.code,
1253
+ to: verificationsInIam.to,
1254
+ expiresAt: verificationsInIam.expiresAt,
1255
+ createdAt: verificationsInIam.createdAt,
1256
+ attempt: verificationsInIam.attempt
1257
+ });
1258
+ if (config.phone.sendVerificationOTP) {
1259
+ await config.phone.sendVerificationOTP({
1260
+ phone: user.phone,
1261
+ code,
1262
+ hash: hashedCode,
1263
+ type: "phone-otp"
1264
+ });
1265
+ }
1266
+ return c.json(
1267
+ {
1268
+ user: normalizeAuthUser(user),
1269
+ session: null,
1270
+ verificationId: verification.id,
1271
+ requiresVerification: true
1272
+ },
1273
+ 200
1274
+ );
1275
+ };
1276
+
1277
+ // src/routes/auth/handler/check-account.ts
1278
+ var checkAccountHandler = async (c) => {
1279
+ const body = c.req.valid("json");
1280
+ const config = c.get("config");
1281
+ const database = c.get("database");
1282
+ const tenantId = c.get("tenantId");
1283
+ const resolvedTenantId = ensureTenantId(config, tenantId);
1284
+ const { username } = body;
1285
+ const isEmail = username.includes("@");
1286
+ const userTypeFilter = sql4`${usersInIam.userType} @> ARRAY[${config.userType}]::text[]`;
1287
+ const whereClause = isEmail ? and6(
1288
+ eq6(usersInIam.tenantId, resolvedTenantId),
1289
+ userTypeFilter,
1290
+ sql4`lower(${usersInIam.email}) = lower(${username})`
1291
+ ) : and6(
1292
+ eq6(usersInIam.tenantId, resolvedTenantId),
1293
+ userTypeFilter,
1294
+ eq6(usersInIam.phone, username)
1295
+ );
1296
+ const [result] = await database.select({
1297
+ id: usersInIam.id,
1298
+ fullName: usersInIam.fullName,
1299
+ email: usersInIam.email,
1300
+ phone: usersInIam.phone,
1301
+ verified: isEmail ? usersInIam.emailVerified : usersInIam.phoneVerified,
1302
+ hasPassword: sql4`exists(
1303
+ select 1
1304
+ from ${accountsInIam}
1305
+ where ${eq6(accountsInIam.tenantId, resolvedTenantId)}
1306
+ and ${eq6(accountsInIam.userId, usersInIam.id)}
1307
+ and ${eq6(accountsInIam.provider, "credentials")}
1308
+ and ${sql4`${accountsInIam.password} is not null`}
1309
+ )`
1310
+ }).from(usersInIam).where(whereClause).limit(1);
1311
+ const verified = result?.verified ?? false;
1312
+ const hasPassword = result?.hasPassword ?? false;
1313
+ let needsVerification = false;
1314
+ let verificationId;
1315
+ if (result && !verified) {
1316
+ const type = isEmail ? "email-verification" : "phone-otp";
1317
+ const to = isEmail ? result.email ?? username : result.phone ?? username;
1318
+ if (to) {
1319
+ const { verificationId: vid } = await ensureVerificationForCheckAccount({
1320
+ database,
1321
+ tenantId: resolvedTenantId,
1322
+ userId: result.id,
1323
+ type,
1324
+ to,
1325
+ config
1326
+ });
1327
+ needsVerification = true;
1328
+ verificationId = vid;
1329
+ }
1330
+ }
1331
+ return c.json(
1332
+ {
1333
+ exists: !!result,
1334
+ verified,
1335
+ hasPassword,
1336
+ requiresPasswordSetup: !!result && verified && !hasPassword,
1337
+ ...needsVerification && verificationId ? { needsVerification: true, verificationId } : {},
1338
+ account: result ? {
1339
+ fullName: result.fullName,
1340
+ email: result.email,
1341
+ phone: result.phone,
1342
+ verified,
1343
+ hasPassword,
1344
+ requiresPasswordSetup: verified && !hasPassword
1345
+ } : null
1346
+ },
1347
+ 200
1348
+ );
1349
+ };
1350
+
1351
+ // src/routes/auth/handler/sign-in.ts
1352
+ import { logger as logger2 } from "@mesob/common";
1353
+ import { and as and9, eq as eq9 } from "drizzle-orm";
1354
+
1355
+ // src/errors.ts
1356
+ var AUTH_ERRORS = {
1357
+ USER_NOT_FOUND: "USER_NOT_FOUND",
1358
+ INVALID_PASSWORD: "INVALID_PASSWORD",
1359
+ USER_EXISTS: "USER_EXISTS",
1360
+ VERIFICATION_EXPIRED: "VERIFICATION_EXPIRED",
1361
+ VERIFICATION_MISMATCH: "VERIFICATION_MISMATCH",
1362
+ VERIFICATION_NOT_FOUND: "VERIFICATION_NOT_FOUND",
1363
+ TOO_MANY_ATTEMPTS: "TOO_MANY_ATTEMPTS",
1364
+ REQUIRES_VERIFICATION: "REQUIRES_VERIFICATION",
1365
+ UNAUTHORIZED: "UNAUTHORIZED",
1366
+ ACCESS_DENIED: "ACCESS_DENIED",
1367
+ HAS_NO_PASSWORD: "HAS_NO_PASSWORD",
1368
+ PASSWORD_ALREADY_SET: "PASSWORD_ALREADY_SET"
1369
+ };
1370
+
1371
+ // src/routes/auth/helper/session.ts
1372
+ import { and as and7, asc, eq as eq7, gt as gt3, inArray, sql as sql5 } from "drizzle-orm";
1373
+ var createSessionRecord = async ({
1374
+ tx,
1375
+ tenantId,
1376
+ userId,
1377
+ config,
1378
+ userAgent,
1379
+ ip,
1380
+ action,
1381
+ rememberMe,
1382
+ expiresIn
1383
+ }) => {
1384
+ const sessionToken = generateToken();
1385
+ const hashedToken = await hashToken(sessionToken, config.secret);
1386
+ const sessionDuration = expiresIn || getSessionDuration({
1387
+ sessionConfig: config.session,
1388
+ rememberMe: rememberMe ?? true
1389
+ });
1390
+ const expiresAt = addDuration(sessionDuration);
1391
+ const meta = { action };
1392
+ if (rememberMe !== void 0) {
1393
+ meta.rememberMe = rememberMe;
1394
+ }
1395
+ const [session] = await tx.insert(sessionsInIam).values({
1396
+ tenantId,
1397
+ userId,
1398
+ token: hashedToken,
1399
+ expiresAt,
1400
+ userAgent,
1401
+ ip,
1402
+ meta
1403
+ }).returning({
1404
+ id: sessionsInIam.id,
1405
+ expiresAt: sessionsInIam.expiresAt,
1406
+ createdAt: sessionsInIam.createdAt,
1407
+ updatedAt: sessionsInIam.updatedAt,
1408
+ userAgent: sessionsInIam.userAgent,
1409
+ ip: sessionsInIam.ip
1410
+ });
1411
+ return { session, sessionToken, expiresAt };
1412
+ };
1413
+ var createSession = async ({
1414
+ tx,
1415
+ tenantId,
1416
+ userId,
1417
+ config,
1418
+ userAgent,
1419
+ ip,
1420
+ rememberMe = true
1421
+ }) => {
1422
+ const { session, sessionToken, expiresAt } = await createSessionRecord({
1423
+ tx,
1424
+ tenantId,
1425
+ userId,
1426
+ config,
1427
+ userAgent,
1428
+ ip,
1429
+ rememberMe,
1430
+ action: "sign-up"
1431
+ });
1432
+ return { sessionId: session.id, sessionToken, expiresAt };
1433
+ };
1434
+ var cleanupOldSessions = async ({
1435
+ database,
1436
+ userId,
1437
+ tenantId,
1438
+ maxSessions
1439
+ }) => {
1440
+ const [{ count }] = await database.select({ count: sql5`count(*)` }).from(sessionsInIam).where(
1441
+ and7(
1442
+ eq7(sessionsInIam.tenantId, tenantId),
1443
+ eq7(sessionsInIam.userId, userId),
1444
+ gt3(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1445
+ )
1446
+ );
1447
+ if (count <= maxSessions) {
1448
+ return;
1449
+ }
1450
+ const toDeleteCount = count - maxSessions;
1451
+ const idsToDelete = await database.select({ id: sessionsInIam.id }).from(sessionsInIam).where(
1452
+ and7(
1453
+ eq7(sessionsInIam.tenantId, tenantId),
1454
+ eq7(sessionsInIam.userId, userId),
1455
+ gt3(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1456
+ )
1457
+ ).orderBy(asc(sessionsInIam.createdAt)).limit(toDeleteCount);
1458
+ if (!idsToDelete.length) {
1459
+ return;
1460
+ }
1461
+ await database.delete(sessionsInIam).where(
1462
+ and7(
1463
+ eq7(sessionsInIam.tenantId, tenantId),
1464
+ eq7(sessionsInIam.userId, userId),
1465
+ inArray(
1466
+ sessionsInIam.id,
1467
+ idsToDelete.map((s) => s.id)
1468
+ )
1469
+ )
1470
+ );
1471
+ };
1472
+
1473
+ // src/routes/auth/helper/user.ts
1474
+ import { and as and8, eq as eq8, gt as gt4, sql as sql6 } from "drizzle-orm";
1475
+ var checkExistingUserStatus = async ({
1476
+ tx,
1477
+ identifier,
1478
+ tenantId,
1479
+ isEmail
1480
+ }) => {
1481
+ const whereClause = isEmail ? and8(
1482
+ eq8(usersInIam.tenantId, tenantId),
1483
+ sql6`lower(${usersInIam.email}) = lower(${identifier})`
1484
+ ) : and8(eq8(usersInIam.tenantId, tenantId), eq8(usersInIam.phone, identifier));
1485
+ const [existingUser] = await tx.select().from(usersInIam).where(whereClause).limit(1);
1486
+ if (!existingUser) {
1487
+ return { action: "proceed" };
1488
+ }
1489
+ const isVerified = isEmail ? existingUser.emailVerified : existingUser.phoneVerified;
1490
+ if (isVerified) {
1491
+ return { action: "error", code: AUTH_ERRORS.USER_EXISTS };
1492
+ }
1493
+ const [pendingVerification] = await tx.select().from(verificationsInIam).where(
1494
+ and8(
1495
+ eq8(verificationsInIam.userId, existingUser.id),
1496
+ eq8(verificationsInIam.tenantId, tenantId),
1497
+ gt4(verificationsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1498
+ )
1499
+ ).limit(1);
1500
+ if (pendingVerification) {
1501
+ return {
1502
+ action: "pending",
1503
+ verificationId: pendingVerification.id,
1504
+ user: existingUser
1505
+ };
1506
+ }
1507
+ await deleteUnverifiedUser({ tx, userId: existingUser.id, tenantId });
1508
+ return { action: "proceed" };
1600
1509
  };
1601
- var handlePhoneVerification = async ({
1602
- c,
1603
- user,
1604
- config,
1605
- database,
1510
+ var deleteUnverifiedUser = async ({
1511
+ tx,
1512
+ userId,
1606
1513
  tenantId
1607
1514
  }) => {
1608
- if (!user.phone) {
1609
- return c.json({ error: "User phone not found" }, 401);
1610
- }
1611
- await database.delete(verificationsInIam).where(
1515
+ await tx.delete(verificationsInIam).where(
1612
1516
  and8(
1613
- eq8(verificationsInIam.tenantId, tenantId),
1614
- eq8(verificationsInIam.userId, user.id),
1615
- eq8(verificationsInIam.type, "phone-otp")
1517
+ eq8(verificationsInIam.userId, userId),
1518
+ eq8(verificationsInIam.tenantId, tenantId)
1616
1519
  )
1617
1520
  );
1618
- const code = generateOtpCode(config.phone.otpLength);
1619
- const hashedCode = await hashToken(code, config.secret);
1620
- const expiresAt = addDuration(config.phone.expiresIn);
1621
- const [verification] = await database.insert(verificationsInIam).values({
1521
+ await tx.delete(accountsInIam).where(
1522
+ and8(
1523
+ eq8(accountsInIam.userId, userId),
1524
+ eq8(accountsInIam.tenantId, tenantId)
1525
+ )
1526
+ );
1527
+ await tx.delete(usersInIam).where(and8(eq8(usersInIam.id, userId), eq8(usersInIam.tenantId, tenantId)));
1528
+ };
1529
+ var createUserWithAccount = async ({
1530
+ tx,
1531
+ tenantId,
1532
+ email,
1533
+ phone,
1534
+ password,
1535
+ fullName,
1536
+ handle,
1537
+ config
1538
+ }) => {
1539
+ const [user] = await tx.insert(usersInIam).values({
1540
+ tenantId,
1541
+ fullName,
1542
+ handle,
1543
+ email: email || null,
1544
+ phone: phone || null,
1545
+ emailVerified: email ? !config.email.required : false,
1546
+ phoneVerified: phone ? !config.phone.required : false,
1547
+ userType: [config.userType]
1548
+ }).returning();
1549
+ const passwordHash = await hashPassword(password);
1550
+ await tx.insert(accountsInIam).values({
1622
1551
  tenantId,
1623
1552
  userId: user.id,
1624
- type: "phone-otp",
1625
- code: hashedCode,
1626
- expiresAt,
1627
- to: user.phone,
1628
- attempt: 0
1629
- }).returning({
1630
- id: verificationsInIam.id,
1631
- tenantId: verificationsInIam.tenantId,
1632
- userId: verificationsInIam.userId,
1633
- type: verificationsInIam.type,
1634
- code: verificationsInIam.code,
1635
- to: verificationsInIam.to,
1636
- expiresAt: verificationsInIam.expiresAt,
1637
- createdAt: verificationsInIam.createdAt,
1638
- attempt: verificationsInIam.attempt
1553
+ provider: "credentials",
1554
+ providerAccountId: email || phone || user.id,
1555
+ password: passwordHash
1639
1556
  });
1640
- if (config.phone.sendVerificationOTP) {
1641
- await config.phone.sendVerificationOTP({
1642
- phone: user.phone,
1643
- code,
1644
- hash: hashedCode,
1645
- type: "phone-otp"
1646
- });
1647
- }
1648
- return c.json(
1649
- {
1650
- user: normalizeAuthUser(user),
1651
- session: null,
1652
- verificationId: verification.id,
1653
- requiresVerification: true
1654
- },
1655
- 200
1557
+ return user;
1558
+ };
1559
+ var fetchUserForLogin = async ({
1560
+ database,
1561
+ identifier,
1562
+ tenantId,
1563
+ isEmail,
1564
+ userType
1565
+ }) => {
1566
+ const userTypeFilter = sql6`${usersInIam.userType} @> ARRAY[${userType}]::text[]`;
1567
+ const whereClause = isEmail ? and8(
1568
+ eq8(usersInIam.tenantId, tenantId),
1569
+ userTypeFilter,
1570
+ sql6`lower(${usersInIam.email}) = lower(${identifier})`
1571
+ ) : and8(
1572
+ eq8(usersInIam.tenantId, tenantId),
1573
+ userTypeFilter,
1574
+ eq8(usersInIam.phone, identifier)
1656
1575
  );
1576
+ const [row] = await database.select({
1577
+ id: usersInIam.id,
1578
+ tenantId: usersInIam.tenantId,
1579
+ fullName: usersInIam.fullName,
1580
+ email: usersInIam.email,
1581
+ phone: usersInIam.phone,
1582
+ handle: usersInIam.handle,
1583
+ image: usersInIam.image,
1584
+ emailVerified: usersInIam.emailVerified,
1585
+ phoneVerified: usersInIam.phoneVerified,
1586
+ lastSignInAt: usersInIam.lastSignInAt,
1587
+ bannedUntil: usersInIam.bannedUntil,
1588
+ loginAttempt: usersInIam.loginAttempt,
1589
+ hasPassword: sql6`exists(
1590
+ select 1
1591
+ from ${accountsInIam}
1592
+ where ${eq8(accountsInIam.tenantId, tenantId)}
1593
+ and ${eq8(accountsInIam.userId, usersInIam.id)}
1594
+ and ${eq8(accountsInIam.provider, "credentials")}
1595
+ and ${sql6`${accountsInIam.password} is not null`}
1596
+ )`
1597
+ }).from(usersInIam).where(whereClause).limit(1);
1598
+ return row || null;
1599
+ };
1600
+ var fetchUserByIdWithRoles = async ({
1601
+ database,
1602
+ userId,
1603
+ tenantId
1604
+ }) => {
1605
+ const [result] = await database.select({
1606
+ id: usersInIam.id,
1607
+ tenantId: usersInIam.tenantId,
1608
+ fullName: usersInIam.fullName,
1609
+ email: usersInIam.email,
1610
+ phone: usersInIam.phone,
1611
+ handle: usersInIam.handle,
1612
+ image: usersInIam.image,
1613
+ emailVerified: usersInIam.emailVerified,
1614
+ phoneVerified: usersInIam.phoneVerified,
1615
+ lastSignInAt: usersInIam.lastSignInAt,
1616
+ bannedUntil: usersInIam.bannedUntil,
1617
+ loginAttempt: usersInIam.loginAttempt,
1618
+ ...getUserAuthSelect(tenantId)
1619
+ }).from(usersInIam).where(and8(eq8(usersInIam.id, userId), eq8(usersInIam.tenantId, tenantId))).limit(1);
1620
+ return result || null;
1657
1621
  };
1658
1622
 
1659
1623
  // src/routes/auth/handler/sign-in.ts
@@ -1819,7 +1783,7 @@ var signInHandler = (
1819
1783
  );
1820
1784
 
1821
1785
  // src/routes/auth/handler/sign-out.ts
1822
- import { and as and10, eq as eq10, gt as gt4 } from "drizzle-orm";
1786
+ import { and as and10, eq as eq10, gt as gt5 } from "drizzle-orm";
1823
1787
  import { getCookie } from "hono/cookie";
1824
1788
  var signOutHandler = async (c) => {
1825
1789
  const config = c.get("config");
@@ -1843,7 +1807,7 @@ var signOutHandler = async (c) => {
1843
1807
  }).from(sessionsInIam).where(
1844
1808
  and10(
1845
1809
  eq10(sessionsInIam.token, hashedToken),
1846
- gt4(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1810
+ gt5(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
1847
1811
  )
1848
1812
  ).limit(1);
1849
1813
  if (session) {
@@ -2171,6 +2135,24 @@ var auth_route_default = authRoutes;
2171
2135
  // src/routes/domains/domains.route.ts
2172
2136
  import { createRoute as createRoute2, OpenAPIHono as OpenAPIHono2 } from "@hono/zod-openapi";
2173
2137
 
2138
+ // src/lib/has-role-permission.ts
2139
+ import { grant } from "@mesob/common";
2140
+ import { HTTPException as HTTPException3 } from "hono/http-exception";
2141
+ var toArray = (v) => {
2142
+ return Array.isArray(v) ? v : [v];
2143
+ };
2144
+ var hasPermission = (c, permission) => {
2145
+ const user = c.get("user");
2146
+ const perms = user?.permissions;
2147
+ const check2 = toArray(permission);
2148
+ return grant(check2, perms);
2149
+ };
2150
+ var hasPermissionThrow = (c, permission) => {
2151
+ if (!hasPermission(c, permission)) {
2152
+ throw new HTTPException3(401, { message: "Unauthorized" });
2153
+ }
2154
+ };
2155
+
2174
2156
  // src/routes/domains/domains.schema.ts
2175
2157
  import { z as z2 } from "zod";
2176
2158
  var listDomainsQuerySchema = z2.object({
@@ -2230,10 +2212,11 @@ var createDomainHandler = async (c) => {
2230
2212
  const database = c.get("database");
2231
2213
  const tenantId = c.get("tenantId");
2232
2214
  const resolvedTenantId = ensureTenantId(config, tenantId);
2215
+ const status = (body.status || "pending").toUpperCase();
2233
2216
  const [domain] = await database.insert(domainsInIam).values({
2234
2217
  tenantId: resolvedTenantId,
2235
2218
  domain: body.domain,
2236
- status: body.status || "pending",
2219
+ status,
2237
2220
  meta: body.meta || null,
2238
2221
  isPrimary: body.isPrimary
2239
2222
  }).returning();
@@ -2278,7 +2261,7 @@ var listDomainsHandler = async (c) => {
2278
2261
  const offset = (page - 1) * limit;
2279
2262
  const conditions = [eq13(domainsInIam.tenantId, tenantId)];
2280
2263
  if (query.status) {
2281
- conditions.push(eq13(domainsInIam.status, query.status));
2264
+ conditions.push(eq13(domainsInIam.status, query.status.toUpperCase()));
2282
2265
  }
2283
2266
  const [domains, totalResult] = await Promise.all([
2284
2267
  database.select().from(domainsInIam).where(and13(...conditions)).limit(limit).offset(offset),
@@ -2304,7 +2287,7 @@ var updateDomainHandler = async (c) => {
2304
2287
  updateData.domain = body.domain;
2305
2288
  }
2306
2289
  if (body.status !== void 0) {
2307
- updateData.status = body.status;
2290
+ updateData.status = body.status.toUpperCase();
2308
2291
  }
2309
2292
  if (body.meta !== void 0) {
2310
2293
  updateData.meta = body.meta;
@@ -2502,7 +2485,12 @@ var verifyDomainRoute = createRoute2({
2502
2485
  }
2503
2486
  }
2504
2487
  });
2505
- var domainRoutes = new OpenAPIHono2().openapi(listDomainsRoute, listDomainsHandler).openapi(getDomainRoute, getDomainHandler).openapi(createDomainRoute, createDomainHandler).openapi(updateDomainRoute, updateDomainHandler).openapi(deleteDomainRoute, deleteDomainHandler).openapi(verifyDomainRoute, verifyDomainHandler);
2488
+ var IAM_ALL = "iam:all:all";
2489
+ var domainRoutesBase = new OpenAPIHono2().use("*", (c, next) => {
2490
+ hasPermissionThrow(c, IAM_ALL);
2491
+ return next();
2492
+ });
2493
+ var domainRoutes = domainRoutesBase.openapi(listDomainsRoute, listDomainsHandler).openapi(getDomainRoute, getDomainHandler).openapi(createDomainRoute, createDomainHandler).openapi(updateDomainRoute, updateDomainHandler).openapi(deleteDomainRoute, deleteDomainHandler).openapi(verifyDomainRoute, verifyDomainHandler);
2506
2494
  var domains_route_default = domainRoutes;
2507
2495
 
2508
2496
  // src/routes/email/email.route.ts
@@ -2806,7 +2794,7 @@ var email_route_default = emailRoutes;
2806
2794
  import { createRoute as createRoute4, OpenAPIHono as OpenAPIHono4 } from "@hono/zod-openapi";
2807
2795
 
2808
2796
  // src/routes/password/handler/change.ts
2809
- import { and as and18, eq as eq18, gt as gt5, ne } from "drizzle-orm";
2797
+ import { and as and18, eq as eq18, gt as gt6, ne } from "drizzle-orm";
2810
2798
  import { getCookie as getCookie2 } from "hono/cookie";
2811
2799
  var changePasswordHandler = async (c) => {
2812
2800
  const body = c.req.valid("json");
@@ -2852,7 +2840,7 @@ var changePasswordHandler = async (c) => {
2852
2840
  and18(
2853
2841
  eq18(sessionsInIam.tenantId, resolvedTenantId),
2854
2842
  eq18(sessionsInIam.userId, userId),
2855
- gt5(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString()),
2843
+ gt6(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString()),
2856
2844
  ne(sessionsInIam.token, hashedToken)
2857
2845
  )
2858
2846
  );
@@ -3049,7 +3037,7 @@ var forgotPasswordHandler = async (c) => {
3049
3037
  };
3050
3038
 
3051
3039
  // src/routes/password/handler/reset.ts
3052
- import { and as and20, eq as eq20, gt as gt6 } from "drizzle-orm";
3040
+ import { and as and20, eq as eq20, gt as gt7 } from "drizzle-orm";
3053
3041
 
3054
3042
  // src/routes/password/helper/session.ts
3055
3043
  var createPasswordResetSession = async ({
@@ -3129,7 +3117,7 @@ var resetPasswordHandler = async (c) => {
3129
3117
  and20(
3130
3118
  eq20(sessionsInIam.tenantId, resolvedTenantId),
3131
3119
  eq20(sessionsInIam.userId, verification.userId),
3132
- gt6(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
3120
+ gt7(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
3133
3121
  )
3134
3122
  );
3135
3123
  await database.delete(verificationsInIam).where(eq20(verificationsInIam.id, verificationId));
@@ -3549,7 +3537,7 @@ import {
3549
3537
  notInArray,
3550
3538
  sql as sql12
3551
3539
  } from "drizzle-orm";
3552
- import { HTTPException as HTTPException3 } from "hono/http-exception";
3540
+ import { HTTPException as HTTPException4 } from "hono/http-exception";
3553
3541
  function buildPermissionDescription(code) {
3554
3542
  return {
3555
3543
  en: toTitleCase(code.replaceAll(":", " ").replaceAll("_", " "))
@@ -3606,7 +3594,7 @@ async function assertPermissionsExist({
3606
3594
  (id) => !existingIds.has(id)
3607
3595
  );
3608
3596
  if (missingPermissionIds.length) {
3609
- throw new HTTPException3(400, {
3597
+ throw new HTTPException4(400, {
3610
3598
  message: `Unknown permissions: ${missingPermissionIds.join(", ")}`
3611
3599
  });
3612
3600
  }
@@ -3856,7 +3844,12 @@ var seedPermissionsRoute = createRoute5({
3856
3844
  }
3857
3845
  }
3858
3846
  });
3859
- var permissionRoutes = new OpenAPIHono5().openapi(listPermissionsRoute, listPermissionsHandler).openapi(seedPermissionsRoute, seedPermissionsHandler).openapi(getPermissionRoute, getPermissionHandler);
3847
+ var IAM_ALL2 = "iam:all:all";
3848
+ var permissionRoutesBase = new OpenAPIHono5().use("*", (c, next) => {
3849
+ hasPermissionThrow(c, IAM_ALL2);
3850
+ return next();
3851
+ });
3852
+ var permissionRoutes = permissionRoutesBase.openapi(listPermissionsRoute, listPermissionsHandler).openapi(seedPermissionsRoute, seedPermissionsHandler).openapi(getPermissionRoute, getPermissionHandler);
3860
3853
  var permissions_route_default = permissionRoutes;
3861
3854
 
3862
3855
  // src/routes/phone/phone.route.ts
@@ -4190,7 +4183,7 @@ import { createRoute as createRoute7, OpenAPIHono as OpenAPIHono7 } from "@hono/
4190
4183
  import { z as z4 } from "zod";
4191
4184
 
4192
4185
  // src/routes/profile/handler/account-change-pending.ts
4193
- import { and as and26, eq as eq27, gt as gt7, sql as sql13 } from "drizzle-orm";
4186
+ import { and as and26, eq as eq27, gt as gt8, sql as sql13 } from "drizzle-orm";
4194
4187
  var accountChangePendingHandler = async (c) => {
4195
4188
  const config = c.get("config");
4196
4189
  const database = c.get("database");
@@ -4228,7 +4221,7 @@ var accountChangePendingHandler = async (c) => {
4228
4221
  eq27(verificationsInIam.userId, userId),
4229
4222
  eq27(verificationsInIam.type, "email-verification"),
4230
4223
  eq27(verificationsInIam.to, accountChange.newEmail),
4231
- gt7(verificationsInIam.expiresAt, sql13`CURRENT_TIMESTAMP`)
4224
+ gt8(verificationsInIam.expiresAt, sql13`CURRENT_TIMESTAMP`)
4232
4225
  )
4233
4226
  ).limit(1);
4234
4227
  verification = v || null;
@@ -4243,7 +4236,7 @@ var accountChangePendingHandler = async (c) => {
4243
4236
  eq27(verificationsInIam.userId, userId),
4244
4237
  eq27(verificationsInIam.type, "phone-otp-change-phone"),
4245
4238
  eq27(verificationsInIam.to, accountChange.newPhone),
4246
- gt7(verificationsInIam.expiresAt, sql13`CURRENT_TIMESTAMP`)
4239
+ gt8(verificationsInIam.expiresAt, sql13`CURRENT_TIMESTAMP`)
4247
4240
  )
4248
4241
  ).limit(1);
4249
4242
  verification = v || null;
@@ -4890,7 +4883,15 @@ var revokeRolePermissionRoute = createRoute8({
4890
4883
  }
4891
4884
  }
4892
4885
  });
4893
- var rolePermissionRoutes = new OpenAPIHono8().openapi(listRolePermissionsRoute, listRolePermissionsHandler).openapi(assignRolePermissionRoute, assignRolePermissionHandler).openapi(revokeRolePermissionRoute, revokeRolePermissionHandler);
4886
+ var IAM_ALL3 = "iam:all:all";
4887
+ var rolePermissionRoutesBase = new OpenAPIHono8().use(
4888
+ "*",
4889
+ (c, next) => {
4890
+ hasPermissionThrow(c, IAM_ALL3);
4891
+ return next();
4892
+ }
4893
+ );
4894
+ var rolePermissionRoutes = rolePermissionRoutesBase.openapi(listRolePermissionsRoute, listRolePermissionsHandler).openapi(assignRolePermissionRoute, assignRolePermissionHandler).openapi(revokeRolePermissionRoute, revokeRolePermissionHandler);
4894
4895
  var role_permissions_route_default = rolePermissionRoutes;
4895
4896
 
4896
4897
  // src/routes/roles/roles.route.ts
@@ -6050,7 +6051,12 @@ var seedRolesRoute = createRoute9({
6050
6051
  }
6051
6052
  }
6052
6053
  });
6053
- var roleRoutes = new OpenAPIHono9().openapi(listRolesRoute, listRolesHandler).openapi(seedRolesRoute, seedRolesHandler).openapi(getRoleRoute, getRoleHandler).openapi(createRoleRoute, createRoleHandler).openapi(updateRoleRoute, updateRoleHandler).openapi(listRolePermissionsRoute2, listRolePermissionsHandler2).openapi(assignRolePermissionsRoute, assignRolePermissionsHandler).openapi(revokeRolePermissionRoute2, revokeRolePermissionHandler2).openapi(listRoleUsersRoute, listRoleUsersHandler).openapi(assignRoleUsersRoute, assignRoleUsersHandler).openapi(revokeRoleUserRoute, revokeRoleUserHandler).openapi(deleteRoleRoute, deleteRoleHandler);
6054
+ var IAM_ALL4 = "iam:all:all";
6055
+ var roleRoutesBase = new OpenAPIHono9().use("*", (c, next) => {
6056
+ hasPermissionThrow(c, IAM_ALL4);
6057
+ return next();
6058
+ });
6059
+ var roleRoutes = roleRoutesBase.openapi(listRolesRoute, listRolesHandler).openapi(seedRolesRoute, seedRolesHandler).openapi(getRoleRoute, getRoleHandler).openapi(createRoleRoute, createRoleHandler).openapi(updateRoleRoute, updateRoleHandler).openapi(listRolePermissionsRoute2, listRolePermissionsHandler2).openapi(assignRolePermissionsRoute, assignRolePermissionsHandler).openapi(revokeRolePermissionRoute2, revokeRolePermissionHandler2).openapi(listRoleUsersRoute, listRoleUsersHandler).openapi(assignRoleUsersRoute, assignRoleUsersHandler).openapi(revokeRoleUserRoute, revokeRoleUserHandler).openapi(deleteRoleRoute, deleteRoleHandler);
6054
6060
  var roles_route_default = roleRoutes;
6055
6061
 
6056
6062
  // src/routes/sessions/sessions.route.ts
@@ -6253,7 +6259,12 @@ var revokeAllSessionsRoute = createRoute10({
6253
6259
  }
6254
6260
  }
6255
6261
  });
6256
- var sessionRoutes = new OpenAPIHono10().openapi(listSessionsRoute, listSessionsHandler).openapi(getSessionRoute, getSessionHandler).openapi(revokeSessionRoute, revokeSessionHandler).openapi(revokeAllSessionsRoute, revokeAllSessionsHandler);
6262
+ var IAM_ALL5 = "iam:all:all";
6263
+ var sessionRoutesBase = new OpenAPIHono10().use("*", (c, next) => {
6264
+ hasPermissionThrow(c, IAM_ALL5);
6265
+ return next();
6266
+ });
6267
+ var sessionRoutes = sessionRoutesBase.openapi(listSessionsRoute, listSessionsHandler).openapi(getSessionRoute, getSessionHandler).openapi(revokeSessionRoute, revokeSessionHandler).openapi(revokeAllSessionsRoute, revokeAllSessionsHandler);
6257
6268
  var sessions_route_default = sessionRoutes;
6258
6269
 
6259
6270
  // src/routes/system/system.route.ts
@@ -6277,6 +6288,7 @@ var tenantHandler = (c) => {
6277
6288
  };
6278
6289
 
6279
6290
  // src/routes/system/system.route.ts
6291
+ var IAM_ALL6 = "iam:all:all";
6280
6292
  var tenantRoute = createRoute11({
6281
6293
  method: "get",
6282
6294
  path: "/init",
@@ -6311,10 +6323,11 @@ var tenantRoute = createRoute11({
6311
6323
  }
6312
6324
  }
6313
6325
  });
6314
- var tenantRoutes = new OpenAPIHono11().openapi(
6315
- tenantRoute,
6316
- tenantHandler
6317
- );
6326
+ var tenantRoutesBase = new OpenAPIHono11().use("*", (c, next) => {
6327
+ hasPermissionThrow(c, IAM_ALL6);
6328
+ return next();
6329
+ });
6330
+ var tenantRoutes = tenantRoutesBase.openapi(tenantRoute, tenantHandler);
6318
6331
  var system_route_default = tenantRoutes;
6319
6332
 
6320
6333
  // src/routes/tenants/tenants.route.ts
@@ -6322,42 +6335,7 @@ import { createRoute as createRoute12, OpenAPIHono as OpenAPIHono12 } from "@hon
6322
6335
 
6323
6336
  // src/routes/tenants/handler/create-tenant.ts
6324
6337
  import { eq as eq48 } from "drizzle-orm";
6325
-
6326
- // src/lib/has-role-permission.ts
6327
- import { grant } from "@mesob/common";
6328
- import { HTTPException as HTTPException4 } from "hono/http-exception";
6329
- var toArray = (v) => {
6330
- return Array.isArray(v) ? v : [v];
6331
- };
6332
- var hasRole = (c, role) => {
6333
- const user = c.get("user");
6334
- const codes = user?.roleCodes;
6335
- if (!codes?.length) {
6336
- return false;
6337
- }
6338
- const check2 = toArray(role);
6339
- return check2.some((r) => codes.includes(r));
6340
- };
6341
- var hasRoleThrow = (c, role) => {
6342
- if (!hasRole(c, role)) {
6343
- throw new HTTPException4(401, { message: "Unauthorized" });
6344
- }
6345
- };
6346
- var hasPermission = (c, permission) => {
6347
- const user = c.get("user");
6348
- const perms = user?.permissions;
6349
- const check2 = toArray(permission);
6350
- return grant(check2, perms);
6351
- };
6352
- var hasPermissionThrow = (c, permission) => {
6353
- if (!hasPermission(c, permission)) {
6354
- throw new HTTPException4(401, { message: "Unauthorized" });
6355
- }
6356
- };
6357
-
6358
- // src/routes/tenants/handler/create-tenant.ts
6359
6338
  var createTenantHandler = async (c) => {
6360
- hasRoleThrow(c, ["owner", "tenant-admin"]);
6361
6339
  const body = c.req.valid("json");
6362
6340
  const database = c.get("database");
6363
6341
  const [existing] = await database.select().from(tenantsInIam).where(eq48(tenantsInIam.id, body.id)).limit(1);
@@ -6385,7 +6363,6 @@ var createTenantHandler = async (c) => {
6385
6363
  // src/routes/tenants/handler/delete-tenant.ts
6386
6364
  import { eq as eq49 } from "drizzle-orm";
6387
6365
  var deleteTenantHandler = async (c) => {
6388
- hasRoleThrow(c, ["owner", "tenant-admin"]);
6389
6366
  const { id } = c.req.valid("param");
6390
6367
  const database = c.get("database");
6391
6368
  const [existing] = await database.select().from(tenantsInIam).where(eq49(tenantsInIam.id, id)).limit(1);
@@ -6399,7 +6376,6 @@ var deleteTenantHandler = async (c) => {
6399
6376
  // src/routes/tenants/handler/get-tenant.ts
6400
6377
  import { eq as eq50 } from "drizzle-orm";
6401
6378
  var getTenantHandler = async (c) => {
6402
- hasRoleThrow(c, ["owner", "tenant-admin"]);
6403
6379
  const { id } = c.req.valid("param");
6404
6380
  const database = c.get("database");
6405
6381
  const [tenant] = await database.select().from(tenantsInIam).where(eq50(tenantsInIam.id, id)).limit(1);
@@ -6417,7 +6393,6 @@ var sortColumnMap3 = {
6417
6393
  name: sql23`${tenantsInIam.name}::text`
6418
6394
  };
6419
6395
  var listTenantsHandler = async (c) => {
6420
- hasRoleThrow(c, ["owner", "tenant-admin"]);
6421
6396
  const query = c.req.valid("query");
6422
6397
  const database = c.get("database");
6423
6398
  const page = query.page || 1;
@@ -6456,7 +6431,6 @@ var listTenantsHandler = async (c) => {
6456
6431
  // src/routes/tenants/handler/update-tenant.ts
6457
6432
  import { eq as eq52, sql as sql24 } from "drizzle-orm";
6458
6433
  var updateTenantHandler = async (c) => {
6459
- hasRoleThrow(c, ["owner", "tenant-admin"]);
6460
6434
  const { id } = c.req.valid("param");
6461
6435
  const body = c.req.valid("json");
6462
6436
  const database = c.get("database");
@@ -6730,7 +6704,12 @@ var deleteTenantRoute = createRoute12({
6730
6704
  }
6731
6705
  }
6732
6706
  });
6733
- var tenantRoutes2 = new OpenAPIHono12().openapi(listTenantsRoute, listTenantsHandler).openapi(getTenantRoute, getTenantHandler).openapi(createTenantRoute, createTenantHandler).openapi(updateTenantRoute, updateTenantHandler).openapi(deleteTenantRoute, deleteTenantHandler);
6707
+ var IAM_ALL7 = "iam:all:all";
6708
+ var tenantRoutesBase2 = new OpenAPIHono12().use("*", (c, next) => {
6709
+ hasPermissionThrow(c, IAM_ALL7);
6710
+ return next();
6711
+ });
6712
+ var tenantRoutes2 = tenantRoutesBase2.openapi(listTenantsRoute, listTenantsHandler).openapi(getTenantRoute, getTenantHandler).openapi(createTenantRoute, createTenantHandler).openapi(updateTenantRoute, updateTenantHandler).openapi(deleteTenantRoute, deleteTenantHandler);
6734
6713
  var tenants_route_default = tenantRoutes2;
6735
6714
 
6736
6715
  // src/routes/user-roles/user-roles.route.ts
@@ -6905,7 +6884,12 @@ var revokeUserRoleRoute = createRoute13({
6905
6884
  }
6906
6885
  }
6907
6886
  });
6908
- var userRoleRoutes = new OpenAPIHono13().openapi(listUserRolesRoute, listUserRolesHandler).openapi(assignUserRoleRoute, assignUserRoleHandler).openapi(revokeUserRoleRoute, revokeUserRoleHandler);
6887
+ var IAM_ALL8 = "iam:all:all";
6888
+ var userRoleRoutesBase = new OpenAPIHono13().use("*", (c, next) => {
6889
+ hasPermissionThrow(c, IAM_ALL8);
6890
+ return next();
6891
+ });
6892
+ var userRoleRoutes = userRoleRoutesBase.openapi(listUserRolesRoute, listUserRolesHandler).openapi(assignUserRoleRoute, assignUserRoleHandler).openapi(revokeUserRoleRoute, revokeUserRoleHandler);
6909
6893
  var user_roles_route_default = userRoleRoutes;
6910
6894
 
6911
6895
  // src/routes/users/users.route.ts
@@ -6922,27 +6906,24 @@ var banUserHandler = async (c) => {
6922
6906
  if (!existing) {
6923
6907
  return c.json({ error: "User not found" }, 404);
6924
6908
  }
6925
- const [updated] = await database.update(usersInIam).set({
6926
- bannedUntil: body.bannedUntil || null,
6909
+ await database.update(usersInIam).set({
6910
+ bannedUntil: body.bannedUntil ?? null,
6927
6911
  updatedAt: sql25`CURRENT_TIMESTAMP`
6928
- }).where(and50(eq55(usersInIam.id, id), eq55(usersInIam.tenantId, tenantId))).returning({
6929
- id: usersInIam.id,
6930
- tenantId: usersInIam.tenantId,
6931
- fullName: usersInIam.fullName,
6932
- email: usersInIam.email,
6933
- phone: usersInIam.phone,
6934
- handle: usersInIam.handle,
6935
- image: usersInIam.image,
6936
- emailVerified: usersInIam.emailVerified,
6937
- phoneVerified: usersInIam.phoneVerified,
6938
- lastSignInAt: usersInIam.lastSignInAt
6912
+ }).where(and50(eq55(usersInIam.id, id), eq55(usersInIam.tenantId, tenantId)));
6913
+ const userWithRoles = await fetchUserWithRoles({
6914
+ database,
6915
+ userId: id,
6916
+ tenantId
6939
6917
  });
6940
- if (!updated) {
6918
+ if (!userWithRoles) {
6941
6919
  return c.json({ error: "User not found" }, 404);
6942
6920
  }
6943
- return c.json({ user: normalizeUser(updated) }, 200);
6921
+ return c.json({ user: normalizeUser(userWithRoles) }, 200);
6944
6922
  };
6945
6923
 
6924
+ // src/routes/users/helper/invite.ts
6925
+ import { and as and52, eq as eq57 } from "drizzle-orm";
6926
+
6946
6927
  // src/routes/users/helper/user.ts
6947
6928
  import { and as and51, eq as eq56, sql as sql26 } from "drizzle-orm";
6948
6929
  var checkUserExists = async ({
@@ -7012,7 +6993,89 @@ var inviteUser = (
7012
6993
  isEmail
7013
6994
  });
7014
6995
  if (existing) {
7015
- throw new Error("User already exists");
6996
+ const identifierVerified = isEmail ? existing.emailVerified : existing.phoneVerified;
6997
+ const hasInviteType = Array.isArray(existing.userType) && existing.userType.includes(config.userType);
6998
+ if (identifierVerified && hasInviteType) {
6999
+ throw new Error("User already exists");
7000
+ }
7001
+ const updates = {};
7002
+ if (!identifierVerified) {
7003
+ if (payload.emailVerified !== void 0 && payload.email) {
7004
+ updates.emailVerified = Boolean(payload.emailVerified);
7005
+ }
7006
+ if (payload.phoneVerified !== void 0 && payload.phone) {
7007
+ updates.phoneVerified = Boolean(payload.phoneVerified);
7008
+ }
7009
+ }
7010
+ if (!hasInviteType) {
7011
+ updates.userType = [config.userType];
7012
+ }
7013
+ let user2;
7014
+ if (Object.keys(updates).length > 0) {
7015
+ const [updated] = await database.update(usersInIam).set(updates).where(eq57(usersInIam.id, existing.id)).returning();
7016
+ if (!updated) {
7017
+ throw new Error("User update failed");
7018
+ }
7019
+ user2 = updated;
7020
+ } else {
7021
+ user2 = existing;
7022
+ }
7023
+ const [credAccount] = await database.select().from(accountsInIam).where(
7024
+ and52(
7025
+ eq57(accountsInIam.tenantId, tenantId),
7026
+ eq57(accountsInIam.userId, user2.id),
7027
+ eq57(accountsInIam.provider, "credentials")
7028
+ )
7029
+ ).limit(1);
7030
+ const hasPassword2 = Boolean(credAccount?.password);
7031
+ const resolvedInviteUrl2 = resolveInviteUrl({
7032
+ inviteUrl: payload.inviteUrl,
7033
+ identifier,
7034
+ hasPassword: hasPassword2
7035
+ });
7036
+ const delivery2 = {};
7037
+ if (payload.sendVia?.includes("email")) {
7038
+ if (payload.email && config.email.sendInvitation) {
7039
+ try {
7040
+ await config.email.sendInvitation({
7041
+ email: payload.email,
7042
+ fullName: user2.fullName,
7043
+ identifier,
7044
+ inviteUrl: resolvedInviteUrl2,
7045
+ tenantId
7046
+ });
7047
+ delivery2.email = "sent";
7048
+ } catch {
7049
+ delivery2.email = "failed";
7050
+ }
7051
+ } else {
7052
+ delivery2.email = "skipped";
7053
+ }
7054
+ }
7055
+ if (payload.sendVia?.includes("sms")) {
7056
+ if (payload.phone && config.phone.sendInvitation) {
7057
+ try {
7058
+ await config.phone.sendInvitation({
7059
+ phone: payload.phone,
7060
+ fullName: user2.fullName,
7061
+ identifier,
7062
+ inviteUrl: resolvedInviteUrl2,
7063
+ tenantId
7064
+ });
7065
+ delivery2.sms = "sent";
7066
+ } catch {
7067
+ delivery2.sms = "failed";
7068
+ }
7069
+ } else {
7070
+ delivery2.sms = "skipped";
7071
+ }
7072
+ }
7073
+ return {
7074
+ user: normalizeUser(user2),
7075
+ delivery: delivery2,
7076
+ inviteUrl: resolvedInviteUrl2,
7077
+ hasPassword: hasPassword2
7078
+ };
7016
7079
  }
7017
7080
  const userHandle = payload.handle || generateHandle();
7018
7081
  const existingHandle = await checkHandleExists({
@@ -7197,16 +7260,16 @@ var createUserHandler = async (c) => {
7197
7260
  };
7198
7261
 
7199
7262
  // src/routes/users/handler/delete-user.ts
7200
- import { and as and52, eq as eq57 } from "drizzle-orm";
7263
+ import { and as and53, eq as eq58 } from "drizzle-orm";
7201
7264
  var deleteUserHandler = async (c) => {
7202
7265
  const { id } = c.req.valid("param");
7203
7266
  const database = c.get("database");
7204
7267
  const tenantId = c.get("tenantId");
7205
- const [existing] = await database.select().from(usersInIam).where(and52(eq57(usersInIam.id, id), eq57(usersInIam.tenantId, tenantId))).limit(1);
7268
+ const [existing] = await database.select().from(usersInIam).where(and53(eq58(usersInIam.id, id), eq58(usersInIam.tenantId, tenantId))).limit(1);
7206
7269
  if (!existing) {
7207
7270
  return c.json({ error: "User not found" }, 404);
7208
7271
  }
7209
- await database.delete(usersInIam).where(and52(eq57(usersInIam.id, id), eq57(usersInIam.tenantId, tenantId)));
7272
+ await database.delete(usersInIam).where(and53(eq58(usersInIam.id, id), eq58(usersInIam.tenantId, tenantId)));
7210
7273
  return c.json({ message: "User deleted" }, 200);
7211
7274
  };
7212
7275
 
@@ -7250,7 +7313,7 @@ var inviteUserHandler = async (c) => {
7250
7313
  };
7251
7314
 
7252
7315
  // src/routes/users/handler/list-users.ts
7253
- import { and as and53, asc as asc5, desc as desc5, eq as eq58, ilike as ilike4, inArray as inArray6, or as or4, sql as sql27 } from "drizzle-orm";
7316
+ import { and as and54, asc as asc5, desc as desc5, eq as eq59, gt as gt9, ilike as ilike4, inArray as inArray6, or as or4, sql as sql27 } from "drizzle-orm";
7254
7317
  var userSelect = {
7255
7318
  id: usersInIam.id,
7256
7319
  tenantId: usersInIam.tenantId,
@@ -7266,9 +7329,6 @@ var userSelect = {
7266
7329
  userType: usersInIam.userType,
7267
7330
  roleCount: sql27`(select count(*)::int from ${userRolesInIam} where ${userRolesInIam.userId} = ${usersInIam.id} and ${userRolesInIam.tenantId} = ${usersInIam.tenantId})`.as(
7268
7331
  "roleCount"
7269
- ),
7270
- activeSessionCount: sql27`(select count(*)::int from ${sessionsInIam} where ${sessionsInIam.userId} = ${usersInIam.id} and ${sessionsInIam.tenantId} = ${usersInIam.tenantId} and ${sessionsInIam.expiresAt} > now())`.as(
7271
- "activeSessionCount"
7272
7332
  )
7273
7333
  };
7274
7334
  var sortColumnMap4 = {
@@ -7301,26 +7361,27 @@ var listUsersHandler = async (c) => {
7301
7361
  const query = c.req.valid("query");
7302
7362
  const database = c.get("database");
7303
7363
  const tenantId = c.get("tenantId");
7304
- const config = c.get("config");
7364
+ const _config = c.get("config");
7305
7365
  const page = query.page || 1;
7306
7366
  const limit = query.limit || 20;
7307
7367
  const offset = (page - 1) * limit;
7308
- const userTypeFilter = (query.userType && query.userType !== "all" ? query.userType : null) ?? config.userType;
7309
- const conditions = [eq58(usersInIam.tenantId, tenantId)];
7368
+ const userTypeFilter = query.userType && query.userType !== "all" ? query.userType : null;
7369
+ const conditions = [eq59(usersInIam.tenantId, tenantId)];
7310
7370
  if (userTypeFilter) {
7311
7371
  conditions.push(
7312
7372
  sql27`${usersInIam.userType} @> ARRAY[${userTypeFilter}]::text[]`
7313
7373
  );
7314
7374
  }
7315
7375
  if (query.search?.trim()) {
7316
- const term = `%${query.search.trim().replace(/[%_\\]/g, (c2) => `\\${c2}`)}%`;
7317
- conditions.push(
7318
- or4(
7319
- ilike4(usersInIam.fullName, term),
7320
- ilike4(usersInIam.email, term),
7321
- ilike4(usersInIam.phone, term)
7322
- )
7376
+ const term = `%${query.search.trim().replace(/[%_\\]/g, (ch) => `\\${ch}`)}%`;
7377
+ const searchCond = or4(
7378
+ ilike4(usersInIam.fullName, term),
7379
+ ilike4(usersInIam.email, term),
7380
+ ilike4(usersInIam.phone, term)
7323
7381
  );
7382
+ if (searchCond) {
7383
+ conditions.push(searchCond);
7384
+ }
7324
7385
  }
7325
7386
  if (query.email) {
7326
7387
  conditions.push(ilike4(usersInIam.email, `%${query.email}%`));
@@ -7332,38 +7393,52 @@ var listUsersHandler = async (c) => {
7332
7393
  conditions.push(ilike4(usersInIam.handle, `%${query.handle}%`));
7333
7394
  }
7334
7395
  if (query.filter === "verified") {
7335
- conditions.push(
7336
- or4(
7337
- eq58(usersInIam.emailVerified, true),
7338
- eq58(usersInIam.phoneVerified, true)
7339
- )
7396
+ const verifiedCond = or4(
7397
+ eq59(usersInIam.emailVerified, true),
7398
+ eq59(usersInIam.phoneVerified, true)
7340
7399
  );
7400
+ if (verifiedCond) {
7401
+ conditions.push(verifiedCond);
7402
+ }
7341
7403
  } else if (query.filter === "unverified") {
7342
- conditions.push(eq58(usersInIam.emailVerified, false));
7343
- conditions.push(eq58(usersInIam.phoneVerified, false));
7404
+ conditions.push(eq59(usersInIam.emailVerified, false));
7405
+ conditions.push(eq59(usersInIam.phoneVerified, false));
7344
7406
  }
7345
7407
  const orderDir = query.order === "asc" ? asc5 : desc5;
7346
7408
  const sortCol = query.sort && sortColumnMap4[query.sort] ? sortColumnMap4[query.sort] : usersInIam.fullName;
7347
- const whereClause = and53(...conditions);
7409
+ const whereClause = and54(...conditions);
7348
7410
  const [users, totalResult] = await Promise.all([
7349
7411
  database.select(userSelect).from(usersInIam).where(whereClause).orderBy(orderDir(sortCol)).limit(limit).offset(offset),
7350
7412
  database.select({ count: sql27`count(*)` }).from(usersInIam).where(whereClause)
7351
7413
  ]);
7352
7414
  const total = Number(totalResult[0]?.count || 0);
7353
7415
  const userIds = users.map((u) => u.id);
7416
+ const sessionCountRows = userIds.length > 0 ? await database.select({
7417
+ userId: sessionsInIam.userId,
7418
+ count: sql27`count(*)::int`.as("count")
7419
+ }).from(sessionsInIam).where(
7420
+ and54(
7421
+ eq59(sessionsInIam.tenantId, tenantId),
7422
+ inArray6(sessionsInIam.userId, userIds),
7423
+ gt9(sessionsInIam.expiresAt, (/* @__PURE__ */ new Date()).toISOString())
7424
+ )
7425
+ ).groupBy(sessionsInIam.userId) : [];
7426
+ const sessionCountByUser = new Map(
7427
+ sessionCountRows.map((r) => [r.userId, Number(r.count) ?? 0])
7428
+ );
7354
7429
  const roleRows = userIds.length > 0 ? await database.select({
7355
7430
  userId: userRolesInIam.userId,
7356
7431
  code: rolesInIam.code,
7357
7432
  name: rolesInIam.name
7358
7433
  }).from(userRolesInIam).innerJoin(
7359
7434
  rolesInIam,
7360
- and53(
7361
- eq58(rolesInIam.tenantId, userRolesInIam.tenantId),
7362
- eq58(rolesInIam.id, userRolesInIam.roleId)
7435
+ and54(
7436
+ eq59(rolesInIam.tenantId, userRolesInIam.tenantId),
7437
+ eq59(rolesInIam.id, userRolesInIam.roleId)
7363
7438
  )
7364
7439
  ).where(
7365
- and53(
7366
- eq58(userRolesInIam.tenantId, tenantId),
7440
+ and54(
7441
+ eq59(userRolesInIam.tenantId, tenantId),
7367
7442
  inArray6(userRolesInIam.userId, userIds)
7368
7443
  )
7369
7444
  ) : [];
@@ -7382,7 +7457,7 @@ var listUsersHandler = async (c) => {
7382
7457
  ...u,
7383
7458
  roles: null,
7384
7459
  userRoles: userRolesMap.get(u.id) ?? [],
7385
- activeSessionCount: Number(u.activeSessionCount) ?? 0
7460
+ activeSessionCount: sessionCountByUser.get(u.id) ?? 0
7386
7461
  })),
7387
7462
  total,
7388
7463
  page,
@@ -7393,13 +7468,13 @@ var listUsersHandler = async (c) => {
7393
7468
  };
7394
7469
 
7395
7470
  // src/routes/users/handler/search-users.ts
7396
- import { and as and54, eq as eq59, ilike as ilike5, or as or5 } from "drizzle-orm";
7471
+ import { and as and55, eq as eq60, ilike as ilike5, or as or5 } from "drizzle-orm";
7397
7472
  var searchUsersHandler = async (c) => {
7398
7473
  const query = c.req.valid("query");
7399
7474
  const database = c.get("database");
7400
7475
  const tenantId = c.get("tenantId");
7401
7476
  const limit = query.limit || 20;
7402
- const conditions = [eq59(usersInIam.tenantId, tenantId)];
7477
+ const conditions = [eq60(usersInIam.tenantId, tenantId)];
7403
7478
  if (query.search && query.search.trim().length > 0) {
7404
7479
  const searchCondition = or5(
7405
7480
  ilike5(usersInIam.fullName, `%${query.search}%`),
@@ -7417,25 +7492,25 @@ var searchUsersHandler = async (c) => {
7417
7492
  phone: usersInIam.phone,
7418
7493
  handle: usersInIam.handle,
7419
7494
  image: usersInIam.image
7420
- }).from(usersInIam).where(and54(...conditions)).limit(limit);
7495
+ }).from(usersInIam).where(and55(...conditions)).limit(limit);
7421
7496
  return c.json({ users }, 200);
7422
7497
  };
7423
7498
 
7424
7499
  // src/routes/users/handler/update-user.ts
7425
- import { and as and55, eq as eq60, inArray as inArray7, sql as sql28 } from "drizzle-orm";
7500
+ import { and as and56, eq as eq61, inArray as inArray7, sql as sql28 } from "drizzle-orm";
7426
7501
  var updateUserHandler = async (c) => {
7427
7502
  const { id } = c.req.valid("param");
7428
7503
  const body = c.req.valid("json");
7429
7504
  const database = c.get("database");
7430
7505
  const tenantId = c.get("tenantId");
7431
- const [existing] = await database.select().from(usersInIam).where(and55(eq60(usersInIam.id, id), eq60(usersInIam.tenantId, tenantId))).limit(1);
7506
+ const [existing] = await database.select().from(usersInIam).where(and56(eq61(usersInIam.id, id), eq61(usersInIam.tenantId, tenantId))).limit(1);
7432
7507
  if (!existing) {
7433
7508
  return c.json({ error: "User not found" }, 404);
7434
7509
  }
7435
7510
  if (body.handle && body.handle !== existing.handle) {
7436
7511
  const [handleExists] = await database.select().from(usersInIam).where(
7437
- and55(
7438
- eq60(usersInIam.tenantId, tenantId),
7512
+ and56(
7513
+ eq61(usersInIam.tenantId, tenantId),
7439
7514
  sql28`lower(${usersInIam.handle}) = lower(${body.handle})`
7440
7515
  )
7441
7516
  ).limit(1);
@@ -7468,7 +7543,7 @@ var updateUserHandler = async (c) => {
7468
7543
  const [updated] = await database.update(usersInIam).set({
7469
7544
  ...updateData,
7470
7545
  updatedAt: sql28`CURRENT_TIMESTAMP`
7471
- }).where(and55(eq60(usersInIam.id, id), eq60(usersInIam.tenantId, tenantId))).returning({
7546
+ }).where(and56(eq61(usersInIam.id, id), eq61(usersInIam.tenantId, tenantId))).returning({
7472
7547
  id: usersInIam.id,
7473
7548
  tenantId: usersInIam.tenantId,
7474
7549
  fullName: usersInIam.fullName,
@@ -7487,8 +7562,8 @@ var updateUserHandler = async (c) => {
7487
7562
  const roleIds = body.roleIds;
7488
7563
  if (roleIds.length > 0) {
7489
7564
  const validRoles = await database.select({ id: rolesInIam.id, code: rolesInIam.code }).from(rolesInIam).where(
7490
- and55(
7491
- eq60(rolesInIam.tenantId, tenantId),
7565
+ and56(
7566
+ eq61(rolesInIam.tenantId, tenantId),
7492
7567
  inArray7(rolesInIam.id, roleIds)
7493
7568
  )
7494
7569
  );
@@ -7497,9 +7572,9 @@ var updateUserHandler = async (c) => {
7497
7572
  );
7498
7573
  const toInsert = roleIds.filter((rid) => assignableIds.has(rid));
7499
7574
  await database.delete(userRolesInIam).where(
7500
- and55(
7501
- eq60(userRolesInIam.tenantId, tenantId),
7502
- eq60(userRolesInIam.userId, id)
7575
+ and56(
7576
+ eq61(userRolesInIam.tenantId, tenantId),
7577
+ eq61(userRolesInIam.userId, id)
7503
7578
  )
7504
7579
  );
7505
7580
  if (toInsert.length > 0) {
@@ -7513,9 +7588,9 @@ var updateUserHandler = async (c) => {
7513
7588
  }
7514
7589
  } else {
7515
7590
  await database.delete(userRolesInIam).where(
7516
- and55(
7517
- eq60(userRolesInIam.tenantId, tenantId),
7518
- eq60(userRolesInIam.userId, id)
7591
+ and56(
7592
+ eq61(userRolesInIam.tenantId, tenantId),
7593
+ eq61(userRolesInIam.userId, id)
7519
7594
  )
7520
7595
  );
7521
7596
  }
@@ -7917,38 +7992,43 @@ var bulkInviteUsersRoute = createRoute14({
7917
7992
  }
7918
7993
  }
7919
7994
  });
7920
- var userRoutes = new OpenAPIHono14().openapi(listUsersRoute, listUsersHandler).openapi(getUserRoute, getUserHandler).openapi(createUserRoute, createUserHandler).openapi(updateUserRoute, updateUserHandler).openapi(deleteUserRoute, deleteUserHandler).openapi(banUserRoute, banUserHandler).openapi(searchUsersRoute, searchUsersHandler).openapi(inviteUserRoute, inviteUserHandler).openapi(bulkInviteUsersRoute, bulkInviteUsersHandler);
7995
+ var IAM_ALL9 = "iam:all:all";
7996
+ var userRoutesBase = new OpenAPIHono14().use("*", (c, next) => {
7997
+ hasPermissionThrow(c, IAM_ALL9);
7998
+ return next();
7999
+ });
8000
+ var userRoutes = userRoutesBase.openapi(listUsersRoute, listUsersHandler).openapi(getUserRoute, getUserHandler).openapi(createUserRoute, createUserHandler).openapi(updateUserRoute, updateUserHandler).openapi(deleteUserRoute, deleteUserHandler).openapi(banUserRoute, banUserHandler).openapi(searchUsersRoute, searchUsersHandler).openapi(inviteUserRoute, inviteUserHandler).openapi(bulkInviteUsersRoute, bulkInviteUsersHandler);
7921
8001
  var users_route_default = userRoutes;
7922
8002
 
7923
8003
  // src/routes/verifications/verifications.route.ts
7924
8004
  import { createRoute as createRoute15, OpenAPIHono as OpenAPIHono15 } from "@hono/zod-openapi";
7925
8005
 
7926
8006
  // src/routes/verifications/handler/invalidate-verification.ts
7927
- import { and as and56, eq as eq61 } from "drizzle-orm";
8007
+ import { and as and57, eq as eq62 } from "drizzle-orm";
7928
8008
  var invalidateVerificationHandler = async (c) => {
7929
8009
  const { id } = c.req.valid("param");
7930
8010
  const database = c.get("database");
7931
8011
  const tenantId = c.get("tenantId");
7932
8012
  const [existing] = await database.select().from(verificationsInIam).where(
7933
- and56(
7934
- eq61(verificationsInIam.id, id),
7935
- eq61(verificationsInIam.tenantId, tenantId)
8013
+ and57(
8014
+ eq62(verificationsInIam.id, id),
8015
+ eq62(verificationsInIam.tenantId, tenantId)
7936
8016
  )
7937
8017
  ).limit(1);
7938
8018
  if (!existing) {
7939
8019
  return c.json({ error: "Verification not found" }, 404);
7940
8020
  }
7941
8021
  await database.delete(verificationsInIam).where(
7942
- and56(
7943
- eq61(verificationsInIam.id, id),
7944
- eq61(verificationsInIam.tenantId, tenantId)
8022
+ and57(
8023
+ eq62(verificationsInIam.id, id),
8024
+ eq62(verificationsInIam.tenantId, tenantId)
7945
8025
  )
7946
8026
  );
7947
8027
  return c.json({ message: "Verification invalidated" }, 200);
7948
8028
  };
7949
8029
 
7950
8030
  // src/routes/verifications/handler/list-verifications.ts
7951
- import { and as and57, eq as eq62, sql as sql29 } from "drizzle-orm";
8031
+ import { and as and58, eq as eq63, sql as sql29 } from "drizzle-orm";
7952
8032
  var listVerificationsHandler = async (c) => {
7953
8033
  const query = c.req.valid("query");
7954
8034
  const database = c.get("database");
@@ -7956,12 +8036,12 @@ var listVerificationsHandler = async (c) => {
7956
8036
  const page = query.page || 1;
7957
8037
  const limit = query.limit || 20;
7958
8038
  const offset = (page - 1) * limit;
7959
- const conditions = [eq62(verificationsInIam.tenantId, tenantId)];
8039
+ const conditions = [eq63(verificationsInIam.tenantId, tenantId)];
7960
8040
  if (query.userId) {
7961
- conditions.push(eq62(verificationsInIam.userId, query.userId));
8041
+ conditions.push(eq63(verificationsInIam.userId, query.userId));
7962
8042
  }
7963
8043
  if (query.type) {
7964
- conditions.push(eq62(verificationsInIam.type, query.type));
8044
+ conditions.push(eq63(verificationsInIam.type, query.type));
7965
8045
  }
7966
8046
  if (query.status) {
7967
8047
  if (query.status === "active") {
@@ -7975,8 +8055,8 @@ var listVerificationsHandler = async (c) => {
7975
8055
  }
7976
8056
  }
7977
8057
  const [verifications, totalResult] = await Promise.all([
7978
- database.select().from(verificationsInIam).where(and57(...conditions)).limit(limit).offset(offset),
7979
- database.select({ count: sql29`count(*)` }).from(verificationsInIam).where(and57(...conditions))
8058
+ database.select().from(verificationsInIam).where(and58(...conditions)).limit(limit).offset(offset),
8059
+ database.select({ count: sql29`count(*)` }).from(verificationsInIam).where(and58(...conditions))
7980
8060
  ]);
7981
8061
  const total = Number(totalResult[0]?.count || 0);
7982
8062
  return c.json({ verifications, total, page, limit }, 200);
@@ -8558,8 +8638,6 @@ export {
8558
8638
  createSessionMiddleware,
8559
8639
  createTenantMiddleware,
8560
8640
  hasPermission,
8561
- hasPermissionThrow,
8562
- hasRole,
8563
- hasRoleThrow
8641
+ hasPermissionThrow
8564
8642
  };
8565
8643
  //# sourceMappingURL=index.js.map