Skip to content

Releases

v1.7.0

Choose a tag to compare

@github-actions github-actions released this 23 Oct 14:59
3e30b85

OpenCore CLI v1.7.0

Typed library events

Typegen now types the events of OpenCore libraries, in the new serverLibraryEvents and
clientLibraryEvents maps of each resource's .opencore/opencore.gen.ts, keyed by library name:

  • @Server.OnLibraryEvent(library, event) / @Client.OnLibraryEvent(library, event) listeners type
    an event by their first parameter. An optional (payload?: T), defaulted or rest parameter keeps
    its declared type.
  • When several listeners take a payload, the event is typed by the intersection of their
    parameters, since the payload reaches each of them. Listeners that disagree make emit() fail to
    compile instead of one of them being dropped silently.
  • A listener that ignores the payload says nothing about it: the event is typed by its emit()
    calls, or as unknown when there are none.
  • library.emit(event, payload) calls on a library created from a literal name type the events no
    listener types, with the union of the payloads they pass. A payload forwarded from a method
    parameter is typed through that parameter when the class is exported, and from the argument
    otherwise.

Library and event names must resolve to string literals; a plain string is skipped with a
warning. Typed library events require @open-core/framework with library event support in its
Register.

Library name collisions

The framework merges the events of every library sharing a name across the project, although each
resource has its own library bus at runtime. Typegen now warns, at the createServerLibrary /
createClientLibrary call, when another resource creates a library of the same side and name:

server library "core" is also created by resource:resources/characters; typegen merges the events
of libraries sharing a name, so give one of them a different name

The factory is found through its symbol, so aliased imports, re-exports and
Server.createServerLibrary count. Listening to or emitting on a library does not, and libraries
created from a non-literal name are not checked.

opencore build now generates the types of every resource before bundling, with or without
build.typecheck, so both resources of a collision report it on the first build. In opencore dev
a resource reports its warnings once per session.

Typegen fixes

  • @Client.OnView handlers with an optional, defaulted or rest first parameter no longer type their
    WebView message as undefined.
  • A WebView.send() that forwards a method parameter of a class that is not exported is typed from
    its argument, instead of importing the class and breaking the generated file.
  • The __Payload helper is only declared when a map uses it, so projects compiled with
    noUnusedLocals no longer fail on it.
  • The typegen summary reads typegen: N warning(s) in <resource>: it also counts send() and
    emit() calls, which are not handlers.

v1.6.2

Choose a tag to compare

@github-actions github-actions released this 27 Sep 22:25
f529584

OpenCore CLI v1.6.2

Typegen on large resources

Resources whose analysis is larger than 64 KB (a few hundred source files) no longer skip type
generation with typegen analyzer returned invalid JSON: unexpected end of JSON input. The analyzer
exited before Node had flushed its output to the CLI, so only the first 64 KB arrived and that
resource's .opencore/opencore.gen.ts got no events, RPCs or commands.

v1.6.1

Choose a tag to compare

@github-actions github-actions released this 27 Sep 21:23
292b5ee

OpenCore CLI v1.6.1

Typegen reads the TypeScript AST

Typegen now walks each resource with the project's own TypeScript (5.x or 7.x) instead of matching
source text, so every listener the runtime registers is typed:

  • Decorators are matched by the symbol they resolve to: named (import { OnRPC }), aliased
    (import { OnRPC as Rpc }), namespace and barrel re-exports of @open-core/framework/server and
    /client all count, not only @Server.* / @Client.*. A local decorator that happens to be
    called OnNet does not.
  • Names come from the argument's literal type: BankEvents.deposit (as const), a local constant or a
    framework constant such as SYSTEM_EVENTS.chat.message (requires @open-core/framework with literal
    SYSTEM_EVENTS types). A warning is reported only when the name's type is plain string.
  • The decorated method is taken from the AST: multi-line decorator arguments, stacked decorators and
    method names such as do, delete or new no longer skip a handler.
  • WebView.send() payloads are typed from the checker whatever the expression (object literals,
    locals, class fields). Exported types are imported, others are expanded. A typed forwarder,
    send<K extends keyof M>(name: K, data: M[K]), registers one message per key of M, and its call
    sites are no longer read as sends of their own.
  • Generated maps key constants by their value ('bank:withdraw') instead of an __Entry<typeof import(…)>
    reference. Literal names produce the same output as before.

