UNPKG

recoder-code

Version:

🚀 AI-powered development platform - Chat with 32+ models, build projects, automate workflows. Free models included!

367 lines • 14 kB
"use strict"; /** * Analytics Service - Handles tracking and analytics for packages */ Object.defineProperty(exports, "__esModule", { value: true }); exports.AnalyticsService = void 0; const Package_1 = require("../entities/Package"); const Download_1 = require("../entities/Download"); const User_1 = require("../entities/User"); const database_1 = require("../database"); class AnalyticsService { constructor() { this.logger = { info: (msg, ...args) => console.log(`[INFO] ${msg}`, ...args), error: (msg, ...args) => console.error(`[ERROR] ${msg}`, ...args), warn: (msg, ...args) => console.warn(`[WARN] ${msg}`, ...args) }; this.packageRepo = database_1.AppDataSource.getRepository(Package_1.Package); this.downloadRepo = database_1.AppDataSource.getRepository(Download_1.Download); this.userRepo = database_1.AppDataSource.getRepository(User_1.User); } async getGlobalAnalytics() { try { const [totalPackages, activePackages, deprecatedPackages, totalUsers, activeUsers, totalDownloads, popularPackages, trendingPackages, recentlyUpdated] = await Promise.all([ this.packageRepo.count(), this.packageRepo.count({ where: { status: Package_1.PackageStatus.ACTIVE } }), this.packageRepo.count({ where: { status: Package_1.PackageStatus.DEPRECATED } }), this.userRepo.count(), this.userRepo.count({ where: { is_active: true } }), this.getTotalDownloads(), this.getPopularPackages(10), this.getTrendingPackages(10), this.getRecentlyUpdatedPackages(10) ]); return { downloads: { total: totalDownloads, daily: await this.getDailyDownloads(), weekly: await this.getWeeklyDownloads(), monthly: await this.getMonthlyDownloads(), yearly: await this.getYearlyDownloads() }, packages: { total: totalPackages, active: activePackages, deprecated: deprecatedPackages }, users: { total: totalUsers, active: activeUsers }, trends: { popularPackages, trendingPackages, recentlyUpdated } }; } catch (error) { this.logger.error('Failed to get global analytics:', error); throw error; } } async getPackageAnalytics(packageName) { try { const pkg = await this.packageRepo.findOne({ where: { name: packageName }, relations: ['versions'] }); if (!pkg) { return null; } const [totalDownloads, dailyDownloads, weeklyDownloads, monthlyDownloads, dependentsCount, qualityScore] = await Promise.all([ this.getPackageDownloads(pkg.id), this.getPackageDailyDownloads(pkg.id), this.getPackageWeeklyDownloads(pkg.id), this.getPackageMonthlyDownloads(pkg.id), this.getPackageDependents(pkg.id), this.getPackageQualityScore(pkg.id) ]); const popularVersions = await this.getPopularVersions(pkg.id); return { packageId: pkg.id, packageName: pkg.name, downloads: { total: totalDownloads, daily: dailyDownloads, weekly: weeklyDownloads, monthly: monthlyDownloads }, versions: { total: pkg.versions.length, latest: pkg.latest_version || '', popular: popularVersions }, dependencies: { count: pkg.stats?.dependencies || 0, dependents: dependentsCount }, quality: { score: qualityScore, metrics: pkg.quality_metrics || {} } }; } catch (error) { this.logger.error(`Failed to get analytics for package ${packageName}:`, error); throw error; } } async recordDownload(packageId, version, userId, ip) { try { // Record download event const download = this.downloadRepo.create({ package_id: packageId, version_id: packageId, user_id: userId, ip_address: ip || 'unknown', user_agent: '', date: new Date(), date_only: new Date().toISOString().split('T')[0] }); await this.downloadRepo.save(download); // Update package download count await this.packageRepo.increment({ id: packageId }, 'download_count', 1); this.logger.info(`Recorded download: ${packageId}@${version}`); } catch (error) { this.logger.error('Failed to record download:', error); throw error; } } async getTotalDownloads() { const result = await this.downloadRepo.count(); return result; } async getDailyDownloads() { const today = new Date(); today.setHours(0, 0, 0, 0); return this.downloadRepo.createQueryBuilder('download') .where('download.date >= :today', { today }) .getCount(); } async getWeeklyDownloads() { const weekAgo = new Date(); weekAgo.setDate(weekAgo.getDate() - 7); return this.downloadRepo.createQueryBuilder('download') .where('download.date >= :weekAgo', { weekAgo }) .getCount(); } async getMonthlyDownloads() { const monthAgo = new Date(); monthAgo.setMonth(monthAgo.getMonth() - 1); return this.downloadRepo.createQueryBuilder('download') .where('download.date >= :monthAgo', { monthAgo }) .getCount(); } async getYearlyDownloads() { const yearAgo = new Date(); yearAgo.setFullYear(yearAgo.getFullYear() - 1); return this.downloadRepo.createQueryBuilder('download') .where('download.date >= :yearAgo', { yearAgo }) .getCount(); } async getPopularPackages(limit) { return this.packageRepo.find({ order: { download_count: 'DESC' }, take: limit, relations: ['owner'] }); } async getTrendingPackages(limit) { // Get packages with highest download growth in the last week return this.packageRepo.createQueryBuilder('package') .leftJoinAndSelect('package.owner', 'owner') .orderBy('package.download_count', 'DESC') .take(limit) .getMany(); } async getRecentlyUpdatedPackages(limit) { return this.packageRepo.find({ order: { updated_at: 'DESC' }, take: limit, relations: ['owner'] }); } async getPackageDownloads(packageId) { return this.downloadRepo.count({ where: { package_id: packageId } }); } async getPackageDailyDownloads(packageId) { // Implementation would aggregate downloads by day return {}; } async getPackageWeeklyDownloads(packageId) { // Implementation would aggregate downloads by week return {}; } async getPackageMonthlyDownloads(packageId) { // Implementation would aggregate downloads by month return {}; } async getPackageDependents(packageId) { // Implementation would count packages that depend on this package return 0; } async getPackageQualityScore(packageId) { const pkg = await this.packageRepo.findOne({ where: { id: packageId } }); if (!pkg?.quality_metrics) { return 0; } // Calculate overall quality score from metrics const metrics = pkg.quality_metrics; return ((metrics.code_quality || 0) + (metrics.documentation || 0) + (metrics.testing || 0) + (metrics.popularity || 0) + (metrics.maintenance || 0)) / 5; } async getPopularVersions(packageId) { // Implementation would aggregate downloads by version return []; } async updatePackageQuality(packageId, metrics) { try { await this.packageRepo.update(packageId, { quality_metrics: metrics }); this.logger.info(`Updated quality metrics for package ${packageId}`); } catch (error) { this.logger.error(`Failed to update quality metrics for package ${packageId}:`, error); throw error; } } async getDownloadTrends(packageId, period) { try { // Implementation would calculate download trends for the specified period return {}; } catch (error) { this.logger.error(`Failed to get download trends for package ${packageId}:`, error); throw error; } } async trackPackageView(packageId, userId) { try { // Track package view for analytics this.logger.info(`Package viewed: ${packageId} by user ${userId || 'anonymous'}`); // Implementation would: // - Record the view in analytics database // - Update view counts // - Track user engagement } catch (error) { this.logger.error(`Failed to track package view for ${packageId}:`, error); // Don't throw error for analytics failures } } async trackVersionView(packageId, version, userId) { try { // Track package version view for analytics this.logger.info(`Package version viewed: ${packageId}@${version} by user ${userId || 'anonymous'}`); // Implementation would: // - Record the version view in analytics database // - Update version-specific view counts // - Track version popularity } catch (error) { this.logger.error(`Failed to track version view for ${packageId}@${version}:`, error); // Don't throw error for analytics failures } } async trackDownload(packageId, version, userId) { try { // Track package download for analytics this.logger.info(`Package downloaded: ${packageId}@${version} by user ${userId || 'anonymous'}`); // Implementation would: // - Record the download in analytics database // - Update download counts // - Track download trends } catch (error) { this.logger.error(`Failed to track download for ${packageId}@${version}:`, error); // Don't throw error for analytics failures } } async getPackageStats(packageId) { try { const pkg = await this.packageRepo.findOne({ where: { id: packageId }, relations: ['versions'] }); if (!pkg) { return null; } return { packageId: pkg.id, packageName: pkg.name, downloads: { total: pkg.download_count || 0, daily: {}, weekly: {}, monthly: {} }, versions: { total: pkg.versions?.length || 0, latest: pkg.latest_version || '', popular: [] }, dependencies: { count: pkg.stats?.dependencies || 0, dependents: 0 }, quality: { score: await this.getPackageQualityScore(pkg.id), metrics: pkg.quality_metrics || {} } }; } catch (error) { this.logger.error(`Failed to get package stats for ${packageId}:`, error); return null; } } async getDownloadStats(packageId, period) { try { // Get download statistics for a package over a period const downloads = await this.downloadRepo.createQueryBuilder('download') .where('download.package_id = :packageId', { packageId }) .andWhere('download.date >= :startDate', { startDate: this.getStartDateForPeriod(period) }) .getCount(); return { packageId, period, downloads, breakdown: {} }; } catch (error) { this.logger.error(`Failed to get download stats for ${packageId}:`, error); return { packageId, period, downloads: 0, breakdown: {} }; } } getStartDateForPeriod(period) { const now = new Date(); switch (period) { case 'day': return new Date(now.getTime() - 24 * 60 * 60 * 1000); case 'week': return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); case 'month': return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); case 'year': return new Date(now.getTime() - 365 * 24 * 60 * 60 * 1000); default: return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); } } } exports.AnalyticsService = AnalyticsService; //# sourceMappingURL=AnalyticsService.js.map