create-bunspace 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/README.md +181 -0
- package/dist/bin.js +5755 -0
- package/dist/templates/monorepo/CLAUDE.md +164 -0
- package/dist/templates/monorepo/LICENSE +21 -0
- package/dist/templates/monorepo/MUST-FOLLOW-GUIDELINES.md +269 -0
- package/dist/templates/monorepo/README.md +74 -0
- package/dist/templates/monorepo/SYNC_VERIFICATION.md +1 -0
- package/dist/templates/monorepo/apps/example/package.json +19 -0
- package/dist/templates/monorepo/apps/example/src/index.ts +23 -0
- package/dist/templates/monorepo/apps/example/src/types/index.ts +7 -0
- package/dist/templates/monorepo/apps/example/src/utils/index.ts +7 -0
- package/dist/templates/monorepo/core/packages/main/package.json +41 -0
- package/dist/templates/monorepo/core/packages/main/rolldown.config.ts +24 -0
- package/dist/templates/monorepo/core/packages/main/src/index.ts +80 -0
- package/dist/templates/monorepo/core/packages/main/src/types/constants.ts +15 -0
- package/dist/templates/monorepo/core/packages/main/src/types/index.ts +8 -0
- package/dist/templates/monorepo/core/packages/main/src/types/main.types.ts +25 -0
- package/dist/templates/monorepo/core/packages/main/src/utils/index.ts +5 -0
- package/dist/templates/monorepo/core/packages/utils/package.json +43 -0
- package/dist/templates/monorepo/core/packages/utils/rolldown.config.ts +34 -0
- package/dist/templates/monorepo/core/packages/utils/src/index.ts +2 -0
- package/dist/templates/monorepo/core/packages/utils/src/logger.ts +68 -0
- package/dist/templates/monorepo/core/packages/utils/src/result.ts +146 -0
- package/dist/templates/monorepo/core/packages/utils/src/types/constants.ts +15 -0
- package/dist/templates/monorepo/core/packages/utils/src/types/index.ts +8 -0
- package/dist/templates/monorepo/core/packages/utils/src/types/utils.types.ts +32 -0
- package/dist/templates/monorepo/core/packages/utils/src/utils/index.ts +5 -0
- package/dist/templates/monorepo/oxlint.json +14 -0
- package/dist/templates/monorepo/package.json +39 -0
- package/dist/templates/monorepo/tsconfig.json +35 -0
- package/dist/templates/telegram-bot/.oxlintrc.json +33 -0
- package/dist/templates/telegram-bot/.prettierignore +5 -0
- package/dist/templates/telegram-bot/.prettierrc +26 -0
- package/dist/templates/telegram-bot/CLAUDE.deploy.md +356 -0
- package/dist/templates/telegram-bot/CLAUDE.dev.md +266 -0
- package/dist/templates/telegram-bot/CLAUDE.md +280 -0
- package/dist/templates/telegram-bot/Dockerfile +46 -0
- package/dist/templates/telegram-bot/README.md +245 -0
- package/dist/templates/telegram-bot/apps/.gitkeep +0 -0
- package/dist/templates/telegram-bot/bun.lock +208 -0
- package/dist/templates/telegram-bot/core/.env.example +71 -0
- package/dist/templates/telegram-bot/core/README.md +1067 -0
- package/dist/templates/telegram-bot/core/package.json +15 -0
- package/dist/templates/telegram-bot/core/src/config/env.ts +131 -0
- package/dist/templates/telegram-bot/core/src/config/index.ts +97 -0
- package/dist/templates/telegram-bot/core/src/config/logging.ts +110 -0
- package/dist/templates/telegram-bot/core/src/handlers/control.ts +85 -0
- package/dist/templates/telegram-bot/core/src/handlers/health.ts +83 -0
- package/dist/templates/telegram-bot/core/src/handlers/logs.ts +126 -0
- package/dist/templates/telegram-bot/core/src/index.ts +161 -0
- package/dist/templates/telegram-bot/core/src/middleware/auth.ts +41 -0
- package/dist/templates/telegram-bot/core/src/middleware/error-handler.ts +41 -0
- package/dist/templates/telegram-bot/core/src/middleware/logging.ts +1 -0
- package/dist/templates/telegram-bot/core/src/middleware/topics.ts +55 -0
- package/dist/templates/telegram-bot/core/src/types/bot.ts +92 -0
- package/dist/templates/telegram-bot/core/src/types/constants.ts +50 -0
- package/dist/templates/telegram-bot/core/src/types/result.ts +1 -0
- package/dist/templates/telegram-bot/core/src/utils/bot-manager.test.ts +111 -0
- package/dist/templates/telegram-bot/core/src/utils/bot-manager.ts +201 -0
- package/dist/templates/telegram-bot/core/src/utils/commands.ts +63 -0
- package/dist/templates/telegram-bot/core/src/utils/formatters.ts +82 -0
- package/dist/templates/telegram-bot/core/src/utils/instance-manager.ts +189 -0
- package/dist/templates/telegram-bot/core/src/utils/memory.ts +33 -0
- package/dist/templates/telegram-bot/core/src/utils/result.ts +26 -0
- package/dist/templates/telegram-bot/core/src/utils/telegram.ts +31 -0
- package/dist/templates/telegram-bot/core/src/utils/type-guards.ts +71 -0
- package/dist/templates/telegram-bot/core/tsconfig.json +9 -0
- package/dist/templates/telegram-bot/docker-compose.yml +37 -0
- package/dist/templates/telegram-bot/docs/cli-commands.md +377 -0
- package/dist/templates/telegram-bot/docs/development.md +363 -0
- package/dist/templates/telegram-bot/docs/environment.md +460 -0
- package/dist/templates/telegram-bot/docs/examples/middleware-auth.md +335 -0
- package/dist/templates/telegram-bot/docs/examples/simple-command.md +207 -0
- package/dist/templates/telegram-bot/docs/examples/webhook-setup.md +362 -0
- package/dist/templates/telegram-bot/docs/getting-started.md +223 -0
- package/dist/templates/telegram-bot/docs/troubleshooting.md +489 -0
- package/dist/templates/telegram-bot/package.json +49 -0
- package/dist/templates/telegram-bot/packages/utils/package.json +12 -0
- package/dist/templates/telegram-bot/packages/utils/src/index.ts +2 -0
- package/dist/templates/telegram-bot/packages/utils/src/logger.ts +72 -0
- package/dist/templates/telegram-bot/packages/utils/src/result.ts +80 -0
- package/dist/templates/telegram-bot/tools/README.md +47 -0
- package/dist/templates/telegram-bot/tools/commands/doctor.ts +460 -0
- package/dist/templates/telegram-bot/tools/commands/index.ts +35 -0
- package/dist/templates/telegram-bot/tools/commands/ngrok.ts +207 -0
- package/dist/templates/telegram-bot/tools/commands/setup.ts +368 -0
- package/dist/templates/telegram-bot/tools/commands/status.ts +140 -0
- package/dist/templates/telegram-bot/tools/index.ts +16 -0
- package/dist/templates/telegram-bot/tools/package.json +12 -0
- package/dist/templates/telegram-bot/tools/utils/index.ts +13 -0
- package/dist/templates/telegram-bot/tsconfig.json +22 -0
- package/dist/templates/telegram-bot/vitest.config.ts +29 -0
- package/package.json +35 -0
- package/templates/monorepo/CLAUDE.md +164 -0
- package/templates/monorepo/LICENSE +21 -0
- package/templates/monorepo/MUST-FOLLOW-GUIDELINES.md +269 -0
- package/templates/monorepo/README.md +74 -0
- package/templates/monorepo/apps/example/package.json +19 -0
- package/templates/monorepo/apps/example/src/index.ts +23 -0
- package/templates/monorepo/apps/example/src/types/index.ts +7 -0
- package/templates/monorepo/apps/example/src/utils/index.ts +7 -0
- package/templates/monorepo/core/packages/main/package.json +41 -0
- package/templates/monorepo/core/packages/main/rolldown.config.ts +24 -0
- package/templates/monorepo/core/packages/main/src/index.ts +80 -0
- package/templates/monorepo/core/packages/main/src/types/constants.ts +15 -0
- package/templates/monorepo/core/packages/main/src/types/index.ts +8 -0
- package/templates/monorepo/core/packages/main/src/types/main.types.ts +25 -0
- package/templates/monorepo/core/packages/main/src/utils/index.ts +5 -0
- package/templates/monorepo/core/packages/utils/package.json +43 -0
- package/templates/monorepo/core/packages/utils/rolldown.config.ts +34 -0
- package/templates/monorepo/core/packages/utils/src/index.ts +2 -0
- package/templates/monorepo/core/packages/utils/src/logger.ts +68 -0
- package/templates/monorepo/core/packages/utils/src/result.ts +146 -0
- package/templates/monorepo/core/packages/utils/src/types/constants.ts +15 -0
- package/templates/monorepo/core/packages/utils/src/types/index.ts +8 -0
- package/templates/monorepo/core/packages/utils/src/types/utils.types.ts +32 -0
- package/templates/monorepo/core/packages/utils/src/utils/index.ts +5 -0
- package/templates/monorepo/oxlint.json +14 -0
- package/templates/monorepo/package.json +39 -0
- package/templates/monorepo/tsconfig.json +35 -0
- package/templates/telegram-bot/.oxlintrc.json +33 -0
- package/templates/telegram-bot/.prettierignore +5 -0
- package/templates/telegram-bot/.prettierrc +26 -0
- package/templates/telegram-bot/CLAUDE.deploy.md +356 -0
- package/templates/telegram-bot/CLAUDE.dev.md +266 -0
- package/templates/telegram-bot/CLAUDE.md +280 -0
- package/templates/telegram-bot/Dockerfile +46 -0
- package/templates/telegram-bot/README.md +245 -0
- package/templates/telegram-bot/apps/.gitkeep +0 -0
- package/templates/telegram-bot/bun.lock +208 -0
- package/templates/telegram-bot/core/.env.example +71 -0
- package/templates/telegram-bot/core/README.md +1067 -0
- package/templates/telegram-bot/core/package.json +15 -0
- package/templates/telegram-bot/core/src/config/env.ts +131 -0
- package/templates/telegram-bot/core/src/config/index.ts +97 -0
- package/templates/telegram-bot/core/src/config/logging.ts +110 -0
- package/templates/telegram-bot/core/src/handlers/control.ts +85 -0
- package/templates/telegram-bot/core/src/handlers/health.ts +83 -0
- package/templates/telegram-bot/core/src/handlers/logs.ts +126 -0
- package/templates/telegram-bot/core/src/index.ts +161 -0
- package/templates/telegram-bot/core/src/middleware/auth.ts +41 -0
- package/templates/telegram-bot/core/src/middleware/error-handler.ts +41 -0
- package/templates/telegram-bot/core/src/middleware/logging.ts +1 -0
- package/templates/telegram-bot/core/src/middleware/topics.ts +55 -0
- package/templates/telegram-bot/core/src/types/bot.ts +92 -0
- package/templates/telegram-bot/core/src/types/constants.ts +50 -0
- package/templates/telegram-bot/core/src/types/result.ts +1 -0
- package/templates/telegram-bot/core/src/utils/bot-manager.test.ts +111 -0
- package/templates/telegram-bot/core/src/utils/bot-manager.ts +201 -0
- package/templates/telegram-bot/core/src/utils/commands.ts +63 -0
- package/templates/telegram-bot/core/src/utils/formatters.ts +82 -0
- package/templates/telegram-bot/core/src/utils/instance-manager.ts +189 -0
- package/templates/telegram-bot/core/src/utils/memory.ts +33 -0
- package/templates/telegram-bot/core/src/utils/result.ts +26 -0
- package/templates/telegram-bot/core/src/utils/telegram.ts +31 -0
- package/templates/telegram-bot/core/src/utils/type-guards.ts +71 -0
- package/templates/telegram-bot/core/tsconfig.json +9 -0
- package/templates/telegram-bot/docker-compose.yml +37 -0
- package/templates/telegram-bot/docs/cli-commands.md +377 -0
- package/templates/telegram-bot/docs/development.md +363 -0
- package/templates/telegram-bot/docs/environment.md +460 -0
- package/templates/telegram-bot/docs/examples/middleware-auth.md +335 -0
- package/templates/telegram-bot/docs/examples/simple-command.md +207 -0
- package/templates/telegram-bot/docs/examples/webhook-setup.md +362 -0
- package/templates/telegram-bot/docs/getting-started.md +223 -0
- package/templates/telegram-bot/docs/troubleshooting.md +489 -0
- package/templates/telegram-bot/package.json +49 -0
- package/templates/telegram-bot/packages/utils/package.json +12 -0
- package/templates/telegram-bot/packages/utils/src/index.ts +2 -0
- package/templates/telegram-bot/packages/utils/src/logger.ts +72 -0
- package/templates/telegram-bot/packages/utils/src/result.ts +80 -0
- package/templates/telegram-bot/tools/README.md +47 -0
- package/templates/telegram-bot/tools/commands/doctor.ts +460 -0
- package/templates/telegram-bot/tools/commands/index.ts +35 -0
- package/templates/telegram-bot/tools/commands/ngrok.ts +207 -0
- package/templates/telegram-bot/tools/commands/setup.ts +368 -0
- package/templates/telegram-bot/tools/commands/status.ts +140 -0
- package/templates/telegram-bot/tools/index.ts +16 -0
- package/templates/telegram-bot/tools/package.json +12 -0
- package/templates/telegram-bot/tools/utils/index.ts +13 -0
- package/templates/telegram-bot/tsconfig.json +22 -0
- package/templates/telegram-bot/vitest.config.ts +29 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# Example: Auth Middleware
|
|
2
|
+
|
|
3
|
+
Ejemplo de cómo crear middleware de autenticación para comandos restringidos.
|
|
4
|
+
|
|
5
|
+
## Middleware: Solo Usuarios Autorizados
|
|
6
|
+
|
|
7
|
+
### Paso 1: Crear Middleware
|
|
8
|
+
|
|
9
|
+
**Archivo**: `core/src/middleware/auth-only.ts`
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import type { Context, Middleware } from 'telegraf'
|
|
13
|
+
import { botLogger, badge } from '@mks2508/telegram-bot-utils'
|
|
14
|
+
|
|
15
|
+
interface AuthOnlyOptions {
|
|
16
|
+
authorizedIds: Set<string>
|
|
17
|
+
allowGroups?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function authOnly(options: AuthOnlyOptions): Middleware<Context> {
|
|
21
|
+
const { authorizedIds, allowGroups = false } = options
|
|
22
|
+
|
|
23
|
+
return async (ctx, next) => {
|
|
24
|
+
const userId = ctx.from?.id.toString()
|
|
25
|
+
|
|
26
|
+
// Verificar usuario
|
|
27
|
+
if (!userId) {
|
|
28
|
+
botLogger.warn(`${badge('AUTH')} No user ID in context`)
|
|
29
|
+
await ctx.reply('⛔ Could not identify user')
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Verificar autorización
|
|
34
|
+
if (!authorizedIds.has(userId)) {
|
|
35
|
+
botLogger.warn(`${badge('AUTH')} Unauthorized access attempt`, {
|
|
36
|
+
user: userId,
|
|
37
|
+
command: ctx.message?.text,
|
|
38
|
+
})
|
|
39
|
+
await ctx.reply('⛔ You are not authorized to use this command')
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Usuario autorizado, continuar
|
|
44
|
+
botLogger.info(`${badge('AUTH')} User authorized`, { user: userId })
|
|
45
|
+
return next()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Paso 2: Crear Configuración de Usuarios
|
|
51
|
+
|
|
52
|
+
**Archivo**: `core/src/config/auth.ts`
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { getConfig } from './index.js'
|
|
56
|
+
|
|
57
|
+
export function getAuthorizedUsers(): Set<string> {
|
|
58
|
+
const config = getConfig()
|
|
59
|
+
const authorizedIds = config.authorizedUserIds
|
|
60
|
+
|
|
61
|
+
if (!authorizedIds) {
|
|
62
|
+
return new Set()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return new Set(authorizedIds.split(',').map((id) => id.trim()))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// IDs para desarrollo
|
|
69
|
+
export const DEV_USER_IDS = new Set([
|
|
70
|
+
'123456789', // Reemplaza con tu ID
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
// IDs para producción (desde env)
|
|
74
|
+
export function getProdUserIds(): Set<string> {
|
|
75
|
+
return getAuthorizedUsers()
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Paso 3: Usar en Comandos
|
|
80
|
+
|
|
81
|
+
**Archivo**: `core/src/handlers/admin.ts`
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import type { Context } from 'telegraf'
|
|
85
|
+
import { authOnly, getProdUserIds } from '../middleware/auth-only.js'
|
|
86
|
+
import { botLogger } from '@mks2508/telegram-bot-utils'
|
|
87
|
+
|
|
88
|
+
export async function handleAdmin(ctx: Context): Promise<void> {
|
|
89
|
+
// Este comando solo funciona si el middleware auth pasa
|
|
90
|
+
await ctx.reply('🔐 Admin panel')
|
|
91
|
+
await ctx.reply('Available commands: /users, /stats, /broadcast')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Registrar con middleware
|
|
95
|
+
export function registerAdminCommands(bot: any) {
|
|
96
|
+
const prodUserIds = getProdUserIds()
|
|
97
|
+
|
|
98
|
+
bot.command('admin', authOnly({ authorizedIds: prodUserIds }), handleAdmin)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**En `core/src/index.ts`**:
|
|
103
|
+
```typescript
|
|
104
|
+
import { registerAdminCommands } from './handlers/admin.js'
|
|
105
|
+
|
|
106
|
+
// ... después de otros comandos
|
|
107
|
+
registerAdminCommands(bot)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Middleware: Chat Type
|
|
111
|
+
|
|
112
|
+
Solo permitir comandos en privados (no grupos):
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import type { Context, Middleware } from 'telegraf'
|
|
116
|
+
|
|
117
|
+
export function privateOnly(): Middleware<Context> {
|
|
118
|
+
return async (ctx, next) => {
|
|
119
|
+
const chatType = ctx.chat?.type
|
|
120
|
+
|
|
121
|
+
if (chatType !== 'private') {
|
|
122
|
+
await ctx.reply('⚠️ This command only works in private chat')
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return next()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Usar:
|
|
132
|
+
```typescript
|
|
133
|
+
bot.command('secret', privateOnly(), handleSecret)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Middleware: Group Only
|
|
137
|
+
|
|
138
|
+
Solo permitir comandos en grupos:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import type { Context, Middleware } from 'telegraf'
|
|
142
|
+
|
|
143
|
+
export function groupOnly(): Middleware<Context> {
|
|
144
|
+
return async (ctx, next) => {
|
|
145
|
+
const chatType = ctx.chat?.type
|
|
146
|
+
|
|
147
|
+
if (chatType !== 'group' && chatType !== 'supergroup') {
|
|
148
|
+
await ctx.reply('⚠️ This command only works in groups')
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return next()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Middleware: Admin del Chat
|
|
158
|
+
|
|
159
|
+
Solo permitir admins del chat:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import type { Context, Middleware } from 'telegraf'
|
|
163
|
+
|
|
164
|
+
export function chatAdminOnly(): Middleware<Context> {
|
|
165
|
+
return async (ctx, next) => {
|
|
166
|
+
const chatId = ctx.chat?.id
|
|
167
|
+
const userId = ctx.from?.id
|
|
168
|
+
|
|
169
|
+
if (!chatId || !userId) {
|
|
170
|
+
await ctx.reply('⚠️ Could not identify chat or user')
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
// Verificar si el usuario es admin del chat
|
|
176
|
+
const member = await ctx.getChatMember(userId)
|
|
177
|
+
|
|
178
|
+
if (
|
|
179
|
+
member.status !== 'creator' &&
|
|
180
|
+
member.status !== 'administrator'
|
|
181
|
+
) {
|
|
182
|
+
await ctx.reply('⛔ Only chat admins can use this command')
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return next()
|
|
187
|
+
} catch (error) {
|
|
188
|
+
botLogger.error('Failed to check chat admin status', error)
|
|
189
|
+
await ctx.reply('⚠️ Could not verify admin status')
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Middleware: Rate Limiting
|
|
197
|
+
|
|
198
|
+
Limitar frecuencia de comandos por usuario:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
import type { Context, Middleware } from 'telegraf'
|
|
202
|
+
|
|
203
|
+
interface RateLimitEntry {
|
|
204
|
+
count: number
|
|
205
|
+
resetTime: number
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const rateLimits = new Map<string, RateLimitEntry>()
|
|
209
|
+
|
|
210
|
+
interface RateLimitOptions {
|
|
211
|
+
maxRequests: number
|
|
212
|
+
windowMs: number
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function rateLimit(options: RateLimitOptions): Middleware<Context> {
|
|
216
|
+
const { maxRequests, windowMs } = options
|
|
217
|
+
|
|
218
|
+
return async (ctx, next) => {
|
|
219
|
+
const userId = ctx.from?.id.toString()
|
|
220
|
+
|
|
221
|
+
if (!userId) {
|
|
222
|
+
return next()
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const now = Date.now()
|
|
226
|
+
const entry = rateLimits.get(userId)
|
|
227
|
+
|
|
228
|
+
if (!entry || now > entry.resetTime) {
|
|
229
|
+
// Nueva ventana
|
|
230
|
+
rateLimits.set(userId, {
|
|
231
|
+
count: 1,
|
|
232
|
+
resetTime: now + windowMs,
|
|
233
|
+
})
|
|
234
|
+
return next()
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (entry.count >= maxRequests) {
|
|
238
|
+
const waitTime = Math.ceil((entry.resetTime - now) / 1000)
|
|
239
|
+
await ctx.reply(
|
|
240
|
+
`⚠️ Rate limit exceeded. Wait ${waitTime}s before trying again.`
|
|
241
|
+
)
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
entry.count++
|
|
246
|
+
return next()
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Usar:
|
|
252
|
+
```typescript
|
|
253
|
+
// Máximo 5 comandos por minuto
|
|
254
|
+
bot.command('search', rateLimit({ maxRequests: 5, windowMs: 60000 }), handleSearch)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Middleware Combinado
|
|
258
|
+
|
|
259
|
+
Combinar múltiples middleware:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
bot.command(
|
|
263
|
+
'admin',
|
|
264
|
+
authOnly({ authorizedIds: getProdUserIds() }),
|
|
265
|
+
chatAdminOnly(),
|
|
266
|
+
rateLimit({ maxRequests: 10, windowMs: 60000 }),
|
|
267
|
+
handleAdmin
|
|
268
|
+
)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Obtener User IDs
|
|
272
|
+
|
|
273
|
+
### Método 1: Usar el Comando /whoami
|
|
274
|
+
|
|
275
|
+
**Archivo**: `core/src/handlers/debug.ts`
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
export async function handleWhoami(ctx: Context): Promise<void> {
|
|
279
|
+
const user = ctx.from
|
|
280
|
+
const chat = ctx.chat
|
|
281
|
+
|
|
282
|
+
const info = [
|
|
283
|
+
`👤 User Info:`,
|
|
284
|
+
`ID: ${user?.id}`,
|
|
285
|
+
`Username: @${user?.username ?? 'none'}`,
|
|
286
|
+
`First Name: ${user?.first_name ?? 'none'}`,
|
|
287
|
+
`Last Name: ${user?.last_name ?? 'none'}`,
|
|
288
|
+
```,
|
|
289
|
+
`💬 Chat Info:`,
|
|
290
|
+
`ID: ${chat?.id}`,
|
|
291
|
+
`Type: ${chat?.type}`,
|
|
292
|
+
`Title: ${chat?.title ?? 'none'}`,
|
|
293
|
+
].join('\n')
|
|
294
|
+
|
|
295
|
+
await ctx.reply(info)
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Método 2: Usar @GetTelegraphBot
|
|
300
|
+
|
|
301
|
+
1. Enviar un mensaje al bot
|
|
302
|
+
2. Forward el mensaje a @GetTelegraphBot
|
|
303
|
+
3. El bot responde con tu ID
|
|
304
|
+
|
|
305
|
+
### Método 3: Desde Logs
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
bun run dev
|
|
309
|
+
# Enviar cualquier comando al bot
|
|
310
|
+
# Ver el log:
|
|
311
|
+
[Cmd] ℹ /start from user 123456789
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Configurar IDs Autorizados
|
|
315
|
+
|
|
316
|
+
En `core/.env.local`:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
# IDs separados por coma
|
|
320
|
+
TG_AUTHORIZED_USER_IDS=123456789,987654321
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Resumen
|
|
324
|
+
|
|
325
|
+
1. **Crear middleware** en `core/src/middleware/`
|
|
326
|
+
2. **Definir opciones** (authorized IDs, rate limits, etc.)
|
|
327
|
+
3. **Aplicar a comandos** en `core/src/index.ts`
|
|
328
|
+
4. **Obtener user IDs** con /whoami o @GetTelegraphBot
|
|
329
|
+
5. **Configurar IDs** en `.env.local`
|
|
330
|
+
|
|
331
|
+
## Próximos Pasos
|
|
332
|
+
|
|
333
|
+
- [Simple Command Example](./simple-command.md) - Crear comandos
|
|
334
|
+
- [Webhook Setup Example](./webhook-setup.md) - Configurar webhook
|
|
335
|
+
- [Development Guide](../development.md) - Más middleware patterns
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Example: Simple Command
|
|
2
|
+
|
|
3
|
+
Ejemplo completo de cómo agregar un comando simple al bot.
|
|
4
|
+
|
|
5
|
+
## Comando: `/echo`
|
|
6
|
+
|
|
7
|
+
Repite el mensaje que el usuario envía.
|
|
8
|
+
|
|
9
|
+
## Paso 1: Crear Handler
|
|
10
|
+
|
|
11
|
+
**Archivo**: `core/src/handlers/echo.ts`
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import type { Context } from 'telegraf'
|
|
15
|
+
import { botLogger, badge, kv } from '@mks2508/telegram-bot-utils'
|
|
16
|
+
|
|
17
|
+
export async function handleEcho(ctx: Context): Promise<void> {
|
|
18
|
+
const message = ctx.message
|
|
19
|
+
const text = message?.text ?? ''
|
|
20
|
+
|
|
21
|
+
// Extraer argumentos (todo después de /echo)
|
|
22
|
+
const args = text.split(' ').slice(1).join(' ')
|
|
23
|
+
|
|
24
|
+
if (!args) {
|
|
25
|
+
await ctx.reply('Usage: /echo <message>')
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Log el comando
|
|
30
|
+
botLogger.info(`${badge('CMD')} /echo`, kv({
|
|
31
|
+
user: ctx.from?.id,
|
|
32
|
+
message: args,
|
|
33
|
+
}))
|
|
34
|
+
|
|
35
|
+
// Responder
|
|
36
|
+
await ctx.reply(args)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Paso 2: Registrar en Bot
|
|
41
|
+
|
|
42
|
+
**Archivo**: `core/src/index.ts`
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { handleEcho } from './handlers/echo.js'
|
|
46
|
+
|
|
47
|
+
// ... después de bot.command('health', handleHealth)
|
|
48
|
+
|
|
49
|
+
bot.command('echo', handleEcho)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Paso 3: Probar
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bun run dev
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
En Telegram:
|
|
59
|
+
```
|
|
60
|
+
Usuario: /echo hola mundo
|
|
61
|
+
Bot: hola mundo
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Variación: Echo con Mayúsculas
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
export async function handleEchoShout(ctx: Context): Promise<void> {
|
|
68
|
+
const message = ctx.message
|
|
69
|
+
const text = message?.text ?? ''
|
|
70
|
+
const args = text.split(' ').slice(1).join(' ')
|
|
71
|
+
|
|
72
|
+
if (!args) {
|
|
73
|
+
await ctx.reply('Usage: /echoshout <message>')
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
botLogger.info(`${badge('CMD')} /echoshout`, kv({
|
|
78
|
+
user: ctx.from?.id,
|
|
79
|
+
message: args,
|
|
80
|
+
}))
|
|
81
|
+
|
|
82
|
+
// Convertir a mayúsculas y agregar emojis
|
|
83
|
+
const shouted = `📢 ${args.toUpperCase()} 🔊`
|
|
84
|
+
|
|
85
|
+
await ctx.reply(shouted)
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Registrar:
|
|
90
|
+
```typescript
|
|
91
|
+
bot.command('echoshout', handleEchoShout)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Variación: Echo con Repetición
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
interface EchoOptions {
|
|
98
|
+
times?: number
|
|
99
|
+
delay?: number
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function handleEchoRepeat(ctx: Context): Promise<void> {
|
|
103
|
+
const message = ctx.message
|
|
104
|
+
const text = message?.text ?? ''
|
|
105
|
+
const args = text.split(' ').slice(1)
|
|
106
|
+
|
|
107
|
+
// Parsear opciones
|
|
108
|
+
const options: EchoOptions = {}
|
|
109
|
+
let messageText = ''
|
|
110
|
+
|
|
111
|
+
for (let i = 0; i < args.length; i++) {
|
|
112
|
+
const arg = args[i]
|
|
113
|
+
if (arg === '--times' && args[i + 1]) {
|
|
114
|
+
options.times = Number.parseInt(args[i + 1], 10)
|
|
115
|
+
i++
|
|
116
|
+
} else if (arg === '--delay' && args[i + 1]) {
|
|
117
|
+
options.delay = Number.parseInt(args[i + 1], 10)
|
|
118
|
+
i++
|
|
119
|
+
} else {
|
|
120
|
+
messageText = args.slice(i).join(' ')
|
|
121
|
+
break
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!messageText) {
|
|
126
|
+
await ctx.reply('Usage: /echorepeat [--times N] [--delay MS] <message>')
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const times = options.times ?? 1
|
|
131
|
+
const delay = options.delay ?? 500
|
|
132
|
+
|
|
133
|
+
if (times < 1 || times > 10) {
|
|
134
|
+
await ctx.reply('Times must be between 1 and 10')
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
botLogger.info(`${badge('CMD')} /echorepeat`, kv({
|
|
139
|
+
user: ctx.from?.id,
|
|
140
|
+
message: messageText,
|
|
141
|
+
times,
|
|
142
|
+
delay,
|
|
143
|
+
}))
|
|
144
|
+
|
|
145
|
+
// Enviar mensajes con delay
|
|
146
|
+
for (let i = 0; i < times; i++) {
|
|
147
|
+
await ctx.reply(`${i + 1}. ${messageText}`)
|
|
148
|
+
if (i < times - 1) {
|
|
149
|
+
await new Promise(resolve => setTimeout(resolve, delay))
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Uso:
|
|
156
|
+
```
|
|
157
|
+
/echorepeat hola → "1. hola"
|
|
158
|
+
/echorepeat --times 3 hola → "1. hola", "2. hola", "3. hola"
|
|
159
|
+
/echorepeat --delay 1000 hola → "1. hola" (1s delay) "2. hola"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Manejo de Errors
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { botError, err, type Result } from '@mks2508/telegram-bot-utils'
|
|
166
|
+
|
|
167
|
+
function validateEchoMessage(message: string): Result<string> {
|
|
168
|
+
if (!message || message.trim().length === 0) {
|
|
169
|
+
return err(botError('INVALID_ARGS', 'Message cannot be empty'))
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (message.length > 1000) {
|
|
173
|
+
return err(botError('INVALID_ARGS', 'Message too long (max 1000 chars)'))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { ok: true, value: message }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export async function handleEchoSafe(ctx: Context): Promise<void> {
|
|
180
|
+
const message = ctx.message
|
|
181
|
+
const text = message?.text ?? ''
|
|
182
|
+
const args = text.split(' ').slice(1).join(' ')
|
|
183
|
+
|
|
184
|
+
const result = validateEchoMessage(args)
|
|
185
|
+
|
|
186
|
+
if (!result.ok) {
|
|
187
|
+
botLogger.error('Echo validation failed', result.error)
|
|
188
|
+
await ctx.reply(`Error: ${result.error.message}`)
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
await ctx.reply(result.value)
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Resumen
|
|
197
|
+
|
|
198
|
+
1. **Crear handler** en `core/src/handlers/`
|
|
199
|
+
2. **Importar y registrar** en `core/src/index.ts`
|
|
200
|
+
3. **Probar** con `bun run dev`
|
|
201
|
+
4. **Commitear** después de verificar typecheck y lint
|
|
202
|
+
|
|
203
|
+
## Próximos Pasos
|
|
204
|
+
|
|
205
|
+
- [Middleware Auth Example](./middleware-auth.md) - Agregar autenticación
|
|
206
|
+
- [Webhook Setup Example](./webhook-setup.md) - Configurar webhook
|
|
207
|
+
- [Development Guide](../development.md) - Más patrones
|