@llblab/pi-telegram 0.52.2 → 0.53.1
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 +9 -7
- package/BACKLOG.md +1 -18
- package/CHANGELOG.md +15 -0
- package/README.md +7 -11
- package/api/commands.ts +3 -0
- package/dist/api/commands.d.ts +1 -1
- package/dist/lib/activity-verbosity.d.ts +1 -5
- package/dist/lib/activity-verbosity.js +15 -42
- package/dist/lib/activity.d.ts +9 -0
- package/dist/lib/activity.js +39 -10
- package/dist/lib/agent-messages.js +7 -3
- package/dist/lib/bindings.d.ts +43 -5
- package/dist/lib/bindings.js +163 -20
- package/dist/lib/bus-api.d.ts +12 -0
- package/dist/lib/bus-api.js +182 -79
- package/dist/lib/bus-follower.d.ts +111 -31
- package/dist/lib/bus-follower.js +1324 -359
- package/dist/lib/bus-leader.d.ts +41 -91
- package/dist/lib/bus-leader.js +969 -637
- package/dist/lib/bus-transport.js +16 -9
- package/dist/lib/bus.d.ts +215 -18
- package/dist/lib/bus.js +1048 -327
- package/dist/lib/channel-posts.d.ts +5 -0
- package/dist/lib/channel-posts.js +434 -261
- package/dist/lib/command-templates.d.ts +26 -5
- package/dist/lib/command-templates.js +92 -176
- package/dist/lib/commands.d.ts +168 -82
- package/dist/lib/commands.js +1409 -291
- package/dist/lib/config.d.ts +1 -8
- package/dist/lib/config.js +34 -76
- package/dist/lib/delivery.d.ts +2 -2
- package/dist/lib/delivery.js +16 -16
- package/dist/lib/extension.js +639 -171
- package/dist/lib/generative-app-worker.mjs +19 -7
- package/dist/lib/generative-apps.d.ts +0 -5
- package/dist/lib/generative-apps.js +61 -49
- package/dist/lib/inbound.d.ts +5 -0
- package/dist/lib/inbound.js +35 -59
- package/dist/lib/journal.d.ts +33 -3
- package/dist/lib/journal.js +2063 -782
- package/dist/lib/lifecycle.d.ts +2 -6
- package/dist/lib/lifecycle.js +75 -58
- package/dist/lib/locks.d.ts +29 -3
- package/dist/lib/locks.js +289 -108
- package/dist/lib/logging.js +50 -14
- package/dist/lib/media.d.ts +22 -1
- package/dist/lib/media.js +46 -28
- package/dist/lib/menu-model.d.ts +19 -5
- package/dist/lib/menu-model.js +53 -11
- package/dist/lib/menu-queue.d.ts +5 -4
- package/dist/lib/menu-queue.js +45 -63
- package/dist/lib/menu-settings.d.ts +5 -4
- package/dist/lib/menu-settings.js +114 -78
- package/dist/lib/menu-status.d.ts +1 -1
- package/dist/lib/menu-status.js +8 -25
- package/dist/lib/menu-thinking.d.ts +6 -1
- package/dist/lib/menu-thinking.js +14 -21
- package/dist/lib/menu.d.ts +8 -61
- package/dist/lib/menu.js +92 -164
- package/dist/lib/model.d.ts +1 -1
- package/dist/lib/model.js +2 -16
- package/dist/lib/outbound-attachments.d.ts +6 -27
- package/dist/lib/outbound-attachments.js +45 -38
- package/dist/lib/outbound-buttons.js +22 -16
- package/dist/lib/outbound-markup.d.ts +0 -2
- package/dist/lib/outbound-markup.js +51 -64
- package/dist/lib/outbound-voice.js +6 -3
- package/dist/lib/outbound.d.ts +6 -6
- package/dist/lib/outbound.js +65 -51
- package/dist/lib/ownership.js +6 -2
- package/dist/lib/paths.d.ts +5 -0
- package/dist/lib/paths.js +37 -21
- package/dist/lib/pi.d.ts +2 -0
- package/dist/lib/pi.js +8 -1
- package/dist/lib/polling.d.ts +21 -37
- package/dist/lib/polling.js +59 -50
- package/dist/lib/preview.js +39 -19
- package/dist/lib/process-identity.d.ts +24 -0
- package/dist/lib/process-identity.js +133 -0
- package/dist/lib/prompts.js +2 -7
- package/dist/lib/queue.d.ts +14 -16
- package/dist/lib/queue.js +252 -127
- package/dist/lib/recovery.d.ts +2 -83
- package/dist/lib/recovery.js +20 -274
- package/dist/lib/replies.d.ts +16 -24
- package/dist/lib/replies.js +99 -116
- package/dist/lib/routing.d.ts +120 -7
- package/dist/lib/routing.js +4667 -1152
- package/dist/lib/runtime.d.ts +1 -11
- package/dist/lib/sections.d.ts +4 -29
- package/dist/lib/sections.js +7 -20
- package/dist/lib/skills.js +4 -3
- package/dist/lib/status.js +86 -57
- package/dist/lib/sync.d.ts +1 -3
- package/dist/lib/sync.js +67 -43
- package/dist/lib/target.d.ts +4 -0
- package/dist/lib/target.js +18 -0
- package/dist/lib/telegram-api.d.ts +18 -13
- package/dist/lib/telegram-api.js +148 -53
- package/dist/lib/text-groups.js +4 -39
- package/dist/lib/thread-cleanup-manager.d.ts +6 -27
- package/dist/lib/thread-cleanup-manager.js +369 -186
- package/dist/lib/thread-display.d.ts +1 -2
- package/dist/lib/thread-display.js +58 -38
- package/dist/lib/thread-naming.d.ts +28 -8
- package/dist/lib/thread-naming.js +175 -66
- package/dist/lib/thread-reconciler.d.ts +42 -16
- package/dist/lib/thread-reconciler.js +90 -50
- package/dist/lib/threads.d.ts +82 -20
- package/dist/lib/threads.js +2247 -855
- package/dist/lib/time-injection.js +1 -2
- package/dist/lib/turns.js +1 -19
- package/dist/lib/updates.d.ts +169 -80
- package/dist/lib/updates.js +2418 -641
- package/dist/lib/voice.d.ts +7 -22
- package/dist/lib/voice.js +7 -22
- package/dist/lib/wire.js +1 -1
- package/dist/lib/workspace-admission.d.ts +3 -1
- package/dist/lib/workspace-admission.js +425 -211
- package/dist/lib/workspace-identity.js +8 -13
- package/dist/lib/workspace-retirement.d.ts +1 -1
- package/dist/lib/workspace-retirement.js +328 -140
- package/dist/lib/workspace-slots.js +8 -4
- package/dist/package.json +1 -1
- package/docs/architecture.md +31 -29
- package/docs/inbound.md +1 -1
- package/docs/multi-instance-bus.md +15 -3
- package/docs/outbound.md +1 -1
- package/docs/public-api.md +29 -1
- package/docs/ui-style.md +25 -8
- package/lib/activity-verbosity.ts +59 -82
- package/lib/activity.ts +146 -102
- package/lib/agent-messages.ts +12 -5
- package/lib/bindings.ts +389 -82
- package/lib/bus-api.ts +263 -102
- package/lib/bus-follower.ts +2440 -601
- package/lib/bus-leader.ts +2209 -1290
- package/lib/bus-transport.ts +46 -12
- package/lib/bus.ts +1673 -444
- package/lib/channel-posts.ts +848 -327
- package/lib/command-templates.ts +152 -265
- package/lib/commands.ts +2398 -555
- package/lib/config.ts +177 -170
- package/lib/delivery.ts +41 -29
- package/lib/extension.ts +1206 -433
- package/lib/generative-app-worker.mjs +19 -7
- package/lib/generative-apps.ts +324 -211
- package/lib/inbound.ts +95 -97
- package/lib/journal.ts +5311 -1763
- package/lib/keyboard.ts +1 -3
- package/lib/lifecycle.ts +128 -78
- package/lib/locks.ts +677 -203
- package/lib/logging.ts +147 -58
- package/lib/media.ts +82 -43
- package/lib/menu-model.ts +85 -18
- package/lib/menu-queue.ts +88 -129
- package/lib/menu-settings.ts +260 -155
- package/lib/menu-status.ts +20 -60
- package/lib/menu-thinking.ts +41 -56
- package/lib/menu.ts +112 -285
- package/lib/model.ts +8 -22
- package/lib/outbound-attachments.ts +156 -125
- package/lib/outbound-buttons.ts +76 -49
- package/lib/outbound-markup.ts +96 -94
- package/lib/outbound-voice.ts +33 -27
- package/lib/outbound.ts +128 -125
- package/lib/ownership.ts +19 -10
- package/lib/paths.ts +148 -49
- package/lib/pi.ts +35 -15
- package/lib/polling.ts +144 -147
- package/lib/preview.ts +93 -40
- package/lib/process-identity.ts +164 -0
- package/lib/prompts.ts +4 -11
- package/lib/queue.ts +516 -301
- package/lib/recovery.ts +50 -454
- package/lib/rendering.ts +1 -3
- package/lib/replies.ts +248 -209
- package/lib/routing.ts +8509 -2186
- package/lib/runtime.ts +1 -12
- package/lib/sections.ts +24 -89
- package/lib/setup.ts +1 -3
- package/lib/skills.ts +9 -4
- package/lib/status.ts +215 -110
- package/lib/sync.ts +448 -361
- package/lib/target.ts +22 -3
- package/lib/telegram-api.ts +302 -127
- package/lib/text-groups.ts +5 -39
- package/lib/thread-cleanup-manager.ts +833 -331
- package/lib/thread-display.ts +213 -97
- package/lib/thread-naming.ts +232 -87
- package/lib/thread-reconciler.ts +155 -72
- package/lib/threads.ts +5318 -1845
- package/lib/time-injection.ts +1 -4
- package/lib/turns.ts +15 -28
- package/lib/updates.ts +5184 -1612
- package/lib/voice.ts +7 -35
- package/lib/wire.ts +1 -1
- package/lib/workspace-admission.ts +996 -416
- package/lib/workspace-identity.ts +14 -17
- package/lib/workspace-retirement.ts +878 -376
- package/lib/workspace-slots.ts +22 -13
- package/package.json +1 -1
- package/scripts/check-downgrade.mjs +0 -472
- package/scripts/measure-workspace.mjs +0 -108
package/dist/lib/sync.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
* Zones: Telegram bot reality mirror, demand-driven reconciliation, status diagnostics
|
|
4
4
|
* Owns pure contracts for deciding when local Telegram mirror state should be refreshed without querying Telegram on every action
|
|
5
5
|
*/
|
|
6
|
-
import { getTelegramApiErrorRequestTarget, isTelegramStaleTargetHttpError } from "./telegram-api.js";
|
|
7
6
|
import { getTelegramTargetKey } from "./target.js";
|
|
7
|
+
import { getTelegramApiErrorRequestTarget, isTelegramStaleTargetHttpError, } from "./telegram-api.js";
|
|
8
8
|
import * as ThreadReconciler from "./thread-reconciler.js";
|
|
9
|
-
import {
|
|
10
|
-
import { normalizeTelegramWorkspacePath } from "./workspace-identity.js";
|
|
9
|
+
import { commitTelegramWorkspaceProvisionBinding, createTelegramCleanupTargetProtection, getTelegramTargetFromApiBody, getTelegramThreadOwnerKey, isSameTelegramProcessInstance, isTelegramTopicTargetStaleError, provisionOwnBusTopic, } from "./threads.js";
|
|
11
10
|
import { createTelegramWorkspaceAdmissionOperationId, runWithTelegramWorkspaceAdmissionsAsync, } from "./workspace-admission.js";
|
|
12
|
-
import {
|
|
11
|
+
import { normalizeTelegramWorkspacePath } from "./workspace-identity.js";
|
|
12
|
+
import { TelegramWorkspaceSlotUnavailableError } from "./workspace-slots.js";
|
|
13
13
|
function markTelegramConfigSyncChange(state, action, options) {
|
|
14
14
|
const nowMs = options?.nowMs ?? Date.now();
|
|
15
15
|
let nextState = markTelegramSyncSliceFresh(state, "pairing", {
|
|
@@ -32,10 +32,13 @@ export function createTelegramPreservedLeaderQuitHandler(deps) {
|
|
|
32
32
|
const profile = deps.getProfileName();
|
|
33
33
|
if (epoch === undefined || !isSessionCurrent())
|
|
34
34
|
return undefined;
|
|
35
|
-
const isCurrent = () => isSessionCurrent() &&
|
|
36
|
-
deps.
|
|
35
|
+
const isCurrent = () => isSessionCurrent() &&
|
|
36
|
+
deps.getCurrentLeaderEpoch() === epoch &&
|
|
37
|
+
deps.getProfileName() === profile &&
|
|
38
|
+
deps.isPollingSuspended();
|
|
37
39
|
return async () => {
|
|
38
|
-
if (!isCurrent() ||
|
|
40
|
+
if (!isCurrent() ||
|
|
41
|
+
(await deps.resolveAutomaticThreadCleanupEnabled()) !== false)
|
|
39
42
|
return;
|
|
40
43
|
if (!isCurrent())
|
|
41
44
|
return;
|
|
@@ -49,13 +52,20 @@ export function createTelegramPreservedLeaderQuitHandler(deps) {
|
|
|
49
52
|
await deps.topicTargetStore.load();
|
|
50
53
|
if (!isCurrent())
|
|
51
54
|
return;
|
|
52
|
-
const records = deps.topicTargetStore
|
|
55
|
+
const records = deps.topicTargetStore
|
|
56
|
+
.list()
|
|
57
|
+
.filter((record) => record.instanceId === deps.instanceId &&
|
|
58
|
+
(record.status === "active" || record.status === "starting"));
|
|
53
59
|
if (records.length !== 1)
|
|
54
60
|
return;
|
|
55
61
|
const record = records[0];
|
|
56
|
-
if (deps.topicTargetStore
|
|
62
|
+
if (deps.topicTargetStore
|
|
63
|
+
.listPendingCleanups()
|
|
64
|
+
.some((intent) => intent.target.chatId === record.target.chatId &&
|
|
65
|
+
intent.target.threadId === record.target.threadId))
|
|
57
66
|
return;
|
|
58
|
-
if (!await deps.topicTargetStore.detachTargetOwner(record, isCurrent) &&
|
|
67
|
+
if (!(await deps.topicTargetStore.detachTargetOwner(record, isCurrent)) &&
|
|
68
|
+
isCurrent()) {
|
|
59
69
|
throw new Error("Telegram preserved leader detachment was not committed.");
|
|
60
70
|
}
|
|
61
71
|
});
|
|
@@ -93,16 +103,22 @@ export function createTelegramThreadDisconnectAssembly(deps) {
|
|
|
93
103
|
catch (error) {
|
|
94
104
|
// Never retry a stop whose teardown/release outcome may already have committed.
|
|
95
105
|
if (stopAttempted) {
|
|
96
|
-
deps.recordRuntimeEvent("connection", error, {
|
|
106
|
+
deps.recordRuntimeEvent("connection", error, {
|
|
107
|
+
phase: "disconnect-stop",
|
|
108
|
+
});
|
|
97
109
|
throw error;
|
|
98
110
|
}
|
|
99
|
-
deps.recordRuntimeEvent("connection", error, {
|
|
111
|
+
deps.recordRuntimeEvent("connection", error, {
|
|
112
|
+
phase: "disconnect-cleanup",
|
|
113
|
+
});
|
|
100
114
|
let stopped;
|
|
101
115
|
try {
|
|
102
116
|
stopped = await stop();
|
|
103
117
|
}
|
|
104
118
|
catch (stopError) {
|
|
105
|
-
deps.recordRuntimeEvent("connection", stopError, {
|
|
119
|
+
deps.recordRuntimeEvent("connection", stopError, {
|
|
120
|
+
phase: "disconnect-stop",
|
|
121
|
+
});
|
|
106
122
|
throw stopError;
|
|
107
123
|
}
|
|
108
124
|
const separator = /[.!?]$/u.test(stopped) ? " " : ". ";
|
|
@@ -153,8 +169,11 @@ export function createTelegramManualThreadDisconnectHandler(deps) {
|
|
|
153
169
|
target,
|
|
154
170
|
requestedAtMs: (deps.getNowMs ?? Date.now)(),
|
|
155
171
|
};
|
|
156
|
-
const departingRecord = deps.topicTargetStore
|
|
157
|
-
|
|
172
|
+
const departingRecord = deps.topicTargetStore
|
|
173
|
+
.list()
|
|
174
|
+
.find((record) => record.instanceId === currentRecord.instanceId &&
|
|
175
|
+
record.target.chatId === target.chatId &&
|
|
176
|
+
record.target.threadId === target.threadId);
|
|
158
177
|
const isCleanupTargetProtected = createTelegramCleanupTargetProtection(deps.topicTargetStore, departingRecord);
|
|
159
178
|
deps.topicTargetStore.upsertPendingCleanup(intent);
|
|
160
179
|
await deps.topicTargetStore.persist();
|
|
@@ -312,23 +331,32 @@ export function captureTelegramStaleTargetRequestRecovery(body, deps) {
|
|
|
312
331
|
if (!target || epoch === undefined)
|
|
313
332
|
return undefined;
|
|
314
333
|
const key = getTelegramTargetKey(target);
|
|
315
|
-
const record = deps.topicTargetStore
|
|
334
|
+
const record = deps.topicTargetStore
|
|
335
|
+
.list()
|
|
336
|
+
.find((candidate) => getTelegramTargetKey(candidate.target) === key);
|
|
316
337
|
if (!record)
|
|
317
338
|
return undefined;
|
|
318
339
|
const generation = deps.getSessionGeneration();
|
|
319
340
|
const profile = deps.getProfileName();
|
|
320
341
|
const isAuthorityCurrent = () => deps.getCurrentLeaderEpoch() === epoch &&
|
|
321
|
-
deps.getSessionGeneration() === generation &&
|
|
342
|
+
deps.getSessionGeneration() === generation &&
|
|
343
|
+
deps.getProfileName() === profile;
|
|
322
344
|
const isCurrent = () => {
|
|
323
|
-
const current = deps.topicTargetStore
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
345
|
+
const current = deps.topicTargetStore
|
|
346
|
+
.list()
|
|
347
|
+
.find((candidate) => getTelegramTargetKey(candidate.target) === key);
|
|
348
|
+
return (isAuthorityCurrent() &&
|
|
349
|
+
current?.instanceId === record.instanceId &&
|
|
350
|
+
current?.profileKey === record.profileKey &&
|
|
351
|
+
current?.updatedAtMs === record.updatedAtMs &&
|
|
352
|
+
current?.createdAtMs === record.createdAtMs);
|
|
327
353
|
};
|
|
328
354
|
return async (error) => {
|
|
329
355
|
const requestTarget = getTelegramApiErrorRequestTarget(error);
|
|
330
|
-
if (!isTelegramStaleTargetHttpError(error) ||
|
|
331
|
-
|
|
356
|
+
if (!isTelegramStaleTargetHttpError(error) ||
|
|
357
|
+
!requestTarget ||
|
|
358
|
+
getTelegramTargetKey(requestTarget) !== key ||
|
|
359
|
+
!isCurrent())
|
|
332
360
|
return;
|
|
333
361
|
if (await recoverStaleTelegramTopicApiError({ chat_id: target.chatId, message_thread_id: target.threadId }, error, { ...deps, isCurrent, isAuthorityCurrent })) {
|
|
334
362
|
deps.onRecovered();
|
|
@@ -354,7 +382,7 @@ export async function recoverStaleTelegramTopicApiError(apiBody, error, deps) {
|
|
|
354
382
|
const recover = async () => {
|
|
355
383
|
if (deps.isCurrent) {
|
|
356
384
|
if (!deps.topicTargetStore.invalidateTarget ||
|
|
357
|
-
!await deps.topicTargetStore.invalidateTarget(target, deps.isCurrent, String(error)))
|
|
385
|
+
!(await deps.topicTargetStore.invalidateTarget(target, deps.isCurrent, String(error))))
|
|
358
386
|
return false;
|
|
359
387
|
if (deps.isAuthorityCurrent?.() === false)
|
|
360
388
|
return false;
|
|
@@ -436,7 +464,12 @@ export async function ensureTelegramLeaderThreadBinding(deps) {
|
|
|
436
464
|
const legacyLeaderRecord = deps.topicTargetStore.getByProfileKey(leaderProfileKey);
|
|
437
465
|
let capacityUnavailable = false;
|
|
438
466
|
const workspaceIdentity = normalizedLeaderCwd
|
|
439
|
-
? deps.topicTargetStore.claimWorkspaceIdentity(normalizedLeaderCwd, deps.instanceId, legacyLeaderRecord?.instanceId, {
|
|
467
|
+
? deps.topicTargetStore.claimWorkspaceIdentity(normalizedLeaderCwd, deps.instanceId, legacyLeaderRecord?.instanceId, {
|
|
468
|
+
sessionId: deps.sessionId,
|
|
469
|
+
onCapacityUnavailable() {
|
|
470
|
+
capacityUnavailable = true;
|
|
471
|
+
},
|
|
472
|
+
})
|
|
440
473
|
: undefined;
|
|
441
474
|
if (deps.cwd && !workspaceIdentity) {
|
|
442
475
|
if (capacityUnavailable)
|
|
@@ -471,7 +504,9 @@ export async function ensureTelegramLeaderThreadBinding(deps) {
|
|
|
471
504
|
target: { ...committed.target },
|
|
472
505
|
slot: committed.slot ?? result.slot,
|
|
473
506
|
...(committed.threadName ? { threadName: committed.threadName } : {}),
|
|
474
|
-
...(committed.displayTitle
|
|
507
|
+
...(committed.displayTitle
|
|
508
|
+
? { displayTitle: committed.displayTitle }
|
|
509
|
+
: {}),
|
|
475
510
|
};
|
|
476
511
|
};
|
|
477
512
|
try {
|
|
@@ -512,7 +547,9 @@ export async function ensureTelegramLeaderThreadBinding(deps) {
|
|
|
512
547
|
...(legacyLeaderRecord.threadName
|
|
513
548
|
? { threadName: legacyLeaderRecord.threadName }
|
|
514
549
|
: {}),
|
|
515
|
-
...(legacyLeaderRecord.slot
|
|
550
|
+
...(legacyLeaderRecord.slot
|
|
551
|
+
? { slot: legacyLeaderRecord.slot }
|
|
552
|
+
: {}),
|
|
516
553
|
updatedAtMs: legacyLeaderRecord.updatedAtMs,
|
|
517
554
|
}
|
|
518
555
|
: undefined;
|
|
@@ -600,7 +637,9 @@ export async function ensureTelegramLeaderThreadBinding(deps) {
|
|
|
600
637
|
});
|
|
601
638
|
// Legacy callers without session identity may reuse the active instance target.
|
|
602
639
|
// Session-aware callers must resolve their exact Workspace binding instead.
|
|
603
|
-
if (deps.sessionId === undefined &&
|
|
640
|
+
if (deps.sessionId === undefined &&
|
|
641
|
+
!deps.forceFreshUnnamed &&
|
|
642
|
+
priorTargets.length > 0) {
|
|
604
643
|
const record = priorTargets[0];
|
|
605
644
|
deps.recordEvent("telegram", "Leader thread preserved after session lifecycle change", {
|
|
606
645
|
phase: "leader-thread-reused",
|
|
@@ -747,21 +786,6 @@ export function createTelegramProvisioningActivityRuntime() {
|
|
|
747
786
|
},
|
|
748
787
|
};
|
|
749
788
|
}
|
|
750
|
-
const RECONCILE_TRIGGERS = new Set([
|
|
751
|
-
"startup",
|
|
752
|
-
"reload",
|
|
753
|
-
"topic-lifecycle",
|
|
754
|
-
"stale-api-error",
|
|
755
|
-
"setup-change",
|
|
756
|
-
"pairing-change",
|
|
757
|
-
"follower-register",
|
|
758
|
-
"follower-prune",
|
|
759
|
-
"status-request",
|
|
760
|
-
"leader-health-tick",
|
|
761
|
-
]);
|
|
762
|
-
export function shouldReconcileTelegramSync(trigger) {
|
|
763
|
-
return RECONCILE_TRIGGERS.has(trigger);
|
|
764
|
-
}
|
|
765
789
|
export function markTelegramSyncSliceSuspect(state, slice, input) {
|
|
766
790
|
return {
|
|
767
791
|
...state,
|
package/dist/lib/target.d.ts
CHANGED
|
@@ -18,3 +18,7 @@ export declare function areTelegramTargetsEqual(left: TelegramTarget, right: Tel
|
|
|
18
18
|
export declare function getTelegramTargetThreadParams(target: TelegramTarget): {
|
|
19
19
|
message_thread_id?: number;
|
|
20
20
|
};
|
|
21
|
+
/** Pure wire parser for `{ chatId, threadId? }`; unknown fields are dropped and malformed shapes refuse. */
|
|
22
|
+
export declare function parseTelegramTarget(value: unknown): TelegramTarget | undefined;
|
|
23
|
+
/** Pure Bot API integer id parser accepting integer numbers or non-blank integer strings. */
|
|
24
|
+
export declare function parseTelegramIntegerId(value: unknown): number | undefined;
|
package/dist/lib/target.js
CHANGED
|
@@ -25,3 +25,21 @@ export function getTelegramTargetThreadParams(target) {
|
|
|
25
25
|
? { message_thread_id: target.threadId }
|
|
26
26
|
: {};
|
|
27
27
|
}
|
|
28
|
+
/** Pure wire parser for `{ chatId, threadId? }`; unknown fields are dropped and malformed shapes refuse. */
|
|
29
|
+
export function parseTelegramTarget(value) {
|
|
30
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
31
|
+
return undefined;
|
|
32
|
+
const { chatId, threadId } = value;
|
|
33
|
+
if (typeof chatId !== "number")
|
|
34
|
+
return undefined;
|
|
35
|
+
return typeof threadId === "number" ? { chatId, threadId } : { chatId };
|
|
36
|
+
}
|
|
37
|
+
/** Pure Bot API integer id parser accepting integer numbers or non-blank integer strings. */
|
|
38
|
+
export function parseTelegramIntegerId(value) {
|
|
39
|
+
if (typeof value === "number" && Number.isInteger(value))
|
|
40
|
+
return value;
|
|
41
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
42
|
+
return undefined;
|
|
43
|
+
const parsed = Number(value);
|
|
44
|
+
return Number.isInteger(parsed) ? parsed : undefined;
|
|
45
|
+
}
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { TelegramAttachmentSource } from "./media.ts";
|
|
9
9
|
export declare const TELEGRAM_FILE_MAX_BYTES: number;
|
|
10
|
-
|
|
10
|
+
/** First positive safe-integer byte limit among ordered env names, else the caller's default. */
|
|
11
|
+
export declare function getTelegramByteLimitFromEnv(env: NodeJS.ProcessEnv, names: readonly string[], defaultValue: number): number;
|
|
11
12
|
export type TelegramNetworkFamilyPolicy = "auto" | "ipv4" | "ipv6" | "ipv4-fallback";
|
|
12
13
|
type TelegramNetworkFamily = 4 | 6;
|
|
13
14
|
export interface TelegramUser {
|
|
@@ -288,6 +289,8 @@ export interface TelegramApiRetryWait {
|
|
|
288
289
|
retryAfterSeconds?: number;
|
|
289
290
|
}
|
|
290
291
|
export interface TelegramApiCallOptions {
|
|
292
|
+
/** Local per-call effect authority; independent of source completion and transport ownership. */
|
|
293
|
+
assertAuthority?: () => void;
|
|
291
294
|
signal?: AbortSignal;
|
|
292
295
|
maxAttempts?: number;
|
|
293
296
|
retryRateLimit?: boolean;
|
|
@@ -297,6 +300,12 @@ export interface TelegramApiCallOptions {
|
|
|
297
300
|
/** Observability hook fired before a 429 retry wait, never for 5xx waits. */
|
|
298
301
|
onRetryWait?: (wait: TelegramApiRetryWait) => void;
|
|
299
302
|
}
|
|
303
|
+
export declare class TelegramApiAuthorityError extends Error {
|
|
304
|
+
readonly requestIssued: boolean;
|
|
305
|
+
constructor(requestIssued: boolean);
|
|
306
|
+
}
|
|
307
|
+
/** Recheck caller authority, classifying refusal by whether a Bot API request was already issued. */
|
|
308
|
+
export declare function assertTelegramApiCallAuthority(assertAuthority: (() => void) | undefined, requestIssued: boolean): void;
|
|
300
309
|
export interface TelegramFileDownloadOptions {
|
|
301
310
|
signal?: AbortSignal;
|
|
302
311
|
maxFileSizeBytes?: number;
|
|
@@ -338,14 +347,14 @@ export interface TelegramEditGuestInlineMessageContent {
|
|
|
338
347
|
richMessage?: TelegramInputRichMessage;
|
|
339
348
|
parseMode?: "HTML";
|
|
340
349
|
}
|
|
341
|
-
export interface TelegramAnswerCallbackQueryOptions {
|
|
350
|
+
export interface TelegramAnswerCallbackQueryOptions extends Pick<TelegramApiCallOptions, "assertAuthority"> {
|
|
342
351
|
recordRuntimeEvent?: (kind: "api", error: unknown, details?: Record<string, unknown>) => void;
|
|
343
352
|
}
|
|
344
353
|
export interface TelegramApiClient {
|
|
345
354
|
call: <TResponse>(method: string, body: Record<string, unknown>, options?: TelegramApiCallOptions) => Promise<TResponse>;
|
|
346
355
|
callMultipart: <TResponse>(method: string, fields: Record<string, string>, fileField: string, filePath: string, fileName: string, options?: TelegramApiCallOptions) => Promise<TResponse>;
|
|
347
356
|
downloadFile: (fileId: string, suggestedName: string, tempDir: string, options?: TelegramFileDownloadOptions) => Promise<string>;
|
|
348
|
-
answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
|
|
357
|
+
answerCallbackQuery: (callbackQueryId: string, text?: string, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
|
|
349
358
|
answerGuestQuery?: (guestQueryId: string, text?: string, options?: TelegramAnswerGuestQueryOptions) => Promise<void>;
|
|
350
359
|
}
|
|
351
360
|
export interface TelegramApiTargetActivityRuntime {
|
|
@@ -422,16 +431,14 @@ export interface TelegramBridgeApiRuntimeDeps {
|
|
|
422
431
|
chatActionMinIntervalMs?: number;
|
|
423
432
|
chatActionMaxGates?: number;
|
|
424
433
|
}
|
|
425
|
-
export interface TelegramBridgeApiRuntime {
|
|
426
|
-
call: <TResponse>(method: string, body: Record<string, unknown>, options?: TelegramApiCallOptions) => Promise<TResponse>;
|
|
427
|
-
callMultipart: <TResponse>(method: string, fields: Record<string, string>, fileField: string, filePath: string, fileName: string, options?: TelegramApiCallOptions) => Promise<TResponse>;
|
|
434
|
+
export interface TelegramBridgeApiRuntime extends Pick<TelegramApiClient, "call" | "callMultipart"> {
|
|
428
435
|
downloadFile: (fileId: string, suggestedName: string, source?: TelegramAttachmentSource) => Promise<string>;
|
|
429
436
|
deleteWebhook: (signal?: AbortSignal) => Promise<boolean>;
|
|
430
437
|
getUpdates: (body: Record<string, unknown>, signal?: AbortSignal) => Promise<TelegramUpdate[]>;
|
|
431
438
|
setMyCommands: (commands: readonly {
|
|
432
439
|
command: string;
|
|
433
440
|
description: string;
|
|
434
|
-
}[]) => Promise<boolean>;
|
|
441
|
+
}[], options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<boolean>;
|
|
435
442
|
sendChatAction: (chatId: number, action: string, options?: {
|
|
436
443
|
message_thread_id?: number;
|
|
437
444
|
}) => Promise<boolean>;
|
|
@@ -446,12 +453,12 @@ export interface TelegramBridgeApiRuntime {
|
|
|
446
453
|
entities?: unknown[];
|
|
447
454
|
message_thread_id?: number;
|
|
448
455
|
}) => Promise<boolean>;
|
|
449
|
-
sendMessage: (body: TelegramSendMessageBody) => Promise<TelegramSentMessage>;
|
|
450
|
-
sendRichMessage: (body: TelegramSendRichMessageBody) => Promise<TelegramSentMessage>;
|
|
456
|
+
sendMessage: (body: TelegramSendMessageBody, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<TelegramSentMessage>;
|
|
457
|
+
sendRichMessage: (body: TelegramSendRichMessageBody, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<TelegramSentMessage>;
|
|
451
458
|
sendRichMessageDraft: (body: TelegramSendRichMessageDraftBody) => Promise<boolean>;
|
|
452
|
-
editMessageText: (body: TelegramEditMessageTextBody) => Promise<"edited" | "unchanged">;
|
|
459
|
+
editMessageText: (body: TelegramEditMessageTextBody, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<"edited" | "unchanged">;
|
|
453
460
|
editMessageReplyMarkup: (chatId: number, messageId: number, replyMarkup: unknown) => Promise<void>;
|
|
454
|
-
answerCallbackQuery: (callbackQueryId: string, text?: string) => Promise<void>;
|
|
461
|
+
answerCallbackQuery: (callbackQueryId: string, text?: string, options?: Pick<TelegramApiCallOptions, "assertAuthority">) => Promise<void>;
|
|
455
462
|
answerGuestQuery: (guestQueryId: string, text?: string, options?: TelegramAnswerGuestQueryOptions) => Promise<void>;
|
|
456
463
|
/**
|
|
457
464
|
* Temporary Guest Mode ACK experiment: answers the guest query and returns
|
|
@@ -514,8 +521,6 @@ export declare function fetchTelegramBotIdentity(botToken: string, fetchImpl?: t
|
|
|
514
521
|
*/
|
|
515
522
|
export declare function callTelegramMultipart<TResponse>(botToken: string | undefined, method: string, fields: Record<string, string>, fileField: string, filePath: string, fileName: string, options?: TelegramApiCallOptions): Promise<TResponse>;
|
|
516
523
|
export declare function downloadTelegramFile(botToken: string | undefined, fileId: string, suggestedName: string, tempDir: string, options?: TelegramFileDownloadOptions): Promise<string>;
|
|
517
|
-
/** Tooltip-like callback answers omit a terminal sentence period; ellipses and other punctuation stay literal. */
|
|
518
|
-
export declare function formatTelegramCallbackAnswerText(text: string | undefined): string | undefined;
|
|
519
524
|
export declare function answerTelegramCallbackQuery(botToken: string | undefined, callbackQueryId: string, text?: string, options?: TelegramAnswerCallbackQueryOptions): Promise<void>;
|
|
520
525
|
export declare function createTelegramChatActionSender<TAction extends string>(sendChatAction: (chatId: number, action: TAction, options?: {
|
|
521
526
|
message_thread_id?: number;
|