@open-core/identity 1.2.0 → 1.2.2

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.
@@ -1,73 +1,52 @@
1
- import type { Role } from "../entities/role.entity";
2
- import type { CreateRoleInput, UpdateRoleInput } from "../types";
3
- import { RoleRepository } from "../repositories/role.repository";
1
+ import { RoleStore } from "../contracts";
2
+ import type { IdentityOptions, IdentityRole } from "../types";
4
3
  /**
5
- * Service for managing roles and their permissions.
6
- * Handles CRUD operations and permission management for roles.
4
+ * High-level service for managing security roles and their associated permissions.
5
+ *
6
+ * Provides a programmer-friendly API for role administration, including creation,
7
+ * updates, and permission retrieval. This service interacts with the configured
8
+ * {@link RoleStore}.
9
+ *
10
+ * @public
11
+ * @injectable
7
12
  */
8
13
  export declare class RoleService {
9
- private readonly repo;
10
- constructor(repo: RoleRepository);
14
+ private readonly store;
15
+ private readonly options;
11
16
  /**
12
- * Find a role by its ID.
17
+ * Initializes a new instance of the RoleService.
13
18
  *
14
- * @param id - Role ID
15
- * @returns The role or null if not found
19
+ * @param store - Persistence layer for role definitions.
20
+ * @param options - Identity system configuration options.
16
21
  */
17
- findById(id: number): Promise<Role | null>;
22
+ constructor(store: RoleStore, options: IdentityOptions);
18
23
  /**
19
- * Find a role by its internal name.
24
+ * Persists a new security role definition.
20
25
  *
21
- * @param name - Role name (e.g., 'admin', 'user')
22
- * @returns The role or null if not found
26
+ * @param role - The complete role definition to create.
27
+ * @returns A promise that resolves when the role is saved.
23
28
  */
24
- findByName(name: string): Promise<Role | null>;
29
+ create(role: IdentityRole): Promise<void>;
25
30
  /**
26
- * Get all roles.
31
+ * Updates an existing role's rank or permissions.
27
32
  *
28
- * @returns Array of all roles
33
+ * @param name - The unique technical name of the role to update.
34
+ * @param data - Partial object containing the fields to modify.
35
+ * @returns A promise that resolves when the update is complete.
29
36
  */
30
- getAll(): Promise<Role[]>;
37
+ update(name: string, data: Partial<Omit<IdentityRole, "name">>): Promise<void>;
31
38
  /**
32
- * Get the default role for new accounts.
39
+ * Permanently removes a role definition from the system.
33
40
  *
34
- * @returns The default role or null if none is configured
41
+ * @param name - The technical name of the role to delete.
42
+ * @returns A promise that resolves when the role is deleted.
35
43
  */
36
- getDefaultRole(): Promise<Role | null>;
44
+ delete(name: string): Promise<void>;
37
45
  /**
38
- * Create a new role.
46
+ * Retrieves the full list of permissions granted to a specific role.
39
47
  *
40
- * @param input - Role creation data
41
- * @returns The created role
48
+ * @param name - The technical name of the role.
49
+ * @returns A promise resolving to an array of permission strings.
42
50
  */
43
- create(input: CreateRoleInput): Promise<Role>;
44
- /**
45
- * Update an existing role.
46
- *
47
- * @param id - Role ID
48
- * @param input - Update data
49
- * @returns The updated role or null if not found
50
- */
51
- update(id: number, input: UpdateRoleInput): Promise<Role | null>;
52
- /**
53
- * Delete a role.
54
- *
55
- * @param id - Role ID
56
- * @returns true if deleted, false if not found
57
- */
58
- delete(id: number): Promise<boolean>;
59
- /**
60
- * Add a permission to a role.
61
- *
62
- * @param roleId - Role ID
63
- * @param permission - Permission string to add
64
- */
65
- addPermission(roleId: number, permission: string): Promise<void>;
66
- /**
67
- * Remove a permission from a role.
68
- *
69
- * @param roleId - Role ID
70
- * @param permission - Permission string to remove
71
- */
72
- removePermission(roleId: number, permission: string): Promise<void>;
51
+ getPermissions(name: string): Promise<string[]>;
73
52
  }
