mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-02 16:15:39 +00:00
A second switch under System > Usage stats, "Also send anonymous error counts", or `BULWARK_TELEMETRY_ERRORS=on|off`. Off by default, off whenever the heartbeat is off or no third-party traffic is on, and switching the heartbeat off switches it off too. With it on the heartbeat becomes schema 2: the v1 fields unchanged plus `errors`, up to 50 fingerprints of the last complete UTC day with the error name, the top frames in Bulwark's bundles (path, line, column, debug ID), the version, a bucketed count, on how many of the last 7 days it occurred, and a message only when it is a fixed error code. Without the consent the heartbeat stays exactly schema 1. The admin preview shows the v2 payload as soon as the switch is flipped.
95 lines
2.8 KiB
TypeScript
95 lines
2.8 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;
|
|
|
|
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). Off unless an
|
|
* admin turns it on; switching telemetry off switches it off too.
|
|
*/
|
|
errorsConsent?: 'on' | 'off';
|
|
}
|
|
|
|
export const DEFAULT_ENDPOINT = 'https://telemetry.bulwarkmail.org/v1/heartbeat';
|