@gramio/scenes
The API can be changed a little, but we already use it in production environment.
Usage
ts
import { Bot } from "gramio";
import { scenes, Scene } from "@gramio/scenes";
const testScene = new Scene("test")
.params<{ test: boolean }>()
.step("message", async (context) => {
if (context.scene.step.firstTime || context.text !== "1")
return context.send("1");
if (context.scene.params.test === true) await context.send("DEBUG!");
return context.scene.step.next();
});
const bot = new Bot(process.env.TOKEN as string)
.extend(scenes([testScene]))
.command("start", async (context) => {
return context.scene.enter(testScene, {
test: true,
});
});
Share state between steps
ts
import { Scene } from "@gramio/scenes";
const testScene = new Scene("test")
.step("message", async (context) => {
if (context.scene.step.firstTime || context.text !== "1")
return context.send("1");
return context.scene.update({
messageId: context.id,
some: "hii!" as const,
});
})
.step("message", async (context) => {
if (context.scene.step.firstTime || context.text !== "2")
return context.send("2");
console.log(context.scene.state.messageId);
});
Storage usage
ts
import { redisStorage } from "@gramio/storage-redis";
const bot = new Bot(process.env.TOKEN as string)
.extend(
scenes([testScene], {
storage: redisStorage(),
})
)
.command("start", async (context) => {
return context.scene.enter(someScene, {
test: true,
});
});
Scenes derives
Sometimes you wants to control scenes before plugin execute scene steps but after scene fetching from storage.
By default scenes()
function derives what needed to next middlewares if user not in scene. With scenesDerives()
you can get it earlier and manage scene data.
ts
import { scenes, scenesDerives, type AnyScene } from "@gramio/scenes";
import { Bot } from "gramio";
import { redisStorage } from "@gramio/storage-redis";
const storage = redisStorage();
const scenesList: AnyScene[] = [testScene];
const bot = new Bot(process.env.TOKEN as string)
.extend(
scenesDerives(scenesList, {
withCurrentScene: true,
storage,
})
)
.on("message", (context, next) => {
if (context.text === "/start" && context.scene.current) {
if (context.scene.current.is(testScene)) {
console.log(context.scene.current.state);
return context.scene.current.step.previous();
} else return context.scene.current.reenter();
}
return next();
})
.extend(
scenes(scenesList, {
storage,
})
)
.command("start", async (context) => {
return context.scene.enter(testScene, {
test: true,
});
});
IMPORTANT
The same storage and list of scenes should be shared across scenes()
and scenesDerives()
options.