fix: isolate cursor telemetry samples per recording session
Previously, the main process kept two module-scope arrays — activeCursorSamples and pendingCursorSamples — and set-recording-state on a new recording wiped BOTH. When a user stopped recording and immediately started a new one before store-recorded-session fired, the previous recording's pending samples were discarded or later overwritten with the new session's data, producing empty or mismatched .cursor.json files. Replace the two arrays with a small FIFO buffer (createCursorTelemetryBuffer) that: - Keeps pending batches per completed recording, never wiping them on a new session start. - Yields batches in arrival order to storeRecordedSessionFiles. - Caps pending batches (default 8) so a never-stored sequence cannot leak unbounded memory. Unit-tested directly in src/lib/cursorTelemetryBuffer.test.ts, including the rapid-restart race that motivated the change.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
export interface CursorTelemetryPoint {
|
||||
timeMs: number;
|
||||
cx: number;
|
||||
cy: number;
|
||||
}
|
||||
|
||||
export interface CursorTelemetryBuffer {
|
||||
startSession(): void;
|
||||
push(point: CursorTelemetryPoint): void;
|
||||
endSession(): void;
|
||||
takeNextBatch(): CursorTelemetryPoint[];
|
||||
reset(): void;
|
||||
readonly activeCount: number;
|
||||
readonly pendingCount: number;
|
||||
}
|
||||
|
||||
export interface CursorTelemetryBufferOptions {
|
||||
maxActiveSamples: number;
|
||||
maxPendingBatches?: number;
|
||||
}
|
||||
|
||||
const DEFAULT_MAX_PENDING_BATCHES = 8;
|
||||
|
||||
export function createCursorTelemetryBuffer(
|
||||
options: CursorTelemetryBufferOptions,
|
||||
): CursorTelemetryBuffer {
|
||||
const maxActive = options.maxActiveSamples;
|
||||
const maxPending = options.maxPendingBatches ?? DEFAULT_MAX_PENDING_BATCHES;
|
||||
|
||||
let active: CursorTelemetryPoint[] = [];
|
||||
let pending: CursorTelemetryPoint[][] = [];
|
||||
|
||||
return {
|
||||
startSession() {
|
||||
active = [];
|
||||
},
|
||||
push(point) {
|
||||
active.push(point);
|
||||
if (active.length > maxActive) {
|
||||
active.shift();
|
||||
}
|
||||
},
|
||||
endSession() {
|
||||
if (active.length > 0) {
|
||||
pending.push(active);
|
||||
while (pending.length > maxPending) {
|
||||
pending.shift();
|
||||
}
|
||||
}
|
||||
active = [];
|
||||
},
|
||||
takeNextBatch() {
|
||||
return pending.shift() ?? [];
|
||||
},
|
||||
reset() {
|
||||
active = [];
|
||||
pending = [];
|
||||
},
|
||||
get activeCount() {
|
||||
return active.length;
|
||||
},
|
||||
get pendingCount() {
|
||||
return pending.length;
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user