@eryx/signal Module

JSON

A lightweight, re-entrant-safe signal/event system using a doubly-linked list of connections. Signals allow you to fire events and notify all connected callbacks.

Handlers are invoked via task.spawn, so each callback runs in its own coroutine. Disconnecting or connecting handlers during a Fire is safe - the handler list is snapshotted before invocation.

local Signal = require("@eryx/signal")

local onDamage = Signal.new()

local conn = onDamage:connect(function(amount)
	print("Took " .. amount .. " damage!")
end)

onDamage:fire(25)  --> "Took 25 damage!"

conn:disconnect()
onDamage:fire(10)  --> (nothing, handler was disconnected)

Summary

Classes

_signal: Signal<T...>
_next: Connection<T...>?
_prev: Connection<T...>?
connected: boolean
Connection:disconnect<T...>()()
_head: Connection<T...>?
_errorSignal: Signal<any, Connection<T...>>?
Signal.new<T...>()Signal<T...>
Signal:fire<T...>(...)boolean
Signal:wait<T...>()T...
Signal:disconnectAll<T...>()()
Signal:errorSignal<T...>()Signal<any, Connection<T...>>
Signal:connectError<T...>(callback: ((err: any, connection: Connection<T...>) → ()))Connection<any, Connection<T...>>
Signal:connect<T...>(callback: ((T...) → ()))Connection<T...>
Signal:once<T...>(callback: ((T...) → ()))Connection<T...>

API Reference

Classes

Connection

Represents a single subscription to a Signal. Created by Signal:connect or Signal:once. Can be disconnected to stop receiving future events.

Properties

_signal: Signal<T...>
_next: Connection<T...>?
_prev: Connection<T...>?
connected: boolean

Connection._fn

Connection._fn()()

Connection:disconnect

Disconnects this connection from its signal. Future fires will no longer invoke this connection's callback. Safe to call multiple times - subsequent calls are a no-op.

Connection:disconnect<T...>()()

Signal

A generic event dispatcher. Supports connecting multiple handlers, one-shot handlers, yielding until the next fire, and bulk disconnection.

Properties

_head: Connection<T...>?
_errorSignal: Signal<any, Connection<T...>>?

Signal.new

Creates a new Signal.

Signal.new<T...>()Signal<T...>

Returns

Signal<T...>

A new signal with no connections. luau local onPlayerJoin = Signal.new()

Signal:fire

Fires the signal, invoking all connected callbacks with the given arguments. Each handler runs in its own coroutine via task.spawn. The handler list is snapshotted before invocation, so connects/disconnects during callbacks are safe.

Signal:fire<T...>(...)boolean

Parameters

...

Arguments to pass to each connected handler.

Returns

boolean

true if at least one handler was invoked, false otherwise. luau local sig = Signal.new() sig:connect(function(msg) print(msg) end) sig:fire("hello") --> "hello", returns true

Signal:wait

Yields the current coroutine until the signal is next fired, then returns the fired arguments.

Signal:wait<T...>()T...

Returns

T...

The arguments passed to the next Fire call. luau -- In a coroutine: local damage = onDamage:wait() print("Waited and received:", damage)

Signal:disconnectAll

Disconnects all connections from this signal. All existing Connection objects will have their connected property set to false.

Signal:disconnectAll<T...>()()

Signal:errorSignal

Returns a lazily-created signal that fires when any handler connected to this signal raises an error. The error signal fires with (err, connection).

If no error handlers are connected, handler errors are re-thrown so they remain visible rather than being silently swallowed.

local sig = Signal.new()

sig:errorSignal():connect(function(err)
	warn("signal handler failed:", err)
end)
Signal:errorSignal<T...>()Signal<any, Connection<T...>>

Signal:connectError

Connects a callback that will be invoked whenever one of this signal's handlers raises an error. The callback receives the thrown value and the connection whose handler failed.

Signal:connectError<T...>(callback: ((err: any, connection: Connection<T...>) → ()))Connection<any, Connection<T...>>

Signal:connect

Connects a callback to this signal. The callback will be invoked each time the signal is fired, until the returned Connection is disconnected.

Signal:connect<T...>(callback: ((T...) → ()))Connection<T...>

Parameters

callback: ((T...) → ())

The function to call when the signal fires.

Returns

A connection that can be used to disconnect later. luau local conn = signal:connect(function(value) print("Got:", value) end) -- Later: conn:disconnect()

Signal:once

Connects a callback that will only fire once. The connection automatically disconnects itself before invoking the callback.

Signal:once<T...>(callback: ((T...) → ()))Connection<T...>

Parameters

callback: ((T...) → ())

The function to call on the next fire.

Returns

A connection that can be manually disconnected before it fires. luau signal:once(function(value) print("Fired once with:", value) end)