fix(discord): prevent stuck typing indicator

This commit is contained in:
Nimrod Gutman
2026-02-25 10:16:00 +02:00
committed by Nimrod Gutman
parent fb76e316fb
commit a0fa283839
3 changed files with 40 additions and 5 deletions

View File

@@ -85,4 +85,28 @@ describe("createTypingCallbacks", () => {
expect(stop).toHaveBeenCalledTimes(1);
});
it("does not restart keepalive after idle cleanup", async () => {
vi.useFakeTimers();
try {
const start = vi.fn().mockResolvedValue(undefined);
const stop = vi.fn().mockResolvedValue(undefined);
const onStartError = vi.fn();
const callbacks = createTypingCallbacks({ start, stop, onStartError });
await callbacks.onReplyStart();
expect(start).toHaveBeenCalledTimes(1);
callbacks.onIdle?.();
await flushMicrotasks();
await callbacks.onReplyStart();
await vi.advanceTimersByTimeAsync(9_000);
expect(start).toHaveBeenCalledTimes(1);
expect(stop).toHaveBeenCalledTimes(1);
} finally {
vi.useRealTimers();
}
});
});

View File

@@ -17,6 +17,7 @@ export function createTypingCallbacks(params: {
const stop = params.stop;
const keepaliveIntervalMs = params.keepaliveIntervalMs ?? 3_000;
let stopSent = false;
let closed = false;
const fireStart = async () => {
try {
@@ -32,6 +33,9 @@ export function createTypingCallbacks(params: {
});
const onReplyStart = async () => {
if (closed) {
return;
}
stopSent = false;
keepaliveLoop.stop();
await fireStart();
@@ -39,6 +43,7 @@ export function createTypingCallbacks(params: {
};
const fireStop = () => {
closed = true;
keepaliveLoop.stop();
if (!stop || stopSent) {
return;

View File

@@ -723,12 +723,18 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
dispatchError = true;
throw err;
} finally {
// Must stop() first to flush debounced content before clear() wipes state
await draftStream?.stop();
if (!finalizedViaPreviewMessage) {
await draftStream?.clear();
try {
// Must stop() first to flush debounced content before clear() wipes state.
await draftStream?.stop();
if (!finalizedViaPreviewMessage) {
await draftStream?.clear();
}
} catch (err) {
// Draft cleanup should never keep typing alive.
logVerbose(`discord: draft cleanup failed: ${String(err)}`);
} finally {
markDispatchIdle();
}
markDispatchIdle();
if (statusReactionsEnabled) {
if (dispatchError) {
await statusReactions.setError();