Skip to content
jess
api

jess.context

Bind handlers to the phases a ScriptDomain schedules for a context.

jess.context: { bind }

Also require('@jess/context'). This is the script side of a ScriptDomain: a host that embeds jess declares contexts, each with the phases it may run in, and a script binds its handlers to them. Under jess run there is no domain, so bind errors with context.bind: needs a ScriptDomain, and none owns this runtime; jess run, jess test, and command targets run scripts outside one; the examples here are a domain's main script.

jess.context.bind§

jess.context.bind(name: string, handlers: ContextHandlers) -> ()

Binds one handler per phase to the context the host declared as name. A later bind for the same phase replaces the earlier handler; other phases keep theirs.

handlers is keyed by phase name. Each handler gets the phase's payload: seconds for update, fixedUpdate, and lateUpdate; the event for event; whatever the host passed for input, renderPrepare, message, timer, and onDemand; nothing for load, startup, and shutdown.

PhaseWhen
loadOnce, after the domain's code has loaded.
startupOnce, when the domain starts.
fixedUpdateZero or more fixed steps per advance, bounded by the host's catch-up limit.
update, lateUpdateOnce per advance.
input, renderPrepare, message, timer, onDemandWhen the host or a layer above asks.
eventWhen an event queued for the context is delivered.
shutdownOnce, when the domain stops or restarts.

Binding never widens authority. The host's declaration says which phases a context has and which capabilities it holds; a script can only fill in the handlers.

  • Errors: <domain> has no context '<name>'; <context> does not schedule the <phase> phase; '<key>' is not a scheduler phase; context.bind: the <phase> handler is a function, not <type>.
--!strict
local context = require('@jess/context')

local ticks = 0

context.bind('game', {
  startup = function()
    print('starting')
  end,

  update = function(deltaSeconds: number)
    ticks += 1
  end,

  event = function(payload)
    print(`event {payload.kind}`)
  end,

  shutdown = function()
    print(`stopping after {ticks} ticks`)
  end,
})

A handler that raises is reported to the host with the domain, generation, context, and phase it ran in, and where it was bound; the phase goes on to the next context, and the domain keeps running.

An application target needs none of this by hand: each of its managed modules returns its handlers in on.host, and the loader declares a context for it, <package>/<managed id>, and binds them. bind still works on those contexts, under the same rules. The event phase here takes raw events a host posted to a context; a managed module's on.event handlers take named events, and the two never reach each other.

Related: jess.worker, Script Domains.