Skip to main content

Introduction to Contracts

What is a Contract?​

In OpenCore, a Contract is an abstract definition that specifies a stable set of methods the framework can rely on.
Think of contracts as formal boundaries between the framework and your application logic.

Contracts allow OpenCore to remain decoupled from:

  • Databases
  • Authentication systems
  • Permission models
  • Persistence layers
  • Security policies

While still enabling powerful extensibility.

The framework uses contracts to:

  1. Define boundaries – Different subsystems communicate through stable, predictable APIs.
  2. Ensure reliability – Required lifecycle methods (such as onSessionSave) are always present.
  3. Enable flexibility – Implementations can be swapped without modifying the framework itself.

1. How Contracts Work​

Contracts are defined as abstract class definitions.

To customize framework behavior, you:

  1. Extend a contract
  2. Register the implementation before the framework boots

From v0.3.x onward, contracts are not registered implicitly.
Registration happens through the Setup API, not decorators.


Registration model (v0.3+)​

The framework requests a contract.
You provide an implementation explicitly.


setPersistenceProvider(MySqlPersistence)

This registration must happen before calling init().


About @Bind​

The @Bind() decorator does not configure contracts.

Its purpose is:

  • Marking a class as injectable
  • Enabling constructor-based dependency injection
  • Ensuring proper resolution inside controllers and services

Example:

@Bind()
export class MySqlPersistence extends PlayerPersistenceContract {
// injectable class
}

Use @Bind for dependency injection, use setX(...) for framework configuration.


2. Required vs Optional Contracts​

Not all contracts must be implemented. OpenCore provides safe defaults for most of them.

ContractRequiredDefault behavior if not provided
PrincipalProviderContract⚠️ Required in CORE / STANDALONEDefault provider (deny-by-default)
PlayerPersistenceContractOptionalIn-memory persistence (no data survives restart)
SecurityHandlerContractOptionalInternal handler (block + log)
NetEventSecurityObserverContractOptionalInternal observer
RepositoryOptionalNot used unless extended

Notes:

  • RESOURCE mode delegates required contracts to CORE.
  • Missing required contracts cause a fail-fast bootstrap error.
  • Optional contracts always have internal defaults.

3. Why use Contracts?​

  • Zero coupling – The framework never depends on concrete implementations.
  • Predictable execution – The framework controls when and how your logic runs.
  • Inversion of control – You provide behavior; the framework orchestrates it.
  • Security by default – Missing implementations never result in permissive behavior.

Contracts ensure OpenCore remains:

  • Modular
  • Testable
  • Safe by default
  • Extensible without hacks

Requirement rules​

  • Some contracts are required depending on runtime mode.

  • Required contracts must be registered before init().

  • If a required contract is missing, the framework will:

    • Log a fatal error
    • Abort initialization
  • Defaults are applied only when explicitly allowed.

This design prevents silent misconfiguration in production environments.