index.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { Bot, Context } from "grammy";
  2. import { conversations, createConversation, ConversationFlavor, VersionedStateStorage } from "@grammyjs/conversations";
  3. import { KvAdapter } from "@grammyjs/storage-cloudflare";
  4. import { handleStartCommand } from "./handlers/start";
  5. import { handleInteractiveLogin } from "./handlers/login";
  6. import { handleEventsCommand } from "./handlers/events";
  7. import { handleEventDetails } from "./handlers/eventDetails";
  8. import { handleBookEvent } from "./handlers/bookEvent";
  9. import { handleHistoryCommand } from "./handlers/history";
  10. import { handleCancelCommand, handleCancelConfirmation } from "./handlers/cancel";
  11. import { handleLogoutCommand } from "./handlers/logout";
  12. export interface Env {
  13. BOT_INFO: string;
  14. BOT_TOKEN: string;
  15. COSMOE_CREDENTIALS: KVNamespace;
  16. COSMOE_STORAGE: KVNamespace;
  17. }
  18. export function setupCommands(bot: Bot<ConversationFlavor<Context>>, env: Env) {
  19. // Create a KV adapter for conversation storage using COSMOE_STORAGE namespace
  20. const kvAdapter = new KvAdapter(env.COSMOE_STORAGE);
  21. // Define conversation storage using the KV adapter
  22. const conversationStorage = {
  23. read: async (key: string) => {
  24. try {
  25. const value = await kvAdapter.read(key);
  26. return value ? JSON.parse(value as string) : undefined;
  27. } catch (error) {
  28. console.error('Error reading conversation from KV:', error);
  29. return undefined;
  30. }
  31. },
  32. write: async (key: string, value: any) => {
  33. try {
  34. await kvAdapter.write(key, JSON.stringify(value));
  35. } catch (error) {
  36. console.error('Error writing conversation to KV:', error);
  37. }
  38. },
  39. delete: async (key: string) => {
  40. try {
  41. await kvAdapter.delete(key);
  42. } catch (error) {
  43. console.error('Error deleting conversation from KV:', error);
  44. }
  45. },
  46. };
  47. // Install the conversations plugin with KV storage
  48. bot.use(conversations({ storage: conversationStorage }));
  49. // Create the login conversation, with environment bound to the handler
  50. bot.use(createConversation(async (conversation, ctx) => {
  51. await handleInteractiveLogin(conversation, ctx, env);
  52. }, "login"));
  53. bot.command("start", async (ctx: Context) => {
  54. await handleStartCommand(ctx);
  55. });
  56. // Use the interactive conversation for login
  57. bot.command("login", async (ctx) => {
  58. await ctx.conversation.enter("login");
  59. });
  60. bot.command("events", async (ctx: Context) => {
  61. await handleEventsCommand(ctx);
  62. });
  63. // Handle /event_123 format using hears
  64. bot.hears(/^\/event_(.+)$/, async (ctx) => {
  65. await handleEventDetails(ctx);
  66. });
  67. // Handle /book_{event_id}_{slot_id} format
  68. bot.hears(/^\/book_(\d+)_(\d+)$/, async (ctx) => {
  69. await handleBookEvent(ctx, env);
  70. });
  71. bot.command("history", async (ctx: Context) => {
  72. await handleHistoryCommand(ctx, env);
  73. });
  74. // Handle /cancel_{booking_id} format
  75. bot.hears(/^\/cancel_(\d+)$/, async (ctx) => {
  76. await handleCancelCommand(ctx, env);
  77. });
  78. // Handle callback queries for cancel confirmation
  79. bot.callbackQuery(/confirm_cancel_\d+|cancel_action/, async (ctx) => {
  80. if (ctx.callbackQuery.data) {
  81. await handleCancelConfirmation(ctx, env, ctx.callbackQuery.data);
  82. await ctx.answerCallbackQuery();
  83. }
  84. });
  85. bot.command("logout", async (ctx: Context) => {
  86. await handleLogoutCommand(ctx, env);
  87. });
  88. }