docs: correct cx/cy units and sanitize buffer option limits
Two follow-up fixes for CodeRabbit feedback on the docs commit: - CursorTelemetryPoint JSDoc previously described cx/cy as 'device-pixel positions'. The producer sampleCursorPoint() in electron/ipc/handlers.ts clamps them to the [0, 1] range after dividing by the source display's width/height, so they are normalised ratios, not pixel values. Correct the doc comment accordingly. - createCursorTelemetryBuffer now sanitizes maxActiveSamples and maxPendingBatches: non-finite, zero, or negative values fall back to safe positive-integer defaults. Without this, a caller passing Infinity or NaN would hang the trim loops. New test covers the sanitisation path for both options.
This commit is contained in:
@@ -190,6 +190,29 @@ describe("createCursorTelemetryBuffer", () => {
|
||||
warn.mockRestore();
|
||||
});
|
||||
|
||||
it("sanitizes non-finite or non-positive option values to safe defaults", () => {
|
||||
// Infinity / NaN / negative would otherwise turn the trim loops
|
||||
// into infinite loops. The buffer must fall back to defaults.
|
||||
const buf = createCursorTelemetryBuffer({
|
||||
maxActiveSamples: Number.POSITIVE_INFINITY,
|
||||
maxPendingBatches: Number.NaN,
|
||||
});
|
||||
|
||||
buf.startSession();
|
||||
buf.push(sample(1));
|
||||
expect(() => buf.endSession()).not.toThrow();
|
||||
expect(buf.pendingCount).toBe(1);
|
||||
|
||||
const buf2 = createCursorTelemetryBuffer({
|
||||
maxActiveSamples: -5,
|
||||
maxPendingBatches: 0,
|
||||
});
|
||||
buf2.startSession();
|
||||
buf2.push(sample(2));
|
||||
expect(() => buf2.endSession()).not.toThrow();
|
||||
expect(buf2.pendingCount).toBe(1);
|
||||
});
|
||||
|
||||
it("reset() clears both active and pending state", () => {
|
||||
const buf = createCursorTelemetryBuffer({ maxActiveSamples: 10 });
|
||||
buf.startSession();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
/**
|
||||
* A single cursor telemetry sample captured during a recording session.
|
||||
*
|
||||
* Coordinates (`cx`, `cy`) are device-pixel positions relative to the
|
||||
* captured surface; `timeMs` is the offset from the recording's start.
|
||||
* Coordinates (`cx`, `cy`) are clamped ratios in the `[0, 1]` range,
|
||||
* normalised against the captured surface's width and height by the
|
||||
* main-process `sampleCursorPoint()` before being pushed. `timeMs` is the
|
||||
* offset (in milliseconds) from the recording's start.
|
||||
*/
|
||||
export interface CursorTelemetryPoint {
|
||||
timeMs: number;
|
||||
@@ -94,17 +96,29 @@ export interface CursorTelemetryBufferOptions {
|
||||
}
|
||||
|
||||
const DEFAULT_MAX_PENDING_BATCHES = 8;
|
||||
const DEFAULT_MAX_ACTIVE_SAMPLES = 10_000;
|
||||
|
||||
/** Coerce a numeric option into a safe, finite, positive integer. */
|
||||
function sanitizeLimit(value: number | undefined, fallback: number): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
||||
const floored = Math.floor(value);
|
||||
return floored >= 1 ? floored : fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cursor telemetry buffer.
|
||||
*
|
||||
* Numeric options are sanitized: non-finite, negative, or zero values fall
|
||||
* back to safe defaults so a bad caller cannot disable the memory bounds
|
||||
* (which would turn the trim loops into infinite loops).
|
||||
*
|
||||
* @see CursorTelemetryBuffer for the full lifecycle contract.
|
||||
*/
|
||||
export function createCursorTelemetryBuffer(
|
||||
options: CursorTelemetryBufferOptions,
|
||||
): CursorTelemetryBuffer {
|
||||
const maxActive = options.maxActiveSamples;
|
||||
const maxPending = options.maxPendingBatches ?? DEFAULT_MAX_PENDING_BATCHES;
|
||||
const maxActive = sanitizeLimit(options.maxActiveSamples, DEFAULT_MAX_ACTIVE_SAMPLES);
|
||||
const maxPending = sanitizeLimit(options.maxPendingBatches, DEFAULT_MAX_PENDING_BATCHES);
|
||||
|
||||
let active: CursorTelemetryPoint[] = [];
|
||||
let pending: CursorTelemetryPoint[][] = [];
|
||||
|
||||
Reference in New Issue
Block a user