@adriangalilea/utils 1.14.0 → 1.15.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 -1
- package/dist/bot/admin.d.ts +3 -0
- package/dist/bot/admin.d.ts.map +1 -1
- package/dist/bot/admin.js +8 -0
- package/dist/bot/admin.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -444,7 +444,7 @@ Then `pnpm install`. Every `ctx.send` / `ctx.sendDocument` / `ctx.reply` / etc.
|
|
|
444
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. |
|
|
445
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. |
|
|
446
446
|
| `@adriangalilea/utils/bot/groups` | Group-chat identity as plain functions: `chatIdOf(ctx)` (the chat id on any ctx flavour), `isGroupChat(ctx)` / `isPrivateChat(ctx)`, and `isGroupAdmin(ctx, { chatId?, userId? }?)` — the `getChatMember` creator/administrator check behind every admin-gated group setting (auto-summary toggles, "dismiss" buttons on group welcomes), chat/user defaulted from the ctx. Every reader resolves both gramio spellings — message ctxs carry `chat`, callback ctxs (inline-button taps) only `chatId`/`message.chat` — so the same gate works in handlers and taps; read chat ids via `chatIdOf`, never `ctx.chat?.id`. Takes real gramio ctxs and `MenuCtx` with no cast; a miswired ctx panics, an API rejection fails closed (`false`). Composition over policy: bot-owner override stays at your call site (`ctx.isAdmin \|\| await isGroupAdmin(ctx)`). |
|
|
447
|
-
| `@adriangalilea/utils/bot/language` (picker surface) | The language-picker vocabulary and surfaces, so bots don't fork label lists: `flagFor` / `autonym` / `languageLabel` ("🇪🇸 Español"), `languagePickerItem({ label, codes, isActive, pick })` (the 2-up primary-highlighted MenuItem factory — storage and policy live in your closures), and `addLanguageRows(kb, { codes, pack, active? })` (the raw-InlineKeyboard twin for onboarding / group-welcome keyboards). |
|
|
447
|
+
| `@adriangalilea/utils/bot/language` (picker surface) | The language-picker vocabulary and surfaces, so bots don't fork label lists: `flagFor` / `autonym` / `languageLabel` ("🇪🇸 Español"), `languagePickerItem({ label, codes, isActive, pick })` (the 2-up primary-highlighted MenuItem factory — storage and policy live in your closures), and `addLanguageRows(kb, { codes, pack, active?, activeStyle? })` (the raw-InlineKeyboard twin for onboarding / group-welcome keyboards; `activeStyle: "success"` when primary already marks something else on the keyboard). |
|
|
448
448
|
| `@adriangalilea/utils/bot/user` | `userLabel(u)` — the conditional "[name] [@username] [id]" line every bot re-rolls for admin DMs and logs: `Ada Lovelace (@ada · 42)` / `Ada (42)` / `@ada (42)` / `id 42`, missing pieces drop instead of padding. Reads both gramio spellings (`firstName` / `first_name`); plain text by design. |
|
|
449
449
|
| `@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. |
|
|
450
450
|
| `@adriangalilea/utils/bot/llm` | The full LLM-chatbot pipeline in one module. **Input:** `streamChat(response)` parses OpenAI-compatible SSE (OpenAI, vllm, mlx-lm, llama.cpp, Together, Groq, …) into a typed `AsyncGenerator<{type: 'content' \| 'reasoning', text}>`. **Output:** `ctx.startStream()` (low-level: debounced markdown to Telegram, 4000-char split, exposes `wasPartial` after `.end()`). `ctx.startChatStream(response)` (high-level: consumes the stream, renders reasoning as a Telegram `expandable_blockquote` entity + content as streamed markdown — both go through `markdownToFormattable` with graceful degradation — returns `{ content, reasoning }`). **History:** `llmHistory({...})` returns `.plugin` (decorates `ctx.llm` with `.add() / .get() / .clear() / .all() / .clearAll()`, per-(user, thread) OpenAI `ChatMessage` shape, persisted in the shared session record so the menu's 🗑 Forget wipes it automatically) AND `.menuItem` (drop-in "🗑 Delete this thread" for `botMenu` — wipes the LLM history AND calls `deleteForumTopic` so the Telegram thread + all its messages disappear from the chat; falls back to Redis-only clear when no `threadId` is present). |
|
package/dist/bot/admin.d.ts
CHANGED
|
@@ -32,6 +32,9 @@ type MaybePromise<T> = T | Promise<T>;
|
|
|
32
32
|
* per update. The FIRST id is primary (`ctx.adminId`); `ctx.isAdmin` is true for any id in the set.
|
|
33
33
|
*/
|
|
34
34
|
export type Admins = number | readonly number[] | (() => MaybePromise<number | readonly number[]>);
|
|
35
|
+
/** Parse a comma/space-separated id list from an env string ("123, 456 789") into clean
|
|
36
|
+
* positive-integer ids — the raw material for an {@link Admins} source. Worker-safe. */
|
|
37
|
+
export declare function parseIdList(raw: string | undefined): number[];
|
|
35
38
|
export declare const adminContext: (admins: Admins) => Plugin<{}, import("gramio").DeriveDefinitions & {
|
|
36
39
|
global: {
|
|
37
40
|
adminId: number;
|
package/dist/bot/admin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/bot/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC;;;GAGG;AACH,MAAM,MAAM,MAAM,GACf,MAAM,GACN,SAAS,MAAM,EAAE,GACjB,CAAC,MAAM,YAAY,CAAC,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAQpD,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM;;;;;MAsB1C,CAAC"}
|
|
1
|
+
{"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/bot/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,KAAK,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC;;;GAGG;AACH,MAAM,MAAM,MAAM,GACf,MAAM,GACN,SAAS,MAAM,EAAE,GACjB,CAAC,MAAM,YAAY,CAAC,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;AAQpD;yFACyF;AACzF,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAK7D;AAED,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM;;;;;MAsB1C,CAAC"}
|
package/dist/bot/admin.js
CHANGED
|
@@ -28,6 +28,14 @@
|
|
|
28
28
|
import { Plugin } from "gramio";
|
|
29
29
|
/** Coerce any source value to a clean, positive-integer id array (junk writes screamed out). */
|
|
30
30
|
const toIds = (v) => (typeof v === "number" ? [v] : v).filter((n) => typeof n === "number" && Number.isFinite(n) && n > 0);
|
|
31
|
+
/** Parse a comma/space-separated id list from an env string ("123, 456 789") into clean
|
|
32
|
+
* positive-integer ids — the raw material for an {@link Admins} source. Worker-safe. */
|
|
33
|
+
export function parseIdList(raw) {
|
|
34
|
+
return (raw ?? "")
|
|
35
|
+
.split(/[\s,]+/)
|
|
36
|
+
.map((s) => Number(s.trim()))
|
|
37
|
+
.filter((n) => Number.isFinite(n) && n > 0);
|
|
38
|
+
}
|
|
31
39
|
export const adminContext = (admins) => {
|
|
32
40
|
// Normalize every source shape to ONE async resolver. A static source resolves the array once;
|
|
33
41
|
// a function is called on each update — that liveness is the whole point of the plugin.
|
package/dist/bot/admin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/bot/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAahC,gGAAgG;AAChG,MAAM,KAAK,GAAG,CAAC,CAA6B,EAAY,EAAE,CACzD,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAC3D,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,EAAE;IAC9C,+FAA+F;IAC/F,wFAAwF;IACxF,MAAM,OAAO,GACZ,OAAO,MAAM,KAAK,UAAU;QAC3B,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,MAAM,EAAE,CAAC;QACnC,CAAC,CAAC,CAAC,GAAG,EAAE;YACN,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1B,OAAO,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC;QACxB,CAAC,CAAC,EAAE,CAAC;IAER,OAAO,IAAI,MAAM,CAAC,gCAAgC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACxE,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAC;QAC5B,4FAA4F;QAC5F,2CAA2C;QAC3C,MAAM,QAAQ,GACb,UAAU,IAAI,GAAG,CAAC,CAAC,CAAE,GAA6B,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,OAAO;YACN,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YACpB,OAAO,EAAE,OAAO,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;SAC/D,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/bot/admin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAahC,gGAAgG;AAChG,MAAM,KAAK,GAAG,CAAC,CAA6B,EAAY,EAAE,CACzD,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAC3D,CAAC;AAEH;yFACyF;AACzF,MAAM,UAAU,WAAW,CAAC,GAAuB;IAClD,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;SAChB,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;SAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,EAAE;IAC9C,+FAA+F;IAC/F,wFAAwF;IACxF,MAAM,OAAO,GACZ,OAAO,MAAM,KAAK,UAAU;QAC3B,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,MAAM,EAAE,CAAC;QACnC,CAAC,CAAC,CAAC,GAAG,EAAE;YACN,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1B,OAAO,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC;QACxB,CAAC,CAAC,EAAE,CAAC;IAER,OAAO,IAAI,MAAM,CAAC,gCAAgC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACxE,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAC;QAC5B,4FAA4F;QAC5F,2CAA2C;QAC3C,MAAM,QAAQ,GACb,UAAU,IAAI,GAAG,CAAC,CAAC,CAAE,GAA6B,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,OAAO;YACN,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YACpB,OAAO,EAAE,OAAO,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;SAC/D,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC"}
|
package/package.json
CHANGED