import { EventEmitter } from 'node:events'; import { fetch } from 'cross-fetch'; import { SPECIFY_DISABLE_ANALYTICS, SPECIFY_SDK_VERSION } from '../constants/index.js'; import { formatRequestHeaders } from '../httpApi/clients/internals/formatRequestHeaders.js'; import { makeSpecifyHttpApiRoute } from '../httpApi/clients/internals/makeSpecifyHttpApiRoute.js'; import { SDKTelemetryEvent, SDKTelemetryEventContext } from './events.js'; /* v8 ignore start */ const telemetryEvent = 'specifyTelemetryEvent'; const telemetryEmitter = new EventEmitter(); if (!SPECIFY_DISABLE_ANALYTICS) { telemetryEmitter.on(telemetryEvent, ({ name, payload, context, at }: SDKTelemetryEvent) => { fetch(makeSpecifyHttpApiRoute('/telemetry/sdk'), { method: 'POST', body: JSON.stringify({ name, payload, context, at }), headers: formatRequestHeaders(context.personalAccessToken), }).catch(error => {}); }); } const telemetryContext: SDKTelemetryEventContext = {}; export class SDKTelemetry { constructor(context?: SDKTelemetryEventContext) { if (context) { this.setContext({ sdkVersion: SPECIFY_SDK_VERSION, ...context, }); } } setContext(context: SDKTelemetryEventContext) { Object.assign(telemetryContext, context); return this; } track< Name extends SDKTelemetryEvent['name'], Computed extends Extract, >(name: Name, payload: Computed['payload'], context?: SDKTelemetryEventContext) { if (!SPECIFY_DISABLE_ANALYTICS) { const { personalAccessToken, ...sanitizedContext } = { ...telemetryContext, ...context }; telemetryEmitter.emit(telemetryEvent, { name, payload, context: sanitizedContext, at: Date.now(), }); } return this; } } /* v8 ignore stop */