From 1ae248f1b95f07c95d60f9f705561bf148b144fd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 5 Oct 2026 12:22:04 +0000 Subject: [PATCH 1/2] fix(sourcemap): crash finalizing bundles with more than 65,535 files (Sentry CLI-39Q) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ZipWriter.finalize() wrote the entry count straight into the classic end-of-central-directory record's 16-bit fields, so `sourcemap upload` threw `RangeError: The value of "value" is out of range` for any upload directory with more than 65,535 bundle entries (e.g. a large Next.js `.next/server` build). When the count overflows, write the ZIP64 end-of-central-directory record and locator before the classic record and saturate the classic count fields at 0xFFFF, as APPNOTE 4.4.1.4 prescribes. Archives at or below the limit are byte-for-byte unchanged. Fixes CLI-39Q Co-authored-by: Miguel Betegón --- packages/cli/src/lib/sourcemap/zip.ts | 73 ++++++++++++++++++++- packages/cli/test/lib/sourcemap/zip.test.ts | 30 +++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/lib/sourcemap/zip.ts b/packages/cli/src/lib/sourcemap/zip.ts index 2678cb9757..1e5e8e936b 100644 --- a/packages/cli/src/lib/sourcemap/zip.ts +++ b/packages/cli/src/lib/sourcemap/zip.ts @@ -31,6 +31,8 @@ const METHOD_DEFLATE = 8; const LOCAL_FILE_HEADER_SIG = 0x04_03_4b_50; const CENTRAL_DIR_HEADER_SIG = 0x02_01_4b_50; const EOCD_SIG = 0x06_05_4b_50; +const ZIP64_EOCD_SIG = 0x06_06_4b_50; +const ZIP64_EOCD_LOCATOR_SIG = 0x07_06_4b_50; /** Fixed portion of a local file header (before the file name). */ const LOCAL_HEADER_FIXED_SIZE = 30; @@ -41,6 +43,21 @@ const CENTRAL_HEADER_FIXED_SIZE = 46; /** End of central directory record size (no comment). */ const EOCD_SIZE = 22; +/** ZIP64 end of central directory record size (no extensible data). */ +const ZIP64_EOCD_SIZE = 56; + +/** ZIP64 end of central directory locator size. */ +const ZIP64_EOCD_LOCATOR_SIZE = 20; + +/** Version 4.5 — minimum needed to extract ZIP64 archives. */ +const ZIP64_VERSION = 45; + +/** + * Largest entry count the classic EOCD record's 16-bit fields can hold. + * Archives with more entries need the ZIP64 EOCD record (APPNOTE 4.4.1.4). + */ +const MAX_EOCD_ENTRIES = 0xff_ff; + /** * Metadata captured per entry so the central directory can be * written after all entries have been streamed. @@ -256,6 +273,15 @@ export class ZipWriter { } const centralDirSize = this.offset - centralDirOffset; + const entryCount = this.entries.length; + + if (entryCount > MAX_EOCD_ENTRIES) { + await this.writeZip64EndRecords( + entryCount, + centralDirSize, + centralDirOffset + ); + } const eocd = Buffer.alloc(EOCD_SIZE); eocd.writeUInt32LE(EOCD_SIG, 0); @@ -263,8 +289,10 @@ export class ZipWriter { eocd.writeUInt16LE(0, 4); // Disk number with central directory — 0 eocd.writeUInt16LE(0, 6); - eocd.writeUInt16LE(this.entries.length, 8); - eocd.writeUInt16LE(this.entries.length, 10); + // Saturates at 0xFFFF; readers then take the count from the ZIP64 record + const eocdEntryCount = Math.min(entryCount, MAX_EOCD_ENTRIES); + eocd.writeUInt16LE(eocdEntryCount, 8); + eocd.writeUInt16LE(eocdEntryCount, 10); eocd.writeUInt32LE(centralDirSize, 12); eocd.writeUInt32LE(centralDirOffset, 16); // ZIP file comment length — 0 @@ -275,4 +303,45 @@ export class ZipWriter { await this.fh.close(); } } + + /** + * Write the ZIP64 end-of-central-directory record and its locator, + * which carry the entry count when it overflows the classic EOCD + * record. Must be written immediately before the classic EOCD record. + */ + private async writeZip64EndRecords( + entryCount: number, + centralDirSize: number, + centralDirOffset: number + ): Promise { + const recordOffset = this.offset; + + const record = Buffer.alloc(ZIP64_EOCD_SIZE); + record.writeUInt32LE(ZIP64_EOCD_SIG, 0); + // Size of the record excluding the leading signature and this field + record.writeBigUInt64LE(BigInt(ZIP64_EOCD_SIZE - 12), 4); + record.writeUInt16LE(ZIP64_VERSION, 12); + record.writeUInt16LE(ZIP64_VERSION, 14); + // Disk number — 0 + record.writeUInt32LE(0, 16); + // Disk number with central directory — 0 + record.writeUInt32LE(0, 20); + record.writeBigUInt64LE(BigInt(entryCount), 24); + record.writeBigUInt64LE(BigInt(entryCount), 32); + record.writeBigUInt64LE(BigInt(centralDirSize), 40); + record.writeBigUInt64LE(BigInt(centralDirOffset), 48); + + const locator = Buffer.alloc(ZIP64_EOCD_LOCATOR_SIZE); + locator.writeUInt32LE(ZIP64_EOCD_LOCATOR_SIG, 0); + // Disk number with ZIP64 EOCD record — 0 + locator.writeUInt32LE(0, 4); + locator.writeBigUInt64LE(BigInt(recordOffset), 8); + // Total number of disks — 1 + locator.writeUInt32LE(1, 16); + + await this.fh.write(record, 0, record.length); + await this.fh.write(locator, 0, locator.length); + + this.offset += ZIP64_EOCD_SIZE + ZIP64_EOCD_LOCATOR_SIZE; + } } diff --git a/packages/cli/test/lib/sourcemap/zip.test.ts b/packages/cli/test/lib/sourcemap/zip.test.ts index 77aac7c6e3..593d313951 100644 --- a/packages/cli/test/lib/sourcemap/zip.test.ts +++ b/packages/cli/test/lib/sourcemap/zip.test.ts @@ -273,4 +273,34 @@ describe("ZipWriter binary format", () => { expect(entriesOnDisk).toBe(3); expect(totalEntries).toBe(3); }); + + test("writes ZIP64 end records when entries overflow the EOCD count", async () => { + const zipPath = join(tmpDir, "zip64.zip"); + const entryCount = 0x1_00_00; + const zip = await ZipWriter.create(zipPath, { compression: "stored" }); + for (let i = 0; i < entryCount; i++) { + await zip.addEntry(`_/_/chunk-${i}.js`, Buffer.alloc(0)); + } + await zip.finalize(); + + const data = await readFile(zipPath); + const eocdStart = data.length - 22; + expect(data.readUInt16LE(eocdStart + 8)).toBe(0xff_ff); + expect(data.readUInt16LE(eocdStart + 10)).toBe(0xff_ff); + + // ZIP64 locator (20 bytes) sits directly before the classic EOCD + const locatorStart = eocdStart - 20; + expect(data.readUInt32LE(locatorStart)).toBe(0x07_06_4b_50); + const recordStart = Number(data.readBigUInt64LE(locatorStart + 8)); + expect(recordStart).toBe(locatorStart - 56); + expect(data.readUInt32LE(recordStart)).toBe(0x06_06_4b_50); + expect(data.readBigUInt64LE(recordStart + 24)).toBe(BigInt(entryCount)); + expect(data.readBigUInt64LE(recordStart + 32)).toBe(BigInt(entryCount)); + + const proc = spawnSync("unzip", ["-t", zipPath], { + stdio: ["pipe", "pipe", "pipe"], + maxBuffer: 16 * 1024 * 1024, + }); + expect(proc.status).toBe(0); + }, 60_000); }); From 536b641c387706e073b03d0d532e72b4abf196d3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 5 Oct 2026 12:23:21 +0000 Subject: [PATCH 2/2] chore: regenerate docs --- .../skills/sentry-cli/references/agent-conversation.md | 2 +- .../sentry-cli/skills/sentry-cli/references/dashboard.md | 2 +- .../plugins/sentry-cli/skills/sentry-cli/references/event.md | 2 +- .../sentry-cli/skills/sentry-cli/references/explore.md | 2 +- .../sentry-cli/skills/sentry-cli/references/feedback.md | 2 +- .../plugins/sentry-cli/skills/sentry-cli/references/issue.md | 4 ++-- .../plugins/sentry-cli/skills/sentry-cli/references/log.md | 2 +- .../plugins/sentry-cli/skills/sentry-cli/references/replay.md | 2 +- .../plugins/sentry-cli/skills/sentry-cli/references/span.md | 2 +- .../plugins/sentry-cli/skills/sentry-cli/references/trace.md | 4 ++-- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/agent-conversation.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/agent-conversation.md index dd6ffe1d6e..d2cbc9ef72 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/agent-conversation.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/agent-conversation.md @@ -18,7 +18,7 @@ List recent agent conversations **Flags:** - `-n, --limit - Number of conversations (1-1000) - (default: "25")` - `-q, --query - Search query` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "7d")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md index 949428f5bd..66c776eff2 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/dashboard.md @@ -42,7 +42,7 @@ View a dashboard - `-w, --web - Open in browser` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-r, --refresh - Auto-refresh interval in seconds (default: 60, min: 10)` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01"` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01"` - `--renderer - Graphics renderer (defaults to auto; falls back to auto when unavailable) - (default: "auto")` - `--no-graphics-cap - Use the terminal-native graphics width (may fall back to ASCII for very large dashboards)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md index 9cc411d252..59c60af32a 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/event.md @@ -86,7 +86,7 @@ List events for an issue - `-n, --limit - Number of events (1-1000) - (default: "25")` - `-q, --query - Search query (Sentry search syntax)` - `--full - Include full event body (stacktraces)` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "7d")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/explore.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/explore.md index ae1f4fd788..1565de4b12 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/explore.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/explore.md @@ -24,7 +24,7 @@ Query aggregate event data (Explore) - `-s, --sort - Sort field (prefix with - for desc, e.g., "-count()")` - `-e, --environment ... - Environment filter (repeatable, comma-separated)` - `-n, --limit - Number of rows (1-1000) - (default: "25")` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "24h")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "24h")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/feedback.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/feedback.md index 70293ae18b..a8fc76c851 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/feedback.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/feedback.md @@ -19,7 +19,7 @@ List and search User Feedback - `--status - Mailbox: unresolved, resolved, spam, or all - (default: "unresolved")` - `-n, --limit - Number of feedback items (1-1000) - (default: "25")` - `-q, --query - Search query (Sentry issue search syntax)` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "14d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "14d")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/issue.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/issue.md index a6dce81d7c..0ac798f7c3 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/issue.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/issue.md @@ -19,7 +19,7 @@ List issues in a project - `-q, --query - Search query (Sentry syntax, implicit AND, no OR operator)` - `-n, --limit - Maximum number of issues to list - (default: "25")` - `-s, --sort - Sort by: recommended, date, new, freq, user (default: recommended on sentry.io, else date)` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "90d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "90d")` - `-c, --cursor - Pagination cursor (use "next" for next page, "prev" for previous)` - `--compact - Single-line rows for compact output (auto-detects if omitted)` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` @@ -92,7 +92,7 @@ List events for a specific issue - `-n, --limit - Number of events (1-1000) - (default: "25")` - `-q, --query - Search query (Sentry search syntax)` - `--full - Include full event body (stacktraces)` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "7d")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/log.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/log.md index ff35ecf5ff..d36318e088 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/log.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/log.md @@ -19,7 +19,7 @@ List logs from a project - `-n, --limit - Number of log entries (1-1000) - (default: "100")` - `-q, --query - Filter query (e.g., "severity:error", "project:backend", "project:[a,b]")` - `-f, --follow - Stream logs (optionally specify poll interval in seconds)` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01"` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01"` - `-s, --sort - Sort order: "newest" (default) or "oldest" - (default: "newest")` - `--fresh - Bypass cache, re-detect projects, and fetch fresh data` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/replay.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/replay.md index 81447b88e3..a24aaeccf4 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/replay.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/replay.md @@ -20,7 +20,7 @@ List recent Session Replays - `-q, --query - Search query (Sentry replay search syntax)` - `-e, --environment ... - Filter by environment (repeatable, comma-separated)` - `-s, --sort - Sort by: date, oldest, duration, errors, activity, or a raw replay sort field - (default: "date")` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "7d")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/span.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/span.md index 92b764ed16..99d24ee36b 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/span.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/span.md @@ -19,7 +19,7 @@ List spans in a project or trace - `-n, --limit - Number of spans (<=1000) - (default: "25")` - `-q, --query - Filter spans (e.g., "op:db", "project:backend", "project:[cli,api]")` - `-s, --sort - Sort order: date, duration - (default: "date")` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "7d")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` diff --git a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/trace.md b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/trace.md index 6cd22b4503..a41fd7221b 100644 --- a/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/trace.md +++ b/packages/cli/plugins/sentry-cli/skills/sentry-cli/references/trace.md @@ -19,7 +19,7 @@ List recent traces in a project - `-n, --limit - Number of traces (1-1000) - (default: "25")` - `-q, --query - Search query (Sentry search syntax)` - `-s, --sort - Sort by: date, duration - (default: "date")` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "7d")` - `-f, --fresh - Bypass cache, re-detect projects, and fetch fresh data` - `-c, --cursor - Navigate pages: "next", "prev", "first" (or raw cursor string)` @@ -91,7 +91,7 @@ View logs associated with a trace **Flags:** - `-w, --web - Open trace in browser` -- `-t, --period - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "14d")` +- `-t, --period - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "14d")` - `-n, --limit - Number of log entries (<=1000) - (default: "100")` - `-q, --query - Filter query (e.g., "severity:error", "project:backend", "project:[a,b]")` - `-s, --sort - Sort order: "newest" (default) or "oldest" - (default: "newest")`