@@ -7,136 +7,81 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { injectable } from "tsyringe";
11
- import { RoleRepository } from "../repositories/role.repository";
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { injectable, inject } from "tsyringe";
14
+ import { IDENTITY_OPTIONS } from "../tokens";
15
+ import { RoleStore } from "../contracts";
12
16
  /**
13
- * Service for managing roles and their permissions.
14
- * Handles CRUD operations and permission management for roles.
17
+ * High-level service for managing security roles and their associated permissions.
18
+ *
19
+ * Provides a programmer-friendly API for role administration, including creation,
20
+ * updates, and permission retrieval. This service interacts with the configured
21
+ * {@link RoleStore}.
22
+ *
23
+ * @public
24
+ * @injectable
15
25
  */
16
26
  let RoleService = class RoleService {
17
- constructor(repo) {
18
- this.repo = repo;
19
- }
20
- /**
21
- * Find a role by its ID.
22
- *
23
- * @param id - Role ID
24
- * @returns The role or null if not found
25
- */
26
- async findById(id) {
27
- return this.repo.findById(id);
28
- }
29
27
  /**
30
- * Find a role by its internal name.
28
+ * Initializes a new instance of the RoleService.
31
29
  *
32
- * @param name - Role name (e.g., 'admin', 'user')
33
- * @returns The role or null if not found
30
+ * @param store - Persistence layer for role definitions.
31
+ * @param options - Identity system configuration options.
34
32
  */
35
- async findByName(name) {
36
- return this.repo.findByName(name);
33
+ constructor(store, options) {
34
+ this.store = store;
35
+ this.options = options;
37
36
  }
38
37
  /**
39
- * Get all roles.
38
+ * Persists a new security role definition.
40
39
  *
41
- * @returns Array of all roles
40
+ * @param role - The complete role definition to create.
41
+ * @returns A promise that resolves when the role is saved.
42
42
  */
43
- async getAll() {
44
- const result = await this.repo.findMany();
45
- return result.data;
43
+ async create(role) {
44
+ await this.store.save(role);
46
45
  }
47
46
  /**
48
- * Get the default role for new accounts.
47
+ * Updates an existing role's rank or permissions.
49
48
  *
50
- * @returns The default role or null if none is configured
49
+ * @param name - The unique technical name of the role to update.
50
+ * @param data - Partial object containing the fields to modify.
51
+ * @returns A promise that resolves when the update is complete.
51
52
  */
52
- async getDefaultRole() {
53
- return this.repo.getDefaultRole();
54
- }
55
- /**
56
- * Create a new role.
57
- *
58
- * @param input - Role creation data
59
- * @returns The created role
60
- */
61
- async create(input) {
62
- const now = new Date();
63
- const role = {
64
- id: 0, // Will be set by DB
65
- name: input.name,
66
- displayName: input.displayName,
67
- rank: input.rank,
68
- permissions: input.permissions ?? [],
69
- isDefault: input.isDefault ?? false,
70
- createdAt: now,
71
- };
72
- return this.repo.save(role);
73
- }
74
- /**
75
- * Update an existing role.
76
- *
77
- * @param id - Role ID
78
- * @param input - Update data
79
- * @returns The updated role or null if not found
80
- */
81
- async update(id, input) {
82
- const existing = await this.repo.findById(id);
53
+ async update(name, data) {
54
+ const existing = await this.store.findByName(name);
83
55
  if (!existing)
84
- return null;
85
- const updated = {
56
+ return;
57
+ await this.store.save({
86
58
  ...existing,
87
- ...(input.displayName !== undefined && {
88
- displayName: input.displayName,
89
- }),
90
- ...(input.rank !== undefined && { rank: input.rank }),
91
- ...(input.permissions !== undefined && {
92
- permissions: input.permissions,
93
- }),
94
- };
95
- if (input.isDefault !== undefined) {
96
- await this.repo.setDefault(id, input.isDefault);
97
- updated.isDefault = input.isDefault;
98
- }
99
- return this.repo.save(updated);
100
- }
101
- /**
102
- * Delete a role.
103
- *
104
- * @param id - Role ID
105
- * @returns true if deleted, false if not found
106
- */
107
- async delete(id) {
108
- return this.repo.delete(id);
59
+ ...data,
60
+ });
109
61
  }
110
62
  /**
111
- * Add a permission to a role.
63
+ * Permanently removes a role definition from the system.
112
64
  *
113
- * @param roleId - Role ID
114
- * @param permission - Permission string to add
65
+ * @param name - The technical name of the role to delete.
66
+ * @returns A promise that resolves when the role is deleted.
115
67
  */
116
- async addPermission(roleId, permission) {
117
- const role = await this.repo.findById(roleId);
118
- if (!role)
119
- return;
120
- const permissions = new Set(role.permissions);
121
- permissions.add(permission);
122
- await this.repo.updatePermissions(roleId, Array.from(permissions));
68
+ async delete(name) {
69
+ await this.store.delete(name);
123
70
  }
124
71
  /**
125
- * Remove a permission from a role.
72
+ * Retrieves the full list of permissions granted to a specific role.
126
73
  *
127
- * @param roleId - Role ID
128
- * @param permission - Permission string to remove
74
+ * @param name - The technical name of the role.
75
+ * @returns A promise resolving to an array of permission strings.
129
76
  */
130
- async removePermission(roleId, permission) {
131
- const role = await this.repo.findById(roleId);
132
- if (!role)
133
- return;
134
- const filtered = role.permissions.filter((p) => p !== permission);
135
- await this.repo.updatePermissions(roleId, filtered);
77
+ async getPermissions(name) {
78
+ const role = await this.store.findByName(name);
79
+ return role?.permissions || [];
136
80
  }
137
81
  };
138
82
  RoleService = __decorate([
139
83
  injectable(),
140
- __metadata("design:paramtypes", [RoleRepository])
84
+ __param(1, inject(IDENTITY_OPTIONS)),
85
+ __metadata("design:paramtypes", [RoleStore, Object])
141
86
  ], RoleService);
142
87
  export { RoleService };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Injection Token for the Identity configuration options.
3
+ * Required because IdentityOptions is an interface and cannot be injected by type.
4
+ *
5
+ * @public
6
+ */
7
+ export declare const IDENTITY_OPTIONS = "IdentityOptions";
package/dist/tokens.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Injection Token for the Identity configuration options.
3
+ * Required because IdentityOptions is an interface and cannot be injected by type.
4
+ *
5
+ * @public
6
+ */
7
+ export const IDENTITY_OPTIONS = "IdentityOptions";
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Authentication strategy modes.
3
+ *
4
+ * - `local`: Automatic authentication based on FiveM connection identifiers (e.g., license, discord).
5
+ * Ideal for traditional FiveM servers where account creation should be transparent.
6
+ * - `credentials`: Manual authentication using username and password.
7
+ * Suitable for servers with an integrated registration system.
8
+ * - `api`: Delegation of authentication to an external HTTP API.
9
+ * Useful for servers integrated with a web dashboard or external auth service.
10
+ *
11
+ * @public
12
+ */
13
+ export type AuthMode = "local" | "credentials" | "api";
14
+ /**
15
+ * Authorization and principal resolution modes.
16
+ *
17
+ * - `roles`: Uses a static role hierarchy defined in the application code.
18
+ * Provides the best performance and version control for role definitions.
19
+ * - `db`: Fetches roles and permissions dynamically from a persistent store.
20
+ * - `api`: Fetches principal data from an external HTTP API on demand.
21
+ *
22
+ * @public
23
+ */
24
+ export type PrincipalMode = "roles" | "db" | "api";
25
+ /**
26
+ * Represents a security role within the identity system.
27
+ *
28
+ * Roles define base permissions and a rank hierarchy used by the framework's `@Guard` decorator.
29
+ *
30
+ * @public
31
+ */
32
+ export interface IdentityRole {
33
+ /**
34
+ * Technical identifier for the role (e.g., 'admin', 'moderator', 'user').
35
+ */
36
+ name: string;
37
+ /**
38
+ * Hierarchical weight.
39
+ *
40
+ * Used for rank-based authorization.
41
+ * Logic: UserRank >= RequiredRank.
42
+ */
43
+ rank: number;
44
+ /**
45
+ * List of permission strings granted to this role by default.
46
+ *
47
+ * Supports '*' wildcard for full framework access.
48
+ */
49
+ permissions: string[];
50
+ /**
51
+ * Human-readable label for UI display or chat prefix.
52
+ */
53
+ displayName?: string;
54
+ }
55
+ /**
56
+ * Global configuration options for the OpenCore Identity System.
57
+ *
58
+ * @public
59
+ */
60
+ export interface IdentityOptions {
61
+ /**
62
+ * Authentication configuration.
63
+ */
64
+ auth: {
65
+ /**
66
+ * The strategy to use for authenticating players.
67
+ */
68
+ mode: AuthMode;
69
+ /**
70
+ * Whether to automatically create a new account when a player connects
71
+ * with valid identifiers that are not yet registered.
72
+ *
73
+ * Only applicable when mode is 'local'.
74
+ * @defaultValue true
75
+ */
76
+ autoCreate?: boolean;
77
+ /**
78
+ * The primary FiveM identifier used to unique-link an account.
79
+ * @defaultValue 'license'
80
+ */
81
+ primaryIdentifier?: string;
82
+ };
83
+ /**
84
+ * Authorization and permissions configuration.
85
+ */
86
+ principal: {
87
+ /**
88
+ * The strategy to use for resolving roles and permissions.
89
+ */
90
+ mode: PrincipalMode;
91
+ /**
92
+ * Static role definitions.
93
+ *
94
+ * Required when mode is 'roles'.
95
+ */
96
+ roles?: Record<string, IdentityRole>;
97
+ /**
98
+ * The name of the role assigned to newly created accounts.
99
+ * @defaultValue 'user'
100
+ */
101
+ defaultRole?: string;
102
+ /**
103
+ * Time-to-live in milliseconds for cached principal data.
104
+ *
105
+ * Since principal resolution is a high-frequency operation, caching is
106
+ * critical for performance.
107
+ * @defaultValue 300000 (5 minutes)
108
+ */
109
+ cacheTtl?: number;
110
+ };
111
+ }
112
+ /**
113
+ * Represents a persistent identity account.
114
+ *
115
+ * This object links a FiveM player to their persistent roles, permissions,
116
+ * and operational status (e.g., bans).
117
+ *
118
+ * @public
119
+ */
120
+ export interface IdentityAccount {
121
+ /**
122
+ * Internal unique database/store ID.
123
+ */
124
+ id: string;
125
+ /**
126
+ * External stable ID used by the framework (linkedID).
127
+ *
128
+ * Usually a UUID or an external system ID.
129
+ */
130
+ linkedId: string;
131
+ /**
132
+ * Primary connection identifier (e.g., 'license:123...').
133
+ */
134
+ identifier: string;
135
+ /**
136
+ * Current technical role name assigned to this account.
137
+ */
138
+ roleName: string;
139
+ /**
140
+ * Optional technical username for credentials-based authentication.
141
+ */
142
+ username?: string | null;
143
+ /**
144
+ * Hashed password for credentials-based authentication.
145
+ *
146
+ * @internal
147
+ */
148
+ passwordHash?: string | null;
149
+ /**
150
+ * List of specific permission overrides for this account.
151
+ *
152
+ * - `+perm`: Explicitly grant a permission.
153
+ * - `-perm`: Explicitly revoke a permission (even if granted by role).
154
+ */
155
+ customPermissions: string[];
156
+ /**
157
+ * Whether the account is currently prohibited from connecting.
158
+ */
159
+ isBanned: boolean;
160
+ /**
161
+ * The reason provided for the current ban.
162
+ */
163
+ banReason?: string;
164
+ /**
165
+ * Timestamp when the ban expires.
166
+ *
167
+ * If null and isBanned is true, the ban is permanent.
168
+ */
169
+ banExpiresAt?: Date | null;
170
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-core/identity",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Enterprise-grade identity, authentication, and authorization plugin for OpenCore Framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -39,14 +39,13 @@
39
39
  "packageManager": "pnpm@10.13.1",
40
40
  "dependencies": {
41
41
  "@open-core/framework": "^0.2.4",
42
- "bcrypt": "^6.0.0",
42
+ "bcryptjs": "^3.0.3",
43
43
  "reflect-metadata": "^0.2.2",
44
44
  "tsyringe": "^4.10.0",
45
45
  "uuid": "^13.0.0",
46
46
  "zod": "^4.1.13"
47
47
  },
48
48
  "devDependencies": {
49
- "@types/bcrypt": "^6.0.0",
50
49
  "@types/node": "^22.19.1",
51
50
  "eslint": "^9.39.1",
52
51
  "eslint-config-prettier": "^10.1.8",