Files
davila7__claude-code-templates/api/track-command-usage.js
T
Dani 7cb214e083 feat: Add command usage tracking system to Neon Database
This update adds comprehensive tracking of CLI command executions
to understand community usage patterns of the npm package.

**What's New:**
- Command usage logging in Neon Database with PostgreSQL
- Tracks: --chats, --analytics, --health-check, --plugins, --sandbox, and more
- API endpoint: /api/track-command-usage with validation
- Comprehensive test suite (18/18 tests passing)
- Fire-and-forget tracking (non-blocking, respects privacy)
- Auto-aggregated statistics with PostgreSQL triggers
- Useful views: daily usage, platform distribution, popular commands

**Technical Details:**
- Database: Neon PostgreSQL (separate from Supabase component downloads)
- Endpoint: https://www.aitmpl.com/api/track-command-usage
- Privacy: Respects CCT_NO_TRACKING environment variable
- Metadata: Includes tunnel usage, platform, Node version, etc.

**Files Changed:**
- api/track-command-usage.js - New endpoint for command tracking
- database/migrations/002_create_command_usage_logs.sql - Database schema
- cli-tool/src/tracking-service.js - Added trackCommandExecution()
- cli-tool/src/index.js - Integrated tracking for 10+ commands
- api/__tests__/endpoints.test.js - Added comprehensive tests

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-01 15:21:28 -04:00

147 lines
3.4 KiB
JavaScript

// Command Usage Tracking API Endpoint - Neon Database
// Tracks CLI command executions for community analytics
import { neon } from '@neondatabase/serverless';
// Initialize Neon client
function getNeonClient() {
const connectionString = process.env.NEON_DATABASE_URL;
if (!connectionString) {
throw new Error('NEON_DATABASE_URL not configured');
}
return neon(connectionString);
}
// Validate command data
function validateCommandData(data) {
const { command, cliVersion, nodeVersion, platform } = data;
if (!command) {
return { valid: false, error: 'Command name is required' };
}
// Valid commands to track
const validCommands = [
'chats',
'analytics',
'health-check',
'plugins',
'sandbox',
'agents',
'chats-mobile',
'studio',
'command-stats',
'hook-stats',
'mcp-stats'
];
if (!validCommands.includes(command)) {
return { valid: false, error: 'Invalid command name' };
}
if (command.length > 100) {
return { valid: false, error: 'Command name too long' };
}
return { valid: true };
}
// Get client information from request
function getClientInfo(req) {
const userAgent = req.headers['user-agent'] || '';
const ip = req.headers['x-forwarded-for']?.split(',')[0] ||
req.headers['x-real-ip'] ||
'unknown';
return { userAgent, ip };
}
// Main handler
export default async function handler(req, res) {
// CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, User-Agent');
// Handle preflight requests
if (req.method === 'OPTIONS') {
return res.status(200).json({ ok: true });
}
// Only accept POST requests
if (req.method !== 'POST') {
return res.status(405).json({
error: 'Method not allowed',
allowed: ['POST']
});
}
try {
// Extract and validate request body
const {
command,
cliVersion,
nodeVersion,
platform,
arch,
sessionId,
metadata
} = req.body;
const validation = validateCommandData({ command, cliVersion, nodeVersion, platform });
if (!validation.valid) {
return res.status(400).json({ error: validation.error });
}
// Get client information
const clientInfo = getClientInfo(req);
// Initialize Neon client
const sql = getNeonClient();
// Insert command log
await sql`
INSERT INTO command_usage_logs (
command_name,
cli_version,
node_version,
platform,
arch,
session_id,
metadata
) VALUES (
${command},
${cliVersion || 'unknown'},
${nodeVersion || 'unknown'},
${platform || 'unknown'},
${arch || 'unknown'},
${sessionId || null},
${metadata ? JSON.stringify(metadata) : null}
)
`;
// Return success response
res.status(200).json({
success: true,
message: 'Command execution tracked successfully',
data: {
command,
timestamp: new Date().toISOString()
}
});
} catch (error) {
console.error('Command tracking error:', error);
// Return error response
res.status(500).json({
error: 'Internal server error',
message: 'Failed to track command execution',
details: process.env.NODE_ENV === 'development' ? error.message : undefined
});
}
}