Skip to content
Merged
66 changes: 66 additions & 0 deletions script/node-polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import {
} from "node:child_process";
import { statSync } from "node:fs";
import { access, readFile, stat, writeFile } from "node:fs/promises";
import { promisify } from "node:util";
// biome-ignore lint/performance/noNamespaceImport: runtime access to optional `zstdCompress`/`zstdDecompress` exports
import * as zlibModule from "node:zlib";
import { constants as zlibConstants } from "node:zlib";
// node:sqlite is imported lazily inside NodeDatabasePolyfill to avoid
// crashing on Node.js versions without node:sqlite support when the
// bundle is loaded as a library (the consumer may never use SQLite).
Expand Down Expand Up @@ -284,4 +288,66 @@ const BunPolyfill = {
},
};

/**
* Coerce arbitrary compression input (string, ArrayBuffer, TypedArray)
* into a contiguous Buffer without copying where possible.
*/
function toBufferForCompression(
data: NodeJS.TypedArray | Buffer | string | ArrayBuffer
): Buffer {
if (typeof data === "string") {
return Buffer.from(data, "utf-8");
}
if (data instanceof ArrayBuffer) {
return Buffer.from(data);
}
return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
}

// Feature-detected zstd polyfill. `node:zlib.zstdCompress` lands in Node
// 22.15; we do NOT install the polyfill below on older Node because
// Bun.zstdCompress's absence lets the telemetry transport's runtime
// probe fall back to gzip cleanly (see src/lib/telemetry/zstd-transport.ts).
//
// Kept out of the BunPolyfill literal so the `typeof Bun.zstdCompress`
// probe genuinely returns `"undefined"` on older runtimes — assigning
// a noop stub would defeat the feature-detect.
const zlibOptionalZstdCompress = (zlibModule as { zstdCompress?: unknown })
.zstdCompress;
const zlibOptionalZstdDecompress = (zlibModule as { zstdDecompress?: unknown })
.zstdDecompress;

if (
typeof zlibOptionalZstdCompress === "function" &&
typeof zlibOptionalZstdDecompress === "function"
) {
const nodeZstdCompress = promisify(
zlibOptionalZstdCompress as (
buf: Buffer,
options: { params?: Record<number, number> },
cb: (err: Error | null, result: Buffer) => void
) => void
);
const nodeZstdDecompress = promisify(
zlibOptionalZstdDecompress as (
buf: Buffer,
cb: (err: Error | null, result: Buffer) => void
) => void
);

(BunPolyfill as unknown as { zstdCompress: unknown }).zstdCompress = (
data: NodeJS.TypedArray | Buffer | string | ArrayBuffer,
opts?: { level?: number }
): Promise<Buffer> =>
nodeZstdCompress(toBufferForCompression(data), {
params: {
[zlibConstants.ZSTD_c_compressionLevel]: opts?.level ?? 3,
},
});

(BunPolyfill as unknown as { zstdDecompress: unknown }).zstdDecompress = (
data: NodeJS.TypedArray | Buffer | string | ArrayBuffer
): Promise<Buffer> => nodeZstdDecompress(toBufferForCompression(data));
}

globalThis.Bun = BunPolyfill as typeof Bun;
6 changes: 6 additions & 0 deletions src/lib/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
import { ApiError } from "./errors.js";
import { attachSentryReporter, logger } from "./logger.js";
import { getSentryBaseUrl, isSentrySaasUrl } from "./sentry-urls.js";
import { makeCompressedTransport } from "./telemetry/zstd-transport.js";
import { getRealUsername } from "./utils.js";

export type { Span } from "@sentry/core";
Expand Down Expand Up @@ -518,6 +519,11 @@ export function initSentry(
const client = Sentry.init({
dsn: SENTRY_CLI_DSN,
enabled,
// Compress outgoing envelopes with zstd (level 3) instead of gzip —
// smaller payloads, faster compress/decompress on both sides.
// Automatic gzip fallback when running on Node < 22.15 without the
// `Bun.zstdCompress` polyfill (see script/node-polyfills.ts).
transport: makeCompressedTransport,
// Keep default integrations but filter out ones that add overhead without benefit.
// Important: Don't use defaultIntegrations: false as it may break debug ID support.
// NodeSystemError is excluded on runtimes missing util.getSystemErrorMap (Bun) — CLI-K1.
Expand Down
Loading
Loading