Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ List recent agent conversations
**Flags:**
- `-n, --limit <value> - Number of conversations (1-1000) - (default: "25")`
- `-q, --query <value> - Search query`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <value> - Auto-refresh interval in seconds (default: 60, min: 10)`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01"`
- `-t, --period <value> - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01"`
- `--renderer <value> - 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)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ List events for an issue
- `-n, --limit <value> - Number of events (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry search syntax)`
- `--full - Include full event body (stacktraces)`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Query aggregate event data (Explore)
- `-s, --sort <value> - Sort field (prefix with - for desc, e.g., "-count()")`
- `-e, --environment <value>... - Environment filter (repeatable, comma-separated)`
- `-n, --limit <value> - Number of rows (1-1000) - (default: "25")`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "24h")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List and search User Feedback
- `--status <value> - Mailbox: unresolved, resolved, spam, or all - (default: "unresolved")`
- `-n, --limit <value> - Number of feedback items (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry issue search syntax)`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "14d")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List issues in a project
- `-q, --query <value> - Search query (Sentry syntax, implicit AND, no OR operator)`
- `-n, --limit <value> - Maximum number of issues to list - (default: "25")`
- `-s, --sort <value> - Sort by: recommended, date, new, freq, user (default: recommended on sentry.io, else date)`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "90d")`
- `-t, --period <value> - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "90d")`
- `-c, --cursor <value> - 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`
Expand Down Expand Up @@ -92,7 +92,7 @@ List events for a specific issue
- `-n, --limit <value> - Number of events (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry search syntax)`
- `--full - Include full event body (stacktraces)`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List logs from a project
- `-n, --limit <value> - Number of log entries (1-1000) - (default: "100")`
- `-q, --query <value> - Filter query (e.g., "severity:error", "project:backend", "project:[a,b]")`
- `-f, --follow <value> - Stream logs (optionally specify poll interval in seconds)`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01"`
- `-t, --period <value> - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01"`
- `-s, --sort <value> - Sort order: "newest" (default) or "oldest" - (default: "newest")`
- `--fresh - Bypass cache, re-detect projects, and fetch fresh data`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ List recent Session Replays
- `-q, --query <value> - Search query (Sentry replay search syntax)`
- `-e, --environment <value>... - Filter by environment (repeatable, comma-separated)`
- `-s, --sort <value> - Sort by: date, oldest, duration, errors, activity, or a raw replay sort field - (default: "date")`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List spans in a project or trace
- `-n, --limit <value> - Number of spans (<=1000) - (default: "25")`
- `-q, --query <value> - Filter spans (e.g., "op:db", "project:backend", "project:[cli,api]")`
- `-s, --sort <value> - Sort order: date, duration - (default: "date")`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ List recent traces in a project
- `-n, --limit <value> - Number of traces (1-1000) - (default: "25")`
- `-q, --query <value> - Search query (Sentry search syntax)`
- `-s, --sort <value> - Sort by: date, duration - (default: "date")`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "7d")`
- `-t, --period <value> - 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 <value> - Navigate pages: "next", "prev", "first" (or raw cursor string)`

Expand Down Expand Up @@ -91,7 +91,7 @@ View logs associated with a trace

**Flags:**
- `-w, --web - Open trace in browser`
- `-t, --period <value> - Time range: "7d", "2026-08-01..2026-09-01", ">=2026-08-01" - (default: "14d")`
- `-t, --period <value> - Time range: "7d", "2026-09-01..2026-10-01", ">=2026-09-01" - (default: "14d")`
- `-n, --limit <value> - Number of log entries (<=1000) - (default: "100")`
- `-q, --query <value> - Filter query (e.g., "severity:error", "project:backend", "project:[a,b]")`
- `-s, --sort <value> - Sort order: "newest" (default) or "oldest" - (default: "newest")`
Expand Down
73 changes: 71 additions & 2 deletions packages/cli/src/lib/sourcemap/zip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -256,15 +273,26 @@ 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);
// Disk number — 0
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
Expand All @@ -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<void> {
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;
}
}
30 changes: 30 additions & 0 deletions packages/cli/test/lib/sourcemap/zip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
Loading