mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 08:15:55 +00:00
120 lines
3.7 KiB
TypeScript
120 lines
3.7 KiB
TypeScript
// Schema v1 of the anonymous heartbeat, and v2 (v1 plus error counts, sent
|
|
// only with the separate error-count consent). Documented at
|
|
// https://bulwarkmail.org/docs/legal/privacy/telemetry
|
|
|
|
export type ConsentState = 'pending' | 'on' | 'off';
|
|
|
|
export type Platform = 'docker' | 'bare' | 'k8s' | 'unknown';
|
|
export type OsFamily = 'linux' | 'darwin' | 'windows' | 'unknown';
|
|
export type CountBucket = '0' | '1' | '2-5' | '6-10' | '11-50' | '51-200' | '201+';
|
|
|
|
export interface TelemetryFeatures {
|
|
calendar: boolean;
|
|
contacts: boolean;
|
|
files: boolean;
|
|
extensions: boolean;
|
|
oauth_enabled: boolean;
|
|
smime_enabled: boolean;
|
|
}
|
|
|
|
export interface TelemetryPayload {
|
|
schema: '1';
|
|
instance_id: string;
|
|
ts: string;
|
|
version: string;
|
|
build: string | null;
|
|
platform: Platform;
|
|
node_version: string;
|
|
os_family: OsFamily;
|
|
stalwart_version: string | null;
|
|
features: TelemetryFeatures;
|
|
counts: {
|
|
accounts: CountBucket;
|
|
accounts_active_7d: CountBucket;
|
|
extensions_installed: number;
|
|
themes_installed: number;
|
|
};
|
|
uptime_days: number;
|
|
}
|
|
|
|
/** At most this many errors in a v2 heartbeat, the most frequent first. */
|
|
export const MAX_TELEMETRY_ERRORS = 50;
|
|
/** Top frames per error. */
|
|
export const MAX_TELEMETRY_FRAMES = 5;
|
|
|
|
export interface TelemetryErrorFrame {
|
|
/** The bundle file without origin: `/_next/static/chunks/x.js` or `/.next/server/...`. */
|
|
path: string;
|
|
line: number | null;
|
|
col: number | null;
|
|
/** The file's debug ID, which finds its uploaded source map. */
|
|
debug_id: string | null;
|
|
}
|
|
|
|
/** One error fingerprint of the last complete UTC day. */
|
|
export interface TelemetryError {
|
|
/** The error's class name (TypeError, JmapMethodError). */
|
|
name: string;
|
|
fingerprint: string;
|
|
frames: TelemetryErrorFrame[];
|
|
version: string;
|
|
/** How often that day, bucketed like the account counts. */
|
|
count: CountBucket;
|
|
/** On how many of the last 7 days it occurred (1-7). */
|
|
days: number;
|
|
/** Only one of Bulwark's fixed error codes (`Email/set: overQuota`), never free text. */
|
|
message?: string;
|
|
}
|
|
|
|
export interface TelemetryPayloadV2 extends Omit<TelemetryPayload, 'schema'> {
|
|
schema: '2';
|
|
errors: TelemetryError[];
|
|
}
|
|
|
|
export type AnyTelemetryPayload = TelemetryPayload | TelemetryPayloadV2;
|
|
|
|
/**
|
|
* Error counts: off, daily (with the heartbeat, for the day before) or
|
|
* instant (daily, plus the current day's counts within about a minute).
|
|
* 'on' is the daily mode; the stored value predates the instant one.
|
|
*/
|
|
export type ErrorsConsent = 'on' | 'off' | 'instant';
|
|
|
|
/**
|
|
* What instant mode posts to the collector's /v1/errors: the current UTC
|
|
* day's errors that are new or whose count bucket changed since the last send.
|
|
*/
|
|
export interface TelemetryErrorBatch {
|
|
schema: '1';
|
|
instance_id: string;
|
|
/** The UTC day the counts are for (YYYY-MM-DD). */
|
|
day: string;
|
|
errors: TelemetryError[];
|
|
}
|
|
|
|
/** The collector's errors URL next to its heartbeat URL: `.../v1/heartbeat` -> `.../v1/errors`. */
|
|
export function errorsEndpointFor(heartbeatEndpoint: string): string {
|
|
return new URL('errors', heartbeatEndpoint).toString();
|
|
}
|
|
|
|
export interface TelemetryStateFile {
|
|
consent: ConsentState;
|
|
endpoint: string;
|
|
consentedAt: string | null;
|
|
lastSentAt: string | null;
|
|
/**
|
|
* With a shared store only: when the last scheduled heartbeat went out.
|
|
* Unlike lastSentAt, the admin's "send now" doesn't set it.
|
|
*/
|
|
lastScheduledSentAt?: string | null;
|
|
nextScheduledAt: string | null;
|
|
/**
|
|
* The separate consent to add error counts (schema v2), and whether they
|
|
* also go out instantly. Off unless an admin turns it on; switching
|
|
* telemetry off switches it off too.
|
|
*/
|
|
errorsConsent?: ErrorsConsent;
|
|
}
|
|
|
|
export const DEFAULT_ENDPOINT = 'https://telemetry.bulwarkmail.org/v1/heartbeat';
|