@open-core/framework 1.0.1-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 (275) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +350 -0
  3. package/dist/client/client-bootstrap.d.ts +1 -0
  4. package/dist/client/client-bootstrap.js +53 -0
  5. package/dist/client/client-container.d.ts +2 -0
  6. package/dist/client/client-container.js +6 -0
  7. package/dist/client/client-core.d.ts +18 -0
  8. package/dist/client/client-core.js +52 -0
  9. package/dist/client/decorators/controller.d.ts +3 -0
  10. package/dist/client/decorators/controller.js +14 -0
  11. package/dist/client/decorators/export.d.ts +7 -0
  12. package/dist/client/decorators/export.js +15 -0
  13. package/dist/client/decorators/gameEvent.d.ts +47 -0
  14. package/dist/client/decorators/gameEvent.js +54 -0
  15. package/dist/client/decorators/index.d.ts +10 -0
  16. package/dist/client/decorators/index.js +26 -0
  17. package/dist/client/decorators/interval.d.ts +7 -0
  18. package/dist/client/decorators/interval.js +15 -0
  19. package/dist/client/decorators/key.d.ts +2 -0
  20. package/dist/client/decorators/key.js +10 -0
  21. package/dist/client/decorators/localEvent.d.ts +7 -0
  22. package/dist/client/decorators/localEvent.js +15 -0
  23. package/dist/client/decorators/nui.d.ts +1 -0
  24. package/dist/client/decorators/nui.js +9 -0
  25. package/dist/client/decorators/onNet.d.ts +1 -0
  26. package/dist/client/decorators/onNet.js +9 -0
  27. package/dist/client/decorators/resourceLifecycle.d.ts +11 -0
  28. package/dist/client/decorators/resourceLifecycle.js +24 -0
  29. package/dist/client/decorators/tick.d.ts +1 -0
  30. package/dist/client/decorators/tick.js +9 -0
  31. package/dist/client/index.d.ts +6 -0
  32. package/dist/client/index.js +22 -0
  33. package/dist/client/loaders/exports.loader.d.ts +1 -0
  34. package/dist/client/loaders/exports.loader.js +13 -0
  35. package/dist/client/player/player.d.ts +262 -0
  36. package/dist/client/player/player.js +480 -0
  37. package/dist/client/player/player.loader.d.ts +1 -0
  38. package/dist/client/player/player.loader.js +22 -0
  39. package/dist/client/services/core/index.d.ts +1 -0
  40. package/dist/client/services/core/index.js +17 -0
  41. package/dist/client/services/core/spawn.service.d.ts +20 -0
  42. package/dist/client/services/core/spawn.service.js +143 -0
  43. package/dist/client/services/index.d.ts +4 -0
  44. package/dist/client/services/index.js +24 -0
  45. package/dist/client/services/streaming/index.d.ts +1 -0
  46. package/dist/client/services/streaming/index.js +17 -0
  47. package/dist/client/services/streaming/streaming.service.d.ts +165 -0
  48. package/dist/client/services/streaming/streaming.service.js +341 -0
  49. package/dist/client/services/ui/index.d.ts +3 -0
  50. package/dist/client/services/ui/index.js +19 -0
  51. package/dist/client/services/ui/notification.service.d.ts +76 -0
  52. package/dist/client/services/ui/notification.service.js +111 -0
  53. package/dist/client/services/ui/progress.service.d.ts +82 -0
  54. package/dist/client/services/ui/progress.service.js +210 -0
  55. package/dist/client/services/ui/textui.service.d.ts +82 -0
  56. package/dist/client/services/ui/textui.service.js +156 -0
  57. package/dist/client/services/world/blip.service.d.ts +112 -0
  58. package/dist/client/services/world/blip.service.js +215 -0
  59. package/dist/client/services/world/index.d.ts +4 -0
  60. package/dist/client/services/world/index.js +20 -0
  61. package/dist/client/services/world/marker.service.d.ts +94 -0
  62. package/dist/client/services/world/marker.service.js +153 -0
  63. package/dist/client/services/world/ped.service.d.ts +182 -0
  64. package/dist/client/services/world/ped.service.js +302 -0
  65. package/dist/client/services/world/vehicle.service.d.ts +168 -0
  66. package/dist/client/services/world/vehicle.service.js +296 -0
  67. package/dist/client/system/metadata-client.keys.d.ts +13 -0
  68. package/dist/client/system/metadata-client.keys.js +16 -0
  69. package/dist/client/system/processors/export.processor.d.ts +7 -0
  70. package/dist/client/system/processors/export.processor.js +39 -0
  71. package/dist/client/system/processors/gameEvent.processor.d.ts +10 -0
  72. package/dist/client/system/processors/gameEvent.processor.js +58 -0
  73. package/dist/client/system/processors/interval.processor.d.ts +7 -0
  74. package/dist/client/system/processors/interval.processor.js +43 -0
  75. package/dist/client/system/processors/key.processor.d.ts +8 -0
  76. package/dist/client/system/processors/key.processor.js +27 -0
  77. package/dist/client/system/processors/localEvent.processor.d.ts +7 -0
  78. package/dist/client/system/processors/localEvent.processor.js +38 -0
  79. package/dist/client/system/processors/netEvent.processor.d.ts +7 -0
  80. package/dist/client/system/processors/netEvent.processor.js +38 -0
  81. package/dist/client/system/processors/nui.processor.d.ts +7 -0
  82. package/dist/client/system/processors/nui.processor.js +40 -0
  83. package/dist/client/system/processors/resourceLifecycle.processor.d.ts +9 -0
  84. package/dist/client/system/processors/resourceLifecycle.processor.js +69 -0
  85. package/dist/client/system/processors/tick.processor.d.ts +5 -0
  86. package/dist/client/system/processors/tick.processor.js +37 -0
  87. package/dist/client/system/processors.register.d.ts +1 -0
  88. package/dist/client/system/processors.register.js +27 -0
  89. package/dist/client/types/game-events.d.ts +126 -0
  90. package/dist/client/types/game-events.js +83 -0
  91. package/dist/client/types/index.d.ts +1 -0
  92. package/dist/client/types/index.js +17 -0
  93. package/dist/client/ui-bridge.d.ts +116 -0
  94. package/dist/client/ui-bridge.js +201 -0
  95. package/dist/index.d.ts +7 -0
  96. package/dist/index.js +46 -0
  97. package/dist/server/bootstrap.d.ts +16 -0
  98. package/dist/server/bootstrap.js +57 -0
  99. package/dist/server/bus/core-event-bus.d.ts +6 -0
  100. package/dist/server/bus/core-event-bus.js +31 -0
  101. package/dist/server/configs/api.config.d.ts +71 -0
  102. package/dist/server/configs/api.config.js +81 -0
  103. package/dist/server/configs/config.base.d.ts +63 -0
  104. package/dist/server/configs/config.base.js +64 -0
  105. package/dist/server/configs/index.d.ts +2 -0
  106. package/dist/server/configs/index.js +18 -0
  107. package/dist/server/container.d.ts +2 -0
  108. package/dist/server/container.js +6 -0
  109. package/dist/server/controllers/chat.controller.d.ts +10 -0
  110. package/dist/server/controllers/chat.controller.js +50 -0
  111. package/dist/server/controllers/command.controller.d.ts +7 -0
  112. package/dist/server/controllers/command.controller.js +47 -0
  113. package/dist/server/core.d.ts +1 -0
  114. package/dist/server/core.js +7 -0
  115. package/dist/server/database/adapters/oxmysql.adapter.d.ts +89 -0
  116. package/dist/server/database/adapters/oxmysql.adapter.js +149 -0
  117. package/dist/server/database/database.contract.d.ts +128 -0
  118. package/dist/server/database/database.contract.js +29 -0
  119. package/dist/server/database/database.service.d.ts +216 -0
  120. package/dist/server/database/database.service.js +301 -0
  121. package/dist/server/database/index.d.ts +53 -0
  122. package/dist/server/database/index.js +70 -0
  123. package/dist/server/database/types.d.ts +67 -0
  124. package/dist/server/database/types.js +7 -0
  125. package/dist/server/database.d.ts +7 -0
  126. package/dist/server/database.js +23 -0
  127. package/dist/server/decorators/bind.d.ts +2 -0
  128. package/dist/server/decorators/bind.js +15 -0
  129. package/dist/server/decorators/command.d.ts +19 -0
  130. package/dist/server/decorators/command.js +18 -0
  131. package/dist/server/decorators/controller.d.ts +3 -0
  132. package/dist/server/decorators/controller.js +14 -0
  133. package/dist/server/decorators/coreEvent.d.ts +2 -0
  134. package/dist/server/decorators/coreEvent.js +9 -0
  135. package/dist/server/decorators/export.d.ts +1 -0
  136. package/dist/server/decorators/export.js +9 -0
  137. package/dist/server/decorators/guard.d.ts +5 -0
  138. package/dist/server/decorators/guard.js +39 -0
  139. package/dist/server/decorators/index.d.ts +10 -0
  140. package/dist/server/decorators/index.js +26 -0
  141. package/dist/server/decorators/netEvent.d.ts +36 -0
  142. package/dist/server/decorators/netEvent.js +40 -0
  143. package/dist/server/decorators/onTick.d.ts +1 -0
  144. package/dist/server/decorators/onTick.js +9 -0
  145. package/dist/server/decorators/public.d.ts +16 -0
  146. package/dist/server/decorators/public.js +25 -0
  147. package/dist/server/decorators/requiresState.d.ts +55 -0
  148. package/dist/server/decorators/requiresState.js +62 -0
  149. package/dist/server/decorators/throttle.d.ts +9 -0
  150. package/dist/server/decorators/throttle.js +36 -0
  151. package/dist/server/decorators/utils.d.ts +7 -0
  152. package/dist/server/decorators/utils.js +13 -0
  153. package/dist/server/entities/index.d.ts +1 -0
  154. package/dist/server/entities/index.js +17 -0
  155. package/dist/server/entities/player.d.ts +157 -0
  156. package/dist/server/entities/player.js +217 -0
  157. package/dist/server/error-handler.d.ts +2 -0
  158. package/dist/server/error-handler.js +43 -0
  159. package/dist/server/index.d.ts +10 -0
  160. package/dist/server/index.js +29 -0
  161. package/dist/server/loaders/exports.loader.d.ts +0 -0
  162. package/dist/server/loaders/exports.loader.js +23 -0
  163. package/dist/server/loaders/playerSession.loader.d.ts +1 -0
  164. package/dist/server/loaders/playerSession.loader.js +42 -0
  165. package/dist/server/services/access-control.service.d.ts +56 -0
  166. package/dist/server/services/access-control.service.js +99 -0
  167. package/dist/server/services/chat.service.d.ts +7 -0
  168. package/dist/server/services/chat.service.js +31 -0
  169. package/dist/server/services/command.service.d.ts +15 -0
  170. package/dist/server/services/command.service.js +74 -0
  171. package/dist/server/services/config.service.d.ts +75 -0
  172. package/dist/server/services/config.service.js +116 -0
  173. package/dist/server/services/default/default-security.handler.d.ts +6 -0
  174. package/dist/server/services/default/default-security.handler.js +26 -0
  175. package/dist/server/services/http/http.service.d.ts +50 -0
  176. package/dist/server/services/http/http.service.js +126 -0
  177. package/dist/server/services/index.d.ts +10 -0
  178. package/dist/server/services/index.js +26 -0
  179. package/dist/server/services/parallel/index.d.ts +49 -0
  180. package/dist/server/services/parallel/index.js +67 -0
  181. package/dist/server/services/parallel/parallel-compute.service.d.ts +132 -0
  182. package/dist/server/services/parallel/parallel-compute.service.js +449 -0
  183. package/dist/server/services/parallel/types.d.ts +188 -0
  184. package/dist/server/services/parallel/types.js +7 -0
  185. package/dist/server/services/parallel/worker-pool.d.ts +83 -0
  186. package/dist/server/services/parallel/worker-pool.js +350 -0
  187. package/dist/server/services/parallel/worker.d.ts +19 -0
  188. package/dist/server/services/parallel/worker.js +49 -0
  189. package/dist/server/services/persistence.service.d.ts +59 -0
  190. package/dist/server/services/persistence.service.js +166 -0
  191. package/dist/server/services/player.service.d.ts +96 -0
  192. package/dist/server/services/player.service.js +132 -0
  193. package/dist/server/services/rate-limiter.service.d.ts +5 -0
  194. package/dist/server/services/rate-limiter.service.js +39 -0
  195. package/dist/server/services/registers.d.ts +1 -0
  196. package/dist/server/services/registers.js +18 -0
  197. package/dist/server/setup.d.ts +9 -0
  198. package/dist/server/setup.js +28 -0
  199. package/dist/server/system/metadata-server.keys.d.ts +9 -0
  200. package/dist/server/system/metadata-server.keys.js +12 -0
  201. package/dist/server/system/processors/command.processor.d.ts +9 -0
  202. package/dist/server/system/processors/command.processor.js +31 -0
  203. package/dist/server/system/processors/coreEvent.processor.d.ts +7 -0
  204. package/dist/server/system/processors/coreEvent.processor.js +38 -0
  205. package/dist/server/system/processors/export.processor.d.ts +7 -0
  206. package/dist/server/system/processors/export.processor.js +26 -0
  207. package/dist/server/system/processors/netEvent.processor.d.ts +11 -0
  208. package/dist/server/system/processors/netEvent.processor.js +100 -0
  209. package/dist/server/system/processors/tick.processor.d.ts +5 -0
  210. package/dist/server/system/processors/tick.processor.js +36 -0
  211. package/dist/server/system/processors.register.d.ts +1 -0
  212. package/dist/server/system/processors.register.js +21 -0
  213. package/dist/server/templates/admin/admin.controller-template.d.ts +10 -0
  214. package/dist/server/templates/admin/admin.controller-template.js +2 -0
  215. package/dist/server/templates/auth/auth-provider.contract.d.ts +58 -0
  216. package/dist/server/templates/auth/auth-provider.contract.js +23 -0
  217. package/dist/server/templates/index.d.ts +8 -0
  218. package/dist/server/templates/index.js +21 -0
  219. package/dist/server/templates/persistence/index.d.ts +30 -0
  220. package/dist/server/templates/persistence/index.js +34 -0
  221. package/dist/server/templates/persistence/player-persistence.contract.d.ts +86 -0
  222. package/dist/server/templates/persistence/player-persistence.contract.js +52 -0
  223. package/dist/server/templates/repository/index.d.ts +57 -0
  224. package/dist/server/templates/repository/index.js +61 -0
  225. package/dist/server/templates/repository/repository.contract.d.ts +224 -0
  226. package/dist/server/templates/repository/repository.contract.js +342 -0
  227. package/dist/server/templates/repository/repository.types.d.ts +51 -0
  228. package/dist/server/templates/repository/repository.types.js +7 -0
  229. package/dist/server/templates/security/permission.types.d.ts +32 -0
  230. package/dist/server/templates/security/permission.types.js +2 -0
  231. package/dist/server/templates/security/principal-provider.contract.d.ts +43 -0
  232. package/dist/server/templates/security/principal-provider.contract.js +19 -0
  233. package/dist/server/templates/security/security-handler.contract.d.ts +5 -0
  234. package/dist/server/templates/security/security-handler.contract.js +6 -0
  235. package/dist/server/types/core-events.d.ts +17 -0
  236. package/dist/server/types/core-events.js +2 -0
  237. package/dist/server/types/security.types.d.ts +7 -0
  238. package/dist/server/types/security.types.js +2 -0
  239. package/dist/shared/index.d.ts +1 -0
  240. package/dist/shared/index.js +17 -0
  241. package/dist/shared/logger/core-logger.d.ts +35 -0
  242. package/dist/shared/logger/core-logger.js +52 -0
  243. package/dist/shared/logger/index.d.ts +11 -0
  244. package/dist/shared/logger/index.js +26 -0
  245. package/dist/shared/logger/logger.config.d.ts +47 -0
  246. package/dist/shared/logger/logger.config.js +33 -0
  247. package/dist/shared/logger/logger.service.d.ts +161 -0
  248. package/dist/shared/logger/logger.service.js +279 -0
  249. package/dist/shared/logger/logger.types.d.ts +85 -0
  250. package/dist/shared/logger/logger.types.js +74 -0
  251. package/dist/shared/logger/transports/buffered.transport.d.ts +88 -0
  252. package/dist/shared/logger/transports/buffered.transport.js +174 -0
  253. package/dist/shared/logger/transports/console.transport.d.ts +37 -0
  254. package/dist/shared/logger/transports/console.transport.js +134 -0
  255. package/dist/shared/logger/transports/index.d.ts +3 -0
  256. package/dist/shared/logger/transports/index.js +19 -0
  257. package/dist/shared/logger/transports/transport.interface.d.ts +40 -0
  258. package/dist/shared/logger/transports/transport.interface.js +2 -0
  259. package/dist/system/class-constructor.d.ts +1 -0
  260. package/dist/system/class-constructor.js +2 -0
  261. package/dist/system/decorator-processor.d.ts +4 -0
  262. package/dist/system/decorator-processor.js +2 -0
  263. package/dist/system/metadata.scanner.d.ts +7 -0
  264. package/dist/system/metadata.scanner.js +45 -0
  265. package/dist/utils/errors.d.ts +14 -0
  266. package/dist/utils/errors.js +25 -0
  267. package/dist/utils/index.d.ts +4 -0
  268. package/dist/utils/index.js +20 -0
  269. package/dist/utils/result.d.ts +12 -0
  270. package/dist/utils/result.js +10 -0
  271. package/dist/utils/rgb.d.ts +5 -0
  272. package/dist/utils/rgb.js +2 -0
  273. package/dist/utils/vector3.d.ts +13 -0
  274. package/dist/utils/vector3.js +27 -0
  275. package/package.json +70 -0
