All files / core telemetry.ts

87.5% Statements 28/32
100% Branches 4/4
75% Functions 3/4
86.2% Lines 25/29

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96      1x 1x 1x 1x   1x   1x 9x 9x 8x 7x   6x             6x                               5x       5x 5x           1x 5x 5x 4x 3x 3x 2x                                                             2x 2x 1x            
// Copyright 2026 ForgeKit Contributors
// SPDX-License-Identifier: Apache-2.0
// https://github.com/SubhanshuMG/ForgeKit
import * as https from 'https';
import inquirer from 'inquirer';
import chalk from 'chalk';
import { loadConfig, saveConfig, getUserId } from './config';
 
const VERSION = '0.4.0';
 
export function trackEvent(event: string, properties: Record<string, unknown>): void {
  try {
    const config = loadConfig();
    if (!config.telemetry) return;
    if (process.env.CI) return;
 
    const payload = JSON.stringify({
      name: event,
      url: `app://forgekit/${event}`,
      domain: 'forgekit.build',
      props: { ...properties, version: VERSION },
    });
 
    const req = https.request(
      {
        hostname: 'plausible.io',
        path: '/api/event',
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'User-Agent': `forgekit-cli/${VERSION}`,
          'Content-Length': Buffer.byteLength(payload),
        },
      },
      () => {
        // Response intentionally ignored (fire-and-forget)
      }
    );
 
    req.on('error', () => {
      // Silently ignore network errors
    });
 
    req.write(payload);
    req.end();
  } catch {
    // Never throw from telemetry
  }
}
 
export async function askTelemetryConsent(): Promise<void> {
  try {
    const config = loadConfig();
    if (!config.firstRun) return;
    if (!process.stdout.isTTY) {
      saveConfig({ ...config, firstRun: false });
      return;
    }
 
    // Ensure userId is generated on first run
    getUserId();
 
    console.log(
      chalk.dim(
        '\n  ForgeKit collects anonymous usage data to improve the tool.\n' +
        '  No personal information or project contents are ever sent.\n' +
        '  You can change this anytime with: forgekit telemetry enable/disable\n'
      )
    );
 
    const answer = await inquirer.prompt([
      {
        type: 'confirm',
        name: 'telemetry',
        message: 'Enable anonymous telemetry?',
        default: false,
      },
    ]);
 
    saveConfig({
      ...config,
      telemetry: answer.telemetry,
      firstRun: false,
      userId: getUserId(),
    });
  } catch {
    // Never block CLI startup due to telemetry
    try {
      const config = loadConfig();
      saveConfig({ ...config, firstRun: false });
    } catch {
      // Truly give up
    }
  }
}