UNPKG

@mui/x-telemetry

Version:
103 lines (100 loc) 3.28 kB
import { randomBytes } from 'crypto'; import fs from 'fs'; import os from 'os'; import path from 'path'; import notifyAboutMuiXTelemetry from "./notify.mjs"; import getEnvironmentInfo from "./get-environment-info.mjs"; // This is the key that specifies when the user was informed about telemetry collection. const TELEMETRY_KEY_NOTIFY_DATE = 'telemetry.notifiedAt'; // This is a quasi-persistent identifier used to dedupe recurring events. It's // generated from random data and completely anonymous. const TELEMETRY_KEY_ID = `telemetry.anonymousId`; const CONFIG_FILE_NAME = 'config.json'; const PROJECT_NAME = 'mui-x'; function getConfigDirectory(distDir) { const env = getEnvironmentInfo(); const isLikelyEphemeral = env.isCI || env.isDocker; if (isLikelyEphemeral) { return path.join(distDir, 'cache', PROJECT_NAME); } const { platform } = process; const homedir = os.homedir(); if (platform === 'darwin') { return path.join(homedir, 'Library', 'Preferences', PROJECT_NAME); } if (platform === 'win32') { const appData = process.env.APPDATA || path.join(homedir, 'AppData', 'Roaming'); return path.join(appData, PROJECT_NAME, 'Config'); } // Linux / others: follow XDG Base Directory specification const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(homedir, '.config'); return path.join(xdgConfig, PROJECT_NAME); } function readConfigFile(configPath) { try { return JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch { return {}; } } function writeConfigFile(configPath, data) { const dir = path.dirname(configPath); fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(configPath, JSON.stringify(data, null, '\t')); } export class TelemetryStorage { static async init({ distDir }) { const configDirectory = getConfigDirectory(distDir); let configFilePath = null; try { configFilePath = path.join(configDirectory, CONFIG_FILE_NAME); // Verify write access by ensuring the directory exists fs.mkdirSync(configDirectory, { recursive: true }); } catch { configFilePath = null; } return new TelemetryStorage(configFilePath); } constructor(filePath) { this.configPath = filePath; this.notify(); } notify = () => { if (!this.configPath) { return; } // The end-user has already been notified about our telemetry integration. We // don't need to constantly annoy them about it. // We will re-inform users about the telemetry if significant changes are // ever made. const data = readConfigFile(this.configPath); if (data[TELEMETRY_KEY_NOTIFY_DATE]) { return; } data[TELEMETRY_KEY_NOTIFY_DATE] = Date.now().toString(); writeConfigFile(this.configPath, data); notifyAboutMuiXTelemetry(); }; get anonymousId() { if (this.configPath) { const data = readConfigFile(this.configPath); const existing = data[TELEMETRY_KEY_ID]; if (typeof existing === 'string') { return existing; } const generated = randomBytes(32).toString('hex'); data[TELEMETRY_KEY_ID] = generated; writeConfigFile(this.configPath, data); return generated; } return randomBytes(32).toString('hex'); } }