package/README.md ADDED
@@ -0,0 +1,350 @@
1
+ # OpenCore Framework
2
+
3
+ > **The robust TypeScript Engine for FiveM.**
4
+ > Built on strong OOP principles, Layered Architecture, and Security-first design.
5
+ > _Stop writing scripts; start engineering gameplay._
6
+
7
+ [![License: MPL 2.0](https://img.shields.io/badge/License-MPL_2.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0)
8
+ [![Version](https://img.shields.io/badge/beta-1.0.0-orange.svg)](https://github.com/newcore-network/opencore)
9
+ ![Tests](https://img.shields.io/badge/tests-265%20passing-brightgreen)
10
+ ![Coverage](https://img.shields.io/badge/coverage-43%25-yellow)
11
+ ![Core Decorators](https://img.shields.io/badge/core%20decorators-100%25-brightgreen)
12
+
13
+ ## 📋 Table of Contents
14
+
15
+ - [Why OpenCore?](#-why-opencore)
16
+ - [Installation](#-installation)
17
+ - [Quick Start](#-quick-start)
18
+ - [Security System](#️-security-system)
19
+ - [Architecture](#️-architecture)
20
+ - [Testing](#-testing)
21
+ - [Performance](#-performance--benchmarks)
22
+ - [Project Structure](#-project-structure)
23
+ - [Scripts](#-available-scripts)
24
+ - [License](#-license)
25
+
26
+ ---
27
+
28
+ ## 🚀 Why OpenCore?
29
+
30
+ OpenCore transforms FiveM development from chaotic scripting into professional software engineering. Inspired by enterprise frameworks like **Spring Boot** and **NestJS**, it brings structure, security, and strict typing to your server.
31
+
32
+ ### ✨ Key Features
33
+
34
+ - **🛡️ Security by Design:** Built-in Input Validation (**Zod**), Rate Limiting (`@Throttle`), and Access Control (`@Guard`).
35
+ - **🏗️ Decoupled Architecture:** Logic is separated into **Controllers**, **Services**, and **Entities**.
36
+ - **💉 Dependency Injection:** Full IoC container powered by `tsyringe`.
37
+ - **📝 Type-Safe:** No more guessing `source` types or argument structures.
38
+ - **📡 Event-Driven:** Powerful Event Bus for internal and network communication.
39
+ - **⚡ High Performance:** Sub-microsecond latencies, millions of ops/sec.
40
+ - **🧪 Fully Tested:** Comprehensive unit, integration, and load tests.
41
+
42
+ ---
43
+
44
+ ## 📦 Installation
45
+
46
+ ```bash
47
+ pnpm add @open-core/framework reflect-metadata tsyringe zod uuid
48
+ ```
49
+
50
+ > **Note:** Ensure you have `experimentalDecorators` and `emitDecoratorMetadata` enabled in your `tsconfig.json`.
51
+
52
+ ---
53
+
54
+ ## ⚡ Quick Start
55
+
56
+ Define a Controller, validate inputs with Zod, and protect it with a Guard. Zero boilerplate.
57
+
58
+ **Server-side:**
59
+
60
+ ```ts
61
+ import { Server } from '@open-core/framework/server'
62
+ import { z } from 'zod'
63
+
64
+ // 1. Define your Input Schema
65
+ const TransferSchema = z.tuple([
66
+ z.coerce.number().positive(), // Target ID
67
+ z.coerce.number().min(1).max(50000), // Amount
68
+ ])
69
+
70
+ @Server.Controller()
71
+ export class BankController {
72
+ constructor(private readonly bankService: BankService) {}
73
+
74
+ @Server.Command({
75
+ name: 'transfer',
76
+ schema: TransferSchema,
77
+ usage: '/transfer [id] [amount]',
78
+ })
79
+ @Server.Guard({ rank: 1 }) // Must be at least Rank 1 (User)
80
+ @Server.Throttle(1, 2000) // Max 1 request per 2 seconds
81
+ async handleTransfer(player: Server.Player, args: z.infer<typeof TransferSchema>) {
82
+ const [targetId, amount] = args
83
+
84
+ // Logic is pure and type-safe
85
+ await this.bankService.transfer(player, targetId, amount)
86
+
87
+ player.emit('chat:message', `Successfully transferred $${amount}`)
88
+ }
89
+ }
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 🛡️ Security System
95
+
96
+ OpenCore handles the dirty work so you can focus on gameplay.
97
+
98
+ ### 1. Input Validation (`@Command`, `@OnNet`)
99
+
100
+ All network inputs are validated against Zod schemas before they reach your logic. Malformed packets are rejected automatically.
101
+
102
+ ### 2. Access Control (`@Guard`)
103
+
104
+ Protect methods with granular permissions or hierarchical ranks:
105
+
106
+ ```ts
107
+ @Server.Guard({ permission: 'admin.ban' })
108
+ @Server.Guard({ rank: 10 }) // Admin level
109
+ ```
110
+
111
+ ### 3. Rate Limiting (`@Throttle`)
112
+
113
+ Prevent abuse with configurable rate limits:
114
+
115
+ ```ts
116
+ @Server.Throttle(5, 10000) // 5 requests per 10 seconds
117
+ ```
118
+
119
+ ### 4. State Management (`@RequiresState`)
120
+
121
+ Avoid "dead player exploits" or interaction glitches:
122
+
123
+ ```ts
124
+ @Server.RequiresState({ missing: ['dead', 'cuffed'] })
125
+ openInventory(player: Server.Player) { ... }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## 🏗️ Architecture
131
+
132
+ OpenCore follows a clean, layered architecture:
133
+
134
+ | Layer | Responsibility | Example |
135
+ | --------------- | ------------------------------------------------------------ | ---------------- |
136
+ | **Controllers** | Handle entry points (Commands, Events, NUI). Keep them thin. | `BankController` |
137
+ | **Services** | Contain business logic. Singletons injectable anywhere. | `BankService` |
138
+ | **Entities** | Wrappers around FiveM objects with rich APIs. | `Player` |
139
+
140
+ ```
141
+ ┌─────────────────────────────────────────────────────────┐
142
+ │ Client / FiveM │
143
+ └─────────────────────────┬───────────────────────────────┘
144
+
145
+ ┌─────────────────────────▼───────────────────────────────┐
146
+ │ Controllers │
147
+ │ @Command @OnNet @NUI @GameEvent @OnTick │
148
+ └─────────────────────────┬───────────────────────────────┘
149
+
150
+ ┌─────────────────────────▼───────────────────────────────┐
151
+ │ Security Layer (Middleware) │
152
+ │ @Guard @Throttle @RequiresState Zod Validation │
153
+ └─────────────────────────┬───────────────────────────────┘
154
+
155
+ ┌─────────────────────────▼───────────────────────────────┐
156
+ │ Services │
157
+ │ Business Logic • PlayerService • BankService │
158
+ └─────────────────────────┬───────────────────────────────┘
159
+
160
+ ┌─────────────────────────▼───────────────────────────────┐
161
+ │ Core Event Bus │
162
+ │ Internal Events • Cross-Service Communication │
163
+ └─────────────────────────────────────────────────────────┘
164
+ ```
165
+
166
+ ---
167
+
168
+ ## 🧪 Testing
169
+
170
+ OpenCore has a comprehensive testing suite using **Vitest**.
171
+
172
+ ### Test Categories
173
+
174
+ | Category | Description | Command |
175
+ | --------------- | --------------------------------------- | ----------------------- |
176
+ | **Unit** | Individual components and decorators | `pnpm test:unit` |
177
+ | **Integration** | Component interactions and bootstrap | `pnpm test:integration` |
178
+ | **Load** | Performance under simulated player load | `pnpm bench:load` |
179
+ | **All Tests** | Run everything | `pnpm test` |
180
+
181
+ ### Running Tests
182
+
183
+ ```bash
184
+ # Run all tests
185
+ pnpm test
186
+
187
+ # Run specific test suites
188
+ pnpm test:unit
189
+ pnpm test:integration
190
+
191
+ # Watch mode for development
192
+ pnpm test:watch
193
+
194
+ # Generate coverage report
195
+ pnpm test:coverage
196
+ ```
197
+
198
+ ### Test Structure
199
+
200
+ ```
201
+ tests/
202
+ ├── unit/ # Unit tests
203
+ │ ├── server/
204
+ │ │ └── decorators/
205
+ │ │ ├── command.test.ts
206
+ │ │ ├── guard.test.ts
207
+ │ │ ├── throttle.test.ts
208
+ │ │ └── ...
209
+ │ └── utils/
210
+ ├── integration/ # Integration tests
211
+ │ ├── client/
212
+ │ └── server/
213
+ ├── mocks/ # FiveM mocks
214
+ │ └── citizenfx.ts
215
+ └── helpers/ # Test utilities
216
+ ```
217
+
218
+ ### Coverage
219
+
220
+ All core decorators are **100% tested**:
221
+
222
+ - `@Command`, `@Guard`, `@Throttle`, `@OnNet`, `@OnTick`
223
+ - `@Controller`, `@Public`, `@Export`, `@CoreEvent`, `@Bind`
224
+
225
+ ---
226
+
227
+ ## ⚡ Performance & Benchmarks
228
+
229
+ OpenCore is built for performance. Our benchmark suite validates that the framework can handle production workloads with ease.
230
+
231
+ ### Run Benchmarks
232
+
233
+ ```bash
234
+ # Core component benchmarks (Tinybench)
235
+ pnpm bench:core
236
+
237
+ # Load benchmarks with player simulation (Vitest)
238
+ pnpm bench:load
239
+
240
+ # Full benchmark suite with reports
241
+ pnpm bench:all
242
+ ```
243
+
244
+ ### Latest Results (v0.6.0-beta.1)
245
+
246
+ #### Core Components
247
+
248
+ | Component | Operation | Throughput | Latency |
249
+ | ----------------- | ------------------ | ------------- | ------- |
250
+ | **DI Container** | Resolve service | 1.65M ops/sec | 0.61μs |
251
+ | **Zod** | Simple validation | 1.99M ops/sec | 0.50μs |
252
+ | **Zod** | Complex validation | 1.00M ops/sec | 1.00μs |
253
+ | **RateLimiter** | Key check | 2.56M ops/sec | 0.39μs |
254
+ | **AccessControl** | Permission check | 2.76M ops/sec | 0.36μs |
255
+ | **EventBus** | Emit event | 3.22M ops/sec | 0.31μs |
256
+ | **Decorators** | Define metadata | 5.48M ops/sec | 0.18μs |
257
+
258
+ #### Load Tests (500 Concurrent Players)
259
+
260
+ | Scenario | Throughput | p95 Latency | Error Rate |
261
+ | --------------------------- | --------------- | ----------- | ---------- |
262
+ | **Net Events (Simple)** | 92.59M ops/sec | 0.80μs | 0.00% |
263
+ | **Net Events (Validated)** | 11.47M ops/sec | 2.70μs | 0.00% |
264
+ | **Net Events (Concurrent)** | 1.61M ops/sec | 294.22μs | 0.00% |
265
+ | **Serialization (Large)** | 146.53K ops/sec | 951.11μs | 0.00% |
266
+
267
+ #### Key Performance Highlights
268
+
269
+ - ✅ **Zero error rate** across all load scenarios (10 → 500 players)
270
+ - ✅ **Sub-microsecond latency** for core operations
271
+ - ✅ **Excellent scalability** - handles 500+ concurrent players
272
+ - ✅ **Consistent p95/p99** - predictable latency behavior
273
+
274
+ > Full benchmark details available in [`benchmark/README.md`](./benchmark/README.md)
275
+
276
+ ---
277
+
278
+ ## 📁 Project Structure
279
+
280
+ ```
281
+ opencore/
282
+ ├── src/
283
+ │ ├── client/ # Client-side framework
284
+ │ │ ├── decorators/ # @OnNet, @Key, @Tick, @NUI, etc.
285
+ │ │ ├── services/ # Streaming, UI, World services
286
+ │ │ └── system/ # Processors and metadata
287
+ │ ├── server/ # Server-side framework
288
+ │ │ ├── decorators/ # @Command, @Guard, @Throttle, etc.
289
+ │ │ ├── services/ # Player, Command, RateLimiter, etc.
290
+ │ │ ├── entities/ # Player entity
291
+ │ │ └── bus/ # Core Event Bus
292
+ │ ├── shared/ # Shared utilities
293
+ │ │ └── logger/ # Logging system
294
+ │ └── system/ # Core system (MetadataScanner, DI)
295
+ ├── tests/ # Test suites
296
+ │ ├── unit/
297
+ │ ├── integration/
298
+ │ └── mocks/
299
+ ├── benchmark/ # Performance benchmarks
300
+ │ ├── core/ # Tinybench benchmarks
301
+ │ ├── load/ # Vitest load tests
302
+ │ └── reports/ # Generated reports
303
+ └── dist/ # Compiled output
304
+ ```
305
+
306
+ ---
307
+
308
+ ## 📜 Available Scripts
309
+
310
+ | Script | Description |
311
+ | ----------------------- | -------------------------------- |
312
+ | `pnpm build` | Compile TypeScript to JavaScript |
313
+ | `pnpm watch` | Watch mode for development |
314
+ | `pnpm lint` | Run ESLint |
315
+ | `pnpm lint:fix` | Fix ESLint issues |
316
+ | `pnpm format` | Format code with Prettier |
317
+ | `pnpm test` | Run all tests |
318
+ | `pnpm test:unit` | Run unit tests only |
319
+ | `pnpm test:integration` | Run integration tests only |
320
+ | `pnpm test:coverage` | Generate coverage report |
321
+ | `pnpm bench` | Show benchmark options |
322
+ | `pnpm bench:core` | Run core benchmarks |
323
+ | `pnpm bench:load` | Run load benchmarks |
324
+ | `pnpm bench:all` | Run all benchmarks with reports |
325
+
326
+ ---
327
+
328
+ ## 🤝 Contributing
329
+
330
+ Contributions are welcome! Please ensure:
331
+
332
+ 1. All tests pass (`pnpm test`)
333
+ 2. Code is formatted (`pnpm format`)
334
+ 3. No linting errors (`pnpm lint`)
335
+ 4. New features include tests
336
+
337
+ ---
338
+
339
+ ## 📄 License
340
+
341
+ OpenCore is licensed under the **MPL-2.0**.
342
+
343
+ See [LICENSE](./LICENSE) for details.
344
+
345
+ ---
346
+
347
+ <p align="center">
348
+ <strong>OpenCore Framework</strong><br>
349
+ <em>Stop scripting. Start engineering.</em>
350
+ </p>
@@ -0,0 +1 @@
1
+ export declare function initClientCore(): Promise<void>;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initClientCore = initClientCore;
4
+ const metadata_scanner_1 = require("../system/metadata.scanner");
5
+ const client_container_1 = require("./client-container");
6
+ const decorators_1 = require("./decorators");
7
+ const player_loader_1 = require("./player/player.loader");
8
+ const processors_register_1 = require("./system/processors.register");
9
+ const ui_bridge_1 = require("./ui-bridge");
10
+ // Services
11
+ const core_1 = require("./services/core");
12
+ const ui_1 = require("./services/ui");
13
+ const world_1 = require("./services/world");
14
+ const streaming_1 = require("./services/streaming");
15
+ const bootServices = [core_1.Spawner];
16
+ /**
17
+ * Basic setup for client, for configs, decorators, containers... etc
18
+ */
19
+ function setSingletons() {
20
+ // Core services
21
+ client_container_1.di.registerSingleton(core_1.Spawner, core_1.Spawner);
22
+ // NUI
23
+ client_container_1.di.registerSingleton(ui_bridge_1.NuiBridge, ui_bridge_1.NuiBridge);
24
+ // UI services
25
+ client_container_1.di.registerSingleton(ui_1.NotificationService, ui_1.NotificationService);
26
+ client_container_1.di.registerSingleton(ui_1.TextUIService, ui_1.TextUIService);
27
+ client_container_1.di.registerSingleton(ui_1.ProgressService, ui_1.ProgressService);
28
+ // World services
29
+ client_container_1.di.registerSingleton(world_1.MarkerService, world_1.MarkerService);
30
+ client_container_1.di.registerSingleton(world_1.BlipService, world_1.BlipService);
31
+ client_container_1.di.registerSingleton(world_1.VehicleService, world_1.VehicleService);
32
+ client_container_1.di.registerSingleton(world_1.PedService, world_1.PedService);
33
+ // Streaming services
34
+ client_container_1.di.registerSingleton(streaming_1.StreamingService, streaming_1.StreamingService);
35
+ }
36
+ async function bootstraper() {
37
+ for (const Service of bootServices) {
38
+ const instance = client_container_1.di.resolve(Service);
39
+ if (typeof instance.init === 'function') {
40
+ await instance.init();
41
+ }
42
+ }
43
+ }
44
+ async function initClientCore() {
45
+ setSingletons();
46
+ // Register system processors
47
+ (0, processors_register_1.registerSystemClient)();
48
+ await bootstraper();
49
+ // Loaders
50
+ (0, player_loader_1.playerClientLoader)();
51
+ const scanner = client_container_1.di.resolve(metadata_scanner_1.MetadataScanner);
52
+ scanner.scan(decorators_1.clientControllerRegistry);
53
+ }
@@ -0,0 +1,2 @@
1
+ import 'reflect-metadata';
2
+ export declare const di: import("tsyringe").DependencyContainer;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.di = void 0;
4
+ require("reflect-metadata");
5
+ const tsyringe_1 = require("tsyringe");
6
+ exports.di = tsyringe_1.container;
@@ -0,0 +1,18 @@
1
+ import { NuiBridge } from './ui-bridge';
2
+ import { Spawner } from './services/core';
3
+ import { NotificationService, TextUIService, ProgressService } from './services/ui';
4
+ import { MarkerService, BlipService, VehicleService, PedService } from './services/world';
5
+ import { StreamingService } from './services/streaming';
6
+ export declare function init(): Promise<void>;
7
+ export declare const services: {
8
+ readonly spawner: Spawner;
9
+ readonly nui: NuiBridge<Record<string, any>, Record<string, any>>;
10
+ readonly notifications: NotificationService;
11
+ readonly textUI: TextUIService;
12
+ readonly progress: ProgressService;
13
+ readonly markers: MarkerService;
14
+ readonly blips: BlipService;
15
+ readonly vehicles: VehicleService;
16
+ readonly peds: PedService;
17
+ readonly streaming: StreamingService;
18
+ };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.services = void 0;
4
+ exports.init = init;
5
+ const client_bootstrap_1 = require("./client-bootstrap");
6
+ const client_container_1 = require("./client-container");
7
+ const ui_bridge_1 = require("./ui-bridge");
8
+ // Services
9
+ const core_1 = require("./services/core");
10
+ const ui_1 = require("./services/ui");
11
+ const world_1 = require("./services/world");
12
+ const streaming_1 = require("./services/streaming");
13
+ async function init() {
14
+ await (0, client_bootstrap_1.initClientCore)();
15
+ }
16
+ exports.services = {
17
+ // Core
18
+ get spawner() {
19
+ return client_container_1.di.resolve(core_1.Spawner);
20
+ },
21
+ // NUI
22
+ get nui() {
23
+ return client_container_1.di.resolve(ui_bridge_1.NuiBridge);
24
+ },
25
+ // UI
26
+ get notifications() {
27
+ return client_container_1.di.resolve(ui_1.NotificationService);
28
+ },
29
+ get textUI() {
30
+ return client_container_1.di.resolve(ui_1.TextUIService);
31
+ },
32
+ get progress() {
33
+ return client_container_1.di.resolve(ui_1.ProgressService);
34
+ },
35
+ // World
36
+ get markers() {
37
+ return client_container_1.di.resolve(world_1.MarkerService);
38
+ },
39
+ get blips() {
40
+ return client_container_1.di.resolve(world_1.BlipService);
41
+ },
42
+ get vehicles() {
43
+ return client_container_1.di.resolve(world_1.VehicleService);
44
+ },
45
+ get peds() {
46
+ return client_container_1.di.resolve(world_1.PedService);
47
+ },
48
+ // Streaming
49
+ get streaming() {
50
+ return client_container_1.di.resolve(streaming_1.StreamingService);
51
+ },
52
+ };
@@ -0,0 +1,3 @@
1
+ import type { ClassConstructor } from '../../system/class-constructor';
2
+ export declare const clientControllerRegistry: ClassConstructor[];
3
+ export declare function Controller(): (target: ClassConstructor) => void;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientControllerRegistry = void 0;
4
+ exports.Controller = Controller;
5
+ const tsyringe_1 = require("tsyringe");
6
+ const metadata_client_keys_1 = require("../system/metadata-client.keys");
7
+ exports.clientControllerRegistry = [];
8
+ function Controller() {
9
+ return function (target) {
10
+ (0, tsyringe_1.injectable)()(target);
11
+ Reflect.defineMetadata(metadata_client_keys_1.METADATA_KEYS.CONTROLLER, { type: 'client' }, target);
12
+ exports.clientControllerRegistry.push(target);
13
+ };
14
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Decorator to expose a method as a client export.
3
+ * Other resources can call this via exports['resourceName']['exportName']()
4
+ *
5
+ * @param name - Optional custom export name. Defaults to method name.
6
+ */
7
+ export declare function Export(name?: string): (target: any, propertyKey: string) => void;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Export = Export;
4
+ const metadata_client_keys_1 = require("../system/metadata-client.keys");
5
+ /**
6
+ * Decorator to expose a method as a client export.
7
+ * Other resources can call this via exports['resourceName']['exportName']()
8
+ *
9
+ * @param name - Optional custom export name. Defaults to method name.
10
+ */
11
+ function Export(name) {
12
+ return (target, propertyKey) => {
13
+ Reflect.defineMetadata(metadata_client_keys_1.METADATA_KEYS.EXPORT, { exportName: name || propertyKey }, target, propertyKey);
14
+ };
15
+ }
@@ -0,0 +1,47 @@
1
+ import type { GameEventName, GameEventMap } from '../types/game-events';
2
+ /**
3
+ * Decorator for handling native game events from the RAGE engine.
4
+ *
5
+ * These are low-level events triggered internally by GTA V.
6
+ * FiveM captures them via the 'gameEventTriggered' event.
7
+ *
8
+ * **Documentation:** https://docs.fivem.net/docs/game-references/game-events/
9
+ *
10
+ * ## Common Events:
11
+ *
12
+ * | Event | Description |
13
+ * |-------|-------------|
14
+ * | `CEventNetworkEntityDamage` | Entity receives damage |
15
+ * | `CEventNetworkPlayerEnteredVehicle` | Player enters vehicle |
16
+ * | `CEventNetworkPlayerLeftVehicle` | Player exits vehicle |
17
+ * | `CEventNetworkVehicleUndrivable` | Vehicle destroyed |
18
+ * | `CEventShockingSeenPedKilled` | Ped witnesses death |
19
+ * | `CEventGunShot` | Weapon fired |
20
+ *
21
+ * ## Usage:
22
+ *
23
+ * ```typescript
24
+ * @Controller()
25
+ * class CombatController {
26
+ * // Raw args (array)
27
+ * @OnGameEvent('CEventNetworkEntityDamage')
28
+ * onDamage(args: number[]) {
29
+ * const [victim, attacker] = args
30
+ * }
31
+ *
32
+ * // Or with auto-parsing (set autoParse: true)
33
+ * @OnGameEvent('CEventNetworkEntityDamage', { autoParse: true })
34
+ * onDamageParsed(data: EntityDamageEvent) {
35
+ * console.log(data.victim, data.attacker, data.victimDied)
36
+ * }
37
+ * }
38
+ * ```
39
+ *
40
+ * @param eventName - The native game event name (CEvent*)
41
+ * @param options - Optional configuration
42
+ */
43
+ export declare function OnGameEvent<K extends GameEventName>(eventName: K, options?: {
44
+ autoParse?: boolean;
45
+ }): (target: any, propertyKey: string) => void;
46
+ export type { GameEventName, GameEventMap };
47
+ export type { EntityDamageEvent, PlayerEnteredVehicleEvent, PlayerLeftVehicleEvent, SeenPedKilledEvent, VehicleUndrivableEvent, GunShotEvent, } from '../types/game-events';
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OnGameEvent = OnGameEvent;
4
+ const metadata_client_keys_1 = require("../system/metadata-client.keys");
5
+ /**
6
+ * Decorator for handling native game events from the RAGE engine.
7
+ *
8
+ * These are low-level events triggered internally by GTA V.
9
+ * FiveM captures them via the 'gameEventTriggered' event.
10
+ *
11
+ * **Documentation:** https://docs.fivem.net/docs/game-references/game-events/
12
+ *
13
+ * ## Common Events:
14
+ *
15
+ * | Event | Description |
16
+ * |-------|-------------|
17
+ * | `CEventNetworkEntityDamage` | Entity receives damage |
18
+ * | `CEventNetworkPlayerEnteredVehicle` | Player enters vehicle |
19
+ * | `CEventNetworkPlayerLeftVehicle` | Player exits vehicle |
20
+ * | `CEventNetworkVehicleUndrivable` | Vehicle destroyed |
21
+ * | `CEventShockingSeenPedKilled` | Ped witnesses death |
22
+ * | `CEventGunShot` | Weapon fired |
23
+ *
24
+ * ## Usage:
25
+ *
26
+ * ```typescript
27
+ * @Controller()
28
+ * class CombatController {
29
+ * // Raw args (array)
30
+ * @OnGameEvent('CEventNetworkEntityDamage')
31
+ * onDamage(args: number[]) {
32
+ * const [victim, attacker] = args
33
+ * }
34
+ *
35
+ * // Or with auto-parsing (set autoParse: true)
36
+ * @OnGameEvent('CEventNetworkEntityDamage', { autoParse: true })
37
+ * onDamageParsed(data: EntityDamageEvent) {
38
+ * console.log(data.victim, data.attacker, data.victimDied)
39
+ * }
40
+ * }
41
+ * ```
42
+ *
43
+ * @param eventName - The native game event name (CEvent*)
44
+ * @param options - Optional configuration
45
+ */
46
+ function OnGameEvent(eventName, options) {
47
+ return (target, propertyKey) => {
48
+ var _a;
49
+ Reflect.defineMetadata(metadata_client_keys_1.METADATA_KEYS.GAME_EVENT, {
50
+ eventName,
51
+ autoParse: (_a = options === null || options === void 0 ? void 0 : options.autoParse) !== null && _a !== void 0 ? _a : false,
52
+ }, target, propertyKey);
53
+ };
54
+ }
@@ -0,0 +1,10 @@
1
+ export * from './controller';
2
+ export * from './key';
3
+ export * from './nui';
4
+ export * from './onNet';
5
+ export * from './tick';
6
+ export * from './localEvent';
7
+ export * from './interval';
8
+ export * from './export';
9
+ export * from './resourceLifecycle';
10
+ export * from './gameEvent';
@@ -0,0 +1,26 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./controller"), exports);
18
+ __exportStar(require("./key"), exports);
19
+ __exportStar(require("./nui"), exports);
20
+ __exportStar(require("./onNet"), exports);
21
+ __exportStar(require("./tick"), exports);
22
+ __exportStar(require("./localEvent"), exports);
23
+ __exportStar(require("./interval"), exports);
24
+ __exportStar(require("./export"), exports);
25
+ __exportStar(require("./resourceLifecycle"), exports);
26
+ __exportStar(require("./gameEvent"), exports);