@open-core/framework 1.0.1-beta.1 → 1.0.2-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 (40) hide show
  1. package/README.md +10 -0
  2. package/dist/server/bootstrap.js +2 -2
  3. package/dist/server/controllers/command.controller.d.ts +1 -1
  4. package/dist/server/controllers/command.controller.js +6 -6
  5. package/dist/server/decorators/command.d.ts +34 -4
  6. package/dist/server/decorators/command.js +11 -6
  7. package/dist/server/decorators/controller.d.ts +22 -0
  8. package/dist/server/decorators/controller.js +22 -0
  9. package/dist/server/decorators/coreEvent.d.ts +20 -0
  10. package/dist/server/decorators/coreEvent.js +20 -0
  11. package/dist/server/decorators/export.d.ts +38 -0
  12. package/dist/server/decorators/export.js +38 -0
  13. package/dist/server/decorators/guard.d.ts +51 -0
  14. package/dist/server/decorators/guard.js +43 -0
  15. package/dist/server/decorators/index.d.ts +3 -3
  16. package/dist/server/decorators/index.js +6 -3
  17. package/dist/server/decorators/onNet.d.ts +58 -0
  18. package/dist/server/decorators/onNet.js +57 -0
  19. package/dist/server/decorators/onTick.d.ts +31 -0
  20. package/dist/server/decorators/onTick.js +31 -0
  21. package/dist/server/decorators/public.d.ts +19 -8
  22. package/dist/server/decorators/public.js +19 -8
  23. package/dist/server/decorators/requiresState.d.ts +18 -17
  24. package/dist/server/decorators/requiresState.js +18 -17
  25. package/dist/server/decorators/throttle.d.ts +39 -0
  26. package/dist/server/decorators/throttle.js +27 -0
  27. package/dist/server/decorators/utils.d.ts +50 -0
  28. package/dist/server/decorators/utils.js +50 -0
  29. package/dist/server/error-handler.js +2 -2
  30. package/dist/server/services/command.service.d.ts +1 -1
  31. package/dist/server/services/command.service.js +9 -6
  32. package/dist/server/system/processors/command.processor.d.ts +2 -2
  33. package/dist/server/system/processors/command.processor.js +1 -2
  34. package/dist/server/system/processors/netEvent.processor.js +5 -4
  35. package/dist/server/system/schema-generator.d.ts +2 -0
  36. package/dist/server/system/schema-generator.js +28 -0
  37. package/dist/server/templates/admin/admin.controller-template.d.ts +7 -5
  38. package/package.json +19 -1
  39. package/dist/server/decorators/netEvent.d.ts +0 -36
  40. package/dist/server/decorators/netEvent.js +0 -40
package/README.md CHANGED
@@ -325,6 +325,16 @@ opencore/
325
325
 
326
326
  ---
327
327
 
