@adriangalilea/utils 0.5.0 → 0.6.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.
@@ -0,0 +1,516 @@
1
+ /**
2
+ * Access control for personal GramIO bots — a one-stop guard +
3
+ * approve/deny + revocable allow-list with an inline admin menu.
4
+ *
5
+ * stranger DMs your bot
6
+ * │
7
+ * ▼
8
+ * ┌──── plugin gate (this file) ────────────────────┐
9
+ * │ ctx.from.id ∈ admin / defaults / approved? │
10
+ * │ yes → next() │
11
+ * │ no → drop + notify admin (rate-limited) │
12
+ * └─────────────────────────────────────────────────┘
13
+ * │
14
+ * admin gets DM with [✅ Aprobar] [❌ Denegar]
15
+ * │
16
+ * admin taps
17
+ * │
18
+ * stranger's session updated · stranger gets DM
19
+ *
20
+ * **Storage layout.** Per-user state lives in its own key, written
21
+ * through `@gramio/session` so the gate read on the hot path costs
22
+ * nothing extra (session is loaded for the user already). A single
23
+ * tiny index key keeps track of who's pending / approved / denied so
24
+ * the `/access` admin menu can list without scanning the whole DB.
25
+ *
26
+ * storage:
27
+ * access:<userId> → AccessRecord (the user's session)
28
+ * ac:index → { pending, approved, denied }
29
+ *
30
+ * **Cross-user mutations.** When you tap `[✅ Aprobar]` on Pepe's
31
+ * notification, ctx is *yours* (the admin), so `ctx.access` is your
32
+ * own record. To mutate Pepe's record we hit the storage at the same
33
+ * key format we registered the session with (`access:<id>`) and
34
+ * update the index. This isn't a hack — it's our own module
35
+ * coordinating with itself.
36
+ *
37
+ * **Composes with `adminContext`** (kit.ts) — that plugin must be
38
+ * extended first or `bot.start()` throws. Inside this plugin,
39
+ * `ctx.adminId` and `ctx.isAdmin` are typed.
40
+ *
41
+ * Peer deps: `gramio`, `@gramio/storage`, `@gramio/session`.
42
+ *
43
+ * @example
44
+ * import { Bot } from 'gramio'
45
+ * import { redisStorage } from '@gramio/storage-redis'
46
+ * import { adminContext, gracefulStart } from '@adriangalilea/utils/bot/kit'
47
+ * import { accessControl } from '@adriangalilea/utils/bot/access-control'
48
+ *
49
+ * const storage = redisStorage()
50
+ *
51
+ * const bot = new Bot(process.env.BOT_TOKEN!)
52
+ * .extend(adminContext({ adminId: 190202471 }))
53
+ * .extend(accessControl({ storage, defaults: [1158734055] }))
54
+ * .command('start', (ctx) => ctx.send(`hola, source=${ctx.access.source}`))
55
+ *
56
+ * await gracefulStart(bot)
57
+ */
58
+ import { CallbackData, InlineKeyboard, Plugin, } from 'gramio';
59
+ import { session } from '@gramio/session';
60
+ import { inMemoryStorage } from '@gramio/storage';
61
+ const SESSION_KEY_PREFIX = 'access:';
62
+ const INDEX_KEY = 'ac:index';
63
+ const FIRST_MSG_LIMIT = 200;
64
+ const DEFAULT_DENY_MSG = 'Este bot es privado. Tu solicitud se ha enviado al admin.';
65
+ const DEFAULT_THROTTLE_MS = 6 * 60 * 60 * 1000;
66
+ const userSessionKey = (userId) => `${SESSION_KEY_PREFIX}${userId}`;
67
+ // ─── callback schemas ──────────────────────────────────────────────
68
+ //
69
+ // Short `nameId`s keep callback_data under Telegram's 64-byte cap.
70
+ // `v` (optional) carries the originating list view ('pending' | 'denied'
71
+ // | 'approved'). When present, the handler refreshes that list after
72
+ // the action; absent = original notification, edits the message inline.
73
+ const acApprove = new CallbackData('acA').number('uid').string('v', { optional: true });
74
+ const acDeny = new CallbackData('acD').number('uid').string('v', { optional: true });
75
+ const acRevoke = new CallbackData('acR').number('uid');
76
+ const acView = new CallbackData('acV').string('v'); // main | approved | pending | denied
77
+ const acClose = new CallbackData('acC');
78
+ // ─── small helpers ─────────────────────────────────────────────────
79
+ const formatUser = (u, fallbackId) => {
80
+ if (!u)
81
+ return `id ${fallbackId}`;
82
+ const name = [u.firstName, u.lastName].filter(Boolean).join(' ') || `id ${u.id}`;
83
+ const handle = u.username ? `@${u.username}` : `id ${u.id}`;
84
+ return `${name} (${handle})`;
85
+ };
86
+ const fmtAge = (ms) => {
87
+ const s = Math.floor(ms / 1000);
88
+ if (s < 60)
89
+ return `${s}s`;
90
+ const m = Math.floor(s / 60);
91
+ if (m < 60)
92
+ return `${m}min`;
93
+ const h = Math.floor(m / 60);
94
+ if (h < 24)
95
+ return `${h}h`;
96
+ return `${Math.floor(h / 24)}d`;
97
+ };
98
+ const requestNotificationText = (uid, r, repeat) => {
99
+ const parts = [
100
+ repeat ? '🔁 Acceso re-solicitado' : '🔔 Acceso solicitado',
101
+ '',
102
+ `👤 ${formatUser(r.user, uid)}`,
103
+ `🆔 ${uid}`,
104
+ `⏰ hace ${fmtAge(Date.now() - (r.requestedAt ?? Date.now()))}`,
105
+ ];
106
+ if (repeat)
107
+ parts.push(`🔁 intentos: ${(r.rejectedAttempts ?? 0) + 1}`);
108
+ if (r.firstMessage)
109
+ parts.push('', `💬 "${r.firstMessage}"`);
110
+ return parts.join('\n');
111
+ };
112
+ const requestKeyboard = (uid) => new InlineKeyboard()
113
+ .text('✅ Aprobar', acApprove.pack({ uid }))
114
+ .text('❌ Denegar', acDeny.pack({ uid }));
115
+ let warnedMemory = false;
116
+ const warnedMemoryStorage = () => {
117
+ if (!warnedMemory) {
118
+ warnedMemory = true;
119
+ console.warn('[access-control] using inMemoryStorage — approvals will not survive restarts. ' +
120
+ 'Pass `storage: redisStorage()` (or sqliteStorage / cloudflareStorage) for persistence.');
121
+ }
122
+ return inMemoryStorage();
123
+ };
124
+ // ─── index helpers ─────────────────────────────────────────────────
125
+ const emptyIndex = () => ({ pending: [], approved: [], denied: [] });
126
+ const loadIndex = async (storage) => {
127
+ const raw = (await storage.get(INDEX_KEY));
128
+ return {
129
+ pending: raw?.pending ?? [],
130
+ approved: raw?.approved ?? [],
131
+ denied: raw?.denied ?? [],
132
+ };
133
+ };
134
+ const saveIndex = (storage, idx) => storage.set(INDEX_KEY, idx);
135
+ const indexAdd = async (storage, bucket, uid) => {
136
+ const idx = await loadIndex(storage);
137
+ if (!idx[bucket].includes(uid))
138
+ idx[bucket].push(uid);
139
+ await saveIndex(storage, idx);
140
+ };
141
+ const indexMove = async (storage, uid, from, to) => {
142
+ const idx = await loadIndex(storage);
143
+ const remove = (list) => {
144
+ const i = list.indexOf(uid);
145
+ if (i >= 0)
146
+ list.splice(i, 1);
147
+ };
148
+ if (from === 'any') {
149
+ remove(idx.pending);
150
+ remove(idx.approved);
151
+ remove(idx.denied);
152
+ }
153
+ else {
154
+ remove(idx[from]);
155
+ }
156
+ if (!idx[to].includes(uid))
157
+ idx[to].push(uid);
158
+ await saveIndex(storage, idx);
159
+ };
160
+ // ─── per-user record helpers (cross-user storage access) ───────────
161
+ const loadRecord = async (storage, userId) => (await storage.get(userSessionKey(userId)));
162
+ const saveRecord = (storage, userId, rec) => storage.set(userSessionKey(userId), rec);
163
+ // ─── plugin ────────────────────────────────────────────────────────
164
+ export const accessControl = (opts = {}) => {
165
+ const storage = opts.storage ?? warnedMemoryStorage();
166
+ const defaults = new Set(opts.defaults ?? []);
167
+ const denyMessage = opts.denyMessage === false ? null : (opts.denyMessage ?? DEFAULT_DENY_MSG);
168
+ const throttleMs = opts.notifyThrottleMs ?? DEFAULT_THROTTLE_MS;
169
+ return (new Plugin('@adriangalilea/utils/bot/access-control', {
170
+ dependencies: ['@adriangalilea/utils/bot/admin'],
171
+ })
172
+ // Per-user record lives in this session (storage key `access:<senderId>`).
173
+ // The internal name `_accessSession` is plumbing — consumers read
174
+ // `ctx.access` (computed below) instead.
175
+ .extend(session({
176
+ storage,
177
+ key: '_accessSession',
178
+ getSessionKey: (ctx) => userSessionKey(ctx.senderId ?? 0),
179
+ initial: () => ({ status: 'unknown' }),
180
+ }))
181
+ // Compute the gate decision so handlers can read `ctx.access` ergonomically.
182
+ .derive((ctx) => {
183
+ // Only message + callback_query carry a senderId we can gate on.
184
+ if (!ctx.is('message') && !ctx.is('callback_query')) {
185
+ return { access: { allowed: false, reason: 'no-sender' } };
186
+ }
187
+ const senderId = ctx.from.id;
188
+ if (senderId === ctx.adminId) {
189
+ return { access: { allowed: true, source: 'admin' } };
190
+ }
191
+ if (defaults.has(senderId)) {
192
+ return { access: { allowed: true, source: 'default' } };
193
+ }
194
+ const rec = ctx._accessSession;
195
+ if (rec.status === 'approved') {
196
+ return { access: { allowed: true, source: 'store', record: rec } };
197
+ }
198
+ return {
199
+ access: { allowed: false, reason: rec.status },
200
+ };
201
+ })
202
+ // Gate. Authorized passes through; unauthorized triggers admin notify
203
+ // and silent stranger reply, then drops.
204
+ .use(async (ctx, next) => {
205
+ if (ctx.access.allowed) {
206
+ // Activity bump (only for store-approved users — admins/defaults
207
+ // don't have a session record we want to clutter).
208
+ if (ctx.access.source === 'store' && ctx.is('message')) {
209
+ ctx._accessSession.lastActivityAt = Date.now();
210
+ ctx._accessSession.messageCount = (ctx._accessSession.messageCount ?? 0) + 1;
211
+ }
212
+ return next();
213
+ }
214
+ // Acknowledge unauthorized callback queries so the spinner clears.
215
+ if (ctx.is('callback_query')) {
216
+ await ctx.answer({ text: 'Sin acceso.', show_alert: false });
217
+ return;
218
+ }
219
+ // Only message-shaped events have .text/.chat for our notification.
220
+ if (!ctx.is('message'))
221
+ return;
222
+ const userId = ctx.from.id;
223
+ const rec = ctx._accessSession;
224
+ const now = Date.now();
225
+ const isFirstRequest = rec.status === 'unknown';
226
+ if (isFirstRequest) {
227
+ rec.status = 'pending';
228
+ rec.user = {
229
+ id: userId,
230
+ firstName: ctx.from.firstName,
231
+ lastName: ctx.from.lastName,
232
+ username: ctx.from.username,
233
+ };
234
+ rec.chatId = ctx.chat.id;
235
+ rec.requestedAt = now;
236
+ rec.firstMessage = ctx.text?.slice(0, FIRST_MSG_LIMIT);
237
+ rec.messageCount = 0;
238
+ rec.rejectedAttempts = 0;
239
+ await indexAdd(storage, 'pending', userId);
240
+ }
241
+ else {
242
+ rec.rejectedAttempts = (rec.rejectedAttempts ?? 0) + 1;
243
+ }
244
+ const shouldNotify = isFirstRequest || now - (rec.lastNotifiedAt ?? 0) > throttleMs;
245
+ if (shouldNotify) {
246
+ rec.lastNotifiedAt = now;
247
+ try {
248
+ await ctx.bot.api.sendMessage({
249
+ chat_id: ctx.adminId,
250
+ text: requestNotificationText(userId, rec, !isFirstRequest),
251
+ reply_markup: requestKeyboard(userId),
252
+ });
253
+ }
254
+ catch (e) {
255
+ console.error('[access-control] failed to notify admin (have you /started the bot from your account?)', e);
256
+ }
257
+ opts.onAccessRequest?.({ user: rec.user, firstMessage: rec.firstMessage });
258
+ }
259
+ if (denyMessage && isFirstRequest) {
260
+ try {
261
+ await ctx.send(denyMessage);
262
+ }
263
+ catch {
264
+ // user blocked the bot — irrelevant
265
+ }
266
+ }
267
+ // do NOT call next — drop
268
+ })
269
+ // ─── admin actions ────────────────────────────────────────
270
+ .callbackQuery(acApprove, async (ctx) => {
271
+ if (!ctx.isAdmin)
272
+ return ctx.answer({ text: 'Solo admin.', show_alert: true });
273
+ const uid = ctx.queryData.uid;
274
+ const rec = await loadRecord(storage, uid);
275
+ if (!rec)
276
+ return ctx.answer({ text: 'No encontrado.' });
277
+ const wasDenied = rec.status === 'denied';
278
+ const wasPending = rec.status === 'pending';
279
+ rec.status = 'approved';
280
+ rec.approvedAt = Date.now();
281
+ rec.approvedBy = ctx.adminId;
282
+ rec.deniedAt = undefined;
283
+ rec.deniedBy = undefined;
284
+ await saveRecord(storage, uid, rec);
285
+ await indexMove(storage, uid, wasPending ? 'pending' : wasDenied ? 'denied' : 'any', 'approved');
286
+ if (rec.chatId !== undefined) {
287
+ try {
288
+ await ctx.bot.api.sendMessage({
289
+ chat_id: rec.chatId,
290
+ text: wasDenied
291
+ ? '✅ El admin reconsideró: ya tienes acceso.'
292
+ : '✅ Acceso concedido. Ya puedes usar el bot.',
293
+ });
294
+ }
295
+ catch {
296
+ // user blocked / chat gone
297
+ }
298
+ }
299
+ await ctx.answer({ text: '✅ Aprobado' });
300
+ if (ctx.queryData.v) {
301
+ await renderView(ctx, storage, defaults, ctx.queryData.v);
302
+ }
303
+ else {
304
+ try {
305
+ await ctx.editText(`✅ Aprobado · ${formatUser(rec.user, uid)}`);
306
+ }
307
+ catch {
308
+ // not always editable
309
+ }
310
+ }
311
+ opts.onApprove?.({ userId: uid, approvedBy: ctx.adminId });
312
+ })
313
+ .callbackQuery(acDeny, async (ctx) => {
314
+ if (!ctx.isAdmin)
315
+ return ctx.answer({ text: 'Solo admin.', show_alert: true });
316
+ const uid = ctx.queryData.uid;
317
+ const rec = await loadRecord(storage, uid);
318
+ if (!rec)
319
+ return ctx.answer({ text: 'No encontrado.' });
320
+ const wasPending = rec.status === 'pending';
321
+ rec.status = 'denied';
322
+ rec.deniedAt = Date.now();
323
+ rec.deniedBy = ctx.adminId;
324
+ await saveRecord(storage, uid, rec);
325
+ await indexMove(storage, uid, wasPending ? 'pending' : 'any', 'denied');
326
+ if (rec.chatId !== undefined) {
327
+ try {
328
+ await ctx.bot.api.sendMessage({
329
+ chat_id: rec.chatId,
330
+ text: '❌ Acceso denegado.',
331
+ });
332
+ }
333
+ catch {
334
+ // ignore
335
+ }
336
+ }
337
+ await ctx.answer({ text: '❌ Denegado' });
338
+ if (ctx.queryData.v) {
339
+ await renderView(ctx, storage, defaults, ctx.queryData.v);
340
+ }
341
+ else {
342
+ try {
343
+ await ctx.editText(`❌ Denegado · ${formatUser(rec.user, uid)}`);
344
+ }
345
+ catch {
346
+ // ignore
347
+ }
348
+ }
349
+ opts.onDeny?.({ userId: uid, deniedBy: ctx.adminId });
350
+ })
351
+ .callbackQuery(acRevoke, async (ctx) => {
352
+ if (!ctx.isAdmin)
353
+ return ctx.answer({ text: 'Solo admin.', show_alert: true });
354
+ const uid = ctx.queryData.uid;
355
+ const rec = await loadRecord(storage, uid);
356
+ if (!rec)
357
+ return ctx.answer({ text: 'No encontrado.' });
358
+ rec.status = 'denied';
359
+ rec.deniedAt = Date.now();
360
+ rec.deniedBy = ctx.adminId;
361
+ await saveRecord(storage, uid, rec);
362
+ await indexMove(storage, uid, 'approved', 'denied');
363
+ if (rec.chatId !== undefined) {
364
+ try {
365
+ await ctx.bot.api.sendMessage({
366
+ chat_id: rec.chatId,
367
+ text: '↩️ Tu acceso al bot ha sido revocado.',
368
+ });
369
+ }
370
+ catch {
371
+ // ignore
372
+ }
373
+ }
374
+ await ctx.answer({ text: '↩️ Revocado' });
375
+ await renderView(ctx, storage, defaults, 'approved');
376
+ })
377
+ .callbackQuery(acView, async (ctx) => {
378
+ if (!ctx.isAdmin)
379
+ return ctx.answer({ text: 'Solo admin.', show_alert: true });
380
+ await ctx.answer({});
381
+ await renderView(ctx, storage, defaults, ctx.queryData.v);
382
+ })
383
+ .callbackQuery(acClose, async (ctx) => {
384
+ if (!ctx.isAdmin)
385
+ return ctx.answer({ text: 'Solo admin.', show_alert: true });
386
+ await ctx.answer({});
387
+ try {
388
+ await ctx.message?.delete();
389
+ }
390
+ catch {
391
+ // ignore
392
+ }
393
+ })
394
+ .command('access', async (ctx) => {
395
+ if (!ctx.isAdmin)
396
+ return;
397
+ const v = await mainView(storage, defaults);
398
+ await ctx.send(v.text, { reply_markup: v.keyboard });
399
+ }));
400
+ };
401
+ const renderView = async (ctx, storage, defaults, view) => {
402
+ const v = view === 'approved'
403
+ ? await listView(storage, 'approved', defaults)
404
+ : view === 'pending'
405
+ ? await listView(storage, 'pending', defaults)
406
+ : view === 'denied'
407
+ ? await listView(storage, 'denied', defaults)
408
+ : await mainView(storage, defaults);
409
+ try {
410
+ await ctx.editText(v.text, { reply_markup: v.keyboard });
411
+ }
412
+ catch {
413
+ // editText only works while message is recent enough; ignore
414
+ }
415
+ };
416
+ const mainView = async (storage, defaults) => {
417
+ const idx = await loadIndex(storage);
418
+ const text = [
419
+ '🔐 Access Control',
420
+ '',
421
+ `✅ Aprobados: ${idx.approved.length}`,
422
+ `⏳ Pendientes: ${idx.pending.length}`,
423
+ `❌ Denegados: ${idx.denied.length}`,
424
+ `👑 Defaults: ${defaults.size} (hardcoded)`,
425
+ ].join('\n');
426
+ const keyboard = new InlineKeyboard()
427
+ .text(`✅ Aprobados (${idx.approved.length})`, acView.pack({ v: 'approved' }))
428
+ .text(`⏳ Pendientes (${idx.pending.length})`, acView.pack({ v: 'pending' }))
429
+ .row()
430
+ .text(`❌ Denegados (${idx.denied.length})`, acView.pack({ v: 'denied' }))
431
+ .text('🔄 Refresh', acView.pack({ v: 'main' }))
432
+ .row()
433
+ .text('✖️ Cerrar', acClose.pack({}));
434
+ return { text, keyboard };
435
+ };
436
+ const listView = async (storage, filter, defaults) => {
437
+ const idx = await loadIndex(storage);
438
+ const ids = idx[filter];
439
+ // Cap at 20 to keep callback_data + rendering sane.
440
+ const shownIds = ids.slice(0, 20);
441
+ const records = await Promise.all(shownIds.map(async (id) => ({ id, rec: await loadRecord(storage, id) })));
442
+ const headerEmoji = filter === 'approved' ? '✅' : filter === 'pending' ? '⏳' : '❌';
443
+ const headerLabel = filter === 'approved' ? 'Aprobados' : filter === 'pending' ? 'Pendientes' : 'Denegados';
444
+ if (ids.length === 0) {
445
+ const text = `${headerEmoji} ${headerLabel} (0)\n\n(vacío)`;
446
+ const keyboard = new InlineKeyboard().text('⬅️ Volver', acView.pack({ v: 'main' }));
447
+ return { text, keyboard };
448
+ }
449
+ const lines = [`${headerEmoji} ${headerLabel} (${ids.length})`, ''];
450
+ const keyboard = new InlineKeyboard();
451
+ for (let i = 0; i < records.length; i++) {
452
+ const { id, rec } = records[i];
453
+ if (!rec) {
454
+ // index referenced a missing record — show as placeholder
455
+ lines.push(`${i + 1}. id ${id} (datos perdidos)`);
456
+ continue;
457
+ }
458
+ const ageRef = rec.approvedAt ?? rec.deniedAt ?? rec.requestedAt ?? Date.now();
459
+ lines.push(`${i + 1}. ${formatUser(rec.user, id)} · hace ${fmtAge(Date.now() - ageRef)}` +
460
+ (rec.messageCount ? ` · ${rec.messageCount} msgs` : ''));
461
+ if (filter === 'pending') {
462
+ keyboard
463
+ .text(`✅ ${i + 1}`, acApprove.pack({ uid: id, v: 'pending' }))
464
+ .text(`❌ ${i + 1}`, acDeny.pack({ uid: id, v: 'pending' }))
465
+ .row();
466
+ }
467
+ else if (filter === 'approved') {
468
+ keyboard.text(`↩️ Revocar #${i + 1}`, acRevoke.pack({ uid: id })).row();
469
+ }
470
+ else if (filter === 'denied') {
471
+ keyboard
472
+ .text(`✅ Reaprobar #${i + 1}`, acApprove.pack({ uid: id, v: 'denied' }))
473
+ .row();
474
+ }
475
+ }
476
+ if (ids.length > shownIds.length) {
477
+ lines.push('', `(+${ids.length - shownIds.length} más, no mostrados)`);
478
+ }
479
+ if (filter === 'approved' && defaults.size > 0) {
480
+ lines.push('', `+ ${defaults.size} hardcoded defaults`);
481
+ }
482
+ keyboard.text('⬅️ Volver', acView.pack({ v: 'main' }));
483
+ return { text: lines.join('\n'), keyboard };
484
+ };
485
+ // ─── test helper ───────────────────────────────────────────────────
486
+ /**
487
+ * Inject a synthetic access request — for tests/demos when you can't
488
+ * easily spin up a second Telegram account. Writes a `pending` record
489
+ * to storage at the same key the plugin's session would, updates the
490
+ * index, then DMs the admin with the real
491
+ * `[✅ Aprobar][❌ Denegar]` keyboard. Tapping those buttons exercises
492
+ * the real callback handlers end-to-end.
493
+ *
494
+ * Pass the SAME `storage` instance you passed to `accessControl({ storage })`.
495
+ */
496
+ export const simulateAccessRequest = async (bot, storage, adminId, fakeUser, message) => {
497
+ const now = Date.now();
498
+ const rec = {
499
+ status: 'pending',
500
+ user: fakeUser,
501
+ chatId: fakeUser.id,
502
+ requestedAt: now,
503
+ firstMessage: message?.slice(0, FIRST_MSG_LIMIT),
504
+ messageCount: 0,
505
+ rejectedAttempts: 0,
506
+ lastNotifiedAt: now,
507
+ };
508
+ await saveRecord(storage, fakeUser.id, rec);
509
+ await indexAdd(storage, 'pending', fakeUser.id);
510
+ await bot.api.sendMessage({
511
+ chat_id: adminId,
512
+ text: requestNotificationText(fakeUser.id, rec, false),
513
+ reply_markup: requestKeyboard(fakeUser.id),
514
+ });
515
+ };
516
+ //# sourceMappingURL=access-control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-control.js","sourceRoot":"","sources":["../../src/bot/access-control.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Telegram bot plugins for GramIO. Imported as subpaths so this module
3
+ * has zero footprint for consumers that don't use them.
4
+ *
5
+ * Peer deps (all optional): `gramio`, `@gramio/format`, `@gramio/storage`, `marked`.
6
+ *
7
+ * import { adminContext, gracefulStart } from '@adriangalilea/utils/bot/kit'
8
+ * import { accessControl } from '@adriangalilea/utils/bot/access-control'
9
+ * import { llmStream } from '@adriangalilea/utils/bot/llm-stream'
10
+ *
11
+ * Or all-in-one (pulls every subpath):
12
+ * import { ... } from '@adriangalilea/utils/bot'
13
+ */
14
+ export * from './kit.js';
15
+ export * from './access-control.js';
16
+ export * from './llm-stream.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,UAAU,CAAA;AACxB,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Telegram bot plugins for GramIO. Imported as subpaths so this module
3
+ * has zero footprint for consumers that don't use them.
4
+ *
5
+ * Peer deps (all optional): `gramio`, `@gramio/format`, `@gramio/storage`, `marked`.
6
+ *
7
+ * import { adminContext, gracefulStart } from '@adriangalilea/utils/bot/kit'
8
+ * import { accessControl } from '@adriangalilea/utils/bot/access-control'
9
+ * import { llmStream } from '@adriangalilea/utils/bot/llm-stream'
10
+ *
11
+ * Or all-in-one (pulls every subpath):
12
+ * import { ... } from '@adriangalilea/utils/bot'
13
+ */
14
+ export * from './kit.js';
15
+ export * from './access-control.js';
16
+ export * from './llm-stream.js';
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bot/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,cAAc,UAAU,CAAA;AACxB,cAAc,qBAAqB,CAAA;AACnC,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Foundational helpers every bot wants. Two things:
3
+ *
4
+ * `gracefulStart(bot, opts?)` — wires SIGINT/SIGTERM to bot.stop(),
5
+ * runs an optional shutdown hook, force-kills if it hangs.
6
+ *
7
+ * `adminContext({ adminId? })` — reads admin Telegram id from KEV
8
+ * (`TELEGRAM_ADMIN_ID`) with optional hardcoded fallback. Decorates
9
+ * every context with `ctx.adminId` (number) and `ctx.isAdmin`
10
+ * (boolean). Throws at startup if neither source provides an id.
11
+ *
12
+ * Peer deps: `gramio`.
13
+ *
14
+ * @example
15
+ * import { Bot } from 'gramio'
16
+ * import { adminContext, gracefulStart } from '@adriangalilea/utils/bot/kit'
17
+ *
18
+ * const bot = new Bot(process.env.BOT_TOKEN!)
19
+ * .extend(adminContext({ adminId: 190202471 })) // KEV wins, 190… is fallback
20
+ * .command('whoami', (ctx) => ctx.send(`admin? ${ctx.isAdmin}`))
21
+ *
22
+ * await gracefulStart(bot, { onShutdown: () => db.end() })
23
+ */
24
+ import type { AnyBot } from 'gramio';
25
+ import { Plugin } from 'gramio';
26
+ export type GracefulStartOptions = {
27
+ /** Runs after `bot.stop()` resolves, before `process.exit`. Close DBs, flush logs. */
28
+ onShutdown?: () => Promise<void> | void;
29
+ /** Process exit code on graceful shutdown. Default 0. */
30
+ exitCode?: number;
31
+ /** Hard-kill after this many ms if shutdown hangs. Default 10000. */
32
+ forceExitAfterMs?: number;
33
+ /** Logger. Default `console.log`. Set `false` to silence. */
34
+ log?: ((msg: string) => void) | false;
35
+ };
36
+ export declare const gracefulStart: (bot: AnyBot, opts?: GracefulStartOptions) => Promise<void>;
37
+ export type AdminContextOptions = {
38
+ /** Hardcoded fallback used when `KEV.TELEGRAM_ADMIN_ID` is unset. */
39
+ adminId?: number;
40
+ };
41
+ export declare const adminContext: (opts?: AdminContextOptions) => Plugin<{}, import("gramio").DeriveDefinitions & {
42
+ global: {
43
+ adminId: number;
44
+ };
45
+ } & {
46
+ global: {
47
+ isAdmin: boolean;
48
+ };
49
+ }, {}>;
50
+ //# sourceMappingURL=kit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/bot/kit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAK/B,MAAM,MAAM,oBAAoB,GAAG;IACjC,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACvC,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,KAAK,CAAA;CACtC,CAAA;AAED,eAAO,MAAM,aAAa,GACxB,KAAK,MAAM,EACX,OAAM,oBAAyB,KAC9B,OAAO,CAAC,IAAI,CAiCd,CAAA;AAID,MAAM,MAAM,mBAAmB,GAAG;IAChC,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,OAAM,mBAAwB;;;;;;;;MAqB1D,CAAA"}