UNPKG

@mui/x-telemetry

Version:
110 lines (107 loc) 3.78 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.TelemetryStorage = void 0; var _crypto = require("crypto"); var _fs = _interopRequireDefault(require("fs")); var _os = _interopRequireDefault(require("os")); var _path = _interopRequireDefault(require("path")); var _notify = _interopRequireDefault(require("./notify")); var _getEnvironmentInfo = _interopRequireDefault(require("./get-environment-info")); // 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 = (0, _getEnvironmentInfo.default)(); const isLikelyEphemeral = env.isCI || env.isDocker; if (isLikelyEphemeral) { return _path.default.join(distDir, 'cache', PROJECT_NAME); } const { platform } = process; const homedir = _os.default.homedir(); if (platform === 'darwin') { return _path.default.join(homedir, 'Library', 'Preferences', PROJECT_NAME); } if (platform === 'win32') { const appData = process.env.APPDATA || _path.default.join(homedir, 'AppData', 'Roaming'); return _path.default.join(appData, PROJECT_NAME, 'Config'); } // Linux / others: follow XDG Base Directory specification const xdgConfig = process.env.XDG_CONFIG_HOME || _path.default.join(homedir, '.config'); return _path.default.join(xdgConfig, PROJECT_NAME); } function readConfigFile(configPath) { try { return JSON.parse(_fs.default.readFileSync(configPath, 'utf-8')); } catch { return {}; } } function writeConfigFile(configPath, data) { const dir = _path.default.dirname(configPath); _fs.default.mkdirSync(dir, { recursive: true }); _fs.default.writeFileSync(configPath, JSON.stringify(data, null, '\t')); } class TelemetryStorage { static async init({ distDir }) { const configDirectory = getConfigDirectory(distDir); let configFilePath = null; try { configFilePath = _path.default.join(configDirectory, CONFIG_FILE_NAME); // Verify write access by ensuring the directory exists _fs.default.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); (0, _notify.default)(); }; get anonymousId() { if (this.configPath) { const data = readConfigFile(this.configPath); const existing = data[TELEMETRY_KEY_ID]; if (typeof existing === 'string') { return existing; } const generated = (0, _crypto.randomBytes)(32).toString('hex'); data[TELEMETRY_KEY_ID] = generated; writeConfigFile(this.configPath, data); return generated; } return (0, _crypto.randomBytes)(32).toString('hex'); } } exports.TelemetryStorage = TelemetryStorage;