telemeister 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +460 -0
- package/bin/telemeister.js +18 -0
- package/dist/bot/polling.d.ts +20 -0
- package/dist/bot/polling.d.ts.map +1 -0
- package/dist/bot/polling.js +115 -0
- package/dist/bot/polling.js.map +1 -0
- package/dist/bot/session.d.ts +50 -0
- package/dist/bot/session.d.ts.map +1 -0
- package/dist/bot/session.js +92 -0
- package/dist/bot/session.js.map +1 -0
- package/dist/bot/webhook.d.ts +36 -0
- package/dist/bot/webhook.d.ts.map +1 -0
- package/dist/bot/webhook.js +199 -0
- package/dist/bot/webhook.js.map +1 -0
- package/dist/bot-state-types.d.ts +10 -0
- package/dist/bot-state-types.d.ts.map +1 -0
- package/dist/bot-state-types.js +3 -0
- package/dist/bot-state-types.js.map +1 -0
- package/dist/cli/cli.d.ts +14 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +57 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/create-bot.d.ts +5 -0
- package/dist/cli/create-bot.d.ts.map +1 -0
- package/dist/cli/create-bot.js +275 -0
- package/dist/cli/create-bot.js.map +1 -0
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/state-manager.d.ts +9 -0
- package/dist/cli/state-manager.d.ts.map +1 -0
- package/dist/cli/state-manager.js +381 -0
- package/dist/cli/state-manager.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +52 -0
- package/dist/config.js.map +1 -0
- package/dist/core/app-states.d.ts +8 -0
- package/dist/core/app-states.d.ts.map +1 -0
- package/dist/core/app-states.js +8 -0
- package/dist/core/app-states.js.map +1 -0
- package/dist/core/builder.d.ts +138 -0
- package/dist/core/builder.d.ts.map +1 -0
- package/dist/core/builder.js +195 -0
- package/dist/core/builder.js.map +1 -0
- package/dist/core/compact-machine.d.ts +57 -0
- package/dist/core/compact-machine.d.ts.map +1 -0
- package/dist/core/compact-machine.js +113 -0
- package/dist/core/compact-machine.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/types.d.ts +47 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/database.d.ts +43 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +127 -0
- package/dist/database.js.map +1 -0
- package/dist/generated/prisma/browser.d.ts +15 -0
- package/dist/generated/prisma/browser.d.ts.map +1 -0
- package/dist/generated/prisma/browser.js +18 -0
- package/dist/generated/prisma/browser.js.map +1 -0
- package/dist/generated/prisma/client.d.ts +32 -0
- package/dist/generated/prisma/client.d.ts.map +1 -0
- package/dist/generated/prisma/client.js +33 -0
- package/dist/generated/prisma/client.js.map +1 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +166 -0
- package/dist/generated/prisma/commonInputTypes.d.ts.map +1 -0
- package/dist/generated/prisma/commonInputTypes.js +11 -0
- package/dist/generated/prisma/commonInputTypes.js.map +1 -0
- package/dist/generated/prisma/enums.d.ts +2 -0
- package/dist/generated/prisma/enums.d.ts.map +1 -0
- package/dist/generated/prisma/enums.js +11 -0
- package/dist/generated/prisma/enums.js.map +1 -0
- package/dist/generated/prisma/internal/class.d.ts +138 -0
- package/dist/generated/prisma/internal/class.d.ts.map +1 -0
- package/dist/generated/prisma/internal/class.js +50 -0
- package/dist/generated/prisma/internal/class.js.map +1 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +591 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts.map +1 -0
- package/dist/generated/prisma/internal/prismaNamespace.js +96 -0
- package/dist/generated/prisma/internal/prismaNamespace.js.map +1 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +56 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +67 -0
- package/dist/generated/prisma/internal/prismaNamespaceBrowser.js.map +1 -0
- package/dist/generated/prisma/models/User.d.ts +1181 -0
- package/dist/generated/prisma/models/User.d.ts.map +1 -0
- package/dist/generated/prisma/models/User.js +2 -0
- package/dist/generated/prisma/models/User.js.map +1 -0
- package/dist/generated/prisma/models/UserInfo.d.ts +1101 -0
- package/dist/generated/prisma/models/UserInfo.d.ts.map +1 -0
- package/dist/generated/prisma/models/UserInfo.js +2 -0
- package/dist/generated/prisma/models/UserInfo.js.map +1 -0
- package/dist/generated/prisma/models.d.ts +4 -0
- package/dist/generated/prisma/models.d.ts.map +1 -0
- package/dist/generated/prisma/models.js +2 -0
- package/dist/generated/prisma/models.js.map +1 -0
- package/dist/handlers/idle/index.d.ts +2 -0
- package/dist/handlers/idle/index.d.ts.map +1 -0
- package/dist/handlers/idle/index.js +22 -0
- package/dist/handlers/idle/index.js.map +1 -0
- package/dist/handlers/index.d.ts +12 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +14 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/menu/index.d.ts +2 -0
- package/dist/handlers/menu/index.d.ts.map +1 -0
- package/dist/handlers/menu/index.js +35 -0
- package/dist/handlers/menu/index.js.map +1 -0
- package/dist/handlers/menu.d.ts +2 -0
- package/dist/handlers/menu.d.ts.map +1 -0
- package/dist/handlers/menu.js +37 -0
- package/dist/handlers/menu.js.map +1 -0
- package/dist/handlers/welcome/index.d.ts +2 -0
- package/dist/handlers/welcome/index.d.ts.map +1 -0
- package/dist/handlers/welcome/index.js +22 -0
- package/dist/handlers/welcome/index.js.map +1 -0
- package/dist/handlers/welcome.d.ts +2 -0
- package/dist/handlers/welcome.d.ts.map +1 -0
- package/dist/handlers/welcome.js +30 -0
- package/dist/handlers/welcome.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/package.json +111 -0
- package/templates/handler.ts.ejs +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
# Telemeister
|
|
2
|
+
|
|
3
|
+
A TypeScript Telegram Bot Framework with [Grammy](https://grammy.dev), XState-powered Finite State Machines (FSM), Prisma ORM for persistence, and a type-safe builder pattern for defining conversation flows.
|
|
4
|
+
|
|
5
|
+
**Goal**: Build bot infrastructure with explicit structure that allows an LLM to build and verify bots from text descriptions, and detect inconsistencies in those descriptions.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **NPM Package**: Install as a dependency to any bot project
|
|
10
|
+
- **Project Scaffolding**: `npx telemeister create-bot` creates new projects
|
|
11
|
+
- **Grammy Bot Framework**: Modern, TypeScript-first Telegram Bot API library
|
|
12
|
+
- **XState FSM**: Compact, maintainable state machines using XState's "states as data" pattern
|
|
13
|
+
- **Type-Safe State Transitions**: Full TypeScript support with strict transition types
|
|
14
|
+
- **State Machine Configuration**: JSON-based state machine definition (`bot.json`)
|
|
15
|
+
- **Auto-Generated Types**: TypeScript types generated from state machine config
|
|
16
|
+
- **State Diagram Visualization**: Mermaid diagrams (MD + PNG) auto-generated
|
|
17
|
+
- **Prisma ORM 7.x**: Modern database toolkit with driver adapters for SQLite and MySQL
|
|
18
|
+
- **Single Schema**: One Prisma schema works for both SQLite (dev) and MySQL (production)
|
|
19
|
+
- **Builder Pattern**: Fluent API for defining state handlers
|
|
20
|
+
- **Dual Mode**: Supports both Polling and Webhook modes
|
|
21
|
+
- **CLI Tools**: Built-in commands for managing states, transitions, and webhooks
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### Create a New Bot
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx telemeister create-bot my-bot
|
|
29
|
+
cd my-bot
|
|
30
|
+
npm install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Environment Setup
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cp .env.example .env
|
|
37
|
+
# Edit .env with your credentials
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Required environment variables:
|
|
41
|
+
```env
|
|
42
|
+
BOT_TOKEN=your_bot_token # From @BotFather (https://t.me/BotFather)
|
|
43
|
+
|
|
44
|
+
# Database Configuration
|
|
45
|
+
# For SQLite (development):
|
|
46
|
+
DATABASE_URL="file:./dev.db"
|
|
47
|
+
|
|
48
|
+
# For MySQL (production):
|
|
49
|
+
# DATABASE_URL="mysql://user:password@localhost:3306/dbname"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Database Setup
|
|
53
|
+
|
|
54
|
+
**Generate Prisma Client:**
|
|
55
|
+
```bash
|
|
56
|
+
npm run db:generate
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Run Migrations:**
|
|
60
|
+
```bash
|
|
61
|
+
# Development (SQLite)
|
|
62
|
+
npm run db:migrate
|
|
63
|
+
|
|
64
|
+
# Production (MySQL) - after updating DATABASE_URL
|
|
65
|
+
npm run db:deploy
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Run the Bot
|
|
69
|
+
|
|
70
|
+
**Polling mode (development):**
|
|
71
|
+
```bash
|
|
72
|
+
npm run dev
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Webhook mode (production):**
|
|
76
|
+
```bash
|
|
77
|
+
# Set webhook URL first
|
|
78
|
+
npm run webhook:set -- https://your-domain.com/webhook
|
|
79
|
+
|
|
80
|
+
# Start in webhook mode
|
|
81
|
+
BOT_MODE=webhook npm run dev
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Project Structure
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
my-bot/
|
|
88
|
+
├── bot.json # State machine configuration (source of truth, gitignored)
|
|
89
|
+
├── src/
|
|
90
|
+
│ ├── bot-state-types.ts # Auto-generated types (DO NOT EDIT)
|
|
91
|
+
│ ├── bot-diagram.md # Auto-generated Mermaid diagram
|
|
92
|
+
│ ├── bot-diagram.png # Auto-generated diagram image
|
|
93
|
+
│ ├── handlers/ # Your state handlers
|
|
94
|
+
│ │ ├── index.ts # Handler imports
|
|
95
|
+
│ │ ├── idle/ # Idle state handler
|
|
96
|
+
│ │ ├── welcome/ # Welcome state handler
|
|
97
|
+
│ │ └── menu/ # Menu state handler
|
|
98
|
+
│ └── index.ts # Bot entry point
|
|
99
|
+
├── prisma/
|
|
100
|
+
│ └── schema.prisma # Database schema
|
|
101
|
+
├── .env # Environment variables (gitignored)
|
|
102
|
+
└── package.json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## State Management
|
|
106
|
+
|
|
107
|
+
### State Machine Configuration
|
|
108
|
+
|
|
109
|
+
The `bot.json` file is the source of truth for your state machine:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"idle": ["welcome"],
|
|
114
|
+
"welcome": ["menu"],
|
|
115
|
+
"menu": ["welcome", "idle"]
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Each key is a state, and the array contains valid transition targets.
|
|
120
|
+
|
|
121
|
+
### CLI Commands
|
|
122
|
+
|
|
123
|
+
| Command | Description |
|
|
124
|
+
|---------|-------------|
|
|
125
|
+
| `telemeister state:add <name>` | Add a new state + create handler |
|
|
126
|
+
| `telemeister state:delete <name>` | Delete a state (with safety checks) |
|
|
127
|
+
| `telemeister state:sync` | Sync types + create missing handlers |
|
|
128
|
+
| `telemeister state:transition:add <from> <to>` | Add a transition |
|
|
129
|
+
| `telemeister state:transition:delete <from> <to>` | Delete a transition |
|
|
130
|
+
|
|
131
|
+
Or use npm scripts:
|
|
132
|
+
```bash
|
|
133
|
+
npm run state:add -- settings
|
|
134
|
+
npm run state:sync
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Adding a New State
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
telemeister state:add collectEmail
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
This command:
|
|
144
|
+
- Adds `"collectEmail": []` to `bot.json`
|
|
145
|
+
- Creates `src/handlers/collectEmail/index.ts` with a template
|
|
146
|
+
- Updates `src/handlers/index.ts` with the import
|
|
147
|
+
- Regenerates `src/bot-state-types.ts`
|
|
148
|
+
- Regenerates `src/bot-diagram.md` and `src/bot-diagram.png`
|
|
149
|
+
|
|
150
|
+
### Adding Transitions
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
telemeister state:transition:add collectEmail completed
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This updates `bot.json`, regenerates types and diagrams.
|
|
157
|
+
|
|
158
|
+
### Deleting States
|
|
159
|
+
|
|
160
|
+
Safety checks prevent accidental deletion:
|
|
161
|
+
- Cannot delete if handler folder is non-empty
|
|
162
|
+
- Cannot delete if state has outgoing transitions
|
|
163
|
+
- Cannot delete if state has incoming transitions
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# Remove transitions first
|
|
167
|
+
telemeister state:transition:delete collectEmail completed
|
|
168
|
+
|
|
169
|
+
# Then empty the handler folder or move files
|
|
170
|
+
rm -rf src/handlers/collectEmail
|
|
171
|
+
|
|
172
|
+
# Now delete the state
|
|
173
|
+
telemeister state:delete collectEmail
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Syncing
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
telemeister state:sync
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This regenerates:
|
|
183
|
+
- `src/bot-state-types.ts` - TypeScript types from `bot.json`
|
|
184
|
+
- `src/bot-diagram.md` - Mermaid diagram
|
|
185
|
+
- `src/bot-diagram.png` - PNG image (requires mermaid-cli)
|
|
186
|
+
- Creates missing handler folders (never overwrites existing)
|
|
187
|
+
|
|
188
|
+
## Auto-Generated Types
|
|
189
|
+
|
|
190
|
+
The `src/bot-state-types.ts` file is auto-generated:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Auto-generated by state:sync - DO NOT EDIT
|
|
194
|
+
|
|
195
|
+
export type AppStates = 'idle' | 'menu' | 'welcome';
|
|
196
|
+
|
|
197
|
+
export type StateTransitions = {
|
|
198
|
+
idle: 'welcome' | void;
|
|
199
|
+
menu: 'idle' | 'welcome' | void;
|
|
200
|
+
welcome: 'menu' | void;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
export type IdleTransitions = Promise<StateTransitions['idle']>;
|
|
204
|
+
export type MenuTransitions = Promise<StateTransitions['menu']>;
|
|
205
|
+
export type WelcomeTransitions = Promise<StateTransitions['welcome']>;
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Handler API
|
|
209
|
+
|
|
210
|
+
### Strict Transition Types
|
|
211
|
+
|
|
212
|
+
Handlers use generated types for strict return type checking:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { appBuilder, type AppContext } from 'telemeister/core';
|
|
216
|
+
import type { MenuTransitions } from './bot-state-types.js';
|
|
217
|
+
|
|
218
|
+
appBuilder
|
|
219
|
+
.forState('menu')
|
|
220
|
+
.onEnter(async (context: AppContext): MenuTransitions => {
|
|
221
|
+
await context.send('Welcome to menu!');
|
|
222
|
+
// Can only return 'idle', 'welcome', or void
|
|
223
|
+
})
|
|
224
|
+
.onResponse(async (context: AppContext, response): MenuTransitions => {
|
|
225
|
+
if (response === 'back') return 'welcome'; // ✅ Valid
|
|
226
|
+
if (response === 'exit') return 'idle'; // ✅ Valid
|
|
227
|
+
return 'invalid'; // ❌ Type error - not in transitions
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Context Methods
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
interface BotHandlerContext<TState> {
|
|
235
|
+
// User info
|
|
236
|
+
userId: number;
|
|
237
|
+
telegramId: number;
|
|
238
|
+
chatId: number;
|
|
239
|
+
currentState: TState;
|
|
240
|
+
|
|
241
|
+
// Messaging
|
|
242
|
+
send: (text: string) => Promise<unknown>;
|
|
243
|
+
|
|
244
|
+
// Data persistence (per-user)
|
|
245
|
+
setData: <T>(key: string, value: T) => void;
|
|
246
|
+
getData: <T>(key: string) => T | undefined;
|
|
247
|
+
|
|
248
|
+
// State transition
|
|
249
|
+
transition: (toState: TState) => Promise<void>;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Handler Types
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Called when entering a state
|
|
257
|
+
.onEnter(async (context) => {
|
|
258
|
+
await context.send("Welcome!");
|
|
259
|
+
// Optionally return a state for immediate transition
|
|
260
|
+
return "anotherState";
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
// Called when user sends a message
|
|
264
|
+
.onResponse(async (context, response) => {
|
|
265
|
+
// Return state name to transition, or void/undefined to stay
|
|
266
|
+
if (response === "yes") return "confirmed";
|
|
267
|
+
return "cancelled";
|
|
268
|
+
})
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## State Diagram
|
|
272
|
+
|
|
273
|
+
Auto-generated visualizations are updated on every state/transition change:
|
|
274
|
+
|
|
275
|
+
**`src/bot-diagram.md`:**
|
|
276
|
+
```markdown
|
|
277
|
+
# Bot State Diagram
|
|
278
|
+
|
|
279
|
+
```mermaid
|
|
280
|
+
stateDiagram-v2
|
|
281
|
+
idle --> welcome
|
|
282
|
+
welcome --> menu
|
|
283
|
+
menu --> welcome
|
|
284
|
+
menu --> idle
|
|
285
|
+
```
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**`src/bot-diagram.png`:** PNG image rendered by mermaid-cli.
|
|
289
|
+
|
|
290
|
+
## Database Configuration
|
|
291
|
+
|
|
292
|
+
### Switching Between SQLite and MySQL
|
|
293
|
+
|
|
294
|
+
**1. Update `prisma/schema.prisma`:**
|
|
295
|
+
```prisma
|
|
296
|
+
datasource db {
|
|
297
|
+
provider = "sqlite" // Change to "mysql" for production
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**2. Update `.env`:**
|
|
302
|
+
```bash
|
|
303
|
+
# SQLite (development)
|
|
304
|
+
DATABASE_URL="file:./dev.db"
|
|
305
|
+
|
|
306
|
+
# MySQL (production)
|
|
307
|
+
DATABASE_URL="mysql://user:password@localhost:3306/dbname"
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**3. Regenerate and migrate:**
|
|
311
|
+
```bash
|
|
312
|
+
npm run db:generate
|
|
313
|
+
npm run db:migrate
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Database Commands
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
npm run db:generate # Generate Prisma Client after schema changes
|
|
320
|
+
npm run db:migrate # Create and apply migrations (development)
|
|
321
|
+
npm run db:deploy # Apply migrations in production
|
|
322
|
+
npm run db:push # Push schema changes without migration files
|
|
323
|
+
npm run db:studio # Open Prisma Studio (database GUI)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Webhook Commands
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# Set webhook URL
|
|
330
|
+
npm run webhook:set -- https://your-domain.com/webhook
|
|
331
|
+
|
|
332
|
+
# Check webhook info
|
|
333
|
+
npm run webhook:info
|
|
334
|
+
|
|
335
|
+
# Delete webhook (switch back to polling)
|
|
336
|
+
npm run webhook:delete
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Database Schema
|
|
340
|
+
|
|
341
|
+
Users are persisted with:
|
|
342
|
+
- `telegramId` - Telegram user ID
|
|
343
|
+
- `chatId` - Telegram chat ID
|
|
344
|
+
- `currentState` - Current FSM state
|
|
345
|
+
- `stateData` - JSON data storage for user context (in separate `userInfo` relation)
|
|
346
|
+
|
|
347
|
+
### Prisma Schema
|
|
348
|
+
|
|
349
|
+
```prisma
|
|
350
|
+
model User {
|
|
351
|
+
id Int @id @default(autoincrement())
|
|
352
|
+
telegramId Int @unique
|
|
353
|
+
chatId Int
|
|
354
|
+
currentState String @default("idle")
|
|
355
|
+
updatedAt DateTime @updatedAt
|
|
356
|
+
info UserInfo?
|
|
357
|
+
|
|
358
|
+
@@index([currentState])
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
model UserInfo {
|
|
362
|
+
id Int @id @default(autoincrement())
|
|
363
|
+
userId Int @unique
|
|
364
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
365
|
+
stateData String @default("{}")
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Architecture
|
|
370
|
+
|
|
371
|
+
### State Persistence Flow
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
User sends message
|
|
375
|
+
↓
|
|
376
|
+
Load user from DB (by telegramId)
|
|
377
|
+
↓
|
|
378
|
+
Execute onResponse for current state
|
|
379
|
+
↓
|
|
380
|
+
Handler returns nextState (or void)
|
|
381
|
+
↓
|
|
382
|
+
Update DB with new state
|
|
383
|
+
↓
|
|
384
|
+
Execute onEnter for new state
|
|
385
|
+
↓
|
|
386
|
+
Send prompt to user
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Compact FSM Pattern
|
|
390
|
+
|
|
391
|
+
Instead of defining every state in XState:
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
// Traditional - verbose
|
|
395
|
+
states: {
|
|
396
|
+
idle: { on: { START: 'welcome' } },
|
|
397
|
+
welcome: { on: { NEXT: 'menu' } },
|
|
398
|
+
// ... every state
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Telemeister - compact
|
|
402
|
+
states: {
|
|
403
|
+
active: {
|
|
404
|
+
on: {
|
|
405
|
+
TRANSITION: {
|
|
406
|
+
actions: assign({ currentState: ({ event }) => event.toState }),
|
|
407
|
+
target: 'active',
|
|
408
|
+
reenter: true, // Triggers onEnter
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
The actual state value is stored in `context.currentState`. The `bot.json` file is the source of truth for valid states and transitions.
|
|
416
|
+
|
|
417
|
+
## Development
|
|
418
|
+
|
|
419
|
+
### Developing the Telemeister Framework
|
|
420
|
+
|
|
421
|
+
This repository contains the Telemeister framework source code.
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
# Clone and install
|
|
425
|
+
git clone <repo>
|
|
426
|
+
cd telemeister
|
|
427
|
+
npm install
|
|
428
|
+
|
|
429
|
+
# Build
|
|
430
|
+
npm run build
|
|
431
|
+
|
|
432
|
+
# Run CLI locally
|
|
433
|
+
npm run telemeister:state:add -- settings
|
|
434
|
+
|
|
435
|
+
# Or use tsx directly
|
|
436
|
+
npx tsx src/cli/cli.ts state:add settings
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Publishing
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
npm run build
|
|
443
|
+
npm version patch
|
|
444
|
+
npm publish
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Technology Stack
|
|
448
|
+
|
|
449
|
+
- **[Grammy](https://grammy.dev)**: Modern Telegram Bot API framework with excellent TypeScript support
|
|
450
|
+
- **[XState](https://stately.ai/docs/xstate)**: State machines for complex conversation flows
|
|
451
|
+
- **[Prisma ORM 7.x](https://prisma.io)**: Database toolkit with driver adapters
|
|
452
|
+
- **Driver Adapters**: Required adapters for database connections (`@prisma/adapter-better-sqlite3`, `@prisma/adapter-mariadb`)
|
|
453
|
+
- **ESM-Only**: Native ES module support
|
|
454
|
+
- **Generated Client in Source**: Better IDE support and file watching
|
|
455
|
+
- **[EJS](https://ejs.co)**: Template engine for handler generation
|
|
456
|
+
- **[Mermaid CLI](https://github.com/mermaid-js/mermaid-cli)**: Diagram generation
|
|
457
|
+
|
|
458
|
+
## License
|
|
459
|
+
|
|
460
|
+
MIT
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Telemeister CLI Entry Point
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname, join } from 'path';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const cliPath = join(__dirname, '..', 'dist', 'cli', 'index.js');
|
|
14
|
+
|
|
15
|
+
import(cliPath).catch((err) => {
|
|
16
|
+
console.error('Failed to load CLI:', err.message);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grammy-based Polling Mode Implementation
|
|
3
|
+
*
|
|
4
|
+
* Uses Grammy Bot API library with database-backed sessions.
|
|
5
|
+
*/
|
|
6
|
+
import { Bot, type Context } from 'grammy';
|
|
7
|
+
import { type SessionData } from './session.js';
|
|
8
|
+
interface BotContext extends Context {
|
|
9
|
+
session: SessionData;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create and configure the Grammy bot
|
|
13
|
+
*/
|
|
14
|
+
export declare function createBot(botToken: string): Bot<BotContext>;
|
|
15
|
+
/**
|
|
16
|
+
* Start the bot in polling mode
|
|
17
|
+
*/
|
|
18
|
+
export declare function startPollingMode(botToken: string): Promise<void>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=polling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.d.ts","sourceRoot":"","sources":["../../src/bot/polling.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,GAAG,EAAW,KAAK,OAAO,EAAE,MAAM,QAAQ,CAAC;AAGpD,OAAO,EAA4C,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAI1F,UAAU,UAAW,SAAQ,OAAO;IAClC,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,CAyD3D;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtE"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grammy-based Polling Mode Implementation
|
|
3
|
+
*
|
|
4
|
+
* Uses Grammy Bot API library with database-backed sessions.
|
|
5
|
+
*/
|
|
6
|
+
import { Bot, session } from 'grammy';
|
|
7
|
+
import { appBuilder } from '../core/index.js';
|
|
8
|
+
import { PrismaSessionAdapter, getOrCreateSession } from './session.js';
|
|
9
|
+
/**
|
|
10
|
+
* Create and configure the Grammy bot
|
|
11
|
+
*/
|
|
12
|
+
export function createBot(botToken) {
|
|
13
|
+
const bot = new Bot(botToken);
|
|
14
|
+
// Install session middleware with Prisma adapter
|
|
15
|
+
bot.use(session({
|
|
16
|
+
initial: () => ({
|
|
17
|
+
currentState: 'idle',
|
|
18
|
+
stateData: {},
|
|
19
|
+
}),
|
|
20
|
+
storage: new PrismaSessionAdapter(),
|
|
21
|
+
getSessionKey: (ctx) => ctx.from?.id.toString(),
|
|
22
|
+
}));
|
|
23
|
+
// Ensure user exists in database on each update
|
|
24
|
+
bot.use(async (ctx, next) => {
|
|
25
|
+
if (!ctx.from || !ctx.chat) {
|
|
26
|
+
return next();
|
|
27
|
+
}
|
|
28
|
+
const telegramId = ctx.from.id;
|
|
29
|
+
const chatId = ctx.chat.id;
|
|
30
|
+
// Get or create user session
|
|
31
|
+
const userSession = await getOrCreateSession(telegramId, chatId);
|
|
32
|
+
ctx.session = userSession;
|
|
33
|
+
return next();
|
|
34
|
+
});
|
|
35
|
+
// Handle text messages
|
|
36
|
+
bot.on('message:text', async (ctx) => {
|
|
37
|
+
const text = ctx.message.text;
|
|
38
|
+
const session = ctx.session;
|
|
39
|
+
// Create handler context compatible with existing handlers
|
|
40
|
+
const handlerContext = createHandlerContext(ctx, session);
|
|
41
|
+
// Execute onResponse handler for current state
|
|
42
|
+
const nextState = await appBuilder.executeOnResponse(session.currentState, handlerContext, text);
|
|
43
|
+
// Handle state transition
|
|
44
|
+
if (nextState && nextState !== session.currentState) {
|
|
45
|
+
await transitionToState(ctx, session, nextState, handlerContext);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Save any state data changes
|
|
49
|
+
session.stateData =
|
|
50
|
+
handlerContext.getData('__all') || session.stateData;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return bot;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Start the bot in polling mode
|
|
57
|
+
*/
|
|
58
|
+
export async function startPollingMode(botToken) {
|
|
59
|
+
const bot = createBot(botToken);
|
|
60
|
+
console.log('🤖 Bot started in polling mode');
|
|
61
|
+
// Start polling
|
|
62
|
+
await bot.start({
|
|
63
|
+
onStart: () => {
|
|
64
|
+
console.log('✅ Bot is running and polling for updates...');
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create a handler context compatible with existing handlers
|
|
70
|
+
*/
|
|
71
|
+
function createHandlerContext(ctx, session) {
|
|
72
|
+
// Local state data copy for modifications
|
|
73
|
+
const localStateData = { ...session.stateData };
|
|
74
|
+
return {
|
|
75
|
+
userId: session.userId || 0,
|
|
76
|
+
telegramId: ctx.from?.id || 0,
|
|
77
|
+
chatId: ctx.chat?.id || 0,
|
|
78
|
+
currentState: session.currentState,
|
|
79
|
+
send: async (text) => {
|
|
80
|
+
await ctx.reply(text, { parse_mode: 'Markdown' });
|
|
81
|
+
},
|
|
82
|
+
setData: (key, value) => {
|
|
83
|
+
localStateData[key] = value;
|
|
84
|
+
},
|
|
85
|
+
getData: (key) => {
|
|
86
|
+
if (key === '__all') {
|
|
87
|
+
return localStateData;
|
|
88
|
+
}
|
|
89
|
+
return localStateData[key];
|
|
90
|
+
},
|
|
91
|
+
transition: async (toState) => {
|
|
92
|
+
await transitionToState(ctx, session, toState, createHandlerContext(ctx, session));
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Transition to a new state and execute onEnter handler
|
|
98
|
+
*/
|
|
99
|
+
async function transitionToState(ctx, session, toState, handlerContext) {
|
|
100
|
+
// Update session state
|
|
101
|
+
session.currentState = toState;
|
|
102
|
+
// Execute onEnter handler for new state
|
|
103
|
+
const enterNextState = await appBuilder.executeOnEnter(toState, handlerContext);
|
|
104
|
+
// Save state data changes
|
|
105
|
+
session.stateData = handlerContext.getData('__all') || session.stateData;
|
|
106
|
+
// Handle chained transition from onEnter
|
|
107
|
+
if (enterNextState && enterNextState !== toState) {
|
|
108
|
+
// Create fresh context for the next state
|
|
109
|
+
const nextContext = createHandlerContext(ctx, session);
|
|
110
|
+
const nextState = enterNextState;
|
|
111
|
+
nextContext.currentState = nextState;
|
|
112
|
+
await transitionToState(ctx, session, nextState, nextContext);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=polling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polling.js","sourceRoot":"","sources":["../../src/bot/polling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grammy Session Adapter for Prisma Database
|
|
3
|
+
*
|
|
4
|
+
* This adapter integrates Grammy's session system with the Prisma database,
|
|
5
|
+
* allowing user state to persist across restarts.
|
|
6
|
+
*/
|
|
7
|
+
import type { StorageAdapter } from 'grammy';
|
|
8
|
+
/**
|
|
9
|
+
* Session data stored per user
|
|
10
|
+
*/
|
|
11
|
+
export interface SessionData {
|
|
12
|
+
/** Current FSM state */
|
|
13
|
+
currentState: string;
|
|
14
|
+
/** User-specific data storage */
|
|
15
|
+
stateData: Record<string, unknown>;
|
|
16
|
+
/** Internal user ID from database */
|
|
17
|
+
userId?: number;
|
|
18
|
+
/** Telegram chat ID */
|
|
19
|
+
chatId?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Prisma-backed session storage adapter for Grammy
|
|
23
|
+
*
|
|
24
|
+
* This adapter loads/saves session data from/to the database,
|
|
25
|
+
* keyed by Telegram user ID.
|
|
26
|
+
*/
|
|
27
|
+
export declare class PrismaSessionAdapter implements StorageAdapter<SessionData> {
|
|
28
|
+
/**
|
|
29
|
+
* Read session data from database
|
|
30
|
+
* @param key - Telegram user ID (as string)
|
|
31
|
+
*/
|
|
32
|
+
read(key: string): Promise<SessionData | undefined>;
|
|
33
|
+
/**
|
|
34
|
+
* Write session data to database
|
|
35
|
+
* @param key - Telegram user ID (as string)
|
|
36
|
+
* @param value - Session data to save
|
|
37
|
+
*/
|
|
38
|
+
write(key: string, value: SessionData): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Delete session data (not typically used in bots)
|
|
41
|
+
* @param key - Telegram user ID (as string)
|
|
42
|
+
*/
|
|
43
|
+
delete(key: string): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get or create user session
|
|
47
|
+
* This helper ensures a user exists in the database before processing
|
|
48
|
+
*/
|
|
49
|
+
export declare function getOrCreateSession(telegramId: number, chatId: number): Promise<SessionData>;
|
|
50
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/bot/session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAG7C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,wBAAwB;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uBAAuB;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,cAAc,CAAC,WAAW,CAAC;IACtE;;;OAGG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAmBzD;;;;OAIG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3D;;;OAGG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CASzC;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8BjG"}
|