@spfn/auth 0.2.0-beta.44 → 0.2.0-beta.45

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/server.d.ts CHANGED
@@ -378,12 +378,14 @@ declare function updateUsernameService(userId: string | number | bigint, usernam
378
378
  * @spfn/auth - RBAC Initialization Service
379
379
  *
380
380
  * Initialize roles, permissions, and their mappings
381
+ * Uses hash-based change detection to skip unnecessary DB operations
381
382
  */
382
383
 
383
384
  /**
384
385
  * Initialize auth package with RBAC system
385
386
  *
386
- * Creates built-in roles, permissions, and custom configurations
387
+ * Creates built-in roles, permissions, and custom configurations.
388
+ * Uses hash-based change detection - skips DB operations when config is unchanged.
387
389
  *
388
390
  * @param options - Initialization options
389
391
  *
@@ -2821,6 +2823,73 @@ declare const userPermissions: drizzle_orm_pg_core.PgTableWithColumns<{
2821
2823
  type UserPermission = typeof userPermissions.$inferSelect;
2822
2824
  type NewUserPermission = typeof userPermissions.$inferInsert;
2823
2825
 
2826
+ /**
2827
+ * @spfn/auth - Auth Metadata Entity
2828
+ *
2829
+ * Key-value store for auth system metadata
2830
+ * Used for storing RBAC config hash and other system-level settings
2831
+ */
2832
+ declare const authMetadata: drizzle_orm_pg_core.PgTableWithColumns<{
2833
+ name: "auth_metadata";
2834
+ schema: string;
2835
+ columns: {
2836
+ key: drizzle_orm_pg_core.PgColumn<{
2837
+ name: "key";
2838
+ tableName: "auth_metadata";
2839
+ dataType: "string";
2840
+ columnType: "PgText";
2841
+ data: string;
2842
+ driverParam: string;
2843
+ notNull: true;
2844
+ hasDefault: false;
2845
+ isPrimaryKey: true;
2846
+ isAutoincrement: false;
2847
+ hasRuntimeDefault: false;
2848
+ enumValues: [string, ...string[]];
2849
+ baseColumn: never;
2850
+ identity: undefined;
2851
+ generated: undefined;
2852
+ }, {}, {}>;
2853
+ value: drizzle_orm_pg_core.PgColumn<{
2854
+ name: "value";
2855
+ tableName: "auth_metadata";
2856
+ dataType: "string";
2857
+ columnType: "PgText";
2858
+ data: string;
2859
+ driverParam: string;
2860
+ notNull: true;
2861
+ hasDefault: false;
2862
+ isPrimaryKey: false;
2863
+ isAutoincrement: false;
2864
+ hasRuntimeDefault: false;
2865
+ enumValues: [string, ...string[]];
2866
+ baseColumn: never;
2867
+ identity: undefined;
2868
+ generated: undefined;
2869
+ }, {}, {}>;
2870
+ updatedAt: drizzle_orm_pg_core.PgColumn<{
2871
+ name: "updated_at";
2872
+ tableName: "auth_metadata";
2873
+ dataType: "date";
2874
+ columnType: "PgTimestamp";
2875
+ data: Date;
2876
+ driverParam: string;
2877
+ notNull: true;
2878
+ hasDefault: true;
2879
+ isPrimaryKey: false;
2880
+ isAutoincrement: false;
2881
+ hasRuntimeDefault: false;
2882
+ enumValues: undefined;
2883
+ baseColumn: never;
2884
+ identity: undefined;
2885
+ generated: undefined;
2886
+ }, {}, {}>;
2887
+ };
2888
+ dialect: "pg";
2889
+ }>;
2890
+ type AuthMetadataEntity = typeof authMetadata.$inferSelect;
2891
+ type NewAuthMetadataEntity = typeof authMetadata.$inferInsert;
2892
+
2824
2893
  /**
2825
2894
  * Users Repository
2826
2895
  *
@@ -4447,6 +4516,25 @@ declare class SocialAccountsRepository extends BaseRepository {
4447
4516
  }
4448
4517
  declare const socialAccountsRepository: SocialAccountsRepository;
4449
4518
 
4519
+ /**
4520
+ * Auth Metadata Repository
4521
+ *
4522
+ * Key-value 기반 시스템 메타데이터 저장소
4523
+ * RBAC 설정 해시 등 시스템 설정값 관리
4524
+ */
4525
+
4526
+ declare class AuthMetadataRepository extends BaseRepository {
4527
+ /**
4528
+ * 키로 값 조회
4529
+ */
4530
+ get(key: string): Promise<string | null>;
4531
+ /**
4532
+ * 키-값 저장 (upsert)
4533
+ */
4534
+ set(key: string, value: string): Promise<void>;
4535
+ }
4536
+ declare const authMetadataRepository: AuthMetadataRepository;
4537
+
4450
4538
  /**
4451
4539
  * @spfn/auth - Password Helpers
4452
4540
  *
@@ -5434,4 +5522,4 @@ type AuthRegisterPayload = typeof authRegisterEvent._payload;
5434
5522
  type InvitationCreatedPayload = typeof invitationCreatedEvent._payload;
5435
5523
  type InvitationAcceptedPayload = typeof invitationAcceptedEvent._payload;
5436
5524
 
5437
- export { type AuthConfig, AuthContext, type AuthLoginPayload, AuthProviderSchema, type AuthRegisterPayload, COOKIE_NAMES, type CreateOAuthStateParams, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, type OAuthState, type Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionData, type SessionPayload, SocialAccountsRepository, SocialProvider, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, acceptInvitation, addPermissionToRole, authLogger, authLoginEvent, authRegisterEvent, authSchema, cancelInvitation, checkUsernameAvailableService, configureAuth, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, deleteInvitation, deleteRole, exchangeCodeForTokens, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getKeySize, getLocale, getOptionalAuth, getRole, getRoleByName, getRolePermissions, getSessionInfo, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isGoogleOAuthEnabled, keysRepository, listInvitations, parseDuration, permissions, permissionsRepository, refreshAccessToken, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, sealSession, setRolePermissions, shouldRefreshSession, shouldRotateKey, socialAccountsRepository, unsealSession, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };
5525
+ export { type AuthConfig, AuthContext, type AuthLoginPayload, type AuthMetadataEntity, AuthMetadataRepository, AuthProviderSchema, type AuthRegisterPayload, COOKIE_NAMES, type CreateOAuthStateParams, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewAuthMetadataEntity, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, type OAuthState, type Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionData, type SessionPayload, SocialAccountsRepository, SocialProvider, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, acceptInvitation, addPermissionToRole, authLogger, authLoginEvent, authMetadata, authMetadataRepository, authRegisterEvent, authSchema, cancelInvitation, checkUsernameAvailableService, configureAuth, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, deleteInvitation, deleteRole, exchangeCodeForTokens, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getKeySize, getLocale, getOptionalAuth, getRole, getRoleByName, getRolePermissions, getSessionInfo, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isGoogleOAuthEnabled, keysRepository, listInvitations, parseDuration, permissions, permissionsRepository, refreshAccessToken, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, sealSession, setRolePermissions, shouldRefreshSession, shouldRotateKey, socialAccountsRepository, unsealSession, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };
package/dist/server.js CHANGED
@@ -5299,6 +5299,27 @@ var init_user_permissions = __esm({
5299
5299
  }
5300
5300
  });
5301
5301
 
5302
+ // src/server/entities/auth-metadata.ts
5303
+ import { text as text10, timestamp } from "drizzle-orm/pg-core";
5304
+ var authMetadata;
5305
+ var init_auth_metadata = __esm({
5306
+ "src/server/entities/auth-metadata.ts"() {
5307
+ "use strict";
5308
+ init_schema4();
5309
+ authMetadata = authSchema.table(
5310
+ "auth_metadata",
5311
+ {
5312
+ // Metadata key (primary key)
5313
+ key: text10("key").primaryKey(),
5314
+ // Metadata value
5315
+ value: text10("value").notNull(),
5316
+ // Last updated timestamp
5317
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5318
+ }
5319
+ );
5320
+ }
5321
+ });
5322
+
5302
5323
  // src/server/entities/index.ts
5303
5324
  var init_entities = __esm({
5304
5325
  "src/server/entities/index.ts"() {
@@ -5314,6 +5335,7 @@ var init_entities = __esm({
5314
5335
  init_permissions();
5315
5336
  init_role_permissions();
5316
5337
  init_user_permissions();
5338
+ init_auth_metadata();
5317
5339
  }
5318
5340
  });
5319
5341
 
@@ -6315,16 +6337,16 @@ var init_invitations_repository = __esm({
6315
6337
  /**
6316
6338
  * 초대 상태 업데이트
6317
6339
  */
6318
- async updateStatus(id11, status, timestamp) {
6340
+ async updateStatus(id11, status, timestamp2) {
6319
6341
  const updates = {
6320
6342
  status,
6321
6343
  updatedAt: /* @__PURE__ */ new Date()
6322
6344
  };
6323
- if (timestamp) {
6345
+ if (timestamp2) {
6324
6346
  if (status === "accepted") {
6325
- updates.acceptedAt = timestamp;
6347
+ updates.acceptedAt = timestamp2;
6326
6348
  } else if (status === "cancelled") {
6327
- updates.cancelledAt = timestamp;
6349
+ updates.cancelledAt = timestamp2;
6328
6350
  }
6329
6351
  }
6330
6352
  const result = await this.db.update(userInvitations).set(updates).where(eq9(userInvitations.id, id11)).returning();
@@ -6558,6 +6580,43 @@ var init_social_accounts_repository = __esm({
6558
6580
  }
6559
6581
  });
6560
6582
 
6583
+ // src/server/repositories/auth-metadata.repository.ts
6584
+ import { BaseRepository as BaseRepository11 } from "@spfn/core/db";
6585
+ import { eq as eq11 } from "drizzle-orm";
6586
+ var AuthMetadataRepository, authMetadataRepository;
6587
+ var init_auth_metadata_repository = __esm({
6588
+ "src/server/repositories/auth-metadata.repository.ts"() {
6589
+ "use strict";
6590
+ init_auth_metadata();
6591
+ AuthMetadataRepository = class extends BaseRepository11 {
6592
+ /**
6593
+ * 키로 값 조회
6594
+ */
6595
+ async get(key) {
6596
+ const result = await this.readDb.select().from(authMetadata).where(eq11(authMetadata.key, key)).limit(1);
6597
+ return result[0]?.value ?? null;
6598
+ }
6599
+ /**
6600
+ * 키-값 저장 (upsert)
6601
+ */
6602
+ async set(key, value) {
6603
+ await this.db.insert(authMetadata).values({
6604
+ key,
6605
+ value,
6606
+ updatedAt: /* @__PURE__ */ new Date()
6607
+ }).onConflictDoUpdate({
6608
+ target: authMetadata.key,
6609
+ set: {
6610
+ value,
6611
+ updatedAt: /* @__PURE__ */ new Date()
6612
+ }
6613
+ });
6614
+ }
6615
+ };
6616
+ authMetadataRepository = new AuthMetadataRepository();
6617
+ }
6618
+ });
6619
+
6561
6620
  // src/server/repositories/index.ts
6562
6621
  var init_repositories = __esm({
6563
6622
  "src/server/repositories/index.ts"() {
@@ -6572,6 +6631,7 @@ var init_repositories = __esm({
6572
6631
  init_user_profiles_repository();
6573
6632
  init_invitations_repository();
6574
6633
  init_social_accounts_repository();
6634
+ init_auth_metadata_repository();
6575
6635
  }
6576
6636
  });
6577
6637
 
@@ -7355,6 +7415,7 @@ async function changePasswordService(params) {
7355
7415
  // src/server/services/rbac.service.ts
7356
7416
  init_repositories();
7357
7417
  init_rbac();
7418
+ import { createHash } from "crypto";
7358
7419
 
7359
7420
  // src/server/lib/config.ts
7360
7421
  import { env as env5 } from "@spfn/auth/config";
@@ -7417,6 +7478,33 @@ function getSessionTtl(override) {
7417
7478
  }
7418
7479
 
7419
7480
  // src/server/services/rbac.service.ts
7481
+ var RBAC_HASH_KEY = "rbac_config_hash";
7482
+ function computeConfigHash(allRoles, allPermissions, allMappings) {
7483
+ const payload = JSON.stringify({
7484
+ roles: allRoles.map((r) => ({ name: r.name, displayName: r.displayName, description: r.description, priority: r.priority, isSystem: r.isSystem, isBuiltin: r.isBuiltin })).sort((a, b) => a.name.localeCompare(b.name)),
7485
+ permissions: allPermissions.map((p) => ({ name: p.name, displayName: p.displayName, description: p.description, category: p.category, isSystem: p.isSystem, isBuiltin: p.isBuiltin })).sort((a, b) => a.name.localeCompare(b.name)),
7486
+ mappings: Object.keys(allMappings).sort().reduce((acc, key) => {
7487
+ acc[key] = [...allMappings[key]].sort();
7488
+ return acc;
7489
+ }, {})
7490
+ });
7491
+ return createHash("sha256").update(payload).digest("hex");
7492
+ }
7493
+ function collectMappings(options) {
7494
+ const allMappings = { ...BUILTIN_ROLE_PERMISSIONS };
7495
+ if (options.rolePermissions) {
7496
+ for (const [roleName, permNames] of Object.entries(options.rolePermissions)) {
7497
+ if (allMappings[roleName]) {
7498
+ allMappings[roleName] = [
7499
+ .../* @__PURE__ */ new Set([...allMappings[roleName], ...permNames])
7500
+ ];
7501
+ } else {
7502
+ allMappings[roleName] = permNames;
7503
+ }
7504
+ }
7505
+ }
7506
+ return allMappings;
7507
+ }
7420
7508
  async function initializeAuth(options = {}) {
7421
7509
  authLogger.service.info("\u{1F510} Initializing RBAC system...");
7422
7510
  if (options.sessionTtl !== void 0) {
@@ -7429,100 +7517,100 @@ async function initializeAuth(options = {}) {
7429
7517
  ...Object.values(BUILTIN_ROLES),
7430
7518
  ...options.roles || []
7431
7519
  ];
7432
- for (const roleConfig of allRoles) {
7433
- await upsertRole(roleConfig);
7434
- }
7435
7520
  const allPermissions = [
7436
7521
  ...Object.values(BUILTIN_PERMISSIONS),
7437
7522
  ...options.permissions || []
7438
7523
  ];
7439
- for (const permConfig of allPermissions) {
7440
- await upsertPermission(permConfig);
7441
- }
7442
- const allMappings = { ...BUILTIN_ROLE_PERMISSIONS };
7443
- if (options.rolePermissions) {
7444
- for (const [roleName, permNames] of Object.entries(options.rolePermissions)) {
7445
- if (allMappings[roleName]) {
7446
- allMappings[roleName] = [
7447
- .../* @__PURE__ */ new Set([...allMappings[roleName], ...permNames])
7448
- ];
7449
- } else {
7450
- allMappings[roleName] = permNames;
7451
- }
7452
- }
7453
- }
7454
- for (const [roleName, permNames] of Object.entries(allMappings)) {
7455
- await assignPermissionsToRole(roleName, permNames);
7524
+ const allMappings = collectMappings(options);
7525
+ const configHash = computeConfigHash(allRoles, allPermissions, allMappings);
7526
+ const storedHash = await authMetadataRepository.get(RBAC_HASH_KEY);
7527
+ if (storedHash === configHash) {
7528
+ authLogger.service.info("\u2705 RBAC config unchanged, skipping initialization");
7529
+ return;
7456
7530
  }
7531
+ authLogger.service.info("\u{1F504} RBAC config changed, applying updates...");
7532
+ const existingRoles = await rolesRepository.findAll();
7533
+ const existingPermissions = await permissionsRepository.findAll();
7534
+ const rolesByName = new Map(existingRoles.map((r) => [r.name, r]));
7535
+ const permsByName = new Map(existingPermissions.map((p) => [p.name, p]));
7536
+ await syncRoles(allRoles, rolesByName);
7537
+ await syncPermissions(allPermissions, permsByName);
7538
+ const updatedRoles = await rolesRepository.findAll();
7539
+ const updatedPermissions = await permissionsRepository.findAll();
7540
+ const updatedRolesByName = new Map(updatedRoles.map((r) => [r.name, r]));
7541
+ const updatedPermsByName = new Map(updatedPermissions.map((p) => [p.name, p]));
7542
+ await syncMappings(allMappings, updatedRolesByName, updatedPermsByName);
7543
+ await authMetadataRepository.set(RBAC_HASH_KEY, configHash);
7457
7544
  authLogger.service.info("\u2705 RBAC initialization complete");
7458
7545
  authLogger.service.info(`\u{1F4CA} Roles: ${allRoles.length}, Permissions: ${allPermissions.length}`);
7459
7546
  authLogger.service.info("\u{1F512} Built-in roles: user, admin, superadmin");
7460
7547
  }
7461
- async function upsertRole(config) {
7462
- const existing = await rolesRepository.findByName(config.name);
7463
- if (!existing) {
7464
- await rolesRepository.create({
7465
- name: config.name,
7466
- displayName: config.displayName,
7467
- description: config.description || null,
7468
- priority: config.priority ?? 10,
7469
- isSystem: config.isSystem ?? false,
7470
- isBuiltin: config.isBuiltin ?? false,
7471
- isActive: true
7472
- });
7473
- authLogger.service.info(` \u2705 Created role: ${config.name}`);
7474
- } else {
7475
- const updateData = {
7476
- displayName: config.displayName,
7477
- description: config.description || null
7478
- };
7479
- if (!existing.isBuiltin) {
7480
- updateData.priority = config.priority ?? existing.priority;
7548
+ async function syncRoles(configs, existingByName) {
7549
+ for (const config of configs) {
7550
+ const existing = existingByName.get(config.name);
7551
+ if (!existing) {
7552
+ await rolesRepository.create({
7553
+ name: config.name,
7554
+ displayName: config.displayName,
7555
+ description: config.description || null,
7556
+ priority: config.priority ?? 10,
7557
+ isSystem: config.isSystem ?? false,
7558
+ isBuiltin: config.isBuiltin ?? false,
7559
+ isActive: true
7560
+ });
7561
+ authLogger.service.info(` \u2705 Created role: ${config.name}`);
7562
+ } else {
7563
+ const updateData = {
7564
+ displayName: config.displayName,
7565
+ description: config.description || null
7566
+ };
7567
+ if (!existing.isBuiltin) {
7568
+ updateData.priority = config.priority ?? existing.priority;
7569
+ }
7570
+ await rolesRepository.updateById(existing.id, updateData);
7481
7571
  }
7482
- await rolesRepository.updateById(existing.id, updateData);
7483
- }
7484
- }
7485
- async function upsertPermission(config) {
7486
- const existing = await permissionsRepository.findByName(config.name);
7487
- if (!existing) {
7488
- await permissionsRepository.create({
7489
- name: config.name,
7490
- displayName: config.displayName,
7491
- description: config.description || null,
7492
- category: config.category || null,
7493
- isSystem: config.isSystem ?? false,
7494
- isBuiltin: config.isBuiltin ?? false,
7495
- isActive: true,
7496
- metadata: null
7497
- });
7498
- authLogger.service.info(` \u2705 Created permission: ${config.name}`);
7499
- } else {
7500
- await permissionsRepository.updateById(existing.id, {
7501
- displayName: config.displayName,
7502
- description: config.description || null,
7503
- category: config.category || null
7504
- });
7505
7572
  }
7506
7573
  }
7507
- async function assignPermissionsToRole(roleName, permissionNames) {
7508
- const role = await rolesRepository.findByName(roleName);
7509
- if (!role) {
7510
- authLogger.service.warn(` \u26A0\uFE0F Role not found: ${roleName}, skipping permission assignment`);
7511
- return;
7512
- }
7513
- const perms = await permissionsRepository.findByNames(permissionNames);
7514
- if (perms.length === 0) {
7515
- authLogger.service.warn(` \u26A0\uFE0F No permissions found for role: ${roleName}`);
7516
- return;
7574
+ async function syncPermissions(configs, existingByName) {
7575
+ for (const config of configs) {
7576
+ const existing = existingByName.get(config.name);
7577
+ if (!existing) {
7578
+ await permissionsRepository.create({
7579
+ name: config.name,
7580
+ displayName: config.displayName,
7581
+ description: config.description || null,
7582
+ category: config.category || null,
7583
+ isSystem: config.isSystem ?? false,
7584
+ isBuiltin: config.isBuiltin ?? false,
7585
+ isActive: true,
7586
+ metadata: null
7587
+ });
7588
+ authLogger.service.info(` \u2705 Created permission: ${config.name}`);
7589
+ } else {
7590
+ await permissionsRepository.updateById(existing.id, {
7591
+ displayName: config.displayName,
7592
+ description: config.description || null,
7593
+ category: config.category || null
7594
+ });
7595
+ }
7517
7596
  }
7518
- const existingMappings = await rolePermissionsRepository.findByRoleId(role.id);
7519
- const existingPermIds = new Set(existingMappings.map((m) => m.permissionId));
7520
- const newMappings = perms.filter((perm) => !existingPermIds.has(perm.id)).map((perm) => ({
7521
- roleId: role.id,
7522
- permissionId: perm.id
7523
- }));
7524
- if (newMappings.length > 0) {
7525
- await rolePermissionsRepository.createMany(newMappings);
7597
+ }
7598
+ async function syncMappings(allMappings, rolesByName, permsByName) {
7599
+ for (const [roleName, permNames] of Object.entries(allMappings)) {
7600
+ const role = rolesByName.get(roleName);
7601
+ if (!role) {
7602
+ authLogger.service.warn(` \u26A0\uFE0F Role not found: ${roleName}, skipping permission assignment`);
7603
+ continue;
7604
+ }
7605
+ const existingMappings = await rolePermissionsRepository.findByRoleId(role.id);
7606
+ const existingPermIds = new Set(existingMappings.map((m) => m.permissionId));
7607
+ const newMappings = permNames.map((name) => permsByName.get(name)).filter((perm) => perm != null).filter((perm) => !existingPermIds.has(perm.id)).map((perm) => ({
7608
+ roleId: role.id,
7609
+ permissionId: perm.id
7610
+ }));
7611
+ if (newMappings.length > 0) {
7612
+ await rolePermissionsRepository.createMany(newMappings);
7613
+ }
7526
7614
  }
7527
7615
  }
7528
7616
 
@@ -9491,6 +9579,7 @@ function createAuthLifecycle(options = {}) {
9491
9579
  };
9492
9580
  }
9493
9581
  export {
9582
+ AuthMetadataRepository,
9494
9583
  AuthProviderSchema,
9495
9584
  COOKIE_NAMES,
9496
9585
  EmailSchema,
@@ -9518,6 +9607,8 @@ export {
9518
9607
  addPermissionToRole,
9519
9608
  authLogger,
9520
9609
  authLoginEvent,
9610
+ authMetadata,
9611
+ authMetadataRepository,
9521
9612
  authRegisterEvent,
9522
9613
  mainAuthRouter as authRouter,
9523
9614
  authSchema,