diff --git a/src/lib/api/events.ts b/src/lib/api/events.ts index 22e2f5c91..3f253ffcc 100644 --- a/src/lib/api/events.ts +++ b/src/lib/api/events.ts @@ -252,10 +252,10 @@ export async function listIssueEvents( // Trim to exact limit. Unlike listIssuesAllPages (which controls per_page), // the issue events endpoint has no per-page parameter, so the API may return - // more items than requested. We preserve nextCursor so the command-level - // cursor stack can navigate to subsequent pages. - const trimmed = - allEvents.length > limit ? allEvents.slice(0, limit) : allEvents; - - return { data: trimmed, nextCursor }; + // more items than requested. When trimming, drop nextCursor — it points past + // the trimmed items and would cause the cursor stack to skip events. + if (allEvents.length > limit) { + return { data: allEvents.slice(0, limit) }; + } + return { data: allEvents, nextCursor }; } diff --git a/src/lib/db/pagination.ts b/src/lib/db/pagination.ts index c702918d9..3a1773428 100644 --- a/src/lib/db/pagination.ts +++ b/src/lib/db/pagination.ts @@ -14,10 +14,13 @@ import { ValidationError } from "../errors.js"; import { CURSOR_KEYWORDS } from "../list-command.js"; +import { logger } from "../logger.js"; import { getApiBaseUrl } from "../sentry-client.js"; import { getDatabase } from "./index.js"; import { runUpsert } from "./utils.js"; +const log = logger.withTag("pagination"); + /** Default TTL for stored cursors: 5 minutes */ const CURSOR_TTL_MS = 5 * 60 * 1000; @@ -84,7 +87,16 @@ export function getPaginationState( return; } - const stack = JSON.parse(row.cursor_stack) as string[]; + let stack: string[]; + try { + stack = JSON.parse(row.cursor_stack) as string[]; + } catch { + log.debug("Corrupt cursor_stack in pagination DB, clearing state"); + db.query( + "DELETE FROM pagination_cursors WHERE command_key = ? AND context = ?" + ).run(commandKey, contextKey); + return; + } return { stack, index: row.page_index }; } diff --git a/test/lib/formatters/colors.test.ts b/test/lib/formatters/colors.test.ts index c4d7705c7..e3130ee7f 100644 --- a/test/lib/formatters/colors.test.ts +++ b/test/lib/formatters/colors.test.ts @@ -114,21 +114,31 @@ describe("fixabilityColor", () => { }); describe("terminalLink", () => { - /** Save/restore isTTY and env around TTY-specific tests */ + /** Save/restore isTTY and all plain-output env vars around TTY-specific tests */ function withTTY(fn: () => void): void { const savedTTY = process.stdout.isTTY; const savedPlain = process.env.SENTRY_PLAIN_OUTPUT; + const savedNoColor = process.env.NO_COLOR; + const savedForceColor = process.env.FORCE_COLOR; process.stdout.isTTY = true; delete process.env.SENTRY_PLAIN_OUTPUT; + delete process.env.NO_COLOR; + delete process.env.FORCE_COLOR; try { fn(); } finally { process.stdout.isTTY = savedTTY; - if (savedPlain !== undefined) { - process.env.SENTRY_PLAIN_OUTPUT = savedPlain; - } else { - delete process.env.SENTRY_PLAIN_OUTPUT; - } + restoreEnv("SENTRY_PLAIN_OUTPUT", savedPlain); + restoreEnv("NO_COLOR", savedNoColor); + restoreEnv("FORCE_COLOR", savedForceColor); + } + } + + function restoreEnv(key: string, saved: string | undefined): void { + if (saved !== undefined) { + process.env[key] = saved; + } else { + delete process.env[key]; } }