Skip to main content
Glama
analytics.ts2.86 kB
import { Command } from "commander"; import dns from "dns"; import fs from "fs"; import { EventMessage, PostHog } from "posthog-node"; import { v4 as uuid } from "uuid"; import { getFullCommandPath } from "./commands/docs/outputJSON"; import { POSTHOG_API_KEY, POSTHOG_ENDPOINT, ZETACHAIN_CONFIG_FILE, ZETACHAIN_DIR, } from "./constants"; type Config = { uuid?: string; }; const getOrCreateUserUUID = (): string => { try { fs.mkdirSync(ZETACHAIN_DIR, { recursive: true }); } catch { // Silently continue - analytics will work without persistent config } let data: Config = {}; let needsWrite = false; if (fs.existsSync(ZETACHAIN_CONFIG_FILE)) { try { const raw = fs.readFileSync(ZETACHAIN_CONFIG_FILE, "utf8"); if (raw.trim()) data = JSON.parse(raw) as Config; } catch (err) { // Silently recreate config if corrupted data = {}; needsWrite = true; } } else { needsWrite = true; } if (!data || typeof data !== "object") { data = {}; needsWrite = true; } if (!data.uuid || typeof data.uuid !== "string" || data.uuid.length === 0) { data.uuid = uuid(); needsWrite = true; } if (needsWrite) { try { fs.writeFileSync( ZETACHAIN_CONFIG_FILE, JSON.stringify(data, null, 2), "utf8", ); } catch { // Silently continue - will generate new UUID next time } } return data.uuid as string; }; const canResolveHost = async ( hostname: string, timeout = 300, ): Promise<boolean> => { try { const resolve = dns.promises.lookup(hostname); const timeoutPromise = new Promise<never>((_, reject) => setTimeout(() => reject(new Error("dns-timeout")), timeout), ); await Promise.race([resolve, timeoutPromise]); return true; } catch (_err) { return false; } }; export const setupAnalytics = (program: Command) => { program.hook("preAction", async (_thisCommand, actionCommand) => { const opts = program.opts(); if (opts && opts.analytics === false) return; // Skip analytics if the PostHog host cannot be resolved (offline). const host = new URL(POSTHOG_ENDPOINT).hostname; const canResolve = await canResolveHost(host); if (!canResolve) return; let analytics: PostHog | null = null; try { analytics = new PostHog(POSTHOG_API_KEY, { host: POSTHOG_ENDPOINT, }); analytics.on("error", () => {}); const event: EventMessage = { distinctId: getOrCreateUserUUID(), event: "ZetaChain CLI command executed", properties: { command: getFullCommandPath(actionCommand), }, }; analytics.capture(event); await analytics.shutdown(); } catch { // Skip analytics errors (e.g. offline / network failures), to prevent CLI disruption } }); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ExpertVagabond/universal-blockchain'

If you have feedback or need assistance with the MCP directory API, please join our Discord server