@open-core/identity 1.0.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.
Files changed (46) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +682 -0
  3. package/dist/entities/account.entity.d.ts +34 -0
  4. package/dist/entities/account.entity.js +2 -0
  5. package/dist/entities/role.entity.d.ts +35 -0
  6. package/dist/entities/role.entity.js +2 -0
  7. package/dist/events/identity.events.d.ts +24 -0
  8. package/dist/events/identity.events.js +2 -0
  9. package/dist/index.d.ts +70 -0
  10. package/dist/index.js +100 -0
  11. package/dist/repositories/account.repository.d.ts +60 -0
  12. package/dist/repositories/account.repository.js +185 -0
  13. package/dist/repositories/role.repository.d.ts +50 -0
  14. package/dist/repositories/role.repository.js +79 -0
  15. package/dist/services/account.service.d.ts +78 -0
  16. package/dist/services/account.service.js +207 -0
  17. package/dist/services/auth/api-auth.provider.d.ts +30 -0
  18. package/dist/services/auth/api-auth.provider.js +134 -0
  19. package/dist/services/auth/credentials-auth.provider.d.ts +27 -0
  20. package/dist/services/auth/credentials-auth.provider.js +214 -0
  21. package/dist/services/auth/local-auth.provider.d.ts +28 -0
  22. package/dist/services/auth/local-auth.provider.js +135 -0
  23. package/dist/services/cache/memory-cache.service.d.ts +47 -0
  24. package/dist/services/cache/memory-cache.service.js +108 -0
  25. package/dist/services/identity-auth.provider.d.ts +18 -0
  26. package/dist/services/identity-auth.provider.js +125 -0
  27. package/dist/services/identity-principal.provider.d.ts +29 -0
  28. package/dist/services/identity-principal.provider.js +104 -0
  29. package/dist/services/principal/api-principal.provider.d.ts +27 -0
  30. package/dist/services/principal/api-principal.provider.js +141 -0
  31. package/dist/services/principal/local-principal.provider.d.ts +39 -0
  32. package/dist/services/principal/local-principal.provider.js +114 -0
  33. package/dist/services/role.service.d.ts +73 -0
  34. package/dist/services/role.service.js +145 -0
  35. package/dist/setup.d.ts +58 -0
  36. package/dist/setup.js +93 -0
  37. package/dist/types/auth.types.d.ts +48 -0
  38. package/dist/types/auth.types.js +2 -0
  39. package/dist/types/index.d.ts +36 -0
  40. package/dist/types/index.js +2 -0
  41. package/migrations/001_accounts_table.sql +16 -0
  42. package/migrations/002_roles_table.sql +21 -0
  43. package/migrations/003_alter_accounts_add_role.sql +24 -0
  44. package/migrations/004_rename_uuid_to_linked_id.sql +12 -0
  45. package/migrations/005_add_password_hash.sql +7 -0
  46. package/package.json +59 -0
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Represents an authenticated account within OpenCore Identity.
3
+ * This entity is storage-agnostic and maps directly to the accounts table.
4
+ */
5
+ export interface Account {
6
+ /** Numeric primary key for internal references and joins. */
7
+ id: number;
8
+ /** Optional linked ID - can be UUID (local) or external API ID. Auto-generated by default. */
9
+ linkedId: string | null;
10
+ /** Source of the account: 'local', 'api', or custom identifier. */
11
+ externalSource?: string;
12
+ /** Rockstar license identifier (preferred). */
13
+ license: string | null;
14
+ /** Discord user ID. */
15
+ discord: string | null;
16
+ /** Steam hex identifier. */
17
+ steam: string | null;
18
+ /** Optional display name or username. */
19
+ username: string | null;
20
+ /** Role assignment (FK to roles table). */
21
+ roleId: number | null;
22
+ /** Custom permissions specific to this account (overrides/additions to role permissions). */
23
+ customPermissions: string[];
24
+ /** Creation timestamp. */
25
+ createdAt: Date;
26
+ /** Last successful login timestamp. */
27
+ lastLoginAt: Date;
28
+ /** Ban status flag. */
29
+ banned: boolean;
30
+ /** Ban reason text when banned. */
31
+ banReason: string | null;
32
+ /** Ban expiration (null means permanent). */
33
+ banExpires: Date | null;
34
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Role entity representing a security role/rank in the system.
3
+ * Roles define base permissions and hierarchy through rank.
4
+ */
5
+ export interface Role {
6
+ /**
7
+ * Unique identifier for the role
8
+ */
9
+ id: number;
10
+ /**
11
+ * Internal name (e.g., 'admin', 'moderator', 'user')
12
+ */
13
+ name: string;
14
+ /**
15
+ * Display name for UI (e.g., 'Administrator', 'Moderator', 'Player')
16
+ */
17
+ displayName: string;
18
+ /**
19
+ * Numeric rank for hierarchy comparisons (higher = more privileged)
20
+ * Example: 100 = admin, 50 = moderator, 0 = user
21
+ */
22
+ rank: number;
23
+ /**
24
+ * Base permissions granted by this role
25
+ */
26
+ permissions: string[];
27
+ /**
28
+ * Whether this is the default role for new accounts
29
+ */
30
+ isDefault: boolean;
31
+ /**
32
+ * Role creation timestamp
33
+ */
34
+ createdAt: Date;
35
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,24 @@
1
+ import type { AccountIdentifiers } from "../types";
2
+ export interface AccountCreatedEvent {
3
+ accountId: number;
4
+ uuid: string;
5
+ identifiers: AccountIdentifiers;
6
+ }
7
+ export interface AccountBannedEvent {
8
+ accountId: number;
9
+ reason?: string | null;
10
+ expires?: Date | null;
11
+ }
12
+ export interface AccountUnbannedEvent {
13
+ accountId: number;
14
+ }
15
+ export interface AccountLoggedInEvent {
16
+ accountId: number;
17
+ uuid: string;
18
+ }
19
+ export interface IdentityEventMap {
20
+ "identity:accountCreated": AccountCreatedEvent;
21
+ "identity:accountBanned": AccountBannedEvent;
22
+ "identity:accountUnbanned": AccountUnbannedEvent;
23
+ "identity:accountLoggedIn": AccountLoggedInEvent;
24
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,70 @@
1
+ import * as Setup from "./setup";
2
+ import type * as Entities from "./entities/account.entity";
3
+ import type * as RoleEntities from "./entities/role.entity";
4
+ import * as AccountRepo from "./repositories/account.repository";
5
+ import * as RoleRepo from "./repositories/role.repository";
6
+ import * as AcctService from "./services/account.service";
7
+ import * as RService from "./services/role.service";
8
+ import * as CacheService from "./services/cache/memory-cache.service";
9
+ import * as LocalAuth from "./services/auth/local-auth.provider";
10
+ import * as CredentialsAuth from "./services/auth/credentials-auth.provider";
11
+ import * as ApiAuth from "./services/auth/api-auth.provider";
12
+ import * as LocalPrincipal from "./services/principal/local-principal.provider";
13
+ import * as ApiPrincipal from "./services/principal/api-principal.provider";
14
+ import * as AuthProvider from "./services/identity-auth.provider";
15
+ import * as PrincipalProvider from "./services/identity-principal.provider";
16
+ import type * as Types from "./types";
17
+ import type * as AuthTypes from "./types/auth.types";
18
+ import type * as Events from "./events/identity.events";
19
+ export declare namespace Identity {
20
+ const setup: typeof Setup.setupIdentity;
21
+ type SetupOptions = Setup.IdentitySetupOptions;
22
+ type Account = Entities.Account;
23
+ type Role = RoleEntities.Role;
24
+ export import AccountRepository = AccountRepo.AccountRepository;
25
+ export import RoleRepository = RoleRepo.RoleRepository;
26
+ export import AccountService = AcctService.AccountService;
27
+ export import RoleService = RService.RoleService;
28
+ export import MemoryCacheService = CacheService.MemoryCacheService;
29
+ export import LocalAuthProvider = LocalAuth.LocalAuthProvider;
30
+ export import CredentialsAuthProvider = CredentialsAuth.CredentialsAuthProvider;
31
+ export import ApiAuthProvider = ApiAuth.ApiAuthProvider;
32
+ export import LocalPrincipalProvider = LocalPrincipal.LocalPrincipalProvider;
33
+ export import ApiPrincipalProvider = ApiPrincipal.ApiPrincipalProvider;
34
+ export import IdentityAuthProvider = AuthProvider.IdentityAuthProvider;
35
+ export import IdentityPrincipalProvider = PrincipalProvider.IdentityPrincipalProvider;
36
+ type IdentifierType = Types.IdentifierType;
37
+ type AccountIdentifiers = Types.AccountIdentifiers;
38
+ type CreateAccountInput = Types.CreateAccountInput;
39
+ type BanOptions = Types.BanOptions;
40
+ type AuthSession = Types.AuthSession;
41
+ type CreateRoleInput = Types.CreateRoleInput;
42
+ type UpdateRoleInput = Types.UpdateRoleInput;
43
+ type ApiAuthConfig = AuthTypes.ApiAuthConfig;
44
+ type ApiAuthResponse = AuthTypes.ApiAuthResponse;
45
+ type ApiPrincipalResponse = AuthTypes.ApiPrincipalResponse;
46
+ type CacheOptions = AuthTypes.CacheOptions;
47
+ type AccountCreatedEvent = Events.AccountCreatedEvent;
48
+ type AccountBannedEvent = Events.AccountBannedEvent;
49
+ type AccountUnbannedEvent = Events.AccountUnbannedEvent;
50
+ type AccountLoggedInEvent = Events.AccountLoggedInEvent;
51
+ type IdentityEventMap = Events.IdentityEventMap;
52
+ }
53
+ export { setupIdentity, type IdentitySetupOptions } from "./setup";
54
+ export * from "./entities/account.entity";
55
+ export * from "./entities/role.entity";
56
+ export * from "./repositories/account.repository";
57
+ export * from "./repositories/role.repository";
58
+ export * from "./services/account.service";
59
+ export * from "./services/role.service";
60
+ export * from "./services/cache/memory-cache.service";
61
+ export * from "./services/auth/local-auth.provider";
62
+ export * from "./services/auth/credentials-auth.provider";
63
+ export * from "./services/auth/api-auth.provider";
64
+ export * from "./services/principal/local-principal.provider";
65
+ export * from "./services/principal/api-principal.provider";
66
+ export * from "./services/identity-auth.provider";
67
+ export * from "./services/identity-principal.provider";
68
+ export * from "./events/identity.events";
69
+ export * from "./types";
70
+ export * from "./types/auth.types";
package/dist/index.js ADDED
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.setupIdentity = exports.Identity = void 0;
40
+ // Imports for namespace
41
+ const Setup = __importStar(require("./setup"));
42
+ const AccountRepo = __importStar(require("./repositories/account.repository"));
43
+ const RoleRepo = __importStar(require("./repositories/role.repository"));
44
+ const AcctService = __importStar(require("./services/account.service"));
45
+ const RService = __importStar(require("./services/role.service"));
46
+ const CacheService = __importStar(require("./services/cache/memory-cache.service"));
47
+ const LocalAuth = __importStar(require("./services/auth/local-auth.provider"));
48
+ const CredentialsAuth = __importStar(require("./services/auth/credentials-auth.provider"));
49
+ const ApiAuth = __importStar(require("./services/auth/api-auth.provider"));
50
+ const LocalPrincipal = __importStar(require("./services/principal/local-principal.provider"));
51
+ const ApiPrincipal = __importStar(require("./services/principal/api-principal.provider"));
52
+ const AuthProvider = __importStar(require("./services/identity-auth.provider"));
53
+ const PrincipalProvider = __importStar(require("./services/identity-principal.provider"));
54
+ // Namespace for organized exports
55
+ // eslint-disable-next-line @typescript-eslint/no-namespace
56
+ var Identity;
57
+ (function (Identity) {
58
+ // Setup
59
+ Identity.setup = Setup.setupIdentity;
60
+ // Repositories
61
+ Identity.AccountRepository = AccountRepo.AccountRepository;
62
+ Identity.RoleRepository = RoleRepo.RoleRepository;
63
+ // Services
64
+ Identity.AccountService = AcctService.AccountService;
65
+ Identity.RoleService = RService.RoleService;
66
+ Identity.MemoryCacheService = CacheService.MemoryCacheService;
67
+ // Auth Providers
68
+ Identity.LocalAuthProvider = LocalAuth.LocalAuthProvider;
69
+ Identity.CredentialsAuthProvider = CredentialsAuth.CredentialsAuthProvider;
70
+ Identity.ApiAuthProvider = ApiAuth.ApiAuthProvider;
71
+ // Principal Providers
72
+ Identity.LocalPrincipalProvider = LocalPrincipal.LocalPrincipalProvider;
73
+ Identity.ApiPrincipalProvider = ApiPrincipal.ApiPrincipalProvider;
74
+ // Legacy providers (for backward compatibility)
75
+ Identity.IdentityAuthProvider = AuthProvider.IdentityAuthProvider;
76
+ Identity.IdentityPrincipalProvider = PrincipalProvider.IdentityPrincipalProvider;
77
+ })(Identity || (exports.Identity = Identity = {}));
78
+ // Top-level exports for backward compatibility
79
+ var setup_1 = require("./setup");
80
+ Object.defineProperty(exports, "setupIdentity", { enumerable: true, get: function () { return setup_1.setupIdentity; } });
81
+ __exportStar(require("./entities/account.entity"), exports);
82
+ __exportStar(require("./entities/role.entity"), exports);
83
+ __exportStar(require("./repositories/account.repository"), exports);
84
+ __exportStar(require("./repositories/role.repository"), exports);
85
+ __exportStar(require("./services/account.service"), exports);
86
+ __exportStar(require("./services/role.service"), exports);
87
+ __exportStar(require("./services/cache/memory-cache.service"), exports);
88
+ // Auth providers
89
+ __exportStar(require("./services/auth/local-auth.provider"), exports);
90
+ __exportStar(require("./services/auth/credentials-auth.provider"), exports);
91
+ __exportStar(require("./services/auth/api-auth.provider"), exports);
92
+ // Principal providers
93
+ __exportStar(require("./services/principal/local-principal.provider"), exports);
94
+ __exportStar(require("./services/principal/api-principal.provider"), exports);
95
+ // Legacy providers
96
+ __exportStar(require("./services/identity-auth.provider"), exports);
97
+ __exportStar(require("./services/identity-principal.provider"), exports);
98
+ __exportStar(require("./events/identity.events"), exports);
99
+ __exportStar(require("./types"), exports);
100
+ __exportStar(require("./types/auth.types"), exports);
@@ -0,0 +1,60 @@
1
+ import { Server } from "@open-core/framework";
2
+ import type { Account } from "../entities/account.entity";
3
+ import type { Role } from "../entities/role.entity";
4
+ import type { CreateAccountInput, IdentifierType } from "../types";
5
+ interface AccountRow {
6
+ id?: number;
7
+ linked_id: string | null;
8
+ external_source: string | null;
9
+ license: string | null;
10
+ discord: string | null;
11
+ steam: string | null;
12
+ username: string | null;
13
+ role_id: number | null;
14
+ custom_permissions: string;
15
+ created_at: Date;
16
+ last_login_at: Date;
17
+ banned: boolean;
18
+ ban_reason: string | null;
19
+ ban_expires: Date | null;
20
+ }
21
+ /**
22
+ * Repository for the accounts table.
23
+ */
24
+ export declare class AccountRepository extends Server.Repository<Account> {
25
+ protected readonly db: Server.DatabaseContract;
26
+ protected tableName: string;
27
+ constructor(db: Server.DatabaseContract);
28
+ findByLinkedId(linkedId: string): Promise<Account | null>;
29
+ findByIdentifier(type: IdentifierType, value: string): Promise<Account | null>;
30
+ createAccount(input: CreateAccountInput): Promise<Account>;
31
+ updateLastLogin(accountId: number, date: Date): Promise<void>;
32
+ setBan(accountId: number, banned: boolean, reason: string | null, expires: Date | null): Promise<void>;
33
+ updateCustomPermissions(accountId: number, permissions: string[]): Promise<void>;
34
+ updateRole(accountId: number, roleId: number | null): Promise<void>;
35
+ /**
36
+ * Find account by ID with role data joined.
37
+ *
38
+ * @param id - Account ID
39
+ * @returns Account with role or null if not found
40
+ */
41
+ findByIdWithRole(id: number): Promise<{
42
+ account: Account;
43
+ role: Role | null;
44
+ } | null>;
45
+ /**
46
+ * Find account by linkedId with role data joined.
47
+ *
48
+ * @param linkedId - Account linkedId
49
+ * @returns Account with role or null if not found
50
+ */
51
+ findByLinkedIdWithRole(linkedId: string): Promise<{
52
+ account: Account;
53
+ role: Role | null;
54
+ } | null>;
55
+ protected toEntity(row: AccountRow): Account;
56
+ protected toRow(entity: Account): Record<string, unknown>;
57
+ private identifierColumn;
58
+ private parsePermissions;
59
+ }
60
+ export {};
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AccountRepository = void 0;
4
+ const framework_1 = require("@open-core/framework");
5
+ /**
6
+ * Repository for the accounts table.
7
+ */
8
+ class AccountRepository extends framework_1.Server.Repository {
9
+ constructor(db) {
10
+ super(db);
11
+ this.db = db;
12
+ this.tableName = "accounts";
13
+ }
14
+ async findByLinkedId(linkedId) {
15
+ const row = await this.db.single(`SELECT * FROM ${this.tableName} WHERE linked_id = ?`, [linkedId]);
16
+ return row ? this.toEntity(row) : null;
17
+ }
18
+ async findByIdentifier(type, value) {
19
+ const column = this.identifierColumn(type);
20
+ const row = await this.db.single(`SELECT * FROM ${this.tableName} WHERE ${column} = ?`, [value]);
21
+ return row ? this.toEntity(row) : null;
22
+ }
23
+ async createAccount(input) {
24
+ const now = new Date();
25
+ const row = {
26
+ linked_id: input.linkedId ?? null,
27
+ external_source: input.externalSource ?? null,
28
+ license: input.license ?? null,
29
+ discord: input.discord ?? null,
30
+ steam: input.steam ?? null,
31
+ username: input.username ?? null,
32
+ role_id: input.roleId ?? null,
33
+ custom_permissions: JSON.stringify([]),
34
+ created_at: now,
35
+ last_login_at: now,
36
+ banned: false,
37
+ ban_reason: null,
38
+ ban_expires: null,
39
+ };
40
+ const insertId = await this.insertRow(row);
41
+ return this.toEntity({ ...row, id: insertId });
42
+ }
43
+ async updateLastLogin(accountId, date) {
44
+ await this.db.execute(`UPDATE ${this.tableName} SET last_login_at = ? WHERE id = ?`, [date, accountId]);
45
+ }
46
+ async setBan(accountId, banned, reason, expires) {
47
+ await this.db.execute(`UPDATE ${this.tableName} SET banned = ?, ban_reason = ?, ban_expires = ? WHERE id = ?`, [banned, reason, expires, accountId]);
48
+ }
49
+ async updateCustomPermissions(accountId, permissions) {
50
+ await this.db.execute(`UPDATE ${this.tableName} SET custom_permissions = ? WHERE id = ?`, [JSON.stringify(permissions), accountId]);
51
+ }
52
+ async updateRole(accountId, roleId) {
53
+ await this.db.execute(`UPDATE ${this.tableName} SET role_id = ? WHERE id = ?`, [roleId, accountId]);
54
+ }
55
+ /**
56
+ * Find account by ID with role data joined.
57
+ *
58
+ * @param id - Account ID
59
+ * @returns Account with role or null if not found
60
+ */
61
+ async findByIdWithRole(id) {
62
+ const row = await this.db.single(`SELECT
63
+ a.*,
64
+ r.id as role_id,
65
+ r.name as role_name,
66
+ r.display_name as role_display_name,
67
+ r.rank as role_rank,
68
+ r.permissions as role_permissions,
69
+ r.is_default as role_is_default,
70
+ r.created_at as role_created_at
71
+ FROM ${this.tableName} a
72
+ LEFT JOIN roles r ON a.role_id = r.id
73
+ WHERE a.id = ?`, [id]);
74
+ if (!row)
75
+ return null;
76
+ const account = this.toEntity(row);
77
+ const role = row.role_name
78
+ ? {
79
+ id: row.role_id,
80
+ name: row.role_name,
81
+ displayName: row.role_display_name,
82
+ rank: row.role_rank,
83
+ permissions: JSON.parse(row.role_permissions),
84
+ isDefault: Boolean(row.role_is_default),
85
+ createdAt: new Date(row.role_created_at),
86
+ }
87
+ : null;
88
+ return { account, role };
89
+ }
90
+ /**
91
+ * Find account by linkedId with role data joined.
92
+ *
93
+ * @param linkedId - Account linkedId
94
+ * @returns Account with role or null if not found
95
+ */
96
+ async findByLinkedIdWithRole(linkedId) {
97
+ const row = await this.db.single(`SELECT
98
+ a.*,
99
+ r.id as role_id,
100
+ r.name as role_name,
101
+ r.display_name as role_display_name,
102
+ r.rank as role_rank,
103
+ r.permissions as role_permissions,
104
+ r.is_default as role_is_default,
105
+ r.created_at as role_created_at
106
+ FROM ${this.tableName} a
107
+ LEFT JOIN roles r ON a.role_id = r.id
108
+ WHERE a.linked_id = ?`, [linkedId]);
109
+ if (!row)
110
+ return null;
111
+ const account = this.toEntity(row);
112
+ const role = row.role_name
113
+ ? {
114
+ id: row.role_id,
115
+ name: row.role_name,
116
+ displayName: row.role_display_name,
117
+ rank: row.role_rank,
118
+ permissions: JSON.parse(row.role_permissions),
119
+ isDefault: Boolean(row.role_is_default),
120
+ createdAt: new Date(row.role_created_at),
121
+ }
122
+ : null;
123
+ return { account, role };
124
+ }
125
+ toEntity(row) {
126
+ return {
127
+ id: row.id ?? 0,
128
+ linkedId: row.linked_id,
129
+ externalSource: row.external_source ?? undefined,
130
+ license: row.license,
131
+ discord: row.discord,
132
+ steam: row.steam,
133
+ username: row.username,
134
+ roleId: row.role_id,
135
+ customPermissions: this.parsePermissions(row.custom_permissions),
136
+ createdAt: row.created_at ? new Date(row.created_at) : new Date(),
137
+ lastLoginAt: row.last_login_at ? new Date(row.last_login_at) : new Date(),
138
+ banned: Boolean(row.banned),
139
+ banReason: row.ban_reason,
140
+ banExpires: row.ban_expires ? new Date(row.ban_expires) : null,
141
+ };
142
+ }
143
+ toRow(entity) {
144
+ return {
145
+ id: entity.id,
146
+ linked_id: entity.linkedId,
147
+ external_source: entity.externalSource ?? null,
148
+ license: entity.license ?? null,
149
+ discord: entity.discord ?? null,
150
+ steam: entity.steam ?? null,
151
+ username: entity.username ?? null,
152
+ role_id: entity.roleId,
153
+ custom_permissions: JSON.stringify(entity.customPermissions ?? []),
154
+ created_at: entity.createdAt,
155
+ last_login_at: entity.lastLoginAt,
156
+ banned: entity.banned,
157
+ ban_reason: entity.banReason ?? null,
158
+ ban_expires: entity.banExpires,
159
+ };
160
+ }
161
+ identifierColumn(type) {
162
+ switch (type) {
163
+ case "discord":
164
+ return "discord";
165
+ case "steam":
166
+ return "steam";
167
+ case "license":
168
+ default:
169
+ return "license";
170
+ }
171
+ }
172
+ parsePermissions(raw) {
173
+ if (Array.isArray(raw))
174
+ return raw;
175
+ if (!raw)
176
+ return [];
177
+ try {
178
+ return JSON.parse(raw);
179
+ }
180
+ catch {
181
+ return [];
182
+ }
183
+ }
184
+ }
185
+ exports.AccountRepository = AccountRepository;
@@ -0,0 +1,50 @@
1
+ import { Server } from "@open-core/framework";
2
+ import type { Role } from "../entities/role.entity";
3
+ interface RoleRow {
4
+ id?: number;
5
+ name: string;
6
+ display_name: string;
7
+ rank: number;
8
+ permissions: string;
9
+ is_default: boolean;
10
+ created_at: Date;
11
+ }
12
+ /**
13
+ * Repository for the roles table.
14
+ * Manages CRUD operations for roles with custom queries for defaults and names.
15
+ */
16
+ export declare class RoleRepository extends Server.Repository<Role> {
17
+ protected readonly db: Server.DatabaseContract;
18
+ protected tableName: string;
19
+ constructor(db: Server.DatabaseContract);
20
+ /**
21
+ * Find a role by its internal name.
22
+ *
23
+ * @param name - Role name (e.g., 'admin', 'user')
24
+ * @returns The role or null if not found
25
+ */
26
+ findByName(name: string): Promise<Role | null>;
27
+ /**
28
+ * Get the default role for new accounts.
29
+ *
30
+ * @returns The default role or null if none is set
31
+ */
32
+ getDefaultRole(): Promise<Role | null>;
33
+ /**
34
+ * Update role permissions.
35
+ *
36
+ * @param roleId - Role ID
37
+ * @param permissions - New permissions array
38
+ */
39
+ updatePermissions(roleId: number, permissions: string[]): Promise<void>;
40
+ /**
41
+ * Set or unset a role as default.
42
+ *
43
+ * @param roleId - Role ID
44
+ * @param isDefault - Whether this should be the default role
45
+ */
46
+ setDefault(roleId: number, isDefault: boolean): Promise<void>;
47
+ protected toEntity(row: RoleRow): Role;
48
+ protected toRow(entity: Role): Record<string, unknown>;
49
+ }
50
+ export {};
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RoleRepository = void 0;
4
+ const framework_1 = require("@open-core/framework");
5
+ /**
6
+ * Repository for the roles table.
7
+ * Manages CRUD operations for roles with custom queries for defaults and names.
8
+ */
9
+ class RoleRepository extends framework_1.Server.Repository {
10
+ constructor(db) {
11
+ super(db);
12
+ this.db = db;
13
+ this.tableName = "roles";
14
+ }
15
+ /**
16
+ * Find a role by its internal name.
17
+ *
18
+ * @param name - Role name (e.g., 'admin', 'user')
19
+ * @returns The role or null if not found
20
+ */
21
+ async findByName(name) {
22
+ const row = await this.db.single(`SELECT * FROM ${this.tableName} WHERE name = ?`, [name]);
23
+ return row ? this.toEntity(row) : null;
24
+ }
25
+ /**
26
+ * Get the default role for new accounts.
27
+ *
28
+ * @returns The default role or null if none is set
29
+ */
30
+ async getDefaultRole() {
31
+ const row = await this.db.single(`SELECT * FROM ${this.tableName} WHERE is_default = TRUE LIMIT 1`);
32
+ return row ? this.toEntity(row) : null;
33
+ }
34
+ /**
35
+ * Update role permissions.
36
+ *
37
+ * @param roleId - Role ID
38
+ * @param permissions - New permissions array
39
+ */
40
+ async updatePermissions(roleId, permissions) {
41
+ await this.db.execute(`UPDATE ${this.tableName} SET permissions = ? WHERE id = ?`, [JSON.stringify(permissions), roleId]);
42
+ }
43
+ /**
44
+ * Set or unset a role as default.
45
+ *
46
+ * @param roleId - Role ID
47
+ * @param isDefault - Whether this should be the default role
48
+ */
49
+ async setDefault(roleId, isDefault) {
50
+ if (isDefault) {
51
+ // Unset all other defaults first
52
+ await this.db.execute(`UPDATE ${this.tableName} SET is_default = FALSE WHERE id != ?`, [roleId]);
53
+ }
54
+ await this.db.execute(`UPDATE ${this.tableName} SET is_default = ? WHERE id = ?`, [isDefault, roleId]);
55
+ }
56
+ toEntity(row) {
57
+ return {
58
+ id: row.id,
59
+ name: row.name,
60
+ displayName: row.display_name,
61
+ rank: row.rank,
62
+ permissions: JSON.parse(row.permissions),
63
+ isDefault: row.is_default,
64
+ createdAt: new Date(row.created_at),
65
+ };
66
+ }
67
+ toRow(entity) {
68
+ return {
69
+ id: entity.id,
70
+ name: entity.name,
71
+ display_name: entity.displayName,
72
+ rank: entity.rank,
73
+ permissions: JSON.stringify(entity.permissions ?? []),
74
+ is_default: entity.isDefault,
75
+ created_at: entity.createdAt,
76
+ };
77
+ }
78
+ }
79
+ exports.RoleRepository = RoleRepository;