@adriangalilea/utils 2.21.1 → 2.23.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 +4 -11
- package/dist/bot/updates.d.ts +53 -0
- package/dist/bot/updates.d.ts.map +1 -0
- package/dist/bot/updates.js +94 -0
- package/dist/bot/updates.js.map +1 -0
- package/dist/bot/urls.d.ts +8 -0
- package/dist/bot/urls.d.ts.map +1 -1
- package/dist/bot/urls.js +22 -0
- package/dist/bot/urls.js.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -497,17 +497,9 @@ Cloudflare is one adapter, not the architecture: `bot/worker` and `bot/storage-d
|
|
|
497
497
|
- **Forget actually forgets.** `personalData.onForget` runs inside the same try as the session delete: your message logs/metrics/credit rows get wiped too, or the user is told it failed — never a partial erasure reading as success.
|
|
498
498
|
- **The composer owns instance wiring.** Features still compose manually (below) when you need full control, but every "same instance" contract has one home.
|
|
499
499
|
|
|
500
|
-
#### Threaded Mode
|
|
500
|
+
#### Threaded Mode
|
|
501
501
|
|
|
502
|
-
Telegram
|
|
503
|
-
|
|
504
|
-
```yaml
|
|
505
|
-
# pnpm-workspace.yaml
|
|
506
|
-
overrides:
|
|
507
|
-
"@gramio/contexts": "github:adriangalilea/contexts#local-build/auto-thread-private-chat-threaded-mode"
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
Then `pnpm install`. Every `ctx.send` / `ctx.sendDocument` / `ctx.reply` / etc. — including from callback handlers — will auto-forward `message_thread_id` and stay in the thread the message came from. If you don't use Threaded Mode, skip this.
|
|
502
|
+
Telegram's [Threaded Mode](https://telegram.org/blog/threaded-conversations) for private chats (BotFather → Bot Settings → Threaded Mode) auto-threads out of the box: `@gramio/contexts` ≥0.9 (what gramio ≥0.12 resolves) forwards `message_thread_id` on every `ctx.send` / `ctx.sendDocument` / `ctx.reply` — including from callback handlers, which carry `threadId` too. No fork, no override.
|
|
511
503
|
|
|
512
504
|
**Runs on Cloudflare Workers / bun / anywhere.** Every bot subpath below is import-safe off Node — no filesystem access, no `node:*` modules, no import-time side effects anywhere in its graph — **except `bot/kit`**, which deliberately owns the Node-only pieces (process signal handling in `gracefulStart`, kev-backed env reading in `adminContext`). `pnpm test:worker-safe` walks every graph and screams on regression.
|
|
513
505
|
|
|
@@ -524,7 +516,8 @@ Then `pnpm install`. Every `ctx.send` / `ctx.sendDocument` / `ctx.reply` / etc.
|
|
|
524
516
|
| `@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)`). |
|
|
525
517
|
| `@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). |
|
|
526
518
|
| `@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. |
|
|
527
|
-
| `@adriangalilea/utils/bot/urls` | Telegram-message URL + entity parsing, on what the platform ALREADY parsed (entities carry exact UTF-16 spans — never `startsWith("/")` or a mention regex). `urlsInMessage(msg)` → the url module's `Url[]`: the visible text scanned by `urlsIn` PLUS `text_link` entities — hyperlinked words whose URL never appears in the text, invisible to any text scanner (what forwarded newsletters carry); a text_link's `raw` is its anchor words and its span covers them, so span-cutting treats linked words as the link. `isCommandMessage(msg)` (a `bot_command` entity at offset 0), `cutEntities(text, entities, shouldCut)` (exact span surgery; the predicate sees each visible slice), `messageTextAndEntities(msg)` (text or caption with ITS entity set). Framework-agnostic by shape: gramio's `MessageEntity` class and the raw Bot API object both fit. |
|
|
519
|
+
| `@adriangalilea/utils/bot/urls` | Telegram-message URL + entity parsing, on what the platform ALREADY parsed (entities carry exact UTF-16 spans — never `startsWith("/")` or a mention regex). `urlsInMessage(msg)` → the url module's `Url[]`: the visible text scanned by `urlsIn` PLUS `text_link` entities — hyperlinked words whose URL never appears in the text, invisible to any text scanner (what forwarded newsletters carry); a text_link's `raw` is its anchor words and its span covers them, so span-cutting treats linked words as the link. `isCommandMessage(msg)` (a `bot_command` entity at offset 0), `commandToken(msg)` (the leading command without any `@botname` suffix, `/summary@my_bot` → `/summary`; null for ordinary text), `commandAddressee(msg)` (the bot a command is explicitly addressed to, lowercased, null when bare — the group addressing gate: a bare command may belong to any bot in the room, one addressed elsewhere never concerns yours), `cutEntities(text, entities, shouldCut)` (exact span surgery; the predicate sees each visible slice), `messageTextAndEntities(msg)` (text or caption with ITS entity set). Framework-agnostic by shape: gramio's `MessageEntity` class and the raw Bot API object both fit. |
|
|
520
|
+
| `@adriangalilea/utils/bot/updates` | The pending-update queue of a webhook-less bot token, treated as the destroy-on-read resource it is (`getUpdates` with an offset CONFIRMS — destroys — everything below it). `updateQueue({ token, fetch?, apiRoot? })` → `peek({ limit? })` (webhook state + pending count + the queue head, verbatim; sends NO offset so nothing is ever confirmed — repeatable, zero risk), `count()`, `webhookInfo()`, and `drain({ onBatch, limit?, timeoutS?, quietPolls? })` — the one-chance-safe sweep: each raw batch is handed to `onBatch` (persist it somewhere durable) and AWAITED before the offset advances, because the next call is the confirmation; a crash re-delivers the unconfirmed tail on re-run, and the drain ends only after several consecutive silent long-polls, never on the first empty response. A 409 (webhook registered / competing poller) is a typed `SourcedError`, never a silent retry. Plain `fetch`, injectable for tests; no framework. |
|
|
528
521
|
| `@adriangalilea/utils/bot/inline-feedback` | Behavioral tripwire for BotFather's inline feedback probability (gates `chosen_inline_result`; defaults 0%, silently resets on bot transfer and inline-mode toggling, invisible to `getMe`): served-but-never-chosen crosses a threshold → throttled admin DM naming the exact BotFather switch. Storage injected as three ops; never throws into the answer path. |
|
|
529
522
|
| `@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. |
|
|
530
523
|
| `@adriangalilea/utils/llm` | Multi-provider LLM caller on the Vercel AI SDK — the policy layer the SDK doesn't ship. `createLlm({ providers, health? })` → `.stream(req)` (typed events: `delta` / `reasoning` / `reset` / `tool-call` / `end`) and `.complete(req)`. **Failover:** priority-ordered across OpenAI-compatible, Anthropic-compatible, and OpenRouter endpoints; multiple keys per provider (health tracked per key fingerprint); per-key circuit breaker with exponential cool-down persisted in any KV-shaped `HealthStore`; an attempt that dies after emitting yields `reset` (discard, next candidate regenerates); empty completions count as failures. **Accounting:** tokens summed across billed attempts; `costUsd` is the ACTUAL charge (OpenRouter usage accounting via `providerMetadata`, or a `cost` field on the raw usage frame) — never a price-table estimate. **Knobs:** per-model temperature, maxTokens caps, `disableThinking` mapped to each dialect. **Tools:** AI SDK `tool()` + `toolChoice` pass through (re-exported). Worker-safe; peers: `ai`, `@ai-sdk/openai-compatible`, `@ai-sdk/anthropic`, `@openrouter/ai-sdk-provider`. |
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** A raw Bot API update. Only `update_id` is load-bearing here; everything else passes through. */
|
|
2
|
+
export interface TelegramUpdate {
|
|
3
|
+
update_id: number;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface QueuePeek {
|
|
7
|
+
/** The registered webhook URL, or null when the token polls (getUpdates works). */
|
|
8
|
+
webhookUrl: string | null;
|
|
9
|
+
/** Updates waiting server-side (`getWebhookInfo.pending_update_count`). */
|
|
10
|
+
pending: number;
|
|
11
|
+
/** The first updates in the queue, verbatim. Empty when a webhook is registered (polling
|
|
12
|
+
* would 409) — the count above still tells the story. */
|
|
13
|
+
head: TelegramUpdate[];
|
|
14
|
+
}
|
|
15
|
+
export interface DrainResult {
|
|
16
|
+
drained: number;
|
|
17
|
+
batches: number;
|
|
18
|
+
lastUpdateId?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface UpdateQueueOptions {
|
|
21
|
+
token: string;
|
|
22
|
+
/** Transport override for tests. Defaults to global fetch. */
|
|
23
|
+
fetch?: typeof globalThis.fetch;
|
|
24
|
+
/** Bot API origin override (local Bot API servers). */
|
|
25
|
+
apiRoot?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Peek/drain/count over one bot token's pending-update queue. See the module doc for the
|
|
28
|
+
* destroy-on-read contract each verb upholds. */
|
|
29
|
+
export declare function updateQueue(options: UpdateQueueOptions): {
|
|
30
|
+
/** Raw `getWebhookInfo`. */
|
|
31
|
+
webhookInfo(): Promise<Record<string, unknown>>;
|
|
32
|
+
/** Updates waiting server-side, without touching any of them. */
|
|
33
|
+
count(): Promise<number>;
|
|
34
|
+
/** Non-destructive look: webhook state, pending count, and the first `limit` updates,
|
|
35
|
+
* verbatim. Confirms NOTHING — repeat as often as you like. */
|
|
36
|
+
peek({ limit }?: {
|
|
37
|
+
limit?: number;
|
|
38
|
+
}): Promise<QueuePeek>;
|
|
39
|
+
/**
|
|
40
|
+
* Drain the queue, one-chance-safe. `onBatch` receives each raw batch and is AWAITED
|
|
41
|
+
* before the offset advances — persist there, because the next `getUpdates` call is the
|
|
42
|
+
* confirmation that destroys the batch server-side. An `onBatch` throw aborts the drain
|
|
43
|
+
* with nothing confirmed beyond what `onBatch` already accepted; re-running resumes at
|
|
44
|
+
* the unconfirmed tail. Ends after `quietPolls` consecutive empty long-polls.
|
|
45
|
+
*/
|
|
46
|
+
drain({ onBatch, limit, timeoutS, quietPolls, }: {
|
|
47
|
+
onBatch: (updates: TelegramUpdate[]) => void | Promise<void>;
|
|
48
|
+
limit?: number;
|
|
49
|
+
timeoutS?: number;
|
|
50
|
+
quietPolls?: number;
|
|
51
|
+
}): Promise<DrainResult>;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=updates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updates.d.ts","sourceRoot":"","sources":["../../src/bot/updates.ts"],"names":[],"mappings":"AAqBA,mGAAmG;AACnG,MAAM,WAAW,cAAc;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACzB,mFAAmF;IACnF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB;8DAC0D;IAC1D,IAAI,EAAE,cAAc,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;kDACkD;AAClD,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB;IA0BrD,4BAA4B;mBACb,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAI/C,iEAAiE;aAClD,OAAO,CAAC,MAAM,CAAC;IAK9B;oEACgE;qBACtC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAQ,OAAO,CAAC,SAAS,CAAC;IAQtE;;;;;;OAMG;qDAMA;QACF,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,WAAW,CAAC;EAsBzB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pending-update queue of a webhook-less bot token, handled with the respect a
|
|
3
|
+
* destroy-on-read resource deserves. Telegram's `getUpdates` CONFIRMS (discards) every update
|
|
4
|
+
* older than the offset it is called with — reading is destructive, and a queue drained
|
|
5
|
+
* carelessly is gone forever. Two safety properties are the whole point:
|
|
6
|
+
*
|
|
7
|
+
* PEEK is free. `getUpdates` WITHOUT an offset confirms nothing: webhook state, the pending
|
|
8
|
+
* count, and the head of the queue are all inspectable, repeatably, at zero risk.
|
|
9
|
+
*
|
|
10
|
+
* DRAIN is write-before-confirm. Each raw batch is handed to the caller's `onBatch` (persist
|
|
11
|
+
* it there — disk, db, anywhere durable) and AWAITED before the next `getUpdates` call
|
|
12
|
+
* advances the offset, because that next call IS the confirmation. A crash mid-drain loses
|
|
13
|
+
* nothing: re-run, and the unconfirmed tail re-delivers. The drain ends only after the queue
|
|
14
|
+
* stays silent across several consecutive long-polls, never on the first empty response.
|
|
15
|
+
*
|
|
16
|
+
* Framework-free: plain `fetch` against the Bot API, injectable for tests. A 409 means the
|
|
17
|
+
* token has a webhook registered or another poller is competing — surfaced as a typed error,
|
|
18
|
+
* never retried silently.
|
|
19
|
+
*/
|
|
20
|
+
import { SourcedError } from "../offensive.js";
|
|
21
|
+
/** Peek/drain/count over one bot token's pending-update queue. See the module doc for the
|
|
22
|
+
* destroy-on-read contract each verb upholds. */
|
|
23
|
+
export function updateQueue(options) {
|
|
24
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
25
|
+
const root = options.apiRoot ?? "https://api.telegram.org";
|
|
26
|
+
const call = async (method, params) => {
|
|
27
|
+
const res = await doFetch(`${root}/bot${options.token}/${method}`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { "content-type": "application/json" },
|
|
30
|
+
body: JSON.stringify(params ?? {}),
|
|
31
|
+
});
|
|
32
|
+
const body = (await res.json());
|
|
33
|
+
if (!body.ok) {
|
|
34
|
+
throw new SourcedError({
|
|
35
|
+
source: "telegram",
|
|
36
|
+
operation: method,
|
|
37
|
+
message: body.error_code === 409
|
|
38
|
+
? `${body.description ?? "409"} (a webhook is registered, or another poller is competing)`
|
|
39
|
+
: (body.description ?? "unknown error"),
|
|
40
|
+
status: body.error_code ?? res.status,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return body.result;
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
/** Raw `getWebhookInfo`. */
|
|
47
|
+
webhookInfo() {
|
|
48
|
+
return call("getWebhookInfo");
|
|
49
|
+
},
|
|
50
|
+
/** Updates waiting server-side, without touching any of them. */
|
|
51
|
+
async count() {
|
|
52
|
+
const info = await call("getWebhookInfo");
|
|
53
|
+
return info.pending_update_count ?? 0;
|
|
54
|
+
},
|
|
55
|
+
/** Non-destructive look: webhook state, pending count, and the first `limit` updates,
|
|
56
|
+
* verbatim. Confirms NOTHING — repeat as often as you like. */
|
|
57
|
+
async peek({ limit = 1 } = {}) {
|
|
58
|
+
const info = await call("getWebhookInfo");
|
|
59
|
+
const webhookUrl = info.url ? info.url : null;
|
|
60
|
+
// With a webhook registered getUpdates would 409; the count already tells the story.
|
|
61
|
+
const head = webhookUrl ? [] : await call("getUpdates", { limit, timeout: 0 });
|
|
62
|
+
return { webhookUrl, pending: info.pending_update_count ?? 0, head };
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* Drain the queue, one-chance-safe. `onBatch` receives each raw batch and is AWAITED
|
|
66
|
+
* before the offset advances — persist there, because the next `getUpdates` call is the
|
|
67
|
+
* confirmation that destroys the batch server-side. An `onBatch` throw aborts the drain
|
|
68
|
+
* with nothing confirmed beyond what `onBatch` already accepted; re-running resumes at
|
|
69
|
+
* the unconfirmed tail. Ends after `quietPolls` consecutive empty long-polls.
|
|
70
|
+
*/
|
|
71
|
+
async drain({ onBatch, limit = 100, timeoutS = 10, quietPolls = 3, }) {
|
|
72
|
+
let offset;
|
|
73
|
+
let drained = 0;
|
|
74
|
+
let batches = 0;
|
|
75
|
+
let lastUpdateId;
|
|
76
|
+
let quiet = 0;
|
|
77
|
+
while (quiet < quietPolls) {
|
|
78
|
+
const batch = await call("getUpdates", { offset, limit, timeout: timeoutS });
|
|
79
|
+
if (batch.length === 0) {
|
|
80
|
+
quiet += 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
quiet = 0;
|
|
84
|
+
await onBatch(batch); // persist FIRST…
|
|
85
|
+
lastUpdateId = batch[batch.length - 1].update_id;
|
|
86
|
+
offset = lastUpdateId + 1; // …the NEXT call confirms
|
|
87
|
+
drained += batch.length;
|
|
88
|
+
batches += 1;
|
|
89
|
+
}
|
|
90
|
+
return { drained, batches, lastUpdateId };
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=updates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updates.js","sourceRoot":"","sources":["../../src/bot/updates.ts"],"names":[],"mappings":"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"}
|
package/dist/bot/urls.d.ts
CHANGED
|
@@ -56,6 +56,14 @@ export declare function messageTextAndEntities(message: MessageLike): {
|
|
|
56
56
|
export declare function urlsInMessage(message: MessageLike, opts?: UrlsInOptions): Url[];
|
|
57
57
|
/** True when the message IS a command: a `bot_command` entity at offset 0 — Telegram's own parse, not `startsWith("/")`. */
|
|
58
58
|
export declare function isCommandMessage(message: MessageLike): boolean;
|
|
59
|
+
/** The visible command token of a leading `bot_command` entity, without any `@botname` suffix
|
|
60
|
+
* (`/summary@my_bot …` → `/summary`). Null for ordinary text. */
|
|
61
|
+
export declare function commandToken(message: MessageLike): string | null;
|
|
62
|
+
/** The bot a leading command is explicitly addressed to (`/cmd@BotName` → `botname`), or null for
|
|
63
|
+
* a bare `/cmd`. Lowercased — Telegram usernames are case-insensitive. This is the addressing
|
|
64
|
+
* gate for command replies in groups: a bare command may belong to any bot in the room, and one
|
|
65
|
+
* addressed elsewhere never concerns yours — answering it is spam. */
|
|
66
|
+
export declare function commandAddressee(message: MessageLike): string | null;
|
|
59
67
|
/**
|
|
60
68
|
* The message text with the entity spans `shouldCut` selects replaced by a
|
|
61
69
|
* space (offsets are honored exactly, so nested/adjacent formatting never
|
package/dist/bot/urls.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../src/bot/urls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,aAAa,EAAiB,MAAM,2BAA2B,CAAC;AAExF,sGAAsG;AACtG,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED;+FAC+F;AAC/F,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,kBAAkB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,oBAAoB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAA;CAAE,CAI9G;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,GAAG,EAAE,CA0B/E;AAED,4HAA4H;AAC5H,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAG9D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,UAAU,EAAE,EAC/B,SAAS,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GACvD,MAAM,CASR"}
|
|
1
|
+
{"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../src/bot/urls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,aAAa,EAAiB,MAAM,2BAA2B,CAAC;AAExF,sGAAsG;AACtG,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED;+FAC+F;AAC/F,MAAM,WAAW,WAAW;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,kBAAkB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,oBAAoB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAA;CAAE,CAI9G;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,GAAG,EAAE,CA0B/E;AAED,4HAA4H;AAC5H,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAG9D;AAED;kEACkE;AAClE,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAMhE;AAED;;;uEAGuE;AACvE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAMpE;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,UAAU,EAAE,EAC/B,SAAS,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,GACvD,MAAM,CASR"}
|
package/dist/bot/urls.js
CHANGED
|
@@ -65,6 +65,28 @@ export function isCommandMessage(message) {
|
|
|
65
65
|
const { entities } = messageTextAndEntities(message);
|
|
66
66
|
return entities.some((e) => e.type === "bot_command" && e.offset === 0);
|
|
67
67
|
}
|
|
68
|
+
/** The visible command token of a leading `bot_command` entity, without any `@botname` suffix
|
|
69
|
+
* (`/summary@my_bot …` → `/summary`). Null for ordinary text. */
|
|
70
|
+
export function commandToken(message) {
|
|
71
|
+
const { text, entities } = messageTextAndEntities(message);
|
|
72
|
+
const entity = entities.find((e) => e.type === "bot_command" && e.offset === 0);
|
|
73
|
+
if (!entity)
|
|
74
|
+
return null;
|
|
75
|
+
const token = text.slice(0, entity.length).split("@", 1)[0];
|
|
76
|
+
return token || "/?";
|
|
77
|
+
}
|
|
78
|
+
/** The bot a leading command is explicitly addressed to (`/cmd@BotName` → `botname`), or null for
|
|
79
|
+
* a bare `/cmd`. Lowercased — Telegram usernames are case-insensitive. This is the addressing
|
|
80
|
+
* gate for command replies in groups: a bare command may belong to any bot in the room, and one
|
|
81
|
+
* addressed elsewhere never concerns yours — answering it is spam. */
|
|
82
|
+
export function commandAddressee(message) {
|
|
83
|
+
const { text, entities } = messageTextAndEntities(message);
|
|
84
|
+
const entity = entities.find((e) => e.type === "bot_command" && e.offset === 0);
|
|
85
|
+
if (!entity)
|
|
86
|
+
return null;
|
|
87
|
+
const addressee = text.slice(0, entity.length).split("@", 2)[1];
|
|
88
|
+
return addressee ? addressee.toLowerCase() : null;
|
|
89
|
+
}
|
|
68
90
|
/**
|
|
69
91
|
* The message text with the entity spans `shouldCut` selects replaced by a
|
|
70
92
|
* space (offsets are honored exactly, so nested/adjacent formatting never
|
package/dist/bot/urls.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urls.js","sourceRoot":"","sources":["../../src/bot/urls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAgC,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAuBxF,kFAAkF;AAClF,MAAM,UAAU,sBAAsB,CAAC,OAAoB;IAC1D,OAAO,OAAO,CAAC,IAAI,KAAK,SAAS;QAChC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE,EAAE;QAC1D,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;AAC7E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,OAAoB,EAAE,IAAoB;IACvE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,GAAG;YAAE,SAAS;QACzD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,QAAQ;YAAE,SAAS;QACxB,GAAG,CAAC,IAAI,CAAC;YACR,GAAG,QAAQ;YACX,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC7D,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,GAAG,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM;SAClC,CAAC,CAAC;IACJ,CAAC;IACD,yFAAyF;IACzF,wFAAwF;IACxF,wFAAwF;IACxF,4EAA4E;IAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC;IACrF,IAAI,OAAO,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACtC,IAAI,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/E,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AAC9C,CAAC;AAED,4HAA4H;AAC5H,MAAM,UAAU,gBAAgB,CAAC,OAAoB;IACpD,MAAM,EAAE,QAAQ,EAAE,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACrD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAC1B,IAAY,EACZ,QAA+B,EAC/B,SAAyD;IAEzD,MAAM,MAAM,GAAG,QAAQ;SACrB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SACtE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACxB,GAAG,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC"}
|
|
1
|
+
{"version":3,"file":"urls.js","sourceRoot":"","sources":["../../src/bot/urls.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adriangalilea/utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.23.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",
|
|
@@ -156,6 +156,10 @@
|
|
|
156
156
|
"types": "./dist/bot/urls.d.ts",
|
|
157
157
|
"default": "./dist/bot/urls.js"
|
|
158
158
|
},
|
|
159
|
+
"./bot/updates": {
|
|
160
|
+
"types": "./dist/bot/updates.d.ts",
|
|
161
|
+
"default": "./dist/bot/updates.js"
|
|
162
|
+
},
|
|
159
163
|
"./bot/reactions": {
|
|
160
164
|
"types": "./dist/bot/reactions.d.ts",
|
|
161
165
|
"default": "./dist/bot/reactions.js"
|
|
@@ -205,6 +209,7 @@
|
|
|
205
209
|
"test:self-echo": "tsx tests/self-echo-test.ts",
|
|
206
210
|
"test:url": "tsx tests/url-test.ts",
|
|
207
211
|
"test:bot-urls": "tsx tests/bot-urls-test.ts",
|
|
212
|
+
"test:bot-updates": "tsx tests/bot-updates-test.ts",
|
|
208
213
|
"test:reactions": "tsx tests/reactions-test.ts"
|
|
209
214
|
},
|
|
210
215
|
"keywords": [
|