-
Notifications
You must be signed in to change notification settings - Fork 0
API Types
Types.luau exports the framework's strict-mode annotation surface: entity types, FSM types, scheduler types, persistence types, logger types, and the structural Orchestrator interface.
Important
Docs audit note (2026-05): This page was re-audited against FSM/Orchestrator/Core/Types.luau. When this page and runtime behavior differ, trust Types.luau for type annotations and the runtime module docs for behavior.
--!strict
local Types = require(game:GetService("ReplicatedStorage").RBXStateMachine.Types)
local function attach(entity: Types.BaseEntity, fsm: Types.BaseStateMachine)
entity:Log({ Level = "INFO", Message = "attached" })
fsm:Start({ State = "Idle" })
endTypes.luau is about annotation, not runtime construction. Many return values are still any? at runtime and require casts after guards.
A few exported types intentionally or accidentally lag the runtime surface:
-
Types.Orchestratorstill includes legacyStartServiceManagerAPIand omits newer runtime helpers likeStartServiceManager(),GetServiceManager(), andUnregisterEventBus(). -
Types.LoggerInstanceincludesEnabled: boolean, but the currentLogger.new()implementation only populatesSourceandHistory. -
Signalmethods return an internalConnectionshape, but thatConnectiontype is local-only and not exported by name.
Keep those differences in mind when using Types with --!strict.
export type LogLevel = "INFO" | "WARN" | "ERROR" | "DEBUG"export type BehaviorTreeStatus = "Success" | "Failure" | "Running"export type Signal = {
Connect: (self: any, handler: (...any) -> ()) -> any,
Once: (self: any, handler: (...any) -> ()) -> any,
Fire: (self: any, ...any) -> (),
Wait: (self: any) -> ...any,
Destroy: (self: any) -> (),
}export type Disposable = Instance | RBXScriptConnection | { Destroy: (any) -> () } | () -> ()Used by entity:Manage(...) and fsm:Manage(...).
export type PropertyDef = {
Type: string,
Description: string?,
Replicate: boolean?,
Persist: boolean?,
}export type BaseEntity = {
Name: string,
Instance: Instance,
IsValid: boolean,
OwnerId: string?,
StateUpdated: RBXScriptSignal,
Destroyed: RBXScriptSignal,
Log: (self: BaseEntity, params: { Level: LogLevel, Message: string }) -> (),
DefineSchema: (self: BaseEntity, schema: { [string]: PropertyDef }) -> (),
SetContext: (self: BaseEntity, key: any, value: any) -> (),
Manage: (self: BaseEntity, object: any) -> any,
UpdateEntity: (self: BaseEntity, lockingCallerId: string?) -> boolean,
ApplyChanges: (self: BaseEntity, changes: { [string]: any }) -> (),
GetValidProperties: (self: BaseEntity) -> { [string]: PropertyDef },
Serialize: (self: BaseEntity) -> { [string]: any },
Deserialize: (self: BaseEntity, data: { [string]: any }) -> (),
AcquireLock: (self: BaseEntity, callerId: string) -> boolean,
ReleaseLock: (self: BaseEntity, callerId: string) -> boolean,
Destroy: (self: BaseEntity) -> (),
}Annotation example
local function touchEntity(entity: Types.BaseEntity)
if entity.IsValid then
entity:UpdateEntity()
end
endexport type Transition = {
TargetState: string,
Condition: (fsm: any, dt: number) -> boolean,
}export type StateObject = {
Machine: BaseStateMachine?,
OnEnter: (any, ...any) -> (),
OnHeartbeat: ((any, number) -> ())?,
OnLeave: ((any) -> ())?,
Transitions: { Transition }?,
}export type SubStateConfig = {
InitialState: string,
Transitions: {
OnCompleted: string,
OnFailed: string,
OnCancelled: string?,
},
StoreReference: string?,
}export type State = ((any, ...any) -> (() -> ())?) | StateObjectexport type BaseStateMachine = {
Id: string,
Name: string,
Context: { [any]: any },
IsActive: boolean,
State: string?,
StateDuration: number,
TotalDuration: number,
WaitSpan: number,
TransitionCount: number,
Priority: number,
Completed: RBXScriptSignal,
Failed: RBXScriptSignal,
Cancelled: RBXScriptSignal,
StateChanged: RBXScriptSignal,
Start: (self: BaseStateMachine, params: { State: string, Args: {any}? }) -> (),
ChangeState: (self: BaseStateMachine, params: { Name: string, Args: {any}? }) -> (),
Finish: (self: BaseStateMachine) -> (),
Fail: (self: BaseStateMachine, reason: string) -> (),
Cancel: (self: BaseStateMachine) -> (),
Destroy: (self: BaseStateMachine) -> (),
Manage: (self: BaseStateMachine, object: Disposable) -> Disposable,
AddSubMachine: (self: BaseStateMachine, name: string, subMachineClass: any, config: SubStateConfig) -> (),
AddState: (self: BaseStateMachine, name: string, state: State, validOutcomes: {string}?) -> (),
Log: (self: BaseStateMachine, params: { Level: LogLevel, Message: string, Data: any? }) -> (),
OnCleanup: (self: BaseStateMachine) -> (),
RegisterStates: (self: BaseStateMachine) -> (),
}Annotation example
local function cancelIfRunning(fsm: Types.BaseStateMachine)
if fsm.IsActive then
fsm:Cancel()
end
endexport type Task = {
Name: string,
Action: () -> (),
NextRun: number,
Delay: number,
IsRecurringTask: boolean,
Priority: number,
Event: string,
RunCount: number,
TotalRunTime: number,
MaxRunTime: number,
CreationTime: number,
Reset: () -> (),
}export type ScheduleTaskParams = {
TaskName: string,
TaskAction: () -> (),
TaskExecutionDelay: number?,
IsRecurringTask: boolean?,
Priority: number?,
Event: string?,
}export type Scheduler = {
Settings: any,
History: {any},
LastFrameStats: { FrameTime: number, TaskCount: number, Budget: number },
Initialize: (self: Scheduler, settings: any?) -> Scheduler,
Clear: (self: Scheduler) -> (),
Schedule: (self: Scheduler, params: ScheduleTaskParams) -> Task?,
Deschedule: (self: Scheduler, name: string) -> (),
GetTask: (self: Scheduler, name: string) -> Task?,
GetTaskCount: (self: Scheduler) -> number,
ExecuteTask: (self: Scheduler, taskOrName: string | Task) -> (),
GetSyncData: (self: Scheduler) -> any,
ResetTask: (self: Scheduler, name: string) -> (),
GenerateKey: (self: Scheduler) -> string,
Start: (self: Scheduler) -> (),
}export type RetryConfig = {
enabled: boolean?,
retries: number?,
baseDelay: number?,
jitter: number?,
}export type DataStore = {
CachingTime: number,
RetryConfig: RetryConfig,
SetRetryConfig: (self: DataStore, config: RetryConfig?) -> (),
EnableRetry: (self: DataStore, enabled: boolean) -> (),
SetCachingTime: (self: DataStore, TimeInSeconds: number) -> (),
GetDBName: (self: DataStore) -> string,
GetAsync: (self: DataStore, Key: string) -> (boolean, any, string?),
SetAsync: (self: DataStore, Key: string, value: any) -> (boolean, nil, string?),
UpdateAsync: (self: DataStore, Key: string, transformFunction: (any) -> any) -> (boolean, any, string?),
IncrementAsync: (self: DataStore, Key: string, delta: number) -> (boolean, number?, string?),
RemoveAsync: (self: DataStore, Key: string) -> (boolean, any, string?),
GetSortedAsync: ((self: DataStore, ascending: boolean, pagesize: number, minValue: number?, maxValue: number?) -> (boolean, any, string?))?,
OnUpdate: any,
}export type DataStoreHandler = {
ResetAccessCount: () -> (),
get: (databaseName: string, scope: string?, orderedBool: boolean?) -> DataStore,
}export type PersistenceConfig = {
DataStoreName: string,
Scope: string?,
KeyPrefix: string?,
DataStoreHandler: any,
EnableRetry: boolean?,
RetryConfig: any?,
}export type EntityPersistence = {
Save: (self: EntityPersistence, entity: any, key: string, metadata: { [string]: any }?) -> (boolean, string?),
Load: (self: EntityPersistence, entity: any, key: string) -> (boolean, { [string]: any }?, string?),
Delete: (self: EntityPersistence, key: string) -> (boolean, string?),
Update: (self: EntityPersistence, key: string, mutateFn: (data: { [string]: any }) -> { [string]: any }) -> (boolean, string?),
}export type LogEntry = {
Timestamp: number,
OperationId: string?,
Level: LogLevel,
Message: string,
Data: any?,
}export type LoggerInstance = {
Source: string,
Enabled: boolean,
History: {LogEntry},
Log: (self: LoggerInstance, params: { Level: LogLevel, Message: string, OperationId: string?, Data: any? }) -> (),
GetHistory: (self: LoggerInstance) -> {LogEntry},
}export type LoggerStatic = {
new: (params: { Name: string? }) -> LoggerInstance,
}export type EntityFactory = {
Register: (entityName: string, entityClassDefinition: any) -> (),
get: (entityName: string, params: { [any]: any }?) -> any,
}export type StateMachineInstance = {
Id: string,
Name: string,
State: string,
Context: {[any]: any},
WaitSpan: number,
TransitionCount: number,
Start: (self: StateMachineInstance, params: { State: string, Args: {any}? }) -> (),
ChangeState: (self: StateMachineInstance, params: { Name: string, Args: {any}? }) -> (),
AddState: (self: StateMachineInstance, name: string, state: any, validOutcomes: {string}?) -> (),
AddSubMachine: (self: StateMachineInstance, name: string, subMachineClass: any, config: any) -> (),
Manage: (self: StateMachineInstance, object: Disposable) -> (),
Finish: (self: StateMachineInstance) -> (),
Fail: (self: StateMachineInstance, reason: string) -> (),
Cancel: (self: StateMachineInstance) -> (),
Destroy: (self: StateMachineInstance) -> (),
}export type StateMachineClass = {
Extend: (definition: {[string]: any}) -> StateMachineClass,
new: (params: {[string]: any}) -> StateMachineInstance,
[any]: any,
}export type StateMachineFactory = {
Register: (stateMachineName: string, class: StateMachineClass) -> (),
get: (stateMachineName: string) -> StateMachineClass,
}Exact export in Types.luau:
export type Orchestrator = {
Logger: any,
History: {any},
RegisterComponents: (self: Orchestrator) -> (),
CreateEntity: (params: { EntityClass: any, EntityId: string, Context: {any}?, Persistent: boolean?, PersistenceKey: string? }) -> any?,
CreateStateMachine: (params: { StateMachineClass: any, StateMachineId: string, Context: {any}? }) -> any?,
RetryStateMachine: (stateMachineId: string) -> (),
GetStateMachine: (stateMachineId: string) -> any?,
GetEntity: (entityId: string) -> any?,
CancelStateMachine: (stateMachineId: string) -> boolean,
DeleteEntity: (entityId: string) -> (),
DeleteAllEntities: () -> (),
CancelAll: () -> (),
GetEntities: () -> { [string]: any },
GetStateMachines: () -> { [string]: any },
InitClientListeners: () -> (),
StartServiceManagerAPI: () -> (),
HandleReplication: (entityId: string, changes: {[string]: any}, schema: {[string]: any}) -> (),
RegisterEventBus: (name: string) -> any,
GetEventBus: (name: string) -> any?,
FireEventBus: (name: string, ...any) -> (),
AwaitEventBus: (name: string, timeout: number?) -> any?,
}Strict-mode tip
- cast newer runtime helpers separately when you know they exist, because they are not part of the exported structural type yet
--!strict
local Types = require(path.to.Types)
local function bindEntityFSM(entity: Types.BaseEntity, fsm: Types.BaseStateMachine)
entity:Manage(fsm.Completed:Connect(function()
entity:Log({ Level = "INFO", Message = "FSM completed" })
end))
endlocal params: Types.ScheduleTaskParams = {
TaskName = "RebuildIndex",
TaskAction = function() rebuildIndex() end,
TaskExecutionDelay = 5,
IsRecurringTask = true,
Priority = 2,
Event = "Heartbeat",
}local retry: Types.RetryConfig = {
enabled = true,
retries = 3,
baseDelay = 1,
jitter = 0.2,
}-
Structural types are not runtime guarantees. A type can expose a field that the runtime implementation does not currently populate.
-
Some runtime helpers are missing from
Types.Orchestrator. Extend locally or cast when using newer helpers. -
Most factory/orchestrator returns are still
any?. Guard or cast after existence checks. -
Signalconnection type is implicit. If you need a named connection type in your own module, define a local structural alias.
Quick Links: Home Β· Quick Start Β· API Reference Β· Architecture Β· Examples Β· Glossary
Copyright: Β© 2026 RBXStateMachine contributors Β· Repository Β· License information