@open-core/framework 1.0.1-beta.1 → 1.0.4-beta.1

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 (109) hide show
  1. package/README.md +12 -2
  2. package/dist/client/client-bootstrap.js +11 -14
  3. package/dist/client/client-core.d.ts +0 -17
  4. package/dist/client/client-core.js +0 -45
  5. package/dist/client/controllers/spawner.controller.d.ts +12 -0
  6. package/dist/client/controllers/spawner.controller.js +51 -0
  7. package/dist/client/index.d.ts +1 -0
  8. package/dist/client/index.js +1 -0
  9. package/dist/client/interfaces/appearance.interface.d.ts +19 -0
  10. package/dist/client/interfaces/appearance.interface.js +2 -0
  11. package/dist/client/services/appearance.service.d.ts +6 -0
  12. package/dist/client/services/appearance.service.js +89 -0
  13. package/dist/client/services/{world/blip.service.d.ts → blip.service.d.ts} +1 -1
  14. package/dist/client/services/index.d.ts +9 -4
  15. package/dist/client/services/index.js +9 -8
  16. package/dist/client/services/{world/marker.service.d.ts → marker.service.d.ts} +1 -1
  17. package/dist/client/services/{world/ped.service.d.ts → ped.service.d.ts} +1 -1
  18. package/dist/client/services/spawn.service.d.ts +73 -0
  19. package/dist/client/services/spawn.service.js +261 -0
  20. package/dist/client/services/{ui/textui.service.d.ts → textui.service.d.ts} +1 -1
  21. package/dist/client/services/{world/vehicle.service.d.ts → vehicle.service.d.ts} +1 -1
  22. package/dist/client/system/processors/export.processor.js +1 -1
  23. package/dist/index.d.ts +0 -2
  24. package/dist/index.js +1 -6
  25. package/dist/server/bootstrap.js +2 -2
  26. package/dist/server/controllers/command.controller.d.ts +1 -1
  27. package/dist/server/controllers/command.controller.js +6 -6
  28. package/dist/server/controllers/session.controller.d.ts +9 -0
  29. package/dist/server/controllers/session.controller.js +70 -0
  30. package/dist/server/database/adapters/oxmysql.adapter.js +1 -1
  31. package/dist/server/decorators/command.d.ts +34 -4
  32. package/dist/server/decorators/command.js +11 -6
  33. package/dist/server/decorators/controller.d.ts +22 -0
  34. package/dist/server/decorators/controller.js +22 -0
  35. package/dist/server/decorators/export.d.ts +38 -0
  36. package/dist/server/decorators/export.js +38 -0
  37. package/dist/server/decorators/guard.d.ts +51 -0
  38. package/dist/server/decorators/guard.js +43 -0
  39. package/dist/server/decorators/index.d.ts +4 -4
  40. package/dist/server/decorators/index.js +7 -4
  41. package/dist/server/decorators/onFiveMEvent.d.ts +6 -0
  42. package/dist/server/decorators/{coreEvent.js → onFiveMEvent.js} +8 -3
  43. package/dist/server/decorators/onFrameworkEvent.d.ts +22 -0
  44. package/dist/server/decorators/onFrameworkEvent.js +29 -0
  45. package/dist/server/decorators/onNet.d.ts +58 -0
  46. package/dist/server/decorators/onNet.js +57 -0
  47. package/dist/server/decorators/onTick.d.ts +31 -0
  48. package/dist/server/decorators/onTick.js +31 -0
  49. package/dist/server/decorators/public.d.ts +19 -8
  50. package/dist/server/decorators/public.js +19 -8
  51. package/dist/server/decorators/requiresState.d.ts +18 -17
  52. package/dist/server/decorators/requiresState.js +18 -17
  53. package/dist/server/decorators/throttle.d.ts +39 -0
  54. package/dist/server/decorators/throttle.js +27 -0
  55. package/dist/server/decorators/utils.d.ts +50 -0
  56. package/dist/server/decorators/utils.js +50 -0
  57. package/dist/server/entities/player.js +1 -1
  58. package/dist/server/error-handler.js +2 -2
  59. package/dist/server/helpers/resolve-method.d.ts +5 -0
  60. package/dist/server/helpers/resolve-method.js +18 -0
  61. package/dist/server/index.js +2 -0
  62. package/dist/server/loaders/playerSession.loader.js +13 -4
  63. package/dist/server/services/command.service.d.ts +1 -1
  64. package/dist/server/services/command.service.js +9 -6
  65. package/dist/server/system/metadata-server.keys.d.ts +1 -0
  66. package/dist/server/system/metadata-server.keys.js +1 -0
  67. package/dist/server/system/processors/command.processor.d.ts +2 -2
  68. package/dist/server/system/processors/command.processor.js +1 -2
  69. package/dist/server/system/processors/coreEvent.processor.d.ts +1 -1
  70. package/dist/server/system/processors/coreEvent.processor.js +6 -3
  71. package/dist/server/system/processors/export.processor.d.ts +1 -1
  72. package/dist/server/system/processors/export.processor.js +7 -3
  73. package/dist/server/system/processors/fivemEvent.processor.d.ts +7 -0
  74. package/dist/server/system/processors/fivemEvent.processor.js +40 -0
  75. package/dist/server/system/processors/netEvent.processor.d.ts +1 -1
  76. package/dist/server/system/processors/netEvent.processor.js +12 -9
  77. package/dist/server/system/processors.register.js +2 -0
  78. package/dist/server/system/schema-generator.d.ts +2 -0
  79. package/dist/server/system/schema-generator.js +34 -0
  80. package/dist/server/templates/admin/admin.controller-template.d.ts +7 -5
  81. package/dist/server/templates/auth/auth-provider.contract.d.ts +2 -2
  82. package/dist/server/types/core-events.d.ts +5 -0
  83. package/package.json +29 -1
  84. package/dist/client/loaders/exports.loader.d.ts +0 -1
  85. package/dist/client/loaders/exports.loader.js +0 -13
  86. package/dist/client/services/core/index.d.ts +0 -1
  87. package/dist/client/services/core/index.js +0 -17
  88. package/dist/client/services/core/spawn.service.d.ts +0 -20
  89. package/dist/client/services/core/spawn.service.js +0 -143
  90. package/dist/client/services/streaming/index.d.ts +0 -1
  91. package/dist/client/services/streaming/index.js +0 -17
  92. package/dist/client/services/ui/index.d.ts +0 -3
  93. package/dist/client/services/ui/index.js +0 -19
  94. package/dist/client/services/world/index.d.ts +0 -4
  95. package/dist/client/services/world/index.js +0 -20
  96. package/dist/server/decorators/coreEvent.d.ts +0 -2
  97. package/dist/server/decorators/netEvent.d.ts +0 -36
  98. package/dist/server/decorators/netEvent.js +0 -40
  99. /package/dist/client/services/{world/blip.service.js → blip.service.js} +0 -0
  100. /package/dist/client/services/{world/marker.service.js → marker.service.js} +0 -0
  101. /package/dist/client/services/{ui/notification.service.d.ts → notification.service.d.ts} +0 -0
  102. /package/dist/client/services/{ui/notification.service.js → notification.service.js} +0 -0
  103. /package/dist/client/services/{world/ped.service.js → ped.service.js} +0 -0
  104. /package/dist/client/services/{ui/progress.service.d.ts → progress.service.d.ts} +0 -0
  105. /package/dist/client/services/{ui/progress.service.js → progress.service.js} +0 -0
  106. /package/dist/client/services/{streaming/streaming.service.d.ts → streaming.service.d.ts} +0 -0
  107. /package/dist/client/services/{streaming/streaming.service.js → streaming.service.js} +0 -0
  108. /package/dist/client/services/{ui/textui.service.js → textui.service.js} +0 -0
  109. /package/dist/client/services/{world/vehicle.service.js → vehicle.service.js} +0 -0
