Skip to content

Utilities

Creates a store: a value you can change, commit, and revert, the same way Inkweaver handles state.

createStore<T>(initial: T): Store<T>
interface Store<T> {
clear: () => void;
commit: () => void;
get: () => T;
getCommitted: () => T;
getPrevious: () => T;
onChange: (listener: (value: T, oldValue: T) => void) => () => void;
onClear: (listener: (value: T) => void) => () => void;
onCommit: (listener: (committed: T, previous: T) => void) => () => void;
onRevert: (listener: (value: T) => void) => () => void;
revert: () => void;
set: (value: ((current: T) => T) | T) => T;
update: (partial: Partial<T>) => T;
}
FunctionDescription
getReturns the current value.
setReplaces the current value. Takes a value, or a function that receives the current value.
updateMerges a partial value into the current value.
commitMakes the current value the committed value. Does nothing if the current value hasn’t changed.
getCommittedReturns the value from the most recent commit.
getPreviousReturns the committed value from before the most recent commit.
revertSets the current value back to the committed value.
clearResets the current, committed, and previous values to initial.

Stored values are deeply frozen. A store lives in memory only, so it isn’t saved in history or bookmarks.

Each on function adds a listener, and returns a function that removes it.

ListenerCalled when
onChangeThe current value changes, including through revert and clear.
onCommitcommit records a new committed value.
onRevertrevert is called.
onClearclear is called.

Listeners run synchronously, in the order they were added. If any throw, the rest still run, and the errors are thrown together as an AggregateError.

Example
const store = createStore({ count: 0 });
store.onChange((value) => console.log(value.count));
store.update({ count: 1 }); // logs 1
store.commit();
store.getCommitted(); // { count: 1 }
store.getPrevious(); // { count: 0 }

Runs an async function, and calls onError if it changed state.

immutable<T>(
fn: () => Promise<T>,
onError: (changes: string) => void
): Promise<T>

Use it during development to catch unexpected state changes. onError receives a description of what changed.

Example
await immutable(
() => doSomeWork(),
(changes) => console.warn(`Unexpected state changes: ${changes}`),
);

Gives part of your state a separate value for each level of the screenplay’s call stack. When the story calls into a section, the value gets a new level, and when it returns, the previous value comes back.

withCallStack<T>(
key: string,
onPush?: () => T,
onPop?: (item: undefined | T) => void
): void
ParameterDescription
keyThe state key to track.
onPushReturns the value for a new level. By default, a new level starts as a shallow copy of the current value.
onPopCalled with a level’s value when it’s removed.

Call withCallStack once, from your init command. After that, state[key] always holds the current level’s value, and state[key + "Stack"] holds the full stack.

Example
withCallStack("beat");

With this in place, state.beat holds the beat for the current level, and state.beatStack holds the levels beneath it. Calling into a section starts a new beat, and returning restores the one you left.

withCallStack(
"inventory",
() => ({ items: [] }),
(discarded) =>
console.log(`Left a level holding ${discarded?.items.length} items`),
);