UNPKG

@grammyjs/conversations

Version:

Conversational interfaces for grammY

213 lines (212 loc) 8.88 kB
import { type Checkpoint, type ReplayState } from "./state.js"; export { type Checkpoint, type ReplayState } from "./state.js"; /** * Controls for a replay. This is the object that a {@link ReplayEngine} passes * to the replay function when executing it. */ export interface ReplayControls { /** * Interrupts the current replay and record this event in the replay logs. * The replay will finish with an {@link Interrupted} result. * * Use {@link ReplayEngine.supply} to supply the result of this interrupt to * the underlying replay state. When replaying the modified state, this call * to `interrupt` will resolve with the supplied value. * * You also need to pass a key that identifies this type of interrupt. It is * stored in the replay state and will be collated with the key that is * passed to `interrupt` during the repeated call. If the two keys do not * match, this means that a bad replay was detected and an error will be * thrown. You should discard the replay state and restart the replay from * scratch. * * @param key A key to collate interrupts across replays */ interrupt(key: string): Promise<unknown>; /** * Cancels the replay. This tells the replay engine that a supplied * interrupt value should be rejected. The replay will finish with a * {@link Canceled} result. * * A message object can be passed to `cancel`. This can be used to * communicate to the caller why the interrupt value was rejected. * * @param message A message specifiying the reason for the cancelation */ cancel(message?: unknown): Promise<never>; /** * Performs an action. * * Actions are a way to signal to the replay engine that a particular piece * of code should not be run repeatedly. The result of the action will be * stored in the underlying replay log. During a subsequent replay, the * action will not be repeated. Instead, the return is taken from the replay * log. * * You also need to pass a key that identifies this type of action. It is * stored in the replay state and will be collated with the key that is * passed to `action` during the repeated call. If the two keys do not * match, this means that a bad replay was detected and an error will be * thrown. You should discard the replay state and restart the replay from * scratch. * * @param fn The action to perform * @param key A key to collate actions across replays */ action<R = unknown>(fn: () => R | Promise<R>, key: string): Promise<R>; /** * Creates a checkpoint at the current position of the replay. This can be * passed to {@link ReplayEngine.reset} in order to restart a replay from an * arbitrary position. */ checkpoint(): Checkpoint; } /** A function to be replayed by a {@link ReplayEngine} */ export type Builder = (controls: ReplayControls) => void | Promise<void>; /** The result of a replay performed by a {@link ReplayEngine} */ export type ReplayResult = Returned | Thrown | Interrupted | Canceled; /** * This result is returned by a {@link ReplayEngine} when the builder function * completes normally by returning. */ export interface Returned { /** * Type of the replay result, indicates that the replay has completed * normally because the builder function has returned. */ type: "returned"; /** The return value of the builder function */ returnValue: unknown; } /** * This result is returned by a {@link ReplayEngine} when the builder function * throws an error. */ export interface Thrown { /** * Type of the replay result, indicates that the replay has completed * because the builder function has thrown an error. */ type: "thrown"; /** The error thrown by the builder function */ error: unknown; } /** * This result is returned by a {@link ReplayEngine} when the builder function * interrupts itself by calling {@link ReplayControls.interrupt}. */ export interface Interrupted { /** * Type of the replay result, indicates that the replay has completed * because the builder function has interrupted itself. */ type: "interrupted"; /** The replay state left behind by the replay engine */ state: ReplayState; /** The list of concurrent interrupts that were performed */ interrupts: number[]; } /** * This result is returned by a {@link ReplayEngine} when the builder function * cancels itself by calling {@link ReplayControls.cancel}. */ export interface Canceled { /** * Type of the replay result, indicates that the replay has completed * because the builder function has canceled itself. */ type: "canceled"; /** The message passed to the last concurrent cancel call */ message?: unknown; } /** * A replay engine takes control of the event loop of the JavaScript runtime and * lets you execute a JavaScript function in abnormal ways. The function * execution can be halted, resumed, aborted, and reversed. This lets you run a * function partially and persist the state of execution in a database. Later, * function execution can be resumed from where it was left off. * * Replay engines are the fundamental building block of the conversations * plugin. In a sense, everything else is just a number of wrapper layers to * make working with replay engines more convenient, and to integrate the power * of replay engines into your bot's middleware system. * * Using a standalone replay engine is straightforward. * * 1. Create an instance of this class and pass a normal JavaScript function to * the constructor. The function receives a {@link ReplayControls} object as * its only parameter. * 2. Call {@link ReplayEngine.play} to begin a new execution. It returns a * {@link ReplayResult} object. * 3. Use the {@link ReplayState} you obtained inside the result object and * resume execution by calling {@link ReplayEngine.replay}. * * The `ReplayEngine` class furthermore provides you with static helper methods * to supply values to interrupts, and to reset the replay state to a previously * created checkpoint. */ export declare class ReplayEngine { private readonly builder; /** * Constructs a new replay engine from a builder function. The function * receives a single parameter that can be used to control the replay. * * @param builder A builder function to be executed and replayed */ constructor(builder: Builder); /** * Begins a new execution of the builder function. This starts based on * fresh state. The execution is independent from any previously created * executions. * * A {@link ReplayResult} object is returned to communicate the outcome of * the execution. */ play(): Promise<ReplayResult>; /** * Resumes execution based on a previously created replay state. This is the * most important method of this class. * * A {@link ReplayResult} object is returned to communicate the outcome of * the execution. * * @param state A previously created replay state */ replay(state: ReplayState): Promise<ReplayResult>; /** * Creates a new replay state with a single unresolved interrupt. This state * can be used as a starting point to replay arbitrary builder functions. * * You need to pass the collation key for the aforementioned first * interrupt. This must be the same value that the builder function will * pass to its first interrupt. * * @param key The builder functions first collation key */ static open(key: string): readonly [ReplayState, number]; /** * Mutates a given replay state by supplying a value for a given interrupt. * The next time the state is replayed, the targeted interrupt will return * this value. * * The interrupt value has to be one of the interrupts of a previously * received {@link Interrupted} result. * * In addition to mutating the replay state, a checkpoint is created and * returned. This checkpoint may be used to reset the replay state to its * previous value. This will undo this and all following mutations. * * @param state A replay state to mutate * @param interrupt An interrupt to resolve * @param value The value to supply */ static supply(state: ReplayState, interrupt: number, value: unknown): Checkpoint; /** * Resets a given replay state to a previously received checkpoint by * mutating the replay state. * * @param state The state to mutate * @param checkpoint The checkpoint to which to return */ static reset(state: ReplayState, checkpoint: Checkpoint): void; }