@mui/x-telemetry
Version:
MUI X Telemetry.
110 lines (107 loc) • 3.78 kB
JavaScript
;
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;