Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@mui/x-telemetry

Package Overview
Dependencies
Maintainers
16
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mui/x-telemetry - npm Package Compare versions

Comparing version
9.0.0-alpha.0
to
9.0.0-alpha.2
+20
context.d.mts
export interface TelemetryContextType {
config: {
isInitialized: boolean;
};
traits: Record<string, any> & {
machineId?: string | null;
fingerprint?: {
fullHash?: string | null;
coreHash?: string | null;
components?: Record<string, any> | null;
} | null;
projectId?: string | null;
anonymousId?: string | null;
sessionId?: string | null;
isDocker?: boolean;
isCI?: boolean;
};
}
declare const defaultValue: TelemetryContextType;
export default defaultValue;
// This file will be modified by the `postinstall` script.
// See postinstall/index.ts for more information.
const defaultValue = {
config: {
isInitialized: false
},
traits: {}
};
export default defaultValue;
import muiXTelemetryEvents from "./runtime/events.mjs";
import sendMuiXTelemetryEventOriginal from "./runtime/sender.mjs";
declare const sendMuiXTelemetryEvent: typeof sendMuiXTelemetryEventOriginal | (() => void);
declare const muiXTelemetrySettings: {
enableDebug: () => void;
enableTelemetry: () => void;
disableTelemetry: () => void;
};
export { muiXTelemetryEvents, sendMuiXTelemetryEvent, muiXTelemetrySettings };
/**
* @mui/x-telemetry v9.0.0-alpha.2
*
* @license SEE LICENSE IN LICENSE
* This source code is licensed under the SEE LICENSE IN LICENSE license found in the
* LICENSE file in the root directory of this source tree.
*/
import muiXTelemetryEvents from "./runtime/events.mjs";
import sendMuiXTelemetryEventOriginal from "./runtime/sender.mjs";
import muiXTelemetrySettingsOriginal from "./runtime/settings.mjs";
const noop = () => {};
// To cut unused imports in production as early as possible
const sendMuiXTelemetryEvent = process.env.NODE_ENV === 'production' ? noop : sendMuiXTelemetryEventOriginal;
// To cut unused imports in production as early as possible
const muiXTelemetrySettings = process.env.NODE_ENV === 'production' ? {
enableDebug: noop,
enableTelemetry: noop,
disableTelemetry: noop
} : muiXTelemetrySettingsOriginal;
export { muiXTelemetryEvents, sendMuiXTelemetryEvent, muiXTelemetrySettings };
import isDockerFunction from 'is-docker';
import ciEnvironment from 'ci-info';
let traits;
export default function getEnvironmentInfo() {
if (!traits) {
traits = {
isDocker: isDockerFunction(),
isCI: ciEnvironment.isCI
};
}
return traits;
}
import { createHash } from 'crypto';
export default async function getAnonymousMachineId() {
try {
const nodeMachineId = await import('node-machine-id');
const rawMachineId = await nodeMachineId.machineId(true);
if (!rawMachineId) {
return null;
}
return createHash('sha256').update(rawMachineId).digest('hex');
} catch (_) {
// Ignore any errors
return null;
}
}
import { exec } from 'child_process';
import { createHash } from 'crypto';
import util from 'util';
const asyncExec = util.promisify(exec);
async function execCLI(command) {
try {
const response = await asyncExec(command, {
timeout: 1000,
windowsHide: true
});
return String(response).trim();
} catch (_) {
return null;
}
}
// Q: Why does MUI need a project ID? Why is it looking at my git remote?
// A:
// MUI's telemetry always anonymizes these values. We need a way to
// differentiate different projects to track feature usage accurately.
// For example, to prevent a feature from appearing to be constantly `used`
// and then `unused` when switching between local projects.
async function getRawProjectId() {
return (await execCLI(`git config --local --get remote.origin.url`)) || process.env.REPOSITORY_URL || (await execCLI(`git rev-parse --show-toplevel`)) || process.cwd();
}
export default async function getAnonymousProjectId() {
const rawProjectId = await getRawProjectId();
return createHash('sha256').update(rawProjectId).digest('hex');
}
import _extends from "@babel/runtime/helpers/esm/extends";
import fs from 'fs';
import path from 'path';
import { randomBytes } from 'crypto';
import { fileURLToPath } from 'url';
import getEnvironmentInfo from "./get-environment-info.mjs";
import getAnonymousProjectId from "./get-project-id.mjs";
import getAnonymousMachineId from "./get-machine-id.mjs";
import { TelemetryStorage } from "./storage.mjs";
const dirname = typeof __dirname === 'string' ? __dirname // cjs build in root dir
: (() => {
const filename = fileURLToPath(import.meta.url);
// esm build in `esm` directory, so we need to go up two levels
return path.dirname(path.dirname(filename));
})();
(async () => {
// If Node.js support permissions, we need to check if the current user has
// the necessary permissions to write to the file system.
if (typeof process.permission !== 'undefined' && !(process.permission.has('fs.read') && process.permission.has('fs.write'))) {
return;
}
const storage = await TelemetryStorage.init({
distDir: process.cwd()
});
const [environmentInfo, projectId, machineId] = await Promise.all([getEnvironmentInfo(), getAnonymousProjectId(), getAnonymousMachineId()]);
const contextData = {
config: {
isInitialized: true
},
traits: _extends({}, environmentInfo, {
machineId,
projectId,
sessionId: randomBytes(32).toString('hex'),
anonymousId: storage.anonymousId
})
};
const writeContextData = (filePath, format) => {
const targetPath = path.resolve(dirname, '..', filePath, 'context.js');
fs.writeFileSync(targetPath, format(JSON.stringify(contextData, null, 2)));
};
writeContextData('esm', content => `export default ${content};`);
writeContextData('', content => [`"use strict";`, `Object.defineProperty(exports, "__esModule", { value: true });`, `exports.default = void 0;`, `var _default = exports.default = ${content};`].join('\n'));
})().catch(error => {
console.error('[telemetry] Failed to make initialization. Please, report error to MUI X team:\n' + 'https://mui.com/r/x-telemetry-postinstall-troubleshoot\n', error);
});
export default function notifyAboutMuiXTelemetry() {
console.log(`[Attention]: MUI X now collects completely anonymous telemetry regarding usage.`);
console.log(`This information is used to shape MUI's roadmap and prioritize features.`);
console.log(`You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:`);
console.log('https://mui.com/x/guides/telemetry');
console.log();
}
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');
}
}
interface TelemetryEnvConfig {
NODE_ENV: string | '<unknown>';
IS_COLLECTING: boolean | undefined;
DEBUG: boolean;
}
declare global {
var __MUI_X_TELEMETRY_DISABLED__: boolean | undefined;
}
export declare function getTelemetryEnvConfig(skipCache?: boolean): TelemetryEnvConfig;
export declare function getTelemetryEnvConfigValue<K extends keyof TelemetryEnvConfig>(key: K): TelemetryEnvConfig[K];
export declare function setTelemetryEnvConfigValue<K extends keyof TelemetryEnvConfig>(key: K, value: NonNullable<TelemetryEnvConfig[K]>): void;
export {};
const envEnabledValues = ['1', 'true', 'yes', 'y'];
const envDisabledValues = ['0', 'false', 'no', 'n'];
function getBooleanEnv(value) {
if (!value) {
return undefined;
}
if (envEnabledValues.includes(value)) {
return true;
}
if (envDisabledValues.includes(value)) {
return false;
}
return undefined;
}
function getBooleanEnvFromEnvObject(envKey, envObj) {
const keys = Object.keys(envObj);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (!key.endsWith(envKey)) {
continue;
}
const value = getBooleanEnv(envObj[key]?.toLowerCase());
if (typeof value === 'boolean') {
return value;
}
}
return undefined;
}
function getIsTelemetryCollecting() {
// Check global variable
// eslint-disable-next-line no-underscore-dangle
const globalValue = globalThis.__MUI_X_TELEMETRY_DISABLED__;
if (typeof globalValue === 'boolean') {
// If disabled=true, telemetry is disabled
// If disabled=false, telemetry is enabled
return !globalValue;
}
try {
if (typeof process !== 'undefined' && process.env && typeof process.env === 'object') {
const result = getBooleanEnvFromEnvObject('MUI_X_TELEMETRY_DISABLED', process.env);
if (typeof result === 'boolean') {
// If disabled=true, telemetry is disabled
// If disabled=false, telemetry is enabled
return !result;
}
}
} catch (_) {
// If there is an error, return the default value
}
try {
// Some build tools replace env variables on compilation
// e.g. Next.js, webpack EnvironmentPlugin
const envValue = process.env.MUI_X_TELEMETRY_DISABLED || process.env.NEXT_PUBLIC_MUI_X_TELEMETRY_DISABLED || process.env.GATSBY_MUI_X_TELEMETRY_DISABLED || process.env.REACT_APP_MUI_X_TELEMETRY_DISABLED || process.env.PUBLIC_MUI_X_TELEMETRY_DISABLED;
const result = getBooleanEnv(envValue);
if (typeof result === 'boolean') {
// If disabled=true, telemetry is disabled
// If disabled=false, telemetry is enabled
return !result;
}
} catch (_) {
// If there is an error, return the default value
}
return undefined;
}
function getIsDebugModeEnabled() {
try {
// Check global variable
// eslint-disable-next-line no-underscore-dangle
const globalValue = globalThis.__MUI_X_TELEMETRY_DEBUG__;
if (typeof globalValue === 'boolean') {
return globalValue;
}
if (typeof process !== 'undefined' && process.env && typeof process.env === 'object') {
const result = getBooleanEnvFromEnvObject('MUI_X_TELEMETRY_DEBUG', process.env);
if (typeof result === 'boolean') {
return result;
}
}
// e.g. Webpack EnvironmentPlugin
if (process.env.MUI_X_TELEMETRY_DEBUG) {
const result = getBooleanEnv(process.env.MUI_X_TELEMETRY_DEBUG);
if (typeof result === 'boolean') {
return result;
}
}
} catch (_) {
// If there is an error, return the default value
}
try {
// e.g. Next.js, webpack EnvironmentPlugin
const envValue = process.env.MUI_X_TELEMETRY_DEBUG || process.env.NEXT_PUBLIC_MUI_X_TELEMETRY_DEBUG || process.env.GATSBY_MUI_X_TELEMETRY_DEBUG || process.env.REACT_APP_MUI_X_TELEMETRY_DEBUG || process.env.PUBLIC_MUI_X_TELEMETRY_DEBUG;
const result = getBooleanEnv(envValue);
if (typeof result === 'boolean') {
return result;
}
} catch (_) {
// If there is an error, return the default value
}
return false;
}
function getNodeEnv() {
try {
return process.env.NODE_ENV ?? '<unknown>';
} catch (_) {
return '<unknown>';
}
}
let cachedEnv = null;
export function getTelemetryEnvConfig(skipCache = false) {
if (skipCache || !cachedEnv) {
cachedEnv = {
NODE_ENV: getNodeEnv(),
IS_COLLECTING: getIsTelemetryCollecting(),
DEBUG: getIsDebugModeEnabled()
};
}
return cachedEnv;
}
export function getTelemetryEnvConfigValue(key) {
return getTelemetryEnvConfig()[key];
}
export function setTelemetryEnvConfigValue(key, value) {
getTelemetryEnvConfig()[key] = value;
}
import { TelemetryEventContext } from "../types.mjs";
declare const muiXTelemetryEvents: {
licenseVerification: (() => null) | ((context: TelemetryEventContext, payload: {
packageReleaseInfo: string;
packageName: string;
licenseStatus?: string;
}) => {
eventName: string;
payload: {
packageReleaseInfo: string;
packageName: string;
licenseStatus?: string;
};
context: TelemetryEventContext;
});
};
export default muiXTelemetryEvents;
const noop = () => null;
const muiXTelemetryEvents = {
licenseVerification: process.env.NODE_ENV === 'production' ? noop : (context, payload) => ({
eventName: 'licenseVerification',
payload,
context
})
};
export default muiXTelemetryEvents;
declare function fetchWithRetry(url: string, options: RequestInit, retries?: number): Promise<Response>;
export { fetchWithRetry };
async function fetchWithRetry(url, options, retries = 3) {
try {
const response = await fetch(url, options);
if (response.ok) {
return response;
}
throw /* FIXME (minify-errors-in-prod): Unminified error message in production build! */new Error(`MUI X: Request failed with status ${response.status}`);
} catch (error) {
if (retries === 0) {
throw error;
}
return new Promise(resolve => {
setTimeout(() => {
resolve(fetchWithRetry(url, options, retries - 1));
}, Math.random() * 3_000);
});
}
}
export { fetchWithRetry };
import type { TelemetryContextType } from "../context.mjs";
declare function getTelemetryContext(): Promise<TelemetryContextType>;
export { TelemetryContextType };
export default getTelemetryContext;
import _extends from "@babel/runtime/helpers/esm/extends";
import telemetryContext from "../context.mjs";
import { getWindowStorageItem, setWindowStorageItem } from "./window-storage.mjs";
function generateId(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
function pick(obj, keys) {
return keys.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
}
const getBrowserFingerprint = typeof window === 'undefined' || process.env.NODE_ENV === 'test' ? () => undefined : async () => {
const fingerprintLCKey = 'fingerprint';
try {
const existingFingerprint = getWindowStorageItem('localStorage', fingerprintLCKey);
if (existingFingerprint) {
return JSON.parse(existingFingerprint);
}
const FingerprintJS = await import('@fingerprintjs/fingerprintjs');
const fp = await FingerprintJS.load({
monitoring: false
});
const fpResult = await fp.get();
const components = _extends({}, fpResult.components);
delete components.cookiesEnabled;
const fullHash = FingerprintJS.hashComponents(components);
const coreHash = FingerprintJS.hashComponents(_extends({}, pick(components, ['fonts', 'audio', 'languages', 'deviceMemory', 'timezone', 'sessionStorage', 'localStorage', 'indexedDB', 'openDatabase', 'platform', 'canvas', 'vendor', 'vendorFlavors', 'colorGamut', 'forcedColors', 'monochrome', 'contrast', 'reducedMotion', 'math', 'videoCard', 'architecture'])));
const result = {
fullHash,
coreHash
};
setWindowStorageItem('localStorage', fingerprintLCKey, JSON.stringify(result));
return result;
} catch (_) {
return null;
}
};
function getAnonymousId() {
const localStorageKey = 'anonymous_id';
const existingAnonymousId = getWindowStorageItem('localStorage', localStorageKey);
if (existingAnonymousId) {
return existingAnonymousId;
}
const generated = `anid_${generateId(32)}`;
if (setWindowStorageItem('localStorage', localStorageKey, generated)) {
return generated;
}
return '';
}
function getSessionId() {
const localStorageKey = 'session_id';
const existingSessionId = getWindowStorageItem('sessionStorage', localStorageKey);
if (existingSessionId) {
return existingSessionId;
}
const generated = `sesid_${generateId(32)}`;
if (setWindowStorageItem('sessionStorage', localStorageKey, generated)) {
return generated;
}
return `sestp_${generateId(32)}`;
}
async function getTelemetryContext() {
telemetryContext.traits.sessionId = getSessionId();
// Initialize the context if it hasn't been initialized yet
// (e.g. postinstall not run)
if (!telemetryContext.config.isInitialized) {
telemetryContext.traits.anonymousId = getAnonymousId();
telemetryContext.config.isInitialized = true;
}
if (!telemetryContext.traits.fingerprint) {
telemetryContext.traits.fingerprint = await getBrowserFingerprint();
}
return telemetryContext;
}
export default getTelemetryContext;
import { TelemetryEvent } from "../types.mjs";
declare function sendMuiXTelemetryEvent(event: TelemetryEvent | null): Promise<void>;
export default sendMuiXTelemetryEvent;
import _extends from "@babel/runtime/helpers/esm/extends";
import { getTelemetryEnvConfigValue } from "./config.mjs";
import { fetchWithRetry } from "./fetcher.mjs";
const sendMuiXTelemetryRetries = 3;
function shouldSendTelemetry(telemetryContext) {
// Disable reporting in SSR / Node.js
if (typeof window === 'undefined') {
return false;
}
// Priority to the config (e.g. in code, env)
const envIsCollecting = getTelemetryEnvConfigValue('IS_COLLECTING');
if (typeof envIsCollecting === 'boolean') {
return envIsCollecting;
}
// Disable collection of the telemetry in CI builds,
// as it not related to development process
if (telemetryContext.traits.isCI) {
return false;
}
// Enabled by default
return true;
}
async function sendMuiXTelemetryEvent(event) {
try {
// Disable collection of the telemetry
// in production environment
if (process.env.NODE_ENV === 'production') {
return;
}
const {
default: getTelemetryContext
} = await import("./get-context.mjs");
const telemetryContext = await getTelemetryContext();
if (!event || !shouldSendTelemetry(telemetryContext)) {
return;
}
const eventPayload = _extends({}, event, {
context: _extends({}, telemetryContext.traits, event.context)
});
if (getTelemetryEnvConfigValue('DEBUG')) {
console.log('[mui-x-telemetry] event', JSON.stringify(eventPayload, null, 2));
return;
}
// TODO: batch events and send them in a single request when there will be more
await fetchWithRetry('https://x-telemetry.mui.com/v2/telemetry/record', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Telemetry-Client-Version': "9.0.0-alpha.2" ?? '<dev>',
'X-Telemetry-Node-Env': process.env.NODE_ENV ?? '<unknown>'
},
body: JSON.stringify([eventPayload])
}, sendMuiXTelemetryRetries);
} catch (_) {
console.log('[mui-x-telemetry] error', _);
}
}
export default sendMuiXTelemetryEvent;
declare const muiXTelemetrySettings: {
enableDebug: () => void;
enableTelemetry: () => void;
disableTelemetry: () => void;
};
export default muiXTelemetrySettings;
import { setTelemetryEnvConfigValue } from "./config.mjs";
const muiXTelemetrySettings = {
enableDebug: () => {
setTelemetryEnvConfigValue('DEBUG', true);
},
enableTelemetry: () => {
setTelemetryEnvConfigValue('IS_COLLECTING', true);
},
disableTelemetry: () => {
setTelemetryEnvConfigValue('IS_COLLECTING', false);
}
};
export default muiXTelemetrySettings;
type WindowStorageType = 'localStorage' | 'sessionStorage';
export declare function setWindowStorageItem(type: WindowStorageType, key: string, value: string): boolean;
export declare function getWindowStorageItem(type: WindowStorageType, key: string): string | null;
export {};
const prefix = '__mui_x_telemetry_';
function getStorageKey(key) {
return prefix + btoa(key);
}
export function setWindowStorageItem(type, key, value) {
try {
if (typeof window !== 'undefined' && window[type]) {
window[type].setItem(getStorageKey(key), value);
return true;
}
} catch (_) {
// Storage is unavailable, skip it
}
return false;
}
export function getWindowStorageItem(type, key) {
try {
if (typeof window !== 'undefined' && window[type]) {
return window[type].getItem(getStorageKey(key));
}
} catch (_) {
// Storage is unavailable, skip it
}
return null;
}
export {};
declare global {
interface MUIEnv {
MUI_VERSION?: string;
MUI_X_TELEMETRY_DISABLED?: string;
NEXT_PUBLIC_MUI_X_TELEMETRY_DISABLED?: string;
GATSBY_MUI_X_TELEMETRY_DISABLED?: string;
REACT_APP_MUI_X_TELEMETRY_DISABLED?: string;
PUBLIC_MUI_X_TELEMETRY_DISABLED?: string;
MUI_X_TELEMETRY_DEBUG?: string;
NEXT_PUBLIC_MUI_X_TELEMETRY_DEBUG?: string;
GATSBY_MUI_X_TELEMETRY_DEBUG?: string;
REACT_APP_MUI_X_TELEMETRY_DEBUG?: string;
PUBLIC_MUI_X_TELEMETRY_DEBUG?: string;
}
}
export {};
declare global {
interface MUIEnv {
MUI_VERSION?: string;
MUI_X_TELEMETRY_DISABLED?: string;
NEXT_PUBLIC_MUI_X_TELEMETRY_DISABLED?: string;
GATSBY_MUI_X_TELEMETRY_DISABLED?: string;
REACT_APP_MUI_X_TELEMETRY_DISABLED?: string;
PUBLIC_MUI_X_TELEMETRY_DISABLED?: string;
MUI_X_TELEMETRY_DEBUG?: string;
NEXT_PUBLIC_MUI_X_TELEMETRY_DEBUG?: string;
GATSBY_MUI_X_TELEMETRY_DEBUG?: string;
REACT_APP_MUI_X_TELEMETRY_DEBUG?: string;
PUBLIC_MUI_X_TELEMETRY_DEBUG?: string;
}
}
export interface TelemetryEventContext {
licenseKey?: string;
xLicenseClientVersion?: string;
}
export interface TelemetryEvent {
eventName: string;
payload: Record<string, any>;
context: TelemetryEventContext;
}
export {};
+1
-1
/**
* @mui/x-telemetry v9.0.0-alpha.0
* @mui/x-telemetry v9.0.0-alpha.2
*

@@ -4,0 +4,0 @@ * @license SEE LICENSE IN LICENSE

{
"name": "@mui/x-telemetry",
"version": "9.0.0-alpha.0",
"version": "9.0.0-alpha.2",
"author": "MUI Team",

@@ -24,3 +24,2 @@ "description": "MUI X Telemetry.",

"ci-info": "^4.3.1",
"conf": "^11.0.2",
"is-docker": "^4.0.0",

@@ -33,7 +32,9 @@ "node-machine-id": "^1.1.12"

"type": "commonjs",
"main": "./index.js",
"types": "./index.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"types": "./index.d.mts",
"default": "./index.mjs"
},
"require": {

@@ -44,21 +45,26 @@ "types": "./index.d.ts",

"default": {
"types": "./esm/index.d.ts",
"default": "./esm/index.js"
"types": "./index.d.mts",
"default": "./index.mjs"
}
},
"./*": {
"./postinstall": {
"import": {
"types": "./postinstall/index.d.mts",
"default": "./postinstall/index.mjs"
},
"require": {
"types": "./*/index.d.ts",
"default": "./*/index.js"
"types": "./postinstall/index.d.ts",
"default": "./postinstall/index.js"
},
"default": {
"types": "./esm/*/index.d.ts",
"default": "./esm/*/index.js"
"types": "./postinstall/index.d.mts",
"default": "./postinstall/index.mjs"
}
},
"./esm": null
}
},
"main": "./index.js",
"types": "./index.d.ts",
"scripts": {
"postinstall": "node ./esm/postinstall/index.js"
"postinstall": "node ./postinstall/index.mjs"
}
}

