State Machine
State Machine
Section titled “State Machine”The state machine module (vitamem/lifecycle/state-machine) provides pure functions for managing thread lifecycle transitions. These functions are used internally by the Vitamem facade but are also exported for direct use when you need low-level control.
All functions are imported from the main vitamem package:
import { canTransition, transition, shouldCool, shouldGoDormant, reactivate, InvalidTransitionError,} from "vitamem";Valid Transitions
Section titled “Valid Transitions”The state machine enforces these transitions:
| From | Allowed targets |
|---|---|
active | cooling |
cooling | active, dormant |
dormant | closed |
closed | (none) |
These are defined by the VALID_TRANSITIONS constant:
const VALID_TRANSITIONS: Record<ThreadState, ThreadState[]> = { active: ["cooling"], cooling: ["active", "dormant"], dormant: ["closed"], closed: [],};canTransition(from, to)
Section titled “canTransition(from, to)”Check whether a transition between two states is allowed without throwing.
Signature
Section titled “Signature”function canTransition(from: ThreadState, to: ThreadState): boolean;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
from | ThreadState | The current state |
to | ThreadState | The desired target state |
Returns
Section titled “Returns”true if the transition is valid, false otherwise.
Example
Section titled “Example”canTransition("active", "cooling"); // truecanTransition("active", "dormant"); // false -- must go through coolingcanTransition("closed", "active"); // false -- closed is terminaltransition(thread, to)
Section titled “transition(thread, to)”Transition a thread to a new state. Returns a new Thread object with updated state and timestamps. The original thread object is not mutated.
Signature
Section titled “Signature”function transition(thread: Thread, to: ThreadState): Thread;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
thread | Thread | The thread to transition |
to | ThreadState | The target state |
Returns
Section titled “Returns”A new Thread object with:
stateset totoupdatedAtset to the current time- State-specific timestamps updated:
- Transition to
cooling: setscoolingStartedAt - Transition to
dormant: setsdormantAt, clearscoolingStartedAt - Transition to
closed: setsclosedAt - Transition to
active: clearscoolingStartedAt
- Transition to
Throws
Section titled “Throws”InvalidTransitionError if the transition is not allowed.
Example
Section titled “Example”// Active -> Coolingconst cooled = transition(activeThread, "cooling");console.log(cooled.state); // "cooling"console.log(cooled.coolingStartedAt); // Date (just set)
// Cooling -> Dormantconst dormant = transition(cooled, "dormant");console.log(dormant.state); // "dormant"console.log(dormant.dormantAt); // Date (just set)console.log(dormant.coolingStartedAt); // null (cleared)
// Invalid transition throwstry { transition(activeThread, "dormant"); // active -> dormant not allowed} catch (e) { console.log(e.message); // "Invalid transition: active → dormant"}shouldCool(thread, coolingTimeoutMs)
Section titled “shouldCool(thread, coolingTimeoutMs)”Determine whether an active thread should transition to cooling based on message inactivity.
Signature
Section titled “Signature”function shouldCool(thread: Thread, coolingTimeoutMs: number): boolean;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
thread | Thread | The thread to check |
coolingTimeoutMs | number | Milliseconds of inactivity before cooling (default in facade: 6 hours) |
Returns
Section titled “Returns”true if all of these conditions are met:
- The thread is in the
activestate - The thread has a
lastMessageAttimestamp - The elapsed time since
lastMessageAtis greater than or equal tocoolingTimeoutMs
Returns false otherwise (including if the thread is not active or has no messages).
Example
Section titled “Example”const SIX_HOURS = 6 * 60 * 60 * 1000;
// Thread with recent activityshouldCool(recentThread, SIX_HOURS); // false
// Thread inactive for 7 hoursshouldCool(staleThread, SIX_HOURS); // true
// Thread already coolingshouldCool(coolingThread, SIX_HOURS); // false (wrong state)shouldGoDormant(thread, dormantTimeoutMs)
Section titled “shouldGoDormant(thread, dormantTimeoutMs)”Determine whether a cooling thread should transition to dormant.
Signature
Section titled “Signature”function shouldGoDormant(thread: Thread, dormantTimeoutMs: number): boolean;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
thread | Thread | The thread to check |
dormantTimeoutMs | number | Milliseconds in cooling before going dormant (default in facade: same as coolingTimeoutMs) |
Returns
Section titled “Returns”true if all of these conditions are met:
- The thread is in the
coolingstate - The thread has a
coolingStartedAttimestamp - The elapsed time since
coolingStartedAtis greater than or equal todormantTimeoutMs
Returns false otherwise.
Example
Section titled “Example”const SIX_HOURS = 6 * 60 * 60 * 1000;
// Thread just started coolingshouldGoDormant(justCooled, SIX_HOURS); // false
// Thread has been cooling for 7 hoursshouldGoDormant(longCooled, SIX_HOURS); // truereactivate(thread)
Section titled “reactivate(thread)”Reactivate a cooling thread back to active state. This is a convenience function equivalent to transition(thread, "active").
Signature
Section titled “Signature”function reactivate(thread: Thread): Thread;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
thread | Thread | The thread to reactivate (must be in cooling state) |
Returns
Section titled “Returns”A new Thread object with:
stateset to"active"coolingStartedAtcleared tonullupdatedAtset to the current time
Throws
Section titled “Throws”InvalidTransitionError if the thread is not in the cooling state.
Example
Section titled “Example”// Thread is cooling, user sends a new messageconst active = reactivate(coolingThread);console.log(active.state); // "active"console.log(active.coolingStartedAt); // nullInvalidTransitionError
Section titled “InvalidTransitionError”Error class thrown when an invalid state transition is attempted.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
name | string | Always "InvalidTransitionError" |
message | string | "Invalid transition: {from} → {to}" |
Example
Section titled “Example”import { transition, InvalidTransitionError } from "vitamem";
try { transition(dormantThread, "active");} catch (e) { if (e instanceof InvalidTransitionError) { console.log(e.message); // "Invalid transition: dormant → active" }}