328
+ ## Available Modules
329
+
330
+ A module is a library belonging to the OpenCore family, where you can take advantage of its functionality if you wish, and where we provide the foundation for building a specific system.
331
+
332
+ - [Open-core Identity](https://github.com/newcore-network/opencore-identity): Flexible identity and permission system for OpenCore. Provides multiple authentication strategies, role management, and permission-based authorization through the framework's Principal system. [NPM](https://www.npmjs.com/package/@open-core/identity).
333
+
334
+ ```bash
335
+ pnpm add @open-core/identity
336
+ ```
337
+
328
338
  ## 🤝 Contributing
329
339
 
330
340
  Contributions are welcome! Please ensure:
@@ -7,9 +7,9 @@ const templates_1 = require("./templates");
7
7
  const metadata_scanner_1 = require("../system/metadata.scanner");
8
8
  const processors_register_1 = require("./system/processors.register");
9
9
  const registers_1 = require("./services/registers");
10
- const decorators_1 = require("./decorators");
11
10
  const logger_1 = require("../shared/logger");
12
11
  const auth_provider_contract_1 = require("./templates/auth/auth-provider.contract");
12
+ const controller_1 = require("./decorators/controller");
13
13
  const check = () => {
14
14
  if (!container_1.di.isRegistered(templates_1.PrincipalProviderContract)) {
15
15
  const errorMsg = 'No Principal Provider configured. ' +
@@ -52,6 +52,6 @@ async function initServer() {
52
52
  (0, playerSession_loader_1.playerSessionLoader)();
53
53
  logger_1.loggers.bootstrap.debug('Player session loader active');
54
54
  const scanner = container_1.di.resolve(metadata_scanner_1.MetadataScanner);
55
- scanner.scan(decorators_1.serverControllerRegistry);
55
+ scanner.scan(controller_1.serverControllerRegistry);
56
56
  logger_1.loggers.bootstrap.info('OpenCore Server initialized successfully');
57
57
  }
@@ -3,5 +3,5 @@ import { Player } from '../entities';
3
3
  export declare class CommandNetworkController {
4
4
  private readonly commandService;
5
5
  constructor(commandService: CommandService);
6
- onCommandReceived(player: Player, commandName: string, args: string[], raw: string): Promise<void>;
6
+ onCommandReceived(player: Player, command: string, args: string[], raw: string): Promise<void>;
7
7
  }
@@ -10,7 +10,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.CommandNetworkController = void 0;
13
- const netEvent_1 = require("../decorators/netEvent");
13
+ const onNet_1 = require("../decorators/onNet");
14
14
  const command_service_1 = require("../services/command.service");
15
15
  const entities_1 = require("../entities");
16
16
  const decorators_1 = require("../decorators");
@@ -19,16 +19,16 @@ let CommandNetworkController = class CommandNetworkController {
19
19
  constructor(commandService) {
20
20
  this.commandService = commandService;
21
21
  }
22
- async onCommandReceived(player, commandName, args, raw) {
22
+ async onCommandReceived(player, command, args, raw) {
23
23
  try {
24
- logger_1.loggers.command.trace(`Received: /${commandName}`, {
24
+ logger_1.loggers.command.trace(`Received: /${command}`, {
25
25
  playerId: player.clientID,
26
26
  playerName: player.name,
27
27
  });
28
- await this.commandService.execute(player, commandName, args, raw);
28
+ await this.commandService.execute(player, command, args, raw);
29
29
  }
30
30
  catch (error) {
31
- logger_1.loggers.command.error(`Execution failed: /${commandName}`, {
31
+ logger_1.loggers.command.error(`Execution failed: /${command}`, {
32
32
  playerId: player.clientID,
33
33
  }, error);
34
34
  }
@@ -36,7 +36,7 @@ let CommandNetworkController = class CommandNetworkController {
36
36
  };
37
37
  exports.CommandNetworkController = CommandNetworkController;
38
38
  __decorate([
39
- (0, netEvent_1.OnNet)('core:internal:executeCommand'),
39
+ (0, onNet_1.OnNet)('core:internal:executeCommand'),
40
40
  __metadata("design:type", Function),
41
41
  __metadata("design:paramtypes", [entities_1.Player, String, Array, String]),
42
42
  __metadata("design:returntype", Promise)
@@ -1,19 +1,49 @@
1
1
  import type { ClassConstructor } from '../../system/class-constructor';
2
2
  import type z from 'zod';
3
+ import type { Player } from '../entities/player';
3
4
  export interface CommandConfig {
4
- name: string;
5
+ /**
6
+ * The command name (e.g. "revive", "deposit"), used in chat "/revive"
7
+ */
8
+ command: string;
9
+ /**
10
+ * The command description, maybe "/help revive"
11
+ */
5
12
  description?: string;
13
+ /**
14
+ * The command usage, maybe "/revive <player>"
15
+ */
6
16
  usage?: string;
17
+ /**
18
+ * The command schema, used to validate the arguments, validated with zod
19
+ * @example
20
+ * ```ts
21
+ * Server.Command({
22
+ * command: 'revive',
23
+ * schema: z.object({
24
+ * player: z.string(),
25
+ * }),
26
+ * })
27
+ * ```
28
+ */
7
29
  schema?: z.ZodType;
8
30
  }
9
31
  export interface CommandMetadata extends CommandConfig {
10
32
  methodName: string;
11
33
  target: ClassConstructor;
34
+ paramTypes?: any;
12
35
  }
36
+ type ServerCommandHandler = (player: Player, ...args: any[]) => any;
13
37
  /**
14
38
  * Decorator used to mark a controller method as a command.
15
- * The metadata is collected and later bound to FiveM via RegisterCommand().
39
+ * This method will be registered and then executed by the command service.
40
+ * It will depend on the chat you have implemented following the dependency conventions.
16
41
  *
17
- * @param name - The command name (e.g. "revive", "deposit")
42
+ * @param configOrName - The command name (e.g. "revive", "deposit")
43
+ * @validation zod schema
44
+ * @handlerSignature ```ts
45
+ * (player: Server.Player, args: any[]) => any
46
+ * ```
18
47
  */
19
- export declare function Command(configOrName: string | CommandConfig): (target: any, propertyKey: string) => void;
48
+ export declare function Command(configOrName: string | CommandConfig): <T extends ServerCommandHandler>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => void;
49
+ export {};
@@ -4,15 +4,20 @@ exports.Command = Command;
4
4
  const metadata_server_keys_1 = require("../system/metadata-server.keys");
5
5
  /**
6
6
  * Decorator used to mark a controller method as a command.
7
- * The metadata is collected and later bound to FiveM via RegisterCommand().
7
+ * This method will be registered and then executed by the command service.
8
+ * It will depend on the chat you have implemented following the dependency conventions.
8
9
  *
9
- * @param name - The command name (e.g. "revive", "deposit")
10
+ * @param configOrName - The command name (e.g. "revive", "deposit")
11
+ * @validation zod schema
12
+ * @handlerSignature ```ts
13
+ * (player: Server.Player, args: any[]) => any
14
+ * ```
10
15
  */
11
16
  function Command(configOrName) {
12
- return (target, propertyKey) => {
13
- // Normalizamos: si pasa solo un string, creamos el objeto config
14
- const config = typeof configOrName === 'string' ? { name: configOrName } : configOrName;
15
- const metadata = Object.assign(Object.assign({}, config), { methodName: propertyKey, target: target.constructor });
17
+ return (target, propertyKey, descriptor) => {
18
+ const config = typeof configOrName === 'string' ? { command: configOrName } : configOrName;
19
+ const paramTypes = Reflect.getMetadata('design:paramtypes', target, propertyKey);
20
+ const metadata = Object.assign(Object.assign({}, config), { methodName: propertyKey, target: target.constructor, paramTypes });
16
21
  Reflect.defineMetadata(metadata_server_keys_1.METADATA_KEYS.COMMAND, metadata, target, propertyKey);
17
22
  };
18
23
  }
@@ -1,3 +1,25 @@
1
1
  import type { ClassConstructor } from '../../system/class-constructor';
2
2
  export declare const serverControllerRegistry: ClassConstructor[];
3
+ /**
4
+ * Class decorator used to mark a class as a Server Controller.
5
+ *
6
+ * This decorator performs the following actions:
7
+ * 1. Marks the class as `@injectable` (via tsyringe) for dependency injection.
8
+ * 2. Defines metadata identifying the class as a 'server' type controller.
9
+ * 3. Automatically adds the class constructor to the `serverControllerRegistry`.
10
+ *
11
+ * @returns The decorator function to apply to the class.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { Controller } from '@core/server/decorators'
16
+ *
17
+ * @Server.Controller()
18
+ * export class PlayerController {
19
+ * constructor(private playerService: PlayerService) {
20
+ * // Dependency injection works automatically here
21
+ * }
22
+ * }
23
+ * ```
24
+ */
3
25
  export declare function Controller(): (target: ClassConstructor) => void;
@@ -5,6 +5,28 @@ exports.Controller = Controller;
5
5
  const tsyringe_1 = require("tsyringe");
6
6
  const metadata_server_keys_1 = require("../system/metadata-server.keys");
7
7
  exports.serverControllerRegistry = [];
8
+ /**
9
+ * Class decorator used to mark a class as a Server Controller.
10
+ *
11
+ * This decorator performs the following actions:
12
+ * 1. Marks the class as `@injectable` (via tsyringe) for dependency injection.
13
+ * 2. Defines metadata identifying the class as a 'server' type controller.
14
+ * 3. Automatically adds the class constructor to the `serverControllerRegistry`.
15
+ *
16
+ * @returns The decorator function to apply to the class.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { Controller } from '@core/server/decorators'
21
+ *
22
+ * @Server.Controller()
23
+ * export class PlayerController {
24
+ * constructor(private playerService: PlayerService) {
25
+ * // Dependency injection works automatically here
26
+ * }
27
+ * }
28
+ * ```
29
+ */
8
30
  function Controller() {
9
31
  return function (target) {
10
32
  (0, tsyringe_1.injectable)()(target);
@@ -1,2 +1,22 @@
1
1
  import type { CoreEventMap } from '../types/core-events';
2
+ /**
3
+ * Method decorator used to register a method as a listener for an internal OpenCore framework event.
4
+ *
5
+ * When the specified framework event is emitted, this method will be automatically triggered
6
+ * with the arguments provided by the event payload.
7
+ *
8
+ * @param event - The name of the core event to listen for (typed strictly to `CoreEventMap`).
9
+ *
10
+ *
11
+ * ```ts
12
+ * @Server.Controller()
13
+ * export class SystemController {
14
+ *
15
+ * @OnCoreEvent('server:ready')
16
+ * public onServerStart() {
17
+ * console.log('OpenCore Framework is ready!')
18
+ * }
19
+ * }
20
+ * ```
21
+ */
2
22
  export declare function OnCoreEvent<K extends keyof CoreEventMap>(event: K): (target: any, propertyKey: string) => void;
@@ -2,6 +2,26 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.OnCoreEvent = OnCoreEvent;
4
4
  const metadata_server_keys_1 = require("../system/metadata-server.keys");
5
+ /**
6
+ * Method decorator used to register a method as a listener for an internal OpenCore framework event.
7
+ *
8
+ * When the specified framework event is emitted, this method will be automatically triggered
9
+ * with the arguments provided by the event payload.
10
+ *
11
+ * @param event - The name of the core event to listen for (typed strictly to `CoreEventMap`).
12
+ *
13
+ *
14
+ * ```ts
15
+ * @Server.Controller()
16
+ * export class SystemController {
17
+ *
18
+ * @OnCoreEvent('server:ready')
19
+ * public onServerStart() {
20
+ * console.log('OpenCore Framework is ready!')
21
+ * }
22
+ * }
23
+ * ```
24
+ */
5
25
  function OnCoreEvent(event) {
6
26
  return (target, propertyKey) => {
7
27
  Reflect.defineMetadata(metadata_server_keys_1.METADATA_KEYS.CORE_EVENT, { event }, target, propertyKey);
@@ -1 +1,39 @@
1
+ /**
2
+ * Export
3
+ * -----------------------------------------
4
+ * Declares a method as an externally accessible export
5
+ * within the FiveM environment.
6
+ *
7
+ * Methods decorated with `@Export()` are automatically
8
+ * registered by the framework and exposed as native
9
+ * FXServer exports, allowing other resources to call them
10
+ * using:
11
+ *
12
+ * exports.resourceName.exportName(...)
13
+ *
14
+ * This decorator is typically used inside controller
15
+ * classes, where the framework’s module loader inspects
16
+ * metadata to register commands, events and exports
17
+ * consistently.
18
+ *
19
+ * @param name Optional name to expose. If omitted,
20
+ * the method name is used.
21
+ *
22
+ * ```ts
23
+ * @Server.Controller()
24
+ * export class AccountController {
25
+ * @Server.Export('getAccountById')
26
+ * getAccount(id: string) {
27
+ * return this.accountService.find(id)
28
+ * }
29
+ * }
30
+ *
31
+ * // From another resource:
32
+ * // const result = exports['core-resource'].getAccountById('1234')
33
+ *```
34
+ * Internally, this decorator stores metadata used by
35
+ * the server bootstrap to automatically register the
36
+ * export through FXServer's `global.exports` API.
37
+ *
38
+ */
1
39
  export declare function Export(name?: string): (target: any, propertyKey: string) => void;
@@ -2,6 +2,44 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Export = Export;
4
4
  const metadata_server_keys_1 = require("../system/metadata-server.keys");
5
+ /**
6
+ * Export
7
+ * -----------------------------------------
8
+ * Declares a method as an externally accessible export
9
+ * within the FiveM environment.
10
+ *
11
+ * Methods decorated with `@Export()` are automatically
12
+ * registered by the framework and exposed as native
13
+ * FXServer exports, allowing other resources to call them
14
+ * using:
15
+ *
16
+ * exports.resourceName.exportName(...)
17
+ *
18
+ * This decorator is typically used inside controller
19
+ * classes, where the framework’s module loader inspects
20
+ * metadata to register commands, events and exports
21
+ * consistently.
22
+ *
23
+ * @param name Optional name to expose. If omitted,
24
+ * the method name is used.
25
+ *
26
+ * ```ts
27
+ * @Server.Controller()
28
+ * export class AccountController {
29
+ * @Server.Export('getAccountById')
30
+ * getAccount(id: string) {
31
+ * return this.accountService.find(id)
32
+ * }
33
+ * }
34
+ *
35
+ * // From another resource:
36
+ * // const result = exports['core-resource'].getAccountById('1234')
37
+ *```
38
+ * Internally, this decorator stores metadata used by
39
+ * the server bootstrap to automatically register the
40
+ * export through FXServer's `global.exports` API.
41
+ *
42
+ */
5
43
  function Export(name) {
6
44
  return (target, propertyKey) => {
7
45
  Reflect.defineMetadata(metadata_server_keys_1.METADATA_KEYS.EXPORT, { exportName: name || propertyKey }, target, propertyKey);
@@ -1,5 +1,56 @@
1
1
  export interface GuardOptions {
2
+ /**
3
+ * Minimum rank required to execute the method.
4
+ * Permissions and Role/Ranks are defined by your Principal Controller
5
+ */
2
6
  rank?: number;
7
+ /**
8
+ * Permission required to execute the method.
9
+ * Permissions and Role/Ranks are defined by your Principal Controller
10
+ */
3
11
  permission?: string;
4
12
  }
13
+ /**
14
+ * Guard
15
+ * ------------------------------------------------------------
16
+ * Declarative access-control decorator for controller methods.
17
+ *
18
+ * `@Guard()` protects a method by enforcing rank and/or
19
+ * permission requirements before executing it.
20
+ *
21
+ * Requirements are evaluated through the AccessControlService,
22
+ * which determines whether the player (first argument of the
23
+ * method) is authorized to perform the action.
24
+ *
25
+ * Usage of this decorator allows you to express authorization
26
+ * rules directly at the controller level, promoting a clean
27
+ * and explicit security model.
28
+ *
29
+ * @param options GuardOptions
30
+ * - rank: minimum rank required to execute the method.
31
+ * - permission: specific permission required.
32
+ *
33
+ * Notes:
34
+ * - The decorated method must receive a `Server.Player`
35
+ * instance as its first argument.
36
+ * - When compiling improperly (e.g., benchmarks, stripped
37
+ * decorators), the PropertyDescriptor may be missing.
38
+ * In that case, only metadata is recorded and execution
39
+ * fallback is disabled. This should *never* occur in a
40
+ * production environment.
41
+ *
42
+ * ```ts
43
+ * export class FactionController {
44
+ * @Server.Guard({ permission: 'factions.manage' })
45
+ * async createFaction(player: Player, dto: CreateFactionDTO) {
46
+ * return this.service.create(dto)
47
+ * }
48
+ *
49
+ * @Server.Guard({ rank: 3 })
50
+ * async promoteMember(player: Player, memberID: string) {
51
+ * return this.service.promote(player, memberID)
52
+ * }
53
+ * }
54
+ * ```
55
+ */
5
56
  export declare function Guard(options: GuardOptions): (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => PropertyDescriptor | undefined;
@@ -4,6 +4,49 @@ exports.Guard = Guard;
4
4
  const container_1 = require("../container");
5
5
  const services_1 = require("../services");
6
6
  const logger_1 = require("../../shared/logger");
7
+ /**
8
+ * Guard
9
+ * ------------------------------------------------------------
10
+ * Declarative access-control decorator for controller methods.
11
+ *
12
+ * `@Guard()` protects a method by enforcing rank and/or
13
+ * permission requirements before executing it.
14
+ *
15
+ * Requirements are evaluated through the AccessControlService,
16
+ * which determines whether the player (first argument of the
17
+ * method) is authorized to perform the action.
18
+ *
19
+ * Usage of this decorator allows you to express authorization
20
+ * rules directly at the controller level, promoting a clean
21
+ * and explicit security model.
22
+ *
23
+ * @param options GuardOptions
24
+ * - rank: minimum rank required to execute the method.
25
+ * - permission: specific permission required.
26
+ *
27
+ * Notes:
28
+ * - The decorated method must receive a `Server.Player`
29
+ * instance as its first argument.
30
+ * - When compiling improperly (e.g., benchmarks, stripped
31
+ * decorators), the PropertyDescriptor may be missing.
32
+ * In that case, only metadata is recorded and execution
33
+ * fallback is disabled. This should *never* occur in a
34
+ * production environment.
35
+ *
36
+ * ```ts
37
+ * export class FactionController {
38
+ * @Server.Guard({ permission: 'factions.manage' })
39
+ * async createFaction(player: Player, dto: CreateFactionDTO) {
40
+ * return this.service.create(dto)
41
+ * }
42
+ *
43
+ * @Server.Guard({ rank: 3 })
44
+ * async promoteMember(player: Player, memberID: string) {
45
+ * return this.service.promote(player, memberID)
46
+ * }
47
+ * }
48
+ * ```
49
+ */
7
50
  function Guard(options) {
8
51
  return function (target, propertyKey, descriptor) {
9
52
  var _a;
@@ -1,10 +1,10 @@
1
1
  export * from './bind';
2
2
  export * from './utils';
3
- export * from './command';
3
+ export { Command, CommandConfig } from './command';
4
4
  export * from './coreEvent';
5
- export * from './netEvent';
5
+ export * from './onNet';
6
6
  export * from './onTick';
7
- export * from './controller';
7
+ export { Controller } from './controller';
8
8
  export * from './throttle';
9
9
  export * from './guard';
10
10
  export * from './requiresState';
@@ -14,13 +14,16 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.Controller = exports.Command = void 0;
17
18
  __exportStar(require("./bind"), exports);
18
19
  __exportStar(require("./utils"), exports);
19
- __exportStar(require("./command"), exports);
20
+ var command_1 = require("./command");
21
+ Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return command_1.Command; } });
20
22
  __exportStar(require("./coreEvent"), exports);
21
- __exportStar(require("./netEvent"), exports);
23
+ __exportStar(require("./onNet"), exports);
22
24
  __exportStar(require("./onTick"), exports);
23
- __exportStar(require("./controller"), exports);
25
+ var controller_1 = require("./controller");
26
+ Object.defineProperty(exports, "Controller", { enumerable: true, get: function () { return controller_1.Controller; } });
24
27
  __exportStar(require("./throttle"), exports);
25
28
  __exportStar(require("./guard"), exports);
26
29
  __exportStar(require("./requiresState"), exports);
@@ -0,0 +1,58 @@
1
+ import type { z } from 'zod';
2
+ import type { Player } from '../entities/player';
3
+ export interface NetEventOptions {
4
+ eventName: string;
5
+ schema?: z.ZodType;
6
+ paramTypes?: any;
7
+ }
8
+ type ServerNetHandler<TArgs extends any[] = any[]> = (player: Player, ...args: TArgs) => any;
9
+ /**
10
+ * Registers a server-side network event handler.
11
+ *
12
+ * The decorated method is invoked when the client triggers
13
+ * `emitNet(eventName, ...)`.
14
+ *
15
+ * ## Player Injection
16
+ * The first argument of the handler **must be `Player`** and is automatically
17
+ * replaced with a `Server.Player` instance representing the client that
18
+ * fired the event. You do NOT need to read `source` manually.
19
+ *
20
+ * ## Auto-Validation
21
+ * Arguments after `Player` are automatically validated based on their TypeScript types:
22
+ * - `string` → `z.string()`
23
+ * - `number` → `z.number()`
24
+ * - `boolean` → `z.boolean()`
25
+ * - `any[]` → `z.array(z.any())` (array content not validated)
26
+ *
27
+ * ## Explicit Schema (Advanced)
28
+ * For stricter validation (ranges, formats, nested objects), provide a Zod schema:
29
+ *
30
+ * @example Auto-validation (simple)
31
+ * ```ts
32
+ * @OnNet("auth:login")
33
+ * handleLogin(player: Player, username: string, password: string) {
34
+ * // username and password are validated as strings automatically
35
+ * }
36
+ * ```
37
+ *
38
+ * @example Explicit schema (strict validation)
39
+ * ```ts
40
+ * const transferSchema = z.object({
41
+ * targetId: z.number().positive(),
42
+ * amount: z.number().min(1).max(1000000),
43
+ * })
44
+ *
45
+ * @OnNet("bank:transfer", { schema: transferSchema })
46
+ * handleTransfer(player: Player, data: z.infer<typeof transferSchema>) {
47
+ * // data.amount is guaranteed to be between 1 and 1,000,000
48
+ * }
49
+ * ```
50
+ *
51
+ * @param eventName - The network event name to listen for.
52
+ * @param options - Optional configuration object.
53
+ * @param options.schema - Zod schema for strict payload validation.
54
+ */
55
+ export declare function OnNet<TArgs extends any[]>(eventName: string, options?: {
56
+ schema?: z.ZodType;
57
+ }): <H extends ServerNetHandler<TArgs>>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<H>) => void;
58
+ export {};
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OnNet = OnNet;
4
+ const metadata_server_keys_1 = require("../system/metadata-server.keys");
5
+ /**
6
+ * Registers a server-side network event handler.
7
+ *
8
+ * The decorated method is invoked when the client triggers
9
+ * `emitNet(eventName, ...)`.
10
+ *
11
+ * ## Player Injection
12
+ * The first argument of the handler **must be `Player`** and is automatically
13
+ * replaced with a `Server.Player` instance representing the client that
14
+ * fired the event. You do NOT need to read `source` manually.
15
+ *
16
+ * ## Auto-Validation
17
+ * Arguments after `Player` are automatically validated based on their TypeScript types:
18
+ * - `string` → `z.string()`
19
+ * - `number` → `z.number()`
20
+ * - `boolean` → `z.boolean()`
21
+ * - `any[]` → `z.array(z.any())` (array content not validated)
22
+ *
23
+ * ## Explicit Schema (Advanced)
24
+ * For stricter validation (ranges, formats, nested objects), provide a Zod schema:
25
+ *
26
+ * @example Auto-validation (simple)
27
+ * ```ts
28
+ * @OnNet("auth:login")
29
+ * handleLogin(player: Player, username: string, password: string) {
30
+ * // username and password are validated as strings automatically
31
+ * }
32
+ * ```
33
+ *
34
+ * @example Explicit schema (strict validation)
35
+ * ```ts
36
+ * const transferSchema = z.object({
37
+ * targetId: z.number().positive(),
38
+ * amount: z.number().min(1).max(1000000),
39
+ * })
40
+ *
41
+ * @OnNet("bank:transfer", { schema: transferSchema })
42
+ * handleTransfer(player: Player, data: z.infer<typeof transferSchema>) {
43
+ * // data.amount is guaranteed to be between 1 and 1,000,000
44
+ * }
45
+ * ```
46
+ *
47
+ * @param eventName - The network event name to listen for.
48
+ * @param options - Optional configuration object.
49
+ * @param options.schema - Zod schema for strict payload validation.
50
+ */
51
+ function OnNet(eventName, options) {
52
+ return (target, propertyKey, descriptor) => {
53
+ const paramTypes = Reflect.getMetadata('design:paramtypes', target, propertyKey);
54
+ const metadata = { eventName, schema: options === null || options === void 0 ? void 0 : options.schema, paramTypes };
55
+ Reflect.defineMetadata(metadata_server_keys_1.METADATA_KEYS.NET_EVENT, metadata, target, propertyKey);
56
+ };
57
+ }
@@ -1 +1,32 @@
1
+ /**
2
+ * OnTick
3
+ * ------------------------------------------------------------
4
+ * Marks a method to be executed on every server tick.
5
+ *
6
+ * Methods decorated with `@OnTick()` are automatically
7
+ * registered by the framework's scheduler and invoked on each
8
+ * FXServer tick (~ every 0–10 ms depending on workload).
9
+ *
10
+ * This decorator should be used for lightweight recurring
11
+ * logic: status updates, background checks, cleanup tasks,
12
+ * or time-based processes relevant to gameplay.
13
+ *
14
+ * Heavy or blocking operations should be avoided inside tick
15
+ * handlers, as they directly impact global server performance.
16
+ *
17
+ * ```ts
18
+ * export class SyncController {
19
+ * @OnTick()
20
+ * updatePlayers() {
21
+ * // Runs every tick
22
+ * this.service.syncPositions()
23
+ * }
24
+ * }
25
+ *
26
+ * ```
27
+ *
28
+ * Internally, the decorator only stores metadata. The
29
+ * server bootstrap scans for this metadata and binds the
30
+ * method to FiveM's tick cycle.
31
+ */
1
32
  export declare function OnTick(): (target: any, propertyKey: string) => void;