A file whose top-level symbol spans almost all of it — createFoo() returning
an object of closures — is how Svelte 5 rune stores, React custom-hook modules,
IIFE module-pattern JS and Zustand's create((set,get)=>({…})) are all written.
probe-factory-closure.mjs measures what such a file DELIVERS from within: which
inner symbols' definitions reach the agent, not how many bytes did.
38 lines
1.3 KiB
TypeScript
38 lines
1.3 KiB
TypeScript
import type { MetricSample } from '../stores/types';
|
|
|
|
/** Statistics helpers shared by the store and the panel. */
|
|
|
|
export function meanOf(samples: readonly MetricSample[]): number {
|
|
if (samples.length === 0) return 0;
|
|
let total = 0;
|
|
for (const sample of samples) total += sample.value;
|
|
return total / samples.length;
|
|
}
|
|
|
|
export function medianOf(samples: readonly MetricSample[]): number {
|
|
if (samples.length === 0) return 0;
|
|
const values = samples.map((s) => s.value).sort((a, b) => a - b);
|
|
const mid = Math.floor(values.length / 2);
|
|
return values.length % 2 === 0 ? (values[mid - 1]! + values[mid]!) / 2 : values[mid]!;
|
|
}
|
|
|
|
export function rateOfChange(samples: readonly MetricSample[]): number {
|
|
if (samples.length < 2) return 0;
|
|
const ordered = samples.slice().sort((a, b) => a.at - b.at);
|
|
const first = ordered[0]!;
|
|
const last = ordered[ordered.length - 1]!;
|
|
const elapsed = last.at - first.at;
|
|
return elapsed > 0 ? (last.value - first.value) / elapsed : 0;
|
|
}
|
|
|
|
export function bucketByHour(samples: readonly MetricSample[]): Map<number, MetricSample[]> {
|
|
const buckets = new Map<number, MetricSample[]>();
|
|
for (const sample of samples) {
|
|
const hour = Math.floor(sample.at / 3_600_000);
|
|
const bucket = buckets.get(hour);
|
|
if (bucket) bucket.push(sample);
|
|
else buckets.set(hour, [sample]);
|
|
}
|
|
return buckets;
|
|
}
|