83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
/**
|
|
* Analytics event writer — JSONL append-only with date-based rotation.
|
|
*
|
|
* Writes to ~/.takt/analytics/events/YYYY-MM-DD.jsonl when analytics.enabled = true.
|
|
* Does nothing when disabled.
|
|
*/
|
|
|
|
import { appendFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import type { AnalyticsEvent } from './events.js';
|
|
|
|
export class AnalyticsWriter {
|
|
private static instance: AnalyticsWriter | null = null;
|
|
|
|
private enabled = false;
|
|
private eventsDir: string | null = null;
|
|
|
|
private constructor() {}
|
|
|
|
static getInstance(): AnalyticsWriter {
|
|
if (!AnalyticsWriter.instance) {
|
|
AnalyticsWriter.instance = new AnalyticsWriter();
|
|
}
|
|
return AnalyticsWriter.instance;
|
|
}
|
|
|
|
static resetInstance(): void {
|
|
AnalyticsWriter.instance = null;
|
|
}
|
|
|
|
/**
|
|
* Initialize writer.
|
|
* @param enabled Whether analytics collection is active
|
|
* @param eventsDir Absolute path to the events directory (e.g. ~/.takt/analytics/events)
|
|
*/
|
|
init(enabled: boolean, eventsDir: string): void {
|
|
this.enabled = enabled;
|
|
this.eventsDir = eventsDir;
|
|
|
|
if (this.enabled) {
|
|
if (!existsSync(this.eventsDir)) {
|
|
mkdirSync(this.eventsDir, { recursive: true });
|
|
}
|
|
}
|
|
}
|
|
|
|
isEnabled(): boolean {
|
|
return this.enabled;
|
|
}
|
|
|
|
/** Append an analytics event to the current day's JSONL file */
|
|
write(event: AnalyticsEvent): void {
|
|
if (!this.enabled || !this.eventsDir) {
|
|
return;
|
|
}
|
|
|
|
const filePath = join(this.eventsDir, `${formatDate(event.timestamp)}.jsonl`);
|
|
appendFileSync(filePath, JSON.stringify(event) + '\n', 'utf-8');
|
|
}
|
|
}
|
|
|
|
function formatDate(isoTimestamp: string): string {
|
|
return isoTimestamp.slice(0, 10);
|
|
}
|
|
|
|
// ---- Module-level convenience functions ----
|
|
|
|
export function initAnalyticsWriter(enabled: boolean, eventsDir: string): void {
|
|
AnalyticsWriter.getInstance().init(enabled, eventsDir);
|
|
}
|
|
|
|
export function resetAnalyticsWriter(): void {
|
|
AnalyticsWriter.resetInstance();
|
|
}
|
|
|
|
export function isAnalyticsEnabled(): boolean {
|
|
return AnalyticsWriter.getInstance().isEnabled();
|
|
}
|
|
|
|
export function writeAnalyticsEvent(event: AnalyticsEvent): void {
|
|
AnalyticsWriter.getInstance().write(event);
|
|
}
|