
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@open-core/framework
Advanced tools
Secure, event-driven TypeScript Framework & Runtime engine for CitizenFX (Cfx).
OpenCore is a TypeScript multiplayer runtime framework targeting CitizenFX runtimes (Cfx/RageMP) via adapters.
It is not a gamemode or RP framework. It provides:
License: MPL-2.0
Discord Community | Docs | OpenCore CLI
pnpm add @open-core/framework reflect-metadata tsyringe zod uuid
This framework uses TypeScript decorators. Ensure your project has decorators enabled.
The package exposes subpath entry points:
@open-core/framework (root)@open-core/framework/server@open-core/framework/clientOpenCore follows a Ports & Adapters (Hexagonal) architecture.
src/kernel): engine-agnostic infrastructure (DI, logger, metadata scanning)src/runtime): multiplayer execution model (controllers, processors, security, lifecycle)src/adapters): platform integration (Cfx, Node testing)The runtime never auto-detects the platform. Adapters are selected explicitly at bootstrap time.
OpenCore treats CitizenFX (cfx) as the platform and supports game profiles (gta5 and rdr3).
gameProfile, defaultSpawnModel, etc.).Each instance runs in exactly one mode configured via Server.init():
CORE: authoritative runtime. Typically provides identity/auth/players via exports.RESOURCE: a normal Cfx resource using CORE as provider for some features.STANDALONE: a self-contained runtime (useful for tooling, simulations, or small servers).Initialize the server runtime:
import { Server } from '@open-core/framework/server'
await Server.init({
mode: 'CORE'
})
Some features require providers (depending on your mode and configuration). Configure them before calling init():
import { Server } from '@open-core/framework/server'
Server.setPrincipalProvider(MyPrincipalProvider)
Server.setSecurityHandler(MySecurityHandler)
Server.setPersistenceProvider(MyPlayerPersistence)
Server.setNetEventSecurityObserver(MyNetEventSecurityObserver)
OpenCore uses a decorator + processor pattern.
Decorators store metadata with Reflect.defineMetadata(). During bootstrap, the MetadataScanner reads metadata and processors register handlers.
import { Controller, Command, Guard, Throttle, Player } from '@open-core/framework/server'
import { z } from 'zod'
const TransferSchema = z.tuple([z.coerce.number().int().positive(), z.coerce.number().min(1)])
@Controller()
export class BankController {
@Command({
command: 'transfer',
usage: '/transfer <id> <amount>',
schema: TransferSchema,
})
@Guard({ rank: 1 })
@Throttle(1, 2000)
async transfer(player: Player, args: z.infer<typeof TransferSchema>) {
const [targetId, amount] = args
player.emit('chat:message', `transfer -> ${targetId} (${amount})`)
}
}
@OnNet() handlers always receive Player as the first parameter.
import { Controller, OnNet, Player } from '@open-core/framework/server'
import { z } from 'zod'
const PayloadSchema = z.object({ action: z.string(), amount: z.number().int().positive() })
@Controller()
export class ExampleNetController {
@OnNet('bank:action', { schema: PayloadSchema })
async onBankAction(player: Player, payload: z.infer<typeof PayloadSchema>) {
player.emit('chat:message', `action=${payload.action} amount=${payload.amount}`)
}
}
@Guard({ rank }) or @Guard({ permission })@Throttle(limit, windowMs)@RequiresState({ missing: [...] })Use library wrappers to emit domain events and @OnLibraryEvent() to observe them.
@OnLibraryEvent() listens to events emitted through library.emit(...) only.
It does not listen to emitExternal, emitNetExternal, or emitServer.
import { Server } from '@open-core/framework/server'
const characters = Server.createServerLibrary('characters')
@Controller()
export class CharacterListeners {
@OnLibraryEvent('characters', 'session:created')
onSessionCreated(payload: { sessionId: string; playerId: number }) {
// optional listener for library domain events
}
}
characters.emit('session:created', { sessionId: 's-1', playerId: 10 })
Client usage follows the same pattern with Client.createClientLibrary(...) and
@Client.OnLibraryEvent(...).
Plugin contracts are exposed by runtime entrypoint, not by root:
@open-core/framework/server@open-core/framework/clientimport { Server, type OpenCorePlugin } from '@open-core/framework/server'
import { Client, type OpenCoreClientPlugin } from '@open-core/framework/client'
const serverPlugin: OpenCorePlugin = {
name: 'server-example',
install(ctx) {
ctx.server.registerApiExtension('ExampleServerDecorator', () => {})
},
}
const clientPlugin: OpenCoreClientPlugin = {
name: 'client-example',
install(ctx) {
ctx.client.registerApiExtension('ExampleClientDecorator', () => {})
},
}
await Server.init({ mode: 'CORE', plugins: [serverPlugin] })
await Client.init({ mode: 'CORE', plugins: [clientPlugin] })
Module augmentation for plugin APIs:
declare module '@open-core/framework/server' {
interface ServerPluginApi {
ExampleServerDecorator: () => void
}
}
declare module '@open-core/framework/client' {
interface ClientPluginApi {
ExampleClientDecorator: () => void
}
}
Tests run with Vitest.
pnpm test
pnpm test:unit
pnpm test:integration
pnpm test:coverage
Note: pnpm test does not run benchmarks.
Benchmarks are split by value, so the default run focuses on framework features that matter for real servers.
pnpm bench
pnpm bench:value
pnpm bench:gold
pnpm bench:startup
pnpm bench:diagnostic
pnpm bench:soak
pnpm bench:load
pnpm bench:all
bench / bench:value: value-focused suite. Commands, net events, RPC, lifecycle, ticks, binary path, bootstrap.bench:gold: hot-path load scenarios only.bench:startup: startup and registration cost.bench:diagnostic: internal and low-level synthetic benchmarks.bench:soak: long-running stress scenario.Use benchmark/reports/ as the source of truth. Results vary by machine and should be compared relatively, not treated as product guarantees.
Full reports and methodology are available in benchmark/README.md.
Benchmark reports are generated under benchmark/reports/.
pnpm bench:all generates aggregated reports (text/json/html)benchmark/reports/.load-metrics.jsonFor details about the benchmark system, see benchmark/README.md.
pnpm build
pnpm watch
pnpm lint
pnpm lint:fix
pnpm format
MPL-2.0. See LICENSE.
FAQs
Secure, event-driven TypeScript Framework & Runtime engine for CitizenFX (Cfx).
We found that @open-core/framework demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.