UNPKG

@grammyjs/conversations

Version:

Conversational interfaces for grammY

132 lines (131 loc) 4.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.create = create; exports.inspect = inspect; exports.mutate = mutate; exports.cursor = cursor; const resolve_js_1 = require("./resolve.js"); /** * Creates and returns an empty {@link ReplayState} object. * * The returned replay state can be inspected via {@link inspect}, mutated via * {@link mutate}, and replayed via {@link cursor}. */ function create() { return { send: [], receive: [] }; } /** * Provides inspections tools for a given replay state. * * @param state The replay state to inspect */ function inspect(state) { function opCount() { return state.send.length; } function doneCount() { return state.receive.length; } function payload(op) { if (op < 0) throw new Error(`Op ${op} is invalid`); if (op >= state.send.length) throw new Error(`No op ${op} in state`); return state.send[op].payload; } function checkpoint() { return [opCount(), doneCount()]; } return { opCount, doneCount, payload, checkpoint }; } /** * Provides tools to mutate a given replay state. * * @param state The replay state to mutate */ function mutate(state) { function op(payload) { const index = state.send.length; state.send.push({ payload }); return index; } function done(op, result) { if (op < 0) throw new Error(`Op ${op} is invalid`); if (op >= state.send.length) throw new Error(`No op ${op} in state`); state.receive.push({ send: op, returnValue: result }); } function reset([op, done]) { if (op < 0 || done < 0) throw new Error("Invalid checkpoint"); state.send.splice(op); state.receive.splice(done); } return { op, done, reset }; } /** * Provides tools to iterate a given replay state. * * @param state The replay state to iterate */ function cursor(state) { let changes = (0, resolve_js_1.resolver)(); function notify() { changes.resolve(); changes = (0, resolve_js_1.resolver)(); } let send = 0; // 0 <= send <= state.send.length let receive = 0; // 0 <= receive <= state.receive.length function op(payload) { if (send < state.send.length) { // replay existing data (do nothing) const expected = state.send[send].payload; if (expected !== payload) { throw new Error(`Bad replay, expected op '${expected}'`); } } else { // send === state.send.length // log new data state.send.push({ payload }); } const index = send++; notify(); return index; } async function done(op, result) { if (op < 0) throw new Error(`Op ${op} is invalid`); if (op >= state.send.length) throw new Error(`No op ${op} in state`); let data; if (receive < state.receive.length) { // replay existing data (do nothing) while (state.receive[receive].send !== op) { // make sure we resolve only when it is our turn await changes.promise; if (receive === state.receive.length) { // It will never be our turn, because the replay completed // and we are still here. We will have to call `result`. return await done(op, result); } } // state.receive[receive].send === op data = state.receive[receive].returnValue; } else { // receive === state.receive.length data = await result(); state.receive.push({ send: op, returnValue: data }); } receive++; notify(); return data; } async function perform(action, payload) { const index = op(payload); return await done(index, () => action(index)); } function checkpoint() { return [send, receive]; } return { perform, op, done, checkpoint }; }