Typegen requires typescript in the project, like build.typecheck.

Source validation

The mixed-decorator check only counts real decorators: a file whose comments, strings or type-only
imports mention @Client.* and @Server.* no longer cancels the build.

v1.6.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 16:04
6749647

OpenCore CLI v1.6.0

Requires @open-core/framework v1.2.0 or later for the generated types to take effect.

Type generation for net events, RPCs, commands and WebView messages

opencore build and opencore dev now scan every resource and emit a .opencore/opencore.gen.ts that
registers its handlers with the framework's type registry. Emitting sites then autocomplete to the
declared names and check their payloads against the handler signatures:

Source Types
@Server.OnNet events.emit() on the client (the Player parameter is dropped)
@Client.OnNet player.emit() and events.emit() on the server
@Server.OnRPC / @Client.OnRPC rpc.call() and rpc.notify() arguments, and the call() result
@Server.Command the command map, with description and usage
@Client.OnView / WebView.send() messages in both directions between the client and its WebViews

Names can be string literals, file-local constants or imported constants such as BankEvents.WITHDRAW.
Every resource registers under its own key and the framework merges them, so a name declared in one
resource is known to all of them.

A resource with a WebView directory (ui/, nui/ or the configured one) also gets a
<view>/.opencore/opencore.gen.ts exporting UiCanSend and UiReceives for the UI code. A send()
payload is typed when it forwards a parameter of the enclosing method; any other expression is typed
unknown and reported as a warning.

Generated files are rewritten only when their content changes, and opencore dev regenerates them on
every rebuild.

Strict mode on by default

With build.typegen.strict (default true), an event, RPC or WebView message name that no handler
declares is a compile error. The framework's own opencore:* events are always accepted. Set
strict: false when a project emits names handled outside OpenCore, such as events of a Lua resource:
unknown names are then accepted while known ones keep their autocomplete and payload checks.

Existing projects get these errors in the editor and in tsc after upgrading. They only fail the
build when build.typecheck is enabled.

build.typecheck

Bundling only strips types, so until now no type error could fail a build. With build.typecheck: true,
opencore build regenerates the types and runs the project's own tsc --noEmit before bundling, and
fails without writing any output. opencore dev reports the errors as warnings and keeps watching.

It is off by default so upgrading never breaks an existing build, and requires typescript installed
in the project.

Configuration

build: {
  typecheck: true,
  typegen: {
    enabled: true, // default: true. When false, generated files are deleted and every signature is loose again
    strict: true, // default: true
  },
}

Templates and tooling

  • New projects enable typecheck and typegen in opencore.config.ts.
  • The starter tsconfig.json includes the .opencore directories so the generated types are part of the program.
  • opencore create resource --with-nui adds a ui/tsconfig.json that includes the view's generated types.
  • opencore doctor reports the type generation mode, and warns when strict mode is on without build.typecheck.

v2.0.0-beta.1

v2.0.0-beta.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 31 Jul 16:20
03e1e96

OpenCore CLI v1.5.1

Fix for FiveM Enhanced msgpack codec

Fixed server resources failing on every event and cross-resource export under FiveM Enhanced (Node 26) with:

this.codec.encode is not a function
this.codec.decode is not a function

Large CJS server bundles declare their modules at the script top level, which corrupts the runtime's global msgpack codec and breaks command registration and net events.

The server bundle is now wrapped in an IIFE so those declarations live in a function scope instead of the top level. This applies only to server builds using the default cjs format, client builds already use iife and are unaffected.

v1.5.1

Choose a tag to compare

@github-actions github-actions released this 25 Jul 15:42
a706869

OpenCore CLI v1.5.1

Fix for FiveM Enhanced msgpack codec

Fixed server resources failing on every event and cross-resource export under FiveM Enhanced (Node 26) with:

this.codec.encode is not a function
this.codec.decode is not a function

Large CJS server bundles declare their modules at the script top level, which corrupts the runtime's global msgpack codec and breaks command registration and net events.

The server bundle is now wrapped in an IIFE so those declarations live in a function scope instead of the top level. This applies only to server builds using the default cjs format, client builds already use iife and are unaffected.

v1.5.0

Choose a tag to compare

@github-actions github-actions released this 17 Jun 18:39
1ad3930