@@ -1,9 +1,48 @@
1
1
  import type { SecurityAction } from '../types/security.types';
2
2
  interface ThrottleOptions {
3
+ /**
4
+ * limit of calls per windowMs
5
+ */
3
6
  limit: number;
7
+ /**
8
+ * time window for numeric overload
9
+ */
4
10
  windowMs: number;
11
+ /**
12
+ * action to perform on exceed limit
13
+ */
5
14
  onExceed?: SecurityAction;
15
+ /**
16
+ * custom message to display on exceed limit (ERROR MESSAGE)
17
+ */
6
18
  message?: string;
7
19
  }
20
+ /**
21
+ * Rate-limits how frequently a method can be called by a specific player.
22
+ *
23
+ * Uses `RateLimiterService` and a unique key composed of:
24
+ * `playerID:ClassName:MethodName`.
25
+ *
26
+ * ## Overload
27
+ * - `@Throttle(5, 1000)` → limit = 5 calls per 1000 ms
28
+ * - `@Throttle({ limit, windowMs, onExceed, message })`
29
+ *
30
+ * ## Behavior
31
+ * If the rate limit is exceeded:
32
+ * - A `SecurityError` is thrown.
33
+ * - Optional custom behavior (`onExceed`) may be executed.
34
+ *
35
+ * ## Example
36
+ * ```ts
37
+ * @Throttle(5, 2000)
38
+ * async search(player: Server.Player, query: string) { ... }
39
+ *
40
+ * @Throttle({ limit: 1, windowMs: 5000, message: "Too fast!" })
41
+ * async placeOrder(player: Server.Player) { ... }
42
+ * ```
43
+ *
44
+ * @param optionsOrLimit - Number (simple mode) or full config object.
45
+ * @param windowMs - Time window for numeric overload.
46
+ */
8
47
  export declare function Throttle(optionsOrLimit: number | ThrottleOptions, windowMs?: number): (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => PropertyDescriptor | undefined;
9
48
  export {};
@@ -4,6 +4,33 @@ exports.Throttle = Throttle;
4
4
  const tsyringe_1 = require("tsyringe");
5
5
  const rate_limiter_service_1 = require("../services/rate-limiter.service");
6
6
  const utils_1 = require("../../utils");
7
+ /**
8
+ * Rate-limits how frequently a method can be called by a specific player.
9
+ *
10
+ * Uses `RateLimiterService` and a unique key composed of:
11
+ * `playerID:ClassName:MethodName`.
12
+ *
13
+ * ## Overload
14
+ * - `@Throttle(5, 1000)` → limit = 5 calls per 1000 ms
15
+ * - `@Throttle({ limit, windowMs, onExceed, message })`
16
+ *
17
+ * ## Behavior
18
+ * If the rate limit is exceeded:
19
+ * - A `SecurityError` is thrown.
20
+ * - Optional custom behavior (`onExceed`) may be executed.
21
+ *
22
+ * ## Example
23
+ * ```ts
24
+ * @Throttle(5, 2000)
25
+ * async search(player: Server.Player, query: string) { ... }
26
+ *
27
+ * @Throttle({ limit: 1, windowMs: 5000, message: "Too fast!" })
28
+ * async placeOrder(player: Server.Player) { ... }
29
+ * ```
30
+ *
31
+ * @param optionsOrLimit - Number (simple mode) or full config object.
32
+ * @param windowMs - Time window for numeric overload.
33
+ */
7
34
  function Throttle(optionsOrLimit, windowMs) {
8
35
  return function (target, propertyKey, descriptor) {
9
36
  if (!descriptor) {
@@ -1,7 +1,57 @@
1
1
  import type { BindingScope } from './bind';
2
+ /**
3
+ * Marks a class as a framework-managed Service.
4
+ *
5
+ * The decorator binds the class into the dependency injection
6
+ * container using the provided scope (default: `singleton`).
7
+ *
8
+ * Services represent reusable, stateless or stateful logic such as:
9
+ * - Business rules
10
+ * - Utility layers
11
+ * - Gameplay systems
12
+ * - Internal modules
13
+ *
14
+ * This decorator is a convenience wrapper over `@Bind()`, allowing
15
+ * future extension of service-specific behavior without changing
16
+ * end-user code.
17
+ *
18
+ * ## Example
19
+ * ```ts
20
+ * @Service()
21
+ * export class InventoryService {
22
+ * addItem() { ... }
23
+ * }
24
+ * ```
25
+ *
26
+ * @param options.scope - Optional binding scope (`singleton` | `transient`)
27
+ */
2
28
  export declare function Service(options?: {
3
29
  scope?: BindingScope;
4
30
  }): (target: any) => void;
31
+ /**
32
+ * Marks a class as a Repository within the framework.
33
+ *
34
+ * A Repository abstracts persistence operations (e.g., database,
35
+ * API, in-memory, or hybrid storage). It is registered in the
36
+ * dependency injection container using the provided scope
37
+ * (default: `singleton`).
38
+ *
39
+ * `@Repo()` is intentionally separate from `@Service()` to clearly
40
+ * distinguish persistence-oriented classes from business logic.
41
+ * In the future, repository-specific behavior (caching layers,
42
+ * transactional wrappers, profiling, etc.) can be attached here
43
+ * without modifying user code.
44
+ *
45
+ * ## Example
46
+ * ```ts
47
+ * @Repo()
48
+ * export class AccountRepository {
49
+ * async findById(id: string) { ... }
50
+ * }
51
+ * ```
52
+ *
53
+ * @param options.scope - Optional binding scope (`singleton` | `transient`)
54
+ */
5
55
  export declare function Repo(options?: {
6
56
  scope?: BindingScope;
7
57
  }): (target: any) => void;
@@ -3,10 +3,60 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Service = Service;
4
4
  exports.Repo = Repo;
5
5
  const bind_1 = require("./bind");
6
+ /**
7
+ * Marks a class as a framework-managed Service.
8
+ *
9
+ * The decorator binds the class into the dependency injection
10
+ * container using the provided scope (default: `singleton`).
11
+ *
12
+ * Services represent reusable, stateless or stateful logic such as:
13
+ * - Business rules
14
+ * - Utility layers
15
+ * - Gameplay systems
16
+ * - Internal modules
17
+ *
18
+ * This decorator is a convenience wrapper over `@Bind()`, allowing
19
+ * future extension of service-specific behavior without changing
20
+ * end-user code.
21
+ *
22
+ * ## Example
23
+ * ```ts
24
+ * @Service()
25
+ * export class InventoryService {
26
+ * addItem() { ... }
27
+ * }
28
+ * ```
29
+ *
30
+ * @param options.scope - Optional binding scope (`singleton` | `transient`)
31
+ */
6
32
  function Service(options) {
7
33
  var _a;
8
34
  return (0, bind_1.Bind)((_a = options === null || options === void 0 ? void 0 : options.scope) !== null && _a !== void 0 ? _a : 'singleton');
9
35
  }
36
+ /**
37
+ * Marks a class as a Repository within the framework.
38
+ *
39
+ * A Repository abstracts persistence operations (e.g., database,
40
+ * API, in-memory, or hybrid storage). It is registered in the
41
+ * dependency injection container using the provided scope
42
+ * (default: `singleton`).
43
+ *
44
+ * `@Repo()` is intentionally separate from `@Service()` to clearly
45
+ * distinguish persistence-oriented classes from business logic.
46
+ * In the future, repository-specific behavior (caching layers,
47
+ * transactional wrappers, profiling, etc.) can be attached here
48
+ * without modifying user code.
49
+ *
50
+ * ## Example
51
+ * ```ts
52
+ * @Repo()
53
+ * export class AccountRepository {
54
+ * async findById(id: string) { ... }
55
+ * }
56
+ * ```
57
+ *
58
+ * @param options.scope - Optional binding scope (`singleton` | `transient`)
59
+ */
10
60
  function Repo(options) {
11
61
  var _a;
12
62
  return (0, bind_1.Bind)((_a = options === null || options === void 0 ? void 0 : options.scope) !== null && _a !== void 0 ? _a : 'singleton');
@@ -95,7 +95,7 @@ class Player {
95
95
  * @param vector - The target coordinates (x, y, z).
96
96
  */
97
97
  teleportClient(vector) {
98
- this.emit('core:spawner:teleport', vector);
98
+ this.emit('opencore:spawner:teleport', vector);
99
99
  }
100
100
  /**
101
101
  * Disconnects the player from the server.
@@ -14,8 +14,8 @@ function normalizeError(error, origin) {
14
14
  }
15
15
  function handleCommandError(error, meta, playerId) {
16
16
  const appError = normalizeError(error, 'server');
17
- logger_1.loggers.command.error(`Command execution failed: /${meta.name}`, {
18
- command: meta.name,
17
+ logger_1.loggers.command.error(`Command execution failed: /${meta.command}`, {
18
+ command: meta.command,
19
19
  handler: meta.methodName,
20
20
  playerId,
21
21
  code: appError.code,
@@ -0,0 +1,5 @@
1
+ export declare function resolveMethod(instance: Record<string, any>, methodName: string, errorMessage: string): {
2
+ handler: Function;
3
+ handlerName: string;
4
+ proto: any;
5
+ } | undefined;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveMethod = resolveMethod;
4
+ const logger_1 = require("../../shared/logger");
5
+ function resolveMethod(instance, methodName, errorMessage) {
6
+ const proto = Object.getPrototypeOf(instance);
7
+ const method = instance[methodName];
8
+ if (typeof method !== 'function') {
9
+ logger_1.loggers.scanner.error(errorMessage, {
10
+ className: instance.constructor.name,
11
+ methodName,
12
+ });
13
+ return;
14
+ }
15
+ const handler = method.bind(instance);
16
+ const handlerName = `${instance.constructor.name}.${methodName}`;
17
+ return { handler, handlerName, proto };
18
+ }
@@ -27,3 +27,5 @@ __exportStar(require("./setup"), exports);
27
27
  // Controllers
28
28
  require("./controllers/command.controller");
29
29
  require("./controllers/chat.controller");
30
+ const container_1 = require("./container");
31
+ globalThis.oc_container = container_1.di;
@@ -11,9 +11,9 @@ const playerSessionLoader = () => {
11
11
  const persistenceService = tsyringe_1.container.resolve(persistence_service_1.PlayerPersistenceService);
12
12
  // Initialize persistence service (resolves provider if configured)
13
13
  persistenceService.initialize();
14
- on('playerJoining', async (source) => {
14
+ on('playerJoining', async () => {
15
15
  var _a;
16
- const clientId = Number(source);
16
+ const clientId = source;
17
17
  const license = (_a = GetPlayerIdentifier(clientId.toString(), 0)) !== null && _a !== void 0 ? _a : undefined;
18
18
  const player = playerManager.bind(clientId, { license });
19
19
  logger_1.loggers.session.info(`Player session created`, {
@@ -26,9 +26,18 @@ const playerSessionLoader = () => {
26
26
  clientId,
27
27
  license,
28
28
  });
29
+ setImmediate(() => {
30
+ const currentPlayer = playerManager.getByClient(clientId);
31
+ if (!currentPlayer)
32
+ return;
33
+ (0, core_event_bus_1.emitCoreEvent)('core:playerFullyConnected', {
34
+ clientId,
35
+ license,
36
+ });
37
+ });
29
38
  });
30
- on('playerDropped', async () => {
31
- const clientId = Number(global.source);
39
+ on('playerDropped', async (source) => {
40
+ const clientId = Number(source);
32
41
  const player = playerManager.getByClient(clientId);
33
42
  // Save player data before destroying session
34
43
  if (player) {
@@ -8,7 +8,7 @@ export declare class CommandService {
8
8
  register(meta: CommandMetadata, handler: Function): void;
9
9
  execute(player: Server.Player, commandName: string, args: string[], raw: string): Promise<void>;
10
10
  getAllCommands(): {
11
- name: string;
11
+ command: string;
12
12
  description: string;
13
13
  usage: string;
14
14
  }[];
@@ -18,26 +18,29 @@ const utils_1 = require("../../utils");
18
18
  const zod_1 = __importDefault(require("zod"));
19
19
  const security_handler_contract_1 = require("../templates/security/security-handler.contract");
20
20
  const logger_1 = require("../../shared/logger");
21
+ const schema_generator_1 = require("../system/schema-generator");
21
22
  let CommandService = class CommandService {
22
23
  constructor(securityHandler) {
23
24
  this.securityHandler = securityHandler;
24
25
  this.commands = new Map();
25
26
  }
26
27
  register(meta, handler) {
27
- this.commands.set(meta.name.toLowerCase(), { meta, handler });
28
- logger_1.loggers.command.debug(`Registered: /${meta.name}${meta.schema ? ' [Validated]' : ''}`);
28
+ this.commands.set(meta.command.toLowerCase(), { meta, handler });
29
+ logger_1.loggers.command.debug(`Registered: /${meta.command}${meta.schema ? ' [Validated]' : ''}`);
29
30
  }
30
31
  async execute(player, commandName, args, raw) {
32
+ var _a;
31
33
  const entry = this.commands.get(commandName.toLowerCase());
32
34
  if (!entry) {
33
35
  return;
34
36
  }
35
37
  const { meta, handler } = entry;
36
38
  let validatedArgs = args;
37
- if (meta.schema) {
39
+ // Use explicit schema or auto-generate from paramTypes
40
+ const schema = (_a = meta.schema) !== null && _a !== void 0 ? _a : (0, schema_generator_1.generateSchemaFromTypes)(meta.paramTypes);
41
+ if (schema) {
38
42
  try {
39
- const result = await meta.schema.parseAsync(args);
40
- validatedArgs = Array.isArray(result) ? result : [result];
43
+ validatedArgs = await schema.parseAsync(args);
41
44
  }
42
45
  catch (error) {
43
46
  if (error instanceof zod_1.default.ZodError) {
@@ -60,7 +63,7 @@ let CommandService = class CommandService {
60
63
  return Array.from(this.commands.values()).map((c) => {
61
64
  var _a, _b;
62
65
  return ({
63
- name: c.meta.name,
66
+ command: c.meta.command,
64
67
  description: (_a = c.meta.description) !== null && _a !== void 0 ? _a : '',
65
68
  usage: (_b = c.meta.usage) !== null && _b !== void 0 ? _b : '',
66
69
  });
@@ -4,6 +4,7 @@ export declare const METADATA_KEYS: {
4
4
  NET_EVENT: string;
5
5
  TICK: string;
6
6
  CORE_EVENT: string;
7
+ FIVEM_EVENT: string;
7
8
  EXPORT: string;
8
9
  PUBLIC: string;
9
10
  };
@@ -7,6 +7,7 @@ exports.METADATA_KEYS = {
7
7
  NET_EVENT: 'core:meta:net_event',
8
8
  TICK: 'core:meta:tick',
9
9
  CORE_EVENT: 'core:meta:core_event',
10
+ FIVEM_EVENT: 'core:meta:fivem_event',
10
11
  EXPORT: 'core:meta:export',
11
12
  PUBLIC: 'core:meta:public',
12
13
  };
@@ -1,9 +1,9 @@
1
1
  import { DecoratorProcessor } from '../../../system/decorator-processor';
2
2
  import { CommandService } from '../../services';
3
- import { CommandConfig } from '../../decorators';
3
+ import { CommandMetadata } from '../../decorators/command';
4
4
  export declare class CommandProcessor implements DecoratorProcessor {
5
5
  private commandService;
6
6
  readonly metadataKey: string;
7
7
  constructor(commandService: CommandService);
8
- process(target: any, methodName: string, metadata: CommandConfig): void;
8
+ process(target: any, methodName: string, metadata: CommandMetadata): void;
9
9
  }
@@ -20,8 +20,7 @@ let CommandProcessor = class CommandProcessor {
20
20
  }
21
21
  process(target, methodName, metadata) {
22
22
  const handler = target[methodName].bind(target);
23
- const fullMeta = Object.assign(Object.assign({}, metadata), { methodName, target: target.constructor });
24
- this.commandService.register(fullMeta, handler);
23
+ this.commandService.register(metadata, handler);
25
24
  }
26
25
  };
27
26
  exports.CommandProcessor = CommandProcessor;
@@ -1,7 +1,7 @@
1
1
  import { DecoratorProcessor } from '../../../system/decorator-processor';
2
2
  export declare class CoreEventProcessor implements DecoratorProcessor {
3
3
  readonly metadataKey: string;
4
- process(target: any, methodName: string, metadata: {
4
+ process(instance: any, methodName: string, metadata: {
5
5
  event: string;
6
6
  }): void;
7
7
  }
@@ -11,13 +11,16 @@ const tsyringe_1 = require("tsyringe");
11
11
  const core_event_bus_1 = require("../../bus/core-event-bus");
12
12
  const metadata_server_keys_1 = require("../metadata-server.keys");
13
13
  const logger_1 = require("../../../shared/logger");
14
+ const resolve_method_1 = require("../../helpers/resolve-method");
14
15
  let CoreEventProcessor = class CoreEventProcessor {
15
16
  constructor() {
16
17
  this.metadataKey = metadata_server_keys_1.METADATA_KEYS.CORE_EVENT;
17
18
  }
18
- process(target, methodName, metadata) {
19
- const handler = target[methodName].bind(target);
20
- const handlerName = `${target.constructor.name}.${methodName}`;
19
+ process(instance, methodName, metadata) {
20
+ const result = (0, resolve_method_1.resolveMethod)(instance, methodName, `[CoreEventProcessor] Method "${methodName}" not found`);
21
+ if (!result)
22
+ return;
23
+ const { handler, handlerName } = result;
21
24
  (0, core_event_bus_1.onCoreEvent)(metadata.event, (payload) => {
22
25
  try {
23
26
  handler(payload);
@@ -1,7 +1,7 @@
1
1
  import { DecoratorProcessor } from '../../../system/decorator-processor';
2
2
  export declare class ExportProcessor implements DecoratorProcessor {
3
3
  readonly metadataKey: string;
4
- process(target: any, methodName: string, metadata: {
4
+ process(instance: any, methodName: string, metadata: {
5
5
  exportName: string;
6
6
  }): void;
7
7
  }
@@ -10,13 +10,17 @@ exports.ExportProcessor = void 0;
10
10
  const tsyringe_1 = require("tsyringe");
11
11
  const metadata_server_keys_1 = require("../metadata-server.keys");
12
12
  const logger_1 = require("../../../shared/logger");
13
+ const resolve_method_1 = require("../../helpers/resolve-method");
13
14
  let ExportProcessor = class ExportProcessor {
14
15
  constructor() {
15
16
  this.metadataKey = metadata_server_keys_1.METADATA_KEYS.EXPORT;
16
17
  }
17
- process(target, methodName, metadata) {
18
- const handler = target[methodName].bind(target);
19
- exports(metadata.exportName, handler);
18
+ process(instance, methodName, metadata) {
19
+ const result = (0, resolve_method_1.resolveMethod)(instance, methodName, `[ExportEventProcessor] Method "${methodName}" not found`);
20
+ if (!result)
21
+ return;
22
+ const { handler } = result;
23
+ globalThis.exports(metadata.exportName, handler);
20
24
  logger_1.loggers.exports.debug(`Registered: ${metadata.exportName}`);
21
25
  }
22
26
  };
@@ -0,0 +1,7 @@
1
+ import { DecoratorProcessor } from '../../../system/decorator-processor';
2
+ export declare class FiveMEventProcessor implements DecoratorProcessor {
3
+ readonly metadataKey: string;
4
+ process(instance: any, methodName: string, metadata: {
5
+ event: string;
6
+ }): void;
7
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.FiveMEventProcessor = void 0;
10
+ const tsyringe_1 = require("tsyringe");
11
+ const metadata_server_keys_1 = require("../metadata-server.keys");
12
+ const logger_1 = require("../../../shared/logger");
13
+ const resolve_method_1 = require("../../helpers/resolve-method");
14
+ let FiveMEventProcessor = class FiveMEventProcessor {
15
+ constructor() {
16
+ this.metadataKey = metadata_server_keys_1.METADATA_KEYS.FIVEM_EVENT;
17
+ }
18
+ process(instance, methodName, metadata) {
19
+ const result = (0, resolve_method_1.resolveMethod)(instance, methodName, `[FiveMEventProcessor] Method "${methodName}" not found`);
20
+ if (!result)
21
+ return;
22
+ const { handler, handlerName } = result;
23
+ on(metadata.event, (...args) => {
24
+ try {
25
+ handler(...args);
26
+ }
27
+ catch (error) {
28
+ logger_1.loggers.eventBus.error(`Handler error in FiveMEvent`, {
29
+ event: metadata.event,
30
+ handler: handlerName,
31
+ }, error);
32
+ }
33
+ });
34
+ logger_1.loggers.eventBus.debug(`Registered FiveM event: ${metadata.event} -> ${handlerName}`);
35
+ }
36
+ };
37
+ exports.FiveMEventProcessor = FiveMEventProcessor;
38
+ exports.FiveMEventProcessor = FiveMEventProcessor = __decorate([
39
+ (0, tsyringe_1.injectable)()
40
+ ], FiveMEventProcessor);
@@ -7,5 +7,5 @@ export declare class NetEventProcessor implements DecoratorProcessor {
7
7
  private securityHandler;
8
8
  readonly metadataKey: string;
9
9
  constructor(playerService: PlayerService, securityHandler: SecurityHandlerContract);
10
- process(target: any, methodName: string, metadata: NetEventOptions): void;
10
+ process(instance: any, methodName: string, metadata: NetEventOptions): void;
11
11
  }
@@ -20,19 +20,22 @@ const security_handler_contract_1 = require("../../templates/security/security-h
20
20
  const utils_1 = require("../../../utils");
21
21
  const logger_1 = require("../../../shared/logger");
22
22
  const zod_1 = __importDefault(require("zod"));
23
+ const schema_generator_1 = require("../schema-generator");
24
+ const resolve_method_1 = require("../../helpers/resolve-method");
23
25
  let NetEventProcessor = class NetEventProcessor {
24
26
  constructor(playerService, securityHandler) {
25
27
  this.playerService = playerService;
26
28
  this.securityHandler = securityHandler;
27
29
  this.metadataKey = metadata_server_keys_1.METADATA_KEYS.NET_EVENT;
28
30
  }
29
- process(target, methodName, metadata) {
30
- const handler = target[methodName].bind(target);
31
- const handlerName = `${target.constructor.name}.${methodName}`;
32
- const proto = Object.getPrototypeOf(target);
31
+ process(instance, methodName, metadata) {
32
+ const result = (0, resolve_method_1.resolveMethod)(instance, methodName, `[NetEventProcessor] Method "${methodName}" not found`);
33
+ if (!result)
34
+ return;
35
+ const { handler, handlerName, proto } = result;
33
36
  const isPublic = Reflect.getMetadata(metadata_server_keys_1.METADATA_KEYS.PUBLIC, proto, methodName) === true;
34
37
  onNet(metadata.eventName, async (...args) => {
35
- const sourceId = Number(global.source);
38
+ const sourceId = Number(source);
36
39
  const player = this.playerService.getByClient(sourceId);
37
40
  if (!player) {
38
41
  logger_1.loggers.netEvent.warn(`Event ignored: Player session not found`, {
@@ -53,11 +56,11 @@ let NetEventProcessor = class NetEventProcessor {
53
56
  return;
54
57
  }
55
58
  let validatedArgs = args;
56
- if (metadata.schema) {
59
+ const schema = (0, schema_generator_1.generateSchemaFromTypes)(metadata.paramTypes);
60
+ if (schema) {
57
61
  try {
58
- const payload = args[0];
59
- const parsed = metadata.schema.parse(payload);
60
- validatedArgs = [parsed];
62
+ const parsed = schema.parse(args);
63
+ validatedArgs = Array.isArray(parsed) ? parsed : [parsed];
61
64
  }
62
65
  catch (error) {
63
66
  if (error instanceof zod_1.default.ZodError) {
@@ -7,6 +7,7 @@ const security_handler_contract_1 = require("../templates/security/security-hand
7
7
  const command_processor_1 = require("./processors/command.processor");
8
8
  const coreEvent_processor_1 = require("./processors/coreEvent.processor");
9
9
  const export_processor_1 = require("./processors/export.processor");
10
+ const fivemEvent_processor_1 = require("./processors/fivemEvent.processor");
10
11
  const netEvent_processor_1 = require("./processors/netEvent.processor");
11
12
  const tick_processor_1 = require("./processors/tick.processor");
12
13
  function registerSystemServer() {
@@ -15,6 +16,7 @@ function registerSystemServer() {
15
16
  container_1.di.register('DecoratorProcessor', { useClass: export_processor_1.ExportProcessor });
16
17
  container_1.di.register('DecoratorProcessor', { useClass: coreEvent_processor_1.CoreEventProcessor });
17
18
  container_1.di.register('DecoratorProcessor', { useClass: command_processor_1.CommandProcessor });
19
+ container_1.di.register('DecoratorProcessor', { useClass: fivemEvent_processor_1.FiveMEventProcessor });
18
20
  if (!container_1.di.isRegistered(security_handler_contract_1.SecurityHandlerContract)) {
19
21
  container_1.di.registerSingleton(security_handler_contract_1.SecurityHandlerContract, default_security_handler_1.DefaultSecurityHandler);
20
22
  }
@@ -0,0 +1,2 @@
1
+ import z from 'zod';
2
+ export declare function generateSchemaFromTypes(paramTypes: any[]): z.ZodTuple | null;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateSchemaFromTypes = generateSchemaFromTypes;
7
+ const zod_1 = __importDefault(require("zod"));
8
+ const player_1 = require("../entities/player");
9
+ function typeToZodSchema(type) {
10
+ switch (type) {
11
+ case String:
12
+ return zod_1.default.coerce.string();
13
+ case Number:
14
+ return zod_1.default.coerce.number();
15
+ case Boolean:
16
+ return zod_1.default.coerce.boolean();
17
+ case Array:
18
+ return zod_1.default.array(zod_1.default.any());
19
+ case Object:
20
+ return zod_1.default.any();
21
+ default:
22
+ return zod_1.default.any();
23
+ }
24
+ }
25
+ function generateSchemaFromTypes(paramTypes) {
26
+ var _a;
27
+ if (!paramTypes || paramTypes.length <= 1)
28
+ return null;
29
+ if (paramTypes[0] !== player_1.Player) {
30
+ throw new Error(`@OnNet: First parameter must be Player, got ${(_a = paramTypes[0]) === null || _a === void 0 ? void 0 : _a.name}`);
31
+ }
32
+ const argSchemas = paramTypes.slice(1).map(typeToZodSchema);
33
+ return zod_1.default.tuple(argSchemas);
34
+ }
@@ -1,10 +1,12 @@
1
- import type { Server } from '../../..';
1
+ import type { Player } from '../../entities';
2
+ type CommandArgs = string[] | any;
2
3
  /**
3
4
  * Template for admin controller implementations.
4
5
  */
5
6
  export interface AdminControllerTemplate {
6
- handleBanCommand(player: Server.Player, args: string[], raw?: string): Promise<void>;
7
- handleKickCommand(player: Server.Player, args: string[], raw?: string): Promise<void>;
8
- handleMuteCommand(player: Server.Player, args: string[], raw?: string): Promise<void>;
9
- handleUnmuteCommand(player: Server.Player, args: string[], raw?: string): Promise<void>;
7
+ handleBanCommand(player: Player, args: CommandArgs, raw?: string): Promise<void>;
8
+ handleKickCommand(player: Player, args: CommandArgs, raw?: string): Promise<void>;
9
+ handleMuteCommand(player: Player, args: CommandArgs, raw?: string): Promise<void>;
10
+ handleUnmuteCommand(player: Player, args: CommandArgs, raw?: string): Promise<void>;
10
11
  }
12
+ export {};
@@ -1,5 +1,5 @@
1
- import { LinkedID } from '../../services';
2
- import { Server } from '../../..';
1
+ import type { LinkedID } from '../../services';
2
+ import type { Server } from '../../..';
3
3
  export interface AuthCredentials {
4
4
  /** Standard username/password auth */
5
5
  username?: string;