123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.sendMetric = exports.telemetryAction = exports.THANK_YOU = void 0;
- const tslib_1 = require("tslib");
- const commander_1 = require("commander");
- const debug_1 = tslib_1.__importDefault(require("debug"));
- const colors_1 = tslib_1.__importDefault(require("./colors"));
- const ipc_1 = require("./ipc");
- const log_1 = require("./log");
- const sysconfig_1 = require("./sysconfig");
- const subprocess_1 = require("./util/subprocess");
- const term_1 = require("./util/term");
- const debug = (0, debug_1.default)('capacitor:telemetry');
- exports.THANK_YOU = `\nThank you for helping to make Capacitor better! 💖` +
- `\nInformation about the data we collect is available on our website: ${colors_1.default.strong('https://capacitorjs.com/telemetry')}\n`;
- function telemetryAction(config, action) {
- return async (...actionArgs) => {
- const start = new Date();
- // This is how commanderjs works--the command object is either the last
- // element or second to last if there are additional options (via `.allowUnknownOption()`)
- const lastArg = actionArgs[actionArgs.length - 1];
- const cmd = lastArg instanceof commander_1.Command ? lastArg : actionArgs[actionArgs.length - 2];
- const command = getFullCommandName(cmd);
- let error;
- try {
- await action(...actionArgs);
- }
- catch (e) {
- error = e;
- }
- const end = new Date();
- const duration = end.getTime() - start.getTime();
- const packages = Object.entries({
- ...config.app.package.devDependencies,
- ...config.app.package.dependencies,
- });
- // Only collect packages in the capacitor org:
- // https://www.npmjs.com/org/capacitor
- const capacitorPackages = packages.filter(([k]) => k.startsWith('@capacitor/'));
- const versions = capacitorPackages.map(([k, v]) => [
- `${k.replace(/^@capacitor\//, '').replace(/-/g, '_')}_version`,
- v,
- ]);
- const data = {
- app_id: await getAppIdentifier(config),
- command,
- arguments: cmd.args.join(' '),
- options: JSON.stringify(cmd.opts()),
- duration,
- error: error ? (error.message ? error.message : String(error)) : null,
- node_version: process.version,
- os: config.cli.os,
- ...Object.fromEntries(versions),
- };
- if ((0, term_1.isInteractive)()) {
- let sysconfig = await (0, sysconfig_1.readConfig)();
- if (!error && typeof sysconfig.telemetry === 'undefined') {
- const confirm = await promptForTelemetry();
- sysconfig = { ...sysconfig, telemetry: confirm };
- await (0, sysconfig_1.writeConfig)(sysconfig);
- }
- await sendMetric(sysconfig, 'capacitor_cli_command', data);
- }
- if (error) {
- throw error;
- }
- };
- }
- exports.telemetryAction = telemetryAction;
- /**
- * If telemetry is enabled, send a metric via IPC to a forked process for uploading.
- */
- async function sendMetric(sysconfig, name, data) {
- if (sysconfig.telemetry && (0, term_1.isInteractive)()) {
- const message = {
- name,
- timestamp: new Date().toISOString(),
- session_id: sysconfig.machine,
- source: 'capacitor_cli',
- value: data,
- };
- await (0, ipc_1.send)({ type: 'telemetry', data: message });
- }
- else {
- debug('Telemetry is off (user choice, non-interactive terminal, or CI)--not sending metric');
- }
- }
- exports.sendMetric = sendMetric;
- async function promptForTelemetry() {
- const { confirm } = await (0, log_1.logPrompt)(`${colors_1.default.strong('Would you like to help improve Capacitor by sharing anonymous usage data? 💖')}\n` +
- `Read more about what is being collected and why here: ${colors_1.default.strong('https://capacitorjs.com/telemetry')}. You can change your mind at any time by using the ${colors_1.default.input('npx cap telemetry')} command.`, {
- type: 'confirm',
- name: 'confirm',
- message: 'Share anonymous usage data?',
- initial: true,
- });
- if (confirm) {
- log_1.output.write(exports.THANK_YOU);
- }
- return confirm;
- }
- /**
- * Get a unique anonymous identifier for this app.
- */
- async function getAppIdentifier(config) {
- const { createHash } = await Promise.resolve().then(() => tslib_1.__importStar(require('crypto')));
- // get the first commit hash, which should be universally unique
- const output = await (0, subprocess_1.getCommandOutput)('git', ['rev-list', '--max-parents=0', 'HEAD'], { cwd: config.app.rootDir });
- const firstLine = output === null || output === void 0 ? void 0 : output.split('\n')[0];
- if (!firstLine) {
- debug('Could not obtain unique app identifier');
- return null;
- }
- // use sha1 to create a one-way hash to anonymize
- const id = createHash('sha1').update(firstLine).digest('hex');
- return id;
- }
- /**
- * Walk through the command's parent tree and construct a space-separated name.
- *
- * Probably overkill because we don't have nested commands, but whatever.
- */
- function getFullCommandName(cmd) {
- const names = [];
- while (cmd.parent !== null) {
- names.push(cmd.name());
- cmd = cmd.parent;
- }
- return names.reverse().join(' ');
- }
|