OpenCore CLI v1.5.0

Dependency Resolver

Added build.dependencyResolution for server resources that use build.server.external.

This is mainly for FiveM/RedM resources that need runtime npm packages such as pg, typeorm, database clients, or Prisma adapters while staying inside the FXServer Node.js 22 filesystem sandbox.

Modes

  • auto: uses OpenCore's runtime default. For FiveM/RedM this currently resolves to isolated.
  • isolated: installs physical resource-local dependencies. This is the recommended production mode.
  • symlink: legacy opt-in mode for linking node_modules; not recommended for FXServer sandboxed runtimes.
  • shared-resource: experimental shared dependency resource.
  • bundle: experimental bundling mode for pure JavaScript packages.

Isolated Installs

isolated mode now writes a minimal package.json into each built resource and installs only the external packages that resource actually uses.

The resolver refuses unsafe deploy specs such as latest, *, workspace:, file:, link:, portal:, and local paths.

Sandbox validation is enabled by default and rejects symlinks that resolve outside the generated resource.

pnpm Runtime Layout Fix

pnpm installs now use a hoisted physical layout for generated dependency installs:

pnpm install --prod --ignore-workspace --no-lockfile --reporter=append-only --config.node-linker=hoisted --package-import-method=copy

This fixes transitive runtime imports under FXServer, for example typeorm resolving tslib from the built resource instead of climbing to the workspace root and failing the sandbox check.

Dependency Cache

Generated dependency trees are cached under:

node_modules/.cache/opencore/dependencies/<hash>

Matching resources reuse the cached physical dependency tree when .opencore-deps.json matches the dependency set, package manager, install-script setting, pnpm linker mode, platform, architecture, and Node major version.

Native Package Checks

The resolver detects known native packages and native package indicators such as binding.gyp, prebuilds, .node files, and native package metadata.

Native packages are rejected in bundle mode and reported clearly for dependency-resolution flows.

Bug Fixes

Dev Mode UI Hot-Reload (#16): Fixed an issue where server.js and client.js would disappear from the resource output directory when editing UI files (.tsx, .jsx) in dev mode. The incremental build now preserves sibling artifacts when rebuilding only views, instead of wiping the entire resource directory before the partial rebuild.

Docs

Added dependency resolver documentation and FiveM sandbox guidance:

  • docs/cli/dependency-resolution.md
  • docs/adapters/fivem.md

Use isolated for production FiveM/RedM server resources that require runtime npm dependencies.

v1.4.1

Choose a tag to compare

@github-actions github-actions released this 28 May 15:43

OpenCore CLI v1.4.1

Fix — Dev mode build loop

Fixed an infinite rebuild loop that could happen when running:

  • opencore build
  • opencore dev

The watcher now ignores build-generated artifacts (including .opencore/autoload.*.controllers.ts) and output/deploy directories, preventing recursive self-triggered rebuilds.
Result: dev mode stabilizes after the initial build and only rebuilds on real source changes.

v1.4.0

Choose a tag to compare

@github-actions github-actions released this 21 Apr 19:32
63bd2ae

OpenCore CLI v1.4.0

Feature — Environment System

Angular-style environment support without touching files on disk. esbuild resolves the correct file at build time via aliases.

CLI flags

  • opencore build --environment production (shorthand -e)
  • opencore dev --environment development
  • Priority: flag > OPENCORE_ENVIRONMENT env var > build.environment in config > development

Per-environment build overrides

build: {
  environments: {
    production: {
      minify: true,
      sourceMaps: false,
      logLevel: 'ERROR',
      fileReplacements: [
        { replace: './src/config/api.ts', with: './src/config/api.prod.ts' },
      ],
    },
  },
}

Usage in resources

import { environment } from '@opencore/environment'

if (!environment.production) {
  logger.debug('...')
}

Project structure (generated by opencore init)

environments/
├── environment.model.ts        # Define your AppEnvironment interface here
├── environment.development.ts
└── environment.production.ts

Validation — if environments/ exists but the requested environment file is missing, the build fails with the list of available environments.

v1.3.1

Choose a tag to compare

@github-actions github-actions released this 07 Apr 14:46
4976652

OpenCore CLI v1.3.1

Fix

  • Fixed explicit resources build config issue

Improve

  • Improved entrypoint init templates, reduced and more elegant using loggers const