@adriangalilea/utils 1.3.0 → 1.4.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 +1 -0
- package/dist/bot/profile.d.ts +59 -0
- package/dist/bot/profile.d.ts.map +1 -0
- package/dist/bot/profile.js +140 -0
- package/dist/bot/profile.js.map +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -440,6 +440,7 @@ Then `pnpm install`. Every `ctx.send` / `ctx.sendDocument` / `ctx.reply` / etc.
|
|
|
440
440
|
| `@adriangalilea/utils/bot/kit` | The Node-only corner. `gracefulStart(bot, opts?)` — SIGINT/SIGTERM → `bot.stop()` → exit; force-kills if shutdown hangs. DMs the admin `@<bot> started.` / `@<bot> shutting down.` by default when `KEV.TELEGRAM_ADMIN_ID` is set (graceful only — crashes don't trigger `onStop`); pass `notifyAdmin: false` to disable or `notifyAdmin: 12345` for an explicit chat id.<br>`adminContext({ adminId? })` — reads `TELEGRAM_ADMIN_ID` from `kev` (with optional hardcoded fallback), decorates `ctx.adminId` + `ctx.isAdmin`.<br>Also re-exports `botSession` / `prefixStorage` from `bot/session` so Node consumers keep one import. |
|
|
441
441
|
| `@adriangalilea/utils/bot/session` | `botSession(opts)` — **drop-in replacement for `@gramio/session`'s `session()`** that auto-namespaces every key as `bot-<id>:<senderId>` using `ctx.bot.info.id` (populated by `getMe()` at startup). Use this instead of `session()` — full stop. Multiple bots sharing one Redis/D1 stay isolated by construction; every plugin in this package derives the same prefix internally via `botStorageKey(ctx, userId)` / `botSubKey(ctx, sub)` (from `bot/keys`). No regex, no manual prefix argument, no way to forget.<br>`prefixStorage(storage, prefix)` — escape hatch for adding a top-level prefix on top of the bot-id namespace; almost never needed. Worker-safe (used to live in `bot/kit`, which forced Worker bots to hand-roll the keying). |
|
|
442
442
|
| `@adriangalilea/utils/bot/notify` | Best-effort admin DMs, worker-safe (you pass the ids; no env, no process). `notifyAdmins(bot, adminIds, text, extra?)` — DM each admin, failures logged and swallowed (a notification must never take the bot down). `alertAdminError(bot, adminIds, label, error, throttle?)` — truncated `🚨 label\nName: message`, rate-limited through a caller-owned `alertThrottle(ms?)` so a failure storm sends one alert per window. `gracefulStart`'s start/stop DMs are built on this. |
|
|
443
|
+
| `@adriangalilea/utils/bot/profile` | `syncBotProfile(bot, { name?, description?, about?, commands?, expects?, adminIds? })` — the bot's Telegram-facing identity as CODE, never BotFather: localized name / description / About / public command list, reconciled idempotently on every boot (get → compare → set per field per language; unchanged values cost one read, so cold-start firing is rate-limit-free). `expects: { inline: true }` declares the BotFather-only capabilities the code assumes — a mismatch (inline mode off on an inline-dependent bot) DMs the admins, since the API can only detect it, not fix it. Never throws; failures log and the bot keeps running. |
|
|
443
444
|
| `@adriangalilea/utils/bot/access-control` | Personal-bot ACL — gates non-admin/non-default users; admin gets DM with `[✅ Aprobar][❌ Denegar]` on first attempt; `/access` opens a persistent menu (revoke / reapprove / list pending). Backed by `@gramio/session` per-user + a small index. **Native alternative**: BotFather → Bot Settings → Access → "Restrict bot usage" — flat allow-list at Telegram. Use this plugin when you want in-bot approval flow instead of a BotFather round-trip; both can coexist. |
|
|
444
445
|
| `@adriangalilea/utils/bot/allow-list` | Static allow-list by **id and/or @username** — stateless, no session/storage. `allowList({ ids?, usernames? })` is a plugin that decorates `ctx.allowed` (boolean); gate in your handlers (`if (!ctx.allowed) return`). `makeAllowList(...)` is the pure framework-free predicate. The light counterpart to `access-control` (which adds an approve/deny flow + revocable store, needing session+storage). Username caveat: a `@username` is optional and mutable, and the Bot API can't resolve username→id ahead of time — prefer `ids` when known, `usernames` is the pragmatic fallback. |
|
|
445
446
|
| `@adriangalilea/utils/bot/coalesce` | Joins client-split inbound messages back into one. When a user pastes >4096 chars, Telegram clients fragment it into separate `message` updates with no marker. Middleware detects the burst and emits one combined event. |
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** One public slash command as Telegram publishes it. */
|
|
2
|
+
export interface BotCommandEntry {
|
|
3
|
+
command: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
/** Per-language values; the FIRST key doubles as the unlocalized default. */
|
|
7
|
+
export type Localized<T> = Record<string, T>;
|
|
8
|
+
/** The structural bot surface the sync needs (satisfied by a gramio Bot). */
|
|
9
|
+
export type ProfileBot = {
|
|
10
|
+
info?: {
|
|
11
|
+
username?: string;
|
|
12
|
+
supports_inline_queries?: boolean;
|
|
13
|
+
};
|
|
14
|
+
api: {
|
|
15
|
+
getMyName: (p: object) => Promise<{
|
|
16
|
+
name?: string;
|
|
17
|
+
}>;
|
|
18
|
+
setMyName: (p: object) => Promise<unknown>;
|
|
19
|
+
getMyDescription: (p: object) => Promise<{
|
|
20
|
+
description?: string;
|
|
21
|
+
}>;
|
|
22
|
+
setMyDescription: (p: object) => Promise<unknown>;
|
|
23
|
+
getMyShortDescription: (p: object) => Promise<{
|
|
24
|
+
short_description?: string;
|
|
25
|
+
}>;
|
|
26
|
+
setMyShortDescription: (p: object) => Promise<unknown>;
|
|
27
|
+
getMyCommands: (p: object) => Promise<ReadonlyArray<BotCommandEntry>>;
|
|
28
|
+
setMyCommands: (p: object) => Promise<unknown>;
|
|
29
|
+
sendMessage: (p: {
|
|
30
|
+
chat_id: number;
|
|
31
|
+
text: string;
|
|
32
|
+
}) => Promise<unknown>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export interface BotProfileOptions {
|
|
36
|
+
/** Display name (`setMyName`, 64 chars). */
|
|
37
|
+
name?: Localized<string>;
|
|
38
|
+
/** "What can this bot do?" (`setMyDescription`, 512 chars). */
|
|
39
|
+
description?: Localized<string>;
|
|
40
|
+
/** About / short description (`setMyShortDescription`, 120 chars). */
|
|
41
|
+
about?: Localized<string>;
|
|
42
|
+
/** Public command list per language (admin commands stay out — they're behavior, not menu). */
|
|
43
|
+
commands?: Localized<ReadonlyArray<BotCommandEntry>>;
|
|
44
|
+
/**
|
|
45
|
+
* BotFather-only capabilities this bot's features assume. Checked against `getMe` on every
|
|
46
|
+
* sync; a mismatch WARNS the admins (it can't be fixed over the API, only surfaced).
|
|
47
|
+
*/
|
|
48
|
+
expects?: {
|
|
49
|
+
inline?: boolean;
|
|
50
|
+
};
|
|
51
|
+
/** Admins to DM on an expectation mismatch: a plain array or a live resolver. */
|
|
52
|
+
adminIds?: readonly number[] | (() => Promise<readonly number[]> | readonly number[]);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Reconcile the declared profile with Telegram, field by field, language by language —
|
|
56
|
+
* writes only genuine diffs. Never throws. Call fire-and-forget after `bot.init()`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function syncBotProfile(bot: ProfileBot, opts: BotProfileOptions): Promise<void>;
|
|
59
|
+
//# sourceMappingURL=profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/bot/profile.ts"],"names":[],"mappings":"AA0CA,yDAAyD;AACzD,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,6EAA6E;AAC7E,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAE7C,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAAG;IACxB,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,uBAAuB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAChE,GAAG,EAAE;QACJ,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACrD,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3C,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;YAAE,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACnE,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QAClD,qBAAqB,EAAE,CACtB,CAAC,EAAE,MAAM,KACL,OAAO,CAAC;YAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC7C,qBAAqB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QACvD,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;QACtE,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/C,WAAW,EAAE,CAAC,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KACxE,CAAC;CACF,CAAC;AAEF,MAAM,WAAW,iBAAiB;IACjC,4CAA4C;IAC5C,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IACzB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAChC,sEAAsE;IACtE,KAAK,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1B,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,SAAS,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;IACrD;;;OAGG;IACH,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,EACN,SAAS,MAAM,EAAE,GACjB,CAAC,MAAM,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC;CAC1D;AAqCD;;;GAGG;AACH,wBAAsB,cAAc,CACnC,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,iBAAiB,GACrB,OAAO,CAAC,IAAI,CAAC,CAkEf"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bot/profile` — the bot's Telegram-facing identity as CODE, synced idempotently.
|
|
3
|
+
*
|
|
4
|
+
* A bot should never depend on values typed into BotFather: name, description,
|
|
5
|
+
* About, and the public command list are all settable over the API, so they
|
|
6
|
+
* belong in the repo — reviewable, localized, and reproducible on a fresh
|
|
7
|
+
* token. `syncBotProfile` declares them once and reconciles on every boot with
|
|
8
|
+
* a get → compare → set diff-guard per field per language: unchanged values
|
|
9
|
+
* cost one read, so firing it on every Worker cold start is free of rate-limit
|
|
10
|
+
* risk. Failures are logged and swallowed — a profile hiccup must never take
|
|
11
|
+
* the bot down.
|
|
12
|
+
*
|
|
13
|
+
* What the API canNOT set, BotFather still owns: the token itself and the
|
|
14
|
+
* inline-mode switch. Those are declared as EXPECTATIONS instead — the sync
|
|
15
|
+
* checks `getMe` and DMs the admins when reality disagrees with what the code
|
|
16
|
+
* assumes (an inline-dependent bot silently losing inline mode is exactly the
|
|
17
|
+
* kind of drift nobody notices until users do).
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { syncBotProfile } from '@adriangalilea/utils/bot/profile'
|
|
21
|
+
*
|
|
22
|
+
* void syncBotProfile(bot, {
|
|
23
|
+
* description: { en: 'What I do…', es: 'Lo que hago…' }, // first key = the default
|
|
24
|
+
* about: { en: '⚡ short pitch', es: '⚡ pitch corto' },
|
|
25
|
+
* commands: {
|
|
26
|
+
* en: [{ command: 'start', description: 'Set up' }],
|
|
27
|
+
* es: [{ command: 'start', description: 'Configurar' }],
|
|
28
|
+
* },
|
|
29
|
+
* expects: { inline: true },
|
|
30
|
+
* adminIds: () => store.readAdminIds(ctx, []), // live resolver or plain array
|
|
31
|
+
* })
|
|
32
|
+
*/
|
|
33
|
+
import { createLogger } from "../universal/log.js";
|
|
34
|
+
import { notifyAdmins } from "./notify.js";
|
|
35
|
+
const log = createLogger("bot/profile");
|
|
36
|
+
// Telegram caps, counted in code points so emoji are one glyph each.
|
|
37
|
+
const NAME_MAX = 64;
|
|
38
|
+
const DESCRIPTION_MAX = 512;
|
|
39
|
+
const ABOUT_MAX = 120;
|
|
40
|
+
/** Count Unicode code points (emoji = 1), for Telegram's limits. */
|
|
41
|
+
function glyphs(s) {
|
|
42
|
+
return [...s].length;
|
|
43
|
+
}
|
|
44
|
+
function commandsEqual(a, b) {
|
|
45
|
+
if (a.length !== b.length)
|
|
46
|
+
return false;
|
|
47
|
+
return a.every((cmd, i) => cmd.command === b[i].command && cmd.description === b[i].description);
|
|
48
|
+
}
|
|
49
|
+
function overLimit(field, values, max) {
|
|
50
|
+
for (const [lang, value] of Object.entries(values)) {
|
|
51
|
+
if (glyphs(value) > max) {
|
|
52
|
+
log.error(`${field} (${lang}) exceeds ${max} chars — skipping ${field} sync`);
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const langParam = (lang) => lang ? { language_code: lang } : {};
|
|
59
|
+
/**
|
|
60
|
+
* Reconcile the declared profile with Telegram, field by field, language by language —
|
|
61
|
+
* writes only genuine diffs. Never throws. Call fire-and-forget after `bot.init()`.
|
|
62
|
+
*/
|
|
63
|
+
export async function syncBotProfile(bot, opts) {
|
|
64
|
+
const jobs = [];
|
|
65
|
+
const eachLang = (values, sync) => {
|
|
66
|
+
const entries = Object.entries(values);
|
|
67
|
+
if (entries.length === 0)
|
|
68
|
+
return;
|
|
69
|
+
jobs.push(sync(undefined, entries[0][1])); // first entry = the unlocalized default
|
|
70
|
+
for (const [lang, value] of entries)
|
|
71
|
+
jobs.push(sync(lang, value));
|
|
72
|
+
};
|
|
73
|
+
if (opts.name && !overLimit("name", opts.name, NAME_MAX)) {
|
|
74
|
+
eachLang(opts.name, async (lang, value) => {
|
|
75
|
+
const current = await bot.api.getMyName(langParam(lang));
|
|
76
|
+
if (current.name === value)
|
|
77
|
+
return;
|
|
78
|
+
await bot.api.setMyName({ name: value, ...langParam(lang) });
|
|
79
|
+
log.info(`name synced${lang ? ` (${lang})` : ""}`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (opts.description &&
|
|
83
|
+
!overLimit("description", opts.description, DESCRIPTION_MAX)) {
|
|
84
|
+
eachLang(opts.description, async (lang, value) => {
|
|
85
|
+
const current = await bot.api.getMyDescription(langParam(lang));
|
|
86
|
+
if (current.description === value)
|
|
87
|
+
return;
|
|
88
|
+
await bot.api.setMyDescription({
|
|
89
|
+
description: value,
|
|
90
|
+
...langParam(lang),
|
|
91
|
+
});
|
|
92
|
+
log.info(`description synced${lang ? ` (${lang})` : ""}`);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (opts.about && !overLimit("about", opts.about, ABOUT_MAX)) {
|
|
96
|
+
eachLang(opts.about, async (lang, value) => {
|
|
97
|
+
const current = await bot.api.getMyShortDescription(langParam(lang));
|
|
98
|
+
if (current.short_description === value)
|
|
99
|
+
return;
|
|
100
|
+
await bot.api.setMyShortDescription({
|
|
101
|
+
short_description: value,
|
|
102
|
+
...langParam(lang),
|
|
103
|
+
});
|
|
104
|
+
log.info(`about synced${lang ? ` (${lang})` : ""}`);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (opts.commands) {
|
|
108
|
+
eachLang(opts.commands, async (lang, list) => {
|
|
109
|
+
const current = await bot.api.getMyCommands(langParam(lang));
|
|
110
|
+
if (commandsEqual(current, list))
|
|
111
|
+
return;
|
|
112
|
+
await bot.api.setMyCommands({ commands: [...list], ...langParam(lang) });
|
|
113
|
+
log.info(`commands synced${lang ? ` (${lang})` : ""} (${list.length})`);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
await Promise.all(jobs);
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
log.error(`profile sync failed: ${e instanceof Error ? e.message : e}`);
|
|
121
|
+
}
|
|
122
|
+
await checkExpectations(bot, opts).catch((e) => log.error(`expectation check failed: ${e instanceof Error ? e.message : e}`));
|
|
123
|
+
}
|
|
124
|
+
/** The BotFather-drift check: warn the admins when a declared capability is off. */
|
|
125
|
+
async function checkExpectations(bot, opts) {
|
|
126
|
+
if (!opts.expects?.inline)
|
|
127
|
+
return;
|
|
128
|
+
if (bot.info?.supports_inline_queries !== false)
|
|
129
|
+
return; // true, or unknown (no getMe yet)
|
|
130
|
+
const handle = bot.info?.username ? `@${bot.info.username}` : "this bot";
|
|
131
|
+
log.warn(`inline mode is OFF for ${handle} — the bot's inline features are dead`);
|
|
132
|
+
const ids = typeof opts.adminIds === "function"
|
|
133
|
+
? await opts.adminIds()
|
|
134
|
+
: (opts.adminIds ?? []);
|
|
135
|
+
if (ids.length === 0)
|
|
136
|
+
return;
|
|
137
|
+
await notifyAdmins(bot, ids, `⚠️ ${handle}: inline mode is OFF, but this bot's features depend on it.\n` +
|
|
138
|
+
"Only BotFather can enable it: @BotFather → /setinline (and /setinlinefeedback).");
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/bot/profile.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adriangalilea/utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "TypeScript utilities - logger, currency, formatter, GramIO bot plugins, and more",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -119,6 +119,10 @@
|
|
|
119
119
|
"./bot/create": {
|
|
120
120
|
"types": "./dist/bot/create.d.ts",
|
|
121
121
|
"default": "./dist/bot/create.js"
|
|
122
|
+
},
|
|
123
|
+
"./bot/profile": {
|
|
124
|
+
"types": "./dist/bot/profile.d.ts",
|
|
125
|
+
"default": "./dist/bot/profile.js"
|
|
122
126
|
}
|
|
123
127
|
},
|
|
124
128
|
"files": [
|