103 lines
2.1 KiB
TypeScript
103 lines
2.1 KiB
TypeScript
// Types
|
|
export interface ActivityEntry {
|
|
id: string;
|
|
type: "api" | "fetch";
|
|
startTime: number;
|
|
endTime?: number;
|
|
|
|
// For API calls
|
|
query?: string;
|
|
|
|
// For URL fetches
|
|
url?: string;
|
|
|
|
// Result - status is number (HTTP code) or null (pending/network error)
|
|
status: number | null;
|
|
error?: string;
|
|
}
|
|
|
|
export interface RateLimitInfo {
|
|
used: number;
|
|
max: number;
|
|
oldestTimestamp: number | null;
|
|
windowMs: number;
|
|
}
|
|
|
|
export class ActivityMonitor {
|
|
private entries: ActivityEntry[] = [];
|
|
private readonly maxEntries = 10;
|
|
private listeners = new Set<() => void>();
|
|
private rateLimitInfo: RateLimitInfo = { used: 0, max: 10, oldestTimestamp: null, windowMs: 60000 };
|
|
private nextId = 1;
|
|
|
|
logStart(partial: Omit<ActivityEntry, "id" | "startTime" | "status">): string {
|
|
const id = `act-${this.nextId++}`;
|
|
const entry: ActivityEntry = {
|
|
...partial,
|
|
id,
|
|
startTime: Date.now(),
|
|
status: null,
|
|
};
|
|
this.entries.push(entry);
|
|
if (this.entries.length > this.maxEntries) {
|
|
this.entries.shift();
|
|
}
|
|
this.notify();
|
|
return id;
|
|
}
|
|
|
|
logComplete(id: string, status: number): void {
|
|
const entry = this.entries.find((e) => e.id === id);
|
|
if (entry) {
|
|
entry.endTime = Date.now();
|
|
entry.status = status;
|
|
this.notify();
|
|
}
|
|
}
|
|
|
|
logError(id: string, error: string): void {
|
|
const entry = this.entries.find((e) => e.id === id);
|
|
if (entry) {
|
|
entry.endTime = Date.now();
|
|
entry.error = error;
|
|
this.notify();
|
|
}
|
|
}
|
|
|
|
getEntries(): readonly ActivityEntry[] {
|
|
return this.entries;
|
|
}
|
|
|
|
getRateLimitInfo(): RateLimitInfo {
|
|
return this.rateLimitInfo;
|
|
}
|
|
|
|
updateRateLimit(info: RateLimitInfo): void {
|
|
this.rateLimitInfo = info;
|
|
this.notify();
|
|
}
|
|
|
|
onUpdate(callback: () => void): () => void {
|
|
this.listeners.add(callback);
|
|
return () => this.listeners.delete(callback);
|
|
}
|
|
|
|
clear(): void {
|
|
this.entries = [];
|
|
this.rateLimitInfo = { used: 0, max: 10, oldestTimestamp: null, windowMs: 60000 };
|
|
this.notify();
|
|
}
|
|
|
|
private notify(): void {
|
|
for (const cb of this.listeners) {
|
|
try {
|
|
cb();
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export const activityMonitor = new ActivityMonitor();
|