@llblab/pi-telegram 0.43.2 → 0.44.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/AGENTS.md +1 -1
- package/BACKLOG.md +0 -1
- package/CHANGELOG.md +9 -5
- package/README.md +1 -1
- package/docs/outbound.md +8 -2
- package/docs/public-api.md +1 -0
- package/index.ts +22 -19
- package/lib/activity.ts +19 -5
- package/lib/bindings.ts +9 -1
- package/lib/config.ts +1 -1
- package/lib/delivery.ts +18 -18
- package/lib/lifecycle.ts +7 -1
- package/lib/menu-settings.ts +2 -2
- package/lib/outbound-attachments.ts +23 -30
- package/lib/outbound-voice.ts +28 -42
- package/lib/outbound.ts +18 -14
- package/lib/preview.ts +115 -70
- package/lib/queue.ts +18 -8
- package/lib/replies.ts +46 -38
- package/lib/telegram-api.ts +36 -3
- package/package.json +1 -1
package/lib/telegram-api.ts
CHANGED
|
@@ -1783,11 +1783,44 @@ export function createTelegramBridgeApiRuntime(
|
|
|
1783
1783
|
*/
|
|
1784
1784
|
export function createTelegramApiClient(
|
|
1785
1785
|
getBotToken: () => string | undefined,
|
|
1786
|
-
options: TelegramAnswerCallbackQueryOptions = {},
|
|
1786
|
+
options: TelegramAnswerCallbackQueryOptions & { now?: () => number } = {},
|
|
1787
1787
|
): TelegramApiClient {
|
|
1788
|
+
const now = options.now ?? Date.now;
|
|
1789
|
+
const draftRetryNotBeforeByTarget = new Map<string, number>();
|
|
1788
1790
|
return {
|
|
1789
|
-
call: async (
|
|
1790
|
-
|
|
1791
|
+
call: async <TResponse>(
|
|
1792
|
+
method: string,
|
|
1793
|
+
body: Record<string, unknown>,
|
|
1794
|
+
options?: TelegramApiCallOptions,
|
|
1795
|
+
): Promise<TResponse> => {
|
|
1796
|
+
const token = getBotToken();
|
|
1797
|
+
// Cooldown keys retain only the public bot-id prefix, not the credential.
|
|
1798
|
+
const botId = token?.match(/^(\d+):/)?.[1];
|
|
1799
|
+
const isDraft = method === "sendMessageDraft" || method === "sendRichMessageDraft";
|
|
1800
|
+
const draftKey = isDraft && botId
|
|
1801
|
+
? `${botId}:${String(body.chat_id)}:${String(body.message_thread_id ?? "all")}`
|
|
1802
|
+
: undefined;
|
|
1803
|
+
if (draftKey) {
|
|
1804
|
+
const nowMs = now();
|
|
1805
|
+
for (const [key, deadline] of draftRetryNotBeforeByTarget) {
|
|
1806
|
+
if (nowMs >= deadline) draftRetryNotBeforeByTarget.delete(key);
|
|
1807
|
+
}
|
|
1808
|
+
if (draftRetryNotBeforeByTarget.has(draftKey)) return false as TResponse;
|
|
1809
|
+
}
|
|
1810
|
+
try {
|
|
1811
|
+
// A draft is a replaceable snapshot, not a body to replay after backoff.
|
|
1812
|
+
return await callTelegram<TResponse>(
|
|
1813
|
+
token, method, body, isDraft ? { ...options, maxAttempts: 1 } : options,
|
|
1814
|
+
);
|
|
1815
|
+
} catch (error) {
|
|
1816
|
+
if (draftKey && isRetryableTelegramApiError(error)) {
|
|
1817
|
+
draftRetryNotBeforeByTarget.set(draftKey, Math.max(
|
|
1818
|
+
draftRetryNotBeforeByTarget.get(draftKey) ?? 0,
|
|
1819
|
+
now() + getTelegramRetryDelayMs(error, 0, options?.retryBaseDelayMs ?? 500),
|
|
1820
|
+
));
|
|
1821
|
+
}
|
|
1822
|
+
throw error;
|
|
1823
|
+
}
|
|
1791
1824
|
},
|
|
1792
1825
|
callMultipart: async (
|
|
1793
1826
|
method,
|