@@ -8,3 +8,3 @@ "use strict";

function notifyAboutMuiXTelemetry() {
console.log(`[Attention]: MUI X now may collect completely anonymous telemetry regarding usage.`);
console.log(`[Attention]: MUI X now collects completely anonymous telemetry regarding usage.`);
console.log(`This information is used to shape MUI's roadmap and prioritize features.`);

@@ -11,0 +11,0 @@ console.log(`You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:`);

@@ -8,4 +8,5 @@ "use strict";

exports.TelemetryStorage = void 0;
var _interopRequireWildcard2 = _interopRequireDefault(require("@babel/runtime/helpers/interopRequireWildcard"));
var _crypto = require("crypto");
var _fs = _interopRequireDefault(require("fs"));
var _os = _interopRequireDefault(require("os"));
var _path = _interopRequireDefault(require("path"));

@@ -20,10 +21,39 @@ var _notify = _interopRequireDefault(require("./notify"));

const TELEMETRY_KEY_ID = `telemetry.anonymousId`;
function getStorageDirectory(distDir) {
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');
return _path.default.join(distDir, 'cache', PROJECT_NAME);
}
return undefined;
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 {

@@ -33,26 +63,21 @@ static async init({

}) {
const storageDirectory = getStorageDirectory(distDir);
let conf = null;
const configDirectory = getConfigDirectory(distDir);
let configFilePath = null;
try {
// `conf` incorrectly throws a permission error during initialization
// instead of waiting for first use. We need to handle it, otherwise the
// process may crash.
const {
default: Conf
} = await Promise.resolve().then(() => (0, _interopRequireWildcard2.default)(require('conf')));
conf = new Conf({
projectName: 'mui-x',
cwd: storageDirectory
configFilePath = _path.default.join(configDirectory, CONFIG_FILE_NAME);
// Verify write access by ensuring the directory exists
_fs.default.mkdirSync(configDirectory, {
recursive: true
});
} catch (_) {
conf = null;
} catch {
configFilePath = null;
}
return new TelemetryStorage(conf);
return new TelemetryStorage(configFilePath);
}
constructor(conf) {
this.conf = conf;
constructor(filePath) {
this.configPath = filePath;
this.notify();
}
notify = () => {
if (!this.conf) {
if (!this.configPath) {
return;

@@ -65,21 +90,25 @@ }

// ever made.
if (this.conf.get(TELEMETRY_KEY_NOTIFY_DATE, '')) {
const data = readConfigFile(this.configPath);
if (data[TELEMETRY_KEY_NOTIFY_DATE]) {
return;
}
this.conf.set(TELEMETRY_KEY_NOTIFY_DATE, Date.now().toString());
data[TELEMETRY_KEY_NOTIFY_DATE] = Date.now().toString();
writeConfigFile(this.configPath, data);
(0, _notify.default)();
};
get configPath() {
return this.conf?.path;
}
get anonymousId() {
const val = this.conf && this.conf.get(TELEMETRY_KEY_ID);
if (val) {
return val;
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;
}
const generated = (0, _crypto.randomBytes)(32).toString('hex');
this.conf?.set(TELEMETRY_KEY_ID, generated);
return generated;
return (0, _crypto.randomBytes)(32).toString('hex');
}
}
exports.TelemetryStorage = TelemetryStorage;
+15
-27
# @mui/x-telemetry
Package used by some of MUI X to collects **anonymous** telemetry data about general usage. Participation in this anonymous program is optional, and you may opt-out if you'd not like to share any information.
Package used by some of MUI X to collect **anonymous** telemetry data about general usage during development. Telemetry is **enabled by default** in development mode and is completely removed in production builds. Participation in this anonymous program is optional, and you may opt out if you'd not like to share any information.
## How to opt-in
## How to configure telemetry
Currently, **it's disabled by default,** and you could opt-in to it in 3 ways:
Telemetry is **enabled by default** in development mode. You can enable or disable it in any of the following ways:
1. By setting it directly to package settings on the application start (for example, in the main file).
1. By setting the environment variable.
```dotenv
MUI_X_TELEMETRY_DISABLED=true # Disable telemetry
# or
MUI_X_TELEMETRY_DISABLED=false # Enable telemetry
```
> ⚠️ Note that some frameworks require prefixing the variable with `REACT_APP_`, `NEXT_PUBLIC_`, etc.
2. By using the package settings on application start (for example, in the main file).
```js

@@ -21,14 +31,4 @@ import { muiXTelemetrySettings } from '@mui/x-telemetry';

2. By setting the environment variable.
3. By setting the flag on the global object on application start (for example, in the main file).
```dotenv
MUI_X_TELEMETRY_DISABLED=false # Enable telemetry
# or
MUI_X_TELEMETRY_DISABLED=true # Enable telemetry
```
> ⚠️ Note that some frameworks requires to prefix the variable with `REACT_APP_`, `NEXT_PUBLIC_`, etc.
3. By setting the flag to global object on the application start (for example, in the main file).
```js

@@ -39,13 +39,1 @@ globalThis.__MUI_X_TELEMETRY_DISABLED__ = false; // enabled

```
OR
```js
if (typeof window !== 'undefined') {
window.__MUI_X_TELEMETRY_DISABLED__ = false; // enabled
}
// or
if (typeof window !== 'undefined') {
window.__MUI_X_TELEMETRY_DISABLED__ = true; // disabled
}
```

@@ -13,3 +13,3 @@ "use strict";

}
throw new Error(`Request failed with status ${response.status}`);
throw /* FIXME (minify-errors-in-prod): Unminified error message in production build! */new Error(`MUI X: Request failed with status ${response.status}`);
} catch (error) {

@@ -16,0 +16,0 @@ if (retries === 0) {

@@ -31,4 +31,4 @@ "use strict";

// Disabled by default
return false;
// Enabled by default
return true;
}

@@ -62,3 +62,3 @@ async function sendMuiXTelemetryEvent(event) {

'Content-Type': 'application/json',
'X-Telemetry-Client-Version': "9.0.0-alpha.0" ?? '<dev>',
'X-Telemetry-Client-Version': "9.0.0-alpha.2" ?? '<dev>',
'X-Telemetry-Node-Env': process.env.NODE_ENV ?? '<unknown>'

@@ -65,0 +65,0 @@ },

export interface TelemetryEventContext {
licenseKey?: string;
xLicenseClientVersion?: string;
}

@@ -4,0 +5,0 @@ export interface TelemetryEvent {

export interface TelemetryContextType {
config: {
isInitialized: boolean;
};
traits: Record<string, any> & {
machineId?: string | null;
fingerprint?: {
fullHash?: string | null;
coreHash?: string | null;
components?: Record<string, any> | null;
} | null;
projectId?: string | null;
anonymousId?: string | null;
sessionId?: string | null;
isDocker?: boolean;
isCI?: boolean;
};
}
declare const defaultValue: TelemetryContextType;
export default defaultValue;
// This file will be modified by the `postinstall` script.
// See postinstall/index.ts for more information.
const defaultValue = {
config: {
isInitialized: false
},
traits: {}
};
export default defaultValue;
import muiXTelemetryEvents from "./runtime/events.js";
import sendMuiXTelemetryEventOriginal from "./runtime/sender.js";
declare const sendMuiXTelemetryEvent: typeof sendMuiXTelemetryEventOriginal | (() => void);
declare const muiXTelemetrySettings: {
enableDebug: () => void;
enableTelemetry: () => void;
disableTelemetry: () => void;
};
export { muiXTelemetryEvents, sendMuiXTelemetryEvent, muiXTelemetrySettings };
/**
* @mui/x-telemetry v9.0.0-alpha.0
*
* @license SEE LICENSE IN LICENSE
* This source code is licensed under the SEE LICENSE IN LICENSE license found in the
* LICENSE file in the root directory of this source tree.
*/
import muiXTelemetryEvents from "./runtime/events.js";
import sendMuiXTelemetryEventOriginal from "./runtime/sender.js";
import muiXTelemetrySettingsOriginal from "./runtime/settings.js";
const noop = () => {};
// To cut unused imports in production as early as possible
const sendMuiXTelemetryEvent = process.env.NODE_ENV === 'production' ? noop : sendMuiXTelemetryEventOriginal;
// To cut unused imports in production as early as possible
const muiXTelemetrySettings = process.env.NODE_ENV === 'production' ? {
enableDebug: noop,
enableTelemetry: noop,
disableTelemetry: noop
} : muiXTelemetrySettingsOriginal;
export { muiXTelemetryEvents, sendMuiXTelemetryEvent, muiXTelemetrySettings };
{"type":"module","sideEffects":false}
interface EnvironmentInfo {
isDocker: boolean;
isCI: boolean;
}
export default function getEnvironmentInfo(): EnvironmentInfo;
export {};
import isDockerFunction from 'is-docker';
import ciEnvironment from 'ci-info';
let traits;
export default function getEnvironmentInfo() {
if (!traits) {
traits = {
isDocker: isDockerFunction(),
isCI: ciEnvironment.isCI
};
}
return traits;
}
export default function getAnonymousMachineId(): Promise<string | null>;
import { createHash } from 'crypto';
export default async function getAnonymousMachineId() {
try {
const nodeMachineId = await import('node-machine-id');
const rawMachineId = await nodeMachineId.machineId(true);
if (!rawMachineId) {
return null;
}
return createHash('sha256').update(rawMachineId).digest('hex');
} catch (_) {
// Ignore any errors
return null;
}
}
export default function getAnonymousProjectId(): Promise<string>;
import { exec } from 'child_process';
import { createHash } from 'crypto';
import util from 'util';
const asyncExec = util.promisify(exec);
async function execCLI(command) {
try {
const response = await asyncExec(command, {
timeout: 1000,
windowsHide: true
});
return String(response).trim();
} catch (_) {
return null;
}
}
// Q: Why does MUI need a project ID? Why is it looking at my git remote?
// A:
// MUI's telemetry always anonymizes these values. We need a way to
// differentiate different projects to track feature usage accurately.
// For example, to prevent a feature from appearing to be constantly `used`
// and then `unused` when switching between local projects.
async function getRawProjectId() {
return (await execCLI(`git config --local --get remote.origin.url`)) || process.env.REPOSITORY_URL || (await execCLI(`git rev-parse --show-toplevel`)) || process.cwd();
}
export default async function getAnonymousProjectId() {
const rawProjectId = await getRawProjectId();
return createHash('sha256').update(rawProjectId).digest('hex');
}
import _extends from "@babel/runtime/helpers/esm/extends";
import fs from 'fs';
import path from 'path';
import { randomBytes } from 'crypto';
import { fileURLToPath } from 'url';
import getEnvironmentInfo from "./get-environment-info.js";
import getAnonymousProjectId from "./get-project-id.js";
import getAnonymousMachineId from "./get-machine-id.js";
import { TelemetryStorage } from "./storage.js";
const dirname = typeof __dirname === 'string' ? __dirname // cjs build in root dir
: (() => {
const filename = fileURLToPath(import.meta.url);
// esm build in `esm` directory, so we need to go up two levels
return path.dirname(path.dirname(filename));
})();
(async () => {
// If Node.js support permissions, we need to check if the current user has
// the necessary permissions to write to the file system.
if (typeof process.permission !== 'undefined' && !(process.permission.has('fs.read') && process.permission.has('fs.write'))) {
return;
}
const storage = await TelemetryStorage.init({
distDir: process.cwd()
});
const [environmentInfo, projectId, machineId] = await Promise.all([getEnvironmentInfo(), getAnonymousProjectId(), getAnonymousMachineId()]);
const contextData = {
config: {
isInitialized: true
},
traits: _extends({}, environmentInfo, {
machineId,
projectId,
sessionId: randomBytes(32).toString('hex'),
anonymousId: storage.anonymousId
})
};
const writeContextData = (filePath, format) => {
const targetPath = path.resolve(dirname, '..', filePath, 'context.js');
fs.writeFileSync(targetPath, format(JSON.stringify(contextData, null, 2)));
};
writeContextData('esm', content => `export default ${content};`);
writeContextData('', content => [`"use strict";`, `Object.defineProperty(exports, "__esModule", { value: true });`, `exports.default = void 0;`, `var _default = exports.default = ${content};`].join('\n'));
})().catch(error => {
console.error('[telemetry] Failed to make initialization. Please, report error to MUI X team:\n' + 'https://mui.com/r/x-telemetry-postinstall-troubleshoot\n', error);
});
export default function notifyAboutMuiXTelemetry(): void;
export default function notifyAboutMuiXTelemetry() {
console.log(`[Attention]: MUI X now may collect completely anonymous telemetry regarding usage.`);
console.log(`This information is used to shape MUI's roadmap and prioritize features.`);
console.log(`You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:`);
console.log('https://mui.com/x/guides/telemetry');
console.log();
}
export declare class TelemetryStorage {
private readonly conf;
static init({
distDir
}: {
distDir: string;
}): Promise<TelemetryStorage>;
private constructor();
private notify;
get configPath(): string | undefined;
get anonymousId(): string;
}
import { randomBytes } from 'crypto';
import path from 'path';
import notifyAboutMuiXTelemetry from "./notify.js";
import getEnvironmentInfo from "./get-environment-info.js";
// 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`;
function getStorageDirectory(distDir) {
const env = getEnvironmentInfo();
const isLikelyEphemeral = env.isCI || env.isDocker;
if (isLikelyEphemeral) {
return path.join(distDir, 'cache');
}
return undefined;
}
export class TelemetryStorage {
static async init({
distDir
}) {
const storageDirectory = getStorageDirectory(distDir);
let conf = null;
try {
// `conf` incorrectly throws a permission error during initialization
// instead of waiting for first use. We need to handle it, otherwise the
// process may crash.
const {
default: Conf
} = await import('conf');
conf = new Conf({
projectName: 'mui-x',
cwd: storageDirectory
});
} catch (_) {
conf = null;
}
return new TelemetryStorage(conf);
}
constructor(conf) {
this.conf = conf;
this.notify();
}
notify = () => {
if (!this.conf) {
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.
if (this.conf.get(TELEMETRY_KEY_NOTIFY_DATE, '')) {
return;
}
this.conf.set(TELEMETRY_KEY_NOTIFY_DATE, Date.now().toString());
notifyAboutMuiXTelemetry();
};
get configPath() {
return this.conf?.path;
}
get anonymousId() {
const val = this.conf && this.conf.get(TELEMETRY_KEY_ID);
if (val) {
return val;
}
const generated = randomBytes(32).toString('hex');
this.conf?.set(TELEMETRY_KEY_ID, generated);
return generated;
}
}
interface TelemetryEnvConfig {
NODE_ENV: string | '<unknown>';
IS_COLLECTING: boolean | undefined;
DEBUG: boolean;
}
declare global {
var __MUI_X_TELEMETRY_DISABLED__: boolean | undefined;
}
export declare function getTelemetryEnvConfig(skipCache?: boolean): TelemetryEnvConfig;
export declare function getTelemetryEnvConfigValue<K extends keyof TelemetryEnvConfig>(key: K): TelemetryEnvConfig[K];
export declare function setTelemetryEnvConfigValue<K extends keyof TelemetryEnvConfig>(key: K, value: NonNullable<TelemetryEnvConfig[K]>): void;
export {};
const envEnabledValues = ['1', 'true', 'yes', 'y'];
const envDisabledValues = ['0', 'false', 'no', 'n'];
function getBooleanEnv(value) {
if (!value) {
return undefined;
}
if (envEnabledValues.includes(value)) {
return true;
}
if (envDisabledValues.includes(value)) {
return false;
}
return undefined;
}
function getBooleanEnvFromEnvObject(envKey, envObj) {
const keys = Object.keys(envObj);
for (let i = 0; i < keys.length; i += 1) {
const key = keys[i];
if (!key.endsWith(envKey)) {
continue;
}
const value = getBooleanEnv(envObj[key]?.toLowerCase());
if (typeof value === 'boolean') {
return value;
}
}
return undefined;
}
function getIsTelemetryCollecting() {
// Check global variable
// eslint-disable-next-line no-underscore-dangle
const globalValue = globalThis.__MUI_X_TELEMETRY_DISABLED__;
if (typeof globalValue === 'boolean') {
// If disabled=true, telemetry is disabled
// If disabled=false, telemetry is enabled
return !globalValue;
}
try {
if (typeof process !== 'undefined' && process.env && typeof process.env === 'object') {
const result = getBooleanEnvFromEnvObject('MUI_X_TELEMETRY_DISABLED', process.env);
if (typeof result === 'boolean') {
// If disabled=true, telemetry is disabled
// If disabled=false, telemetry is enabled
return !result;
}
}
} catch (_) {
// If there is an error, return the default value
}
try {
// Some build tools replace env variables on compilation
// e.g. Next.js, webpack EnvironmentPlugin
const envValue = process.env.MUI_X_TELEMETRY_DISABLED || process.env.NEXT_PUBLIC_MUI_X_TELEMETRY_DISABLED || process.env.GATSBY_MUI_X_TELEMETRY_DISABLED || process.env.REACT_APP_MUI_X_TELEMETRY_DISABLED || process.env.PUBLIC_MUI_X_TELEMETRY_DISABLED;
const result = getBooleanEnv(envValue);
if (typeof result === 'boolean') {
// If disabled=true, telemetry is disabled
// If disabled=false, telemetry is enabled
return !result;
}
} catch (_) {
// If there is an error, return the default value
}
return undefined;
}
function getIsDebugModeEnabled() {
try {
// Check global variable
// eslint-disable-next-line no-underscore-dangle
const globalValue = globalThis.__MUI_X_TELEMETRY_DEBUG__;
if (typeof globalValue === 'boolean') {
return globalValue;
}
if (typeof process !== 'undefined' && process.env && typeof process.env === 'object') {
const result = getBooleanEnvFromEnvObject('MUI_X_TELEMETRY_DEBUG', process.env);
if (typeof result === 'boolean') {
return result;
}
}
// e.g. Webpack EnvironmentPlugin
if (process.env.MUI_X_TELEMETRY_DEBUG) {
const result = getBooleanEnv(process.env.MUI_X_TELEMETRY_DEBUG);
if (typeof result === 'boolean') {
return result;
}
}
} catch (_) {
// If there is an error, return the default value
}
try {
// e.g. Next.js, webpack EnvironmentPlugin
const envValue = process.env.MUI_X_TELEMETRY_DEBUG || process.env.NEXT_PUBLIC_MUI_X_TELEMETRY_DEBUG || process.env.GATSBY_MUI_X_TELEMETRY_DEBUG || process.env.REACT_APP_MUI_X_TELEMETRY_DEBUG || process.env.PUBLIC_MUI_X_TELEMETRY_DEBUG;
const result = getBooleanEnv(envValue);
if (typeof result === 'boolean') {
return result;
}
} catch (_) {
// If there is an error, return the default value
}
return false;
}
function getNodeEnv() {
try {
return process.env.NODE_ENV ?? '<unknown>';
} catch (_) {
return '<unknown>';
}
}
let cachedEnv = null;
export function getTelemetryEnvConfig(skipCache = false) {
if (skipCache || !cachedEnv) {
cachedEnv = {
NODE_ENV: getNodeEnv(),
IS_COLLECTING: getIsTelemetryCollecting(),
DEBUG: getIsDebugModeEnabled()
};
}
return cachedEnv;
}
export function getTelemetryEnvConfigValue(key) {
return getTelemetryEnvConfig()[key];
}
export function setTelemetryEnvConfigValue(key, value) {
getTelemetryEnvConfig()[key] = value;
}
import { TelemetryEventContext } from "../types.js";
declare const muiXTelemetryEvents: {
licenseVerification: (() => null) | ((context: TelemetryEventContext, payload: {
packageReleaseInfo: string;
packageName: string;
licenseStatus?: string;
}) => {
eventName: string;
payload: {
packageReleaseInfo: string;
packageName: string;
licenseStatus?: string;
};
context: TelemetryEventContext;
});
};
export default muiXTelemetryEvents;
const noop = () => null;
const muiXTelemetryEvents = {
licenseVerification: process.env.NODE_ENV === 'production' ? noop : (context, payload) => ({
eventName: 'licenseVerification',
payload,
context
})
};
export default muiXTelemetryEvents;
declare function fetchWithRetry(url: string, options: RequestInit, retries?: number): Promise<Response>;
export { fetchWithRetry };
async function fetchWithRetry(url, options, retries = 3) {
try {
const response = await fetch(url, options);
if (response.ok) {
return response;
}
throw new Error(`Request failed with status ${response.status}`);
} catch (error) {
if (retries === 0) {
throw error;
}
return new Promise(resolve => {
setTimeout(() => {
resolve(fetchWithRetry(url, options, retries - 1));
}, Math.random() * 3_000);
});
}
}
export { fetchWithRetry };
import type { TelemetryContextType } from "../context.js";
declare function getTelemetryContext(): Promise<TelemetryContextType>;
export { TelemetryContextType };
export default getTelemetryContext;
import _extends from "@babel/runtime/helpers/esm/extends";
import telemetryContext from "../context.js";
import { getWindowStorageItem, setWindowStorageItem } from "./window-storage.js";
function generateId(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
function pick(obj, keys) {
return keys.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
}
const getBrowserFingerprint = typeof window === 'undefined' || process.env.NODE_ENV === 'test' ? () => undefined : async () => {
const fingerprintLCKey = 'fingerprint';
try {
const existingFingerprint = getWindowStorageItem('localStorage', fingerprintLCKey);
if (existingFingerprint) {
return JSON.parse(existingFingerprint);
}
const FingerprintJS = await import('@fingerprintjs/fingerprintjs');
const fp = await FingerprintJS.load({
monitoring: false
});
const fpResult = await fp.get();
const components = _extends({}, fpResult.components);
delete components.cookiesEnabled;
const fullHash = FingerprintJS.hashComponents(components);
const coreHash = FingerprintJS.hashComponents(_extends({}, pick(components, ['fonts', 'audio', 'languages', 'deviceMemory', 'timezone', 'sessionStorage', 'localStorage', 'indexedDB', 'openDatabase', 'platform', 'canvas', 'vendor', 'vendorFlavors', 'colorGamut', 'forcedColors', 'monochrome', 'contrast', 'reducedMotion', 'math', 'videoCard', 'architecture'])));
const result = {
fullHash,
coreHash
};
setWindowStorageItem('localStorage', fingerprintLCKey, JSON.stringify(result));
return result;
} catch (_) {
return null;
}
};
function getAnonymousId() {
const localStorageKey = 'anonymous_id';
const existingAnonymousId = getWindowStorageItem('localStorage', localStorageKey);
if (existingAnonymousId) {
return existingAnonymousId;
}
const generated = `anid_${generateId(32)}`;
if (setWindowStorageItem('localStorage', localStorageKey, generated)) {
return generated;
}
return '';
}
function getSessionId() {
const localStorageKey = 'session_id';
const existingSessionId = getWindowStorageItem('sessionStorage', localStorageKey);
if (existingSessionId) {
return existingSessionId;
}
const generated = `sesid_${generateId(32)}`;
if (setWindowStorageItem('sessionStorage', localStorageKey, generated)) {
return generated;
}
return `sestp_${generateId(32)}`;
}
async function getTelemetryContext() {
telemetryContext.traits.sessionId = getSessionId();
// Initialize the context if it hasn't been initialized yet
// (e.g. postinstall not run)
if (!telemetryContext.config.isInitialized) {
telemetryContext.traits.anonymousId = getAnonymousId();
telemetryContext.config.isInitialized = true;
}
if (!telemetryContext.traits.fingerprint) {
telemetryContext.traits.fingerprint = await getBrowserFingerprint();
}
return telemetryContext;
}
export default getTelemetryContext;
import { TelemetryEvent } from "../types.js";
declare function sendMuiXTelemetryEvent(event: TelemetryEvent | null): Promise<void>;
export default sendMuiXTelemetryEvent;
import _extends from "@babel/runtime/helpers/esm/extends";
import { getTelemetryEnvConfigValue } from "./config.js";
import { fetchWithRetry } from "./fetcher.js";
const sendMuiXTelemetryRetries = 3;
function shouldSendTelemetry(telemetryContext) {
// Disable reporting in SSR / Node.js
if (typeof window === 'undefined') {
return false;
}
// Priority to the config (e.g. in code, env)
const envIsCollecting = getTelemetryEnvConfigValue('IS_COLLECTING');
if (typeof envIsCollecting === 'boolean') {
return envIsCollecting;
}
// Disable collection of the telemetry in CI builds,
// as it not related to development process
if (telemetryContext.traits.isCI) {
return false;
}
// Disabled by default
return false;
}
async function sendMuiXTelemetryEvent(event) {
try {
// Disable collection of the telemetry
// in production environment
if (process.env.NODE_ENV === 'production') {
return;
}
const {
default: getTelemetryContext
} = await import("./get-context.js");
const telemetryContext = await getTelemetryContext();
if (!event || !shouldSendTelemetry(telemetryContext)) {
return;
}
const eventPayload = _extends({}, event, {
context: _extends({}, telemetryContext.traits, event.context)
});
if (getTelemetryEnvConfigValue('DEBUG')) {
console.log('[mui-x-telemetry] event', JSON.stringify(eventPayload, null, 2));
return;
}
// TODO: batch events and send them in a single request when there will be more
await fetchWithRetry('https://x-telemetry.mui.com/v2/telemetry/record', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Telemetry-Client-Version': "9.0.0-alpha.0" ?? '<dev>',
'X-Telemetry-Node-Env': process.env.NODE_ENV ?? '<unknown>'
},
body: JSON.stringify([eventPayload])
}, sendMuiXTelemetryRetries);
} catch (_) {
console.log('[mui-x-telemetry] error', _);
}
}
export default sendMuiXTelemetryEvent;
declare const muiXTelemetrySettings: {
enableDebug: () => void;
enableTelemetry: () => void;
disableTelemetry: () => void;
};
export default muiXTelemetrySettings;
import { setTelemetryEnvConfigValue } from "./config.js";
const muiXTelemetrySettings = {
enableDebug: () => {
setTelemetryEnvConfigValue('DEBUG', true);
},
enableTelemetry: () => {
setTelemetryEnvConfigValue('IS_COLLECTING', true);
},
disableTelemetry: () => {
setTelemetryEnvConfigValue('IS_COLLECTING', false);
}
};
export default muiXTelemetrySettings;
type WindowStorageType = 'localStorage' | 'sessionStorage';
export declare function setWindowStorageItem(type: WindowStorageType, key: string, value: string): boolean;
export declare function getWindowStorageItem(type: WindowStorageType, key: string): string | null;
export {};
const prefix = '__mui_x_telemetry_';
function getStorageKey(key) {
return prefix + btoa(key);
}
export function setWindowStorageItem(type, key, value) {
try {
if (typeof window !== 'undefined' && window[type]) {
window[type].setItem(getStorageKey(key), value);
return true;
}
} catch (_) {
// Storage is unavailable, skip it
}
return false;
}
export function getWindowStorageItem(type, key) {
try {
if (typeof window !== 'undefined' && window[type]) {
return window[type].getItem(getStorageKey(key));
}
} catch (_) {
// Storage is unavailable, skip it
}
return null;
}
export interface TelemetryEventContext {
licenseKey?: string;
}
export interface TelemetryEvent {
eventName: string;
payload: Record<string, any>;
context: TelemetryEventContext;
}
export {};
interface EnvironmentInfo {
isDocker: boolean;
isCI: boolean;
}
export default function getEnvironmentInfo(): EnvironmentInfo;
export {};
export default function getAnonymousMachineId(): Promise<string | null>;
export default function getAnonymousProjectId(): Promise<string>;
export default function notifyAboutMuiXTelemetry(): void;
export declare class TelemetryStorage {
private readonly conf;
static init({
distDir
}: {
distDir: string;
}): Promise<TelemetryStorage>;
private constructor();
private notify;
get configPath(): string | undefined;
get anonymousId(): string;
}

Sorry, the diff of this file is too big to display