fix: keep the paired user when the poll loop commits its offset
The poll loop persisted the config object it captured when polling started. The store swaps in a fresh object on every persist, so after the initial sync that captured copy lacked later changes: the next offset commit erased the paired user and the bridge re-paired on every message.
This commit is contained in:
1 parent
033a92f3bb
commit
60254b288b
2 files changed
+47
-1
No files matched your search
+9
-1
@@ -971,7 +971,15 @@ export function createTelegramPollLoopRunner<
|
||||
config: deps.getConfig(),
|
||||
deleteWebhook: deps.deleteWebhook,
|
||||
getUpdates: deps.getUpdates,
|
||||
persistConfig: deps.persistConfig,
|
||||
// The loop keeps the config object captured when polling started, but the
|
||||
// store swaps in a fresh object on every persist. Persisting that stale
|
||||
// copy erased later changes such as the paired user, so only the poll
|
||||
// offset is carried onto the store's current config.
|
||||
persistConfig: (polled) => {
|
||||
const current = deps.getConfig();
|
||||
current.lastUpdateId = polled.lastUpdateId;
|
||||
return deps.persistConfig(current);
|
||||
},
|
||||
handleUpdate: deps.handleUpdate,
|
||||
onErrorStatus: (message) => {
|
||||
updateTelegramPollingStatusSafely(deps.updateStatus, ctx, {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
*/
|
||||
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdtempSync, readFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
@@ -29,6 +32,7 @@ import {
|
||||
stopTelegramPollingRuntime,
|
||||
TELEGRAM_ALLOWED_UPDATES,
|
||||
} from "../lib/polling.ts";
|
||||
import { createTelegramConfigStore } from "../lib/config.ts";
|
||||
|
||||
const TEST_CONTEXT = "ctx";
|
||||
|
||||
@@ -601,6 +605,40 @@ test("Poll loop runner binds config, status, and transport ports", async () => {
|
||||
assert.deepEqual(events, ["deleteWebhook", "handle:ctx:6", "persist:6"]);
|
||||
});
|
||||
|
||||
test("Poll loop keeps the paired user when the offset is committed after the initial sync replaced the stored config", async () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "telegram-pairing-"));
|
||||
const configPath = join(dir, "telegram.json");
|
||||
const store = createTelegramConfigStore({ agentDir: dir, configPath });
|
||||
await store.load();
|
||||
store.update((config) => {
|
||||
config.botToken = "123:abc";
|
||||
});
|
||||
await store.persist();
|
||||
let calls = 0;
|
||||
const runPollLoop = createTelegramPollLoopRunner({
|
||||
getConfig: store.get,
|
||||
deleteWebhook: async () => {},
|
||||
getUpdates: async () => {
|
||||
calls += 1;
|
||||
if (calls === 1) return [{ update_id: 1 }]; // initial sync
|
||||
if (calls === 2) return [{ update_id: 2 }]; // the owner's /start
|
||||
throw new DOMException("stop", "AbortError");
|
||||
},
|
||||
persistConfig: store.persist,
|
||||
handleUpdate: async () => {
|
||||
store.setAllowedUserId(777);
|
||||
await store.persist();
|
||||
},
|
||||
updateStatus: () => {},
|
||||
sleep: async () => {},
|
||||
});
|
||||
await runPollLoop("ctx", new AbortController().signal);
|
||||
assert.equal(store.getAllowedUserId(), 777);
|
||||
const saved = JSON.parse(readFileSync(configPath, "utf8"));
|
||||
assert.equal(saved.allowedUserId, 777);
|
||||
assert.equal(saved.lastUpdateId, 2);
|
||||
});
|
||||
|
||||
test("Poll loop runner ignores stale-context status failures while retrying", async () => {
|
||||
const config = { botToken: "123:abc", lastUpdateId: 1 };
|
||||
const events: string[] = [];
|
||||
|
||||
Reference in new issue
Block a user