You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@power-seo/analytics

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@power-seo/analytics - npm Package Compare versions

Comparing version
1.0.0
to
1.0.1
+1
-1
dist/index.cjs.map

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/merge.ts","../src/trends.ts","../src/rankings.ts","../src/dashboard.ts"],"names":["normalizeUrl"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\r\n// @power-seo/analytics — Merge GSC + Audit Data\r\n// ============================================================================\r\n\r\nimport { normalizeUrl } from '@power-seo/core';\r\nimport type { GscPageData, PageInsight, AuditCategory, CategoryResult } from './types.js';\r\n\r\ninterface AuditData {\r\n url: string;\r\n score: number;\r\n categories: Record<AuditCategory, CategoryResult>;\r\n recommendations: string[];\r\n}\r\n\r\nexport function mergeGscWithAudit(\r\n gscData: GscPageData[],\r\n auditResults: AuditData[],\r\n): PageInsight[] {\r\n const auditMap = new Map<string, AuditData>();\r\n for (const result of auditResults) {\r\n auditMap.set(normalizeUrl(result.url), result);\r\n }\r\n\r\n const gscMap = new Map<string, GscPageData>();\r\n for (const page of gscData) {\r\n gscMap.set(normalizeUrl(page.url), page);\r\n }\r\n\r\n const allUrls = new Set([...auditMap.keys(), ...gscMap.keys()]);\r\n const insights: PageInsight[] = [];\r\n\r\n for (const url of allUrls) {\r\n const gsc = gscMap.get(url);\r\n const audit = auditMap.get(url);\r\n const opportunities: string[] = [];\r\n\r\n if (gsc && audit) {\r\n if (gsc.clicks > 50 && audit.score < 70) {\r\n opportunities.push(`High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`);\r\n }\r\n if (gsc.position > 10 && gsc.impressions > 100) {\r\n opportunities.push(`Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`);\r\n }\r\n if (audit.recommendations.length > 0) {\r\n opportunities.push(...audit.recommendations.slice(0, 3));\r\n }\r\n } else if (gsc && !audit) {\r\n opportunities.push('Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.');\r\n } else if (!gsc && audit) {\r\n if (audit.score < 50) {\r\n opportunities.push(`Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`);\r\n }\r\n }\r\n\r\n insights.push({\r\n url,\r\n gscMetrics: gsc ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position } : undefined,\r\n auditScore: audit?.score,\r\n auditCategories: audit?.categories,\r\n opportunities,\r\n });\r\n }\r\n\r\n return insights;\r\n}\r\n\r\nexport function correlateScoreAndTraffic(\r\n insights: PageInsight[],\r\n): { correlation: number; topOpportunities: PageInsight[] } {\r\n const paired = insights.filter((i) => i.gscMetrics && i.auditScore !== undefined);\r\n\r\n if (paired.length < 2) {\r\n return { correlation: 0, topOpportunities: [] };\r\n }\r\n\r\n const scores = paired.map((i) => i.auditScore!);\r\n const clicks = paired.map((i) => i.gscMetrics!.clicks);\r\n\r\n const n = scores.length;\r\n const meanScore = scores.reduce((a, b) => a + b, 0) / n;\r\n const meanClicks = clicks.reduce((a, b) => a + b, 0) / n;\r\n\r\n let numerator = 0;\r\n let denomScore = 0;\r\n let denomClicks = 0;\r\n\r\n for (let i = 0; i < n; i++) {\r\n const diffScore = (scores[i] ?? 0) - meanScore;\r\n const diffClicks = (clicks[i] ?? 0) - meanClicks;\r\n numerator += diffScore * diffClicks;\r\n denomScore += diffScore * diffScore;\r\n denomClicks += diffClicks * diffClicks;\r\n }\r\n\r\n const denominator = Math.sqrt(denomScore * denomClicks);\r\n const correlation = denominator === 0 ? 0 : numerator / denominator;\r\n\r\n // Top opportunities: high traffic, low score\r\n const topOpportunities = [...paired]\r\n .filter((i) => i.gscMetrics!.clicks > 0)\r\n .sort((a, b) => {\r\n const scoreA = (a.gscMetrics!.clicks / (a.auditScore! || 1));\r\n const scoreB = (b.gscMetrics!.clicks / (b.auditScore! || 1));\r\n return scoreB - scoreA;\r\n })\r\n .slice(0, 10);\r\n\r\n return { correlation: Math.round(correlation * 1000) / 1000, topOpportunities };\r\n}\r\n","// ============================================================================\r\n// @power-seo/analytics — Trend Analysis\r\n// ============================================================================\r\n\r\nimport type { TrendPoint, TrendDirection, TrendAnalysis, AuditSnapshot } from './types.js';\r\n\r\nexport function analyzeTrend(points: TrendPoint[], metric = 'value'): TrendAnalysis {\r\n if (points.length === 0) {\r\n return { metric, trend: 'stable', change: 0, points: [] };\r\n }\r\n\r\n if (points.length === 1) {\r\n return { metric, trend: 'stable', change: 0, points };\r\n }\r\n\r\n // Linear regression for slope\r\n const n = points.length;\r\n const xs = points.map((_, i) => i);\r\n const ys = points.map((p) => p.value);\r\n\r\n const meanX = xs.reduce((a, b) => a + b, 0) / n;\r\n const meanY = ys.reduce((a, b) => a + b, 0) / n;\r\n\r\n let numerator = 0;\r\n let denominator = 0;\r\n for (let i = 0; i < n; i++) {\r\n const xi = xs[i] ?? 0;\r\n const yi = ys[i] ?? 0;\r\n numerator += (xi - meanX) * (yi - meanY);\r\n denominator += (xi - meanX) * (xi - meanX);\r\n }\r\n\r\n const slope = denominator === 0 ? 0 : numerator / denominator;\r\n\r\n // Percentage change first→last\r\n const first = points[0]!.value;\r\n const last = points[points.length - 1]!.value;\r\n const change = first === 0 ? 0 : Math.round(((last - first) / Math.abs(first)) * 10000) / 100;\r\n\r\n // Classify trend based on slope relative to mean\r\n const threshold = Math.abs(meanY) * 0.02; // 2% of mean\r\n let trend: TrendDirection;\r\n if (slope > threshold) {\r\n trend = 'improving';\r\n } else if (slope < -threshold) {\r\n trend = 'declining';\r\n } else {\r\n trend = 'stable';\r\n }\r\n\r\n return { metric, trend, change, points };\r\n}\r\n\r\nexport function buildTrendLines(\r\n snapshots: AuditSnapshot[],\r\n): Record<string, TrendAnalysis> {\r\n if (snapshots.length === 0) {\r\n return {};\r\n }\r\n\r\n // Sort by date\r\n const sorted = [...snapshots].sort((a, b) => a.date.localeCompare(b.date));\r\n\r\n // Overall score trend\r\n const overallPoints: TrendPoint[] = sorted.map((s) => ({ date: s.date, value: s.score }));\r\n const result: Record<string, TrendAnalysis> = {\r\n overall: analyzeTrend(overallPoints, 'overall'),\r\n };\r\n\r\n // Per-category trends\r\n const categories = Object.keys(sorted[0]!.categories) as Array<keyof typeof sorted[0]['categories']>;\r\n for (const category of categories) {\r\n const categoryPoints: TrendPoint[] = sorted.map((s) => ({\r\n date: s.date,\r\n value: s.categories[category],\r\n }));\r\n result[category] = analyzeTrend(categoryPoints, category);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport function detectAnomalies(points: TrendPoint[], threshold = 2): TrendPoint[] {\r\n if (points.length < 3) {\r\n return [];\r\n }\r\n\r\n const values = points.map((p) => p.value);\r\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\r\n const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / values.length;\r\n const stdDev = Math.sqrt(variance);\r\n\r\n if (stdDev === 0) {\r\n return [];\r\n }\r\n\r\n return points.filter((p) => Math.abs(p.value - mean) > threshold * stdDev);\r\n}\r\n","// ============================================================================\r\n// @power-seo/analytics — Query Ranking Analysis\r\n// ============================================================================\r\n\r\nimport type { GscQueryData, RankingAnalysis, RankingBucket, PositionChange } from './types.js';\r\n\r\nconst BUCKET_RANGES = [\r\n { range: '1-3', min: 1, max: 3 },\r\n { range: '4-10', min: 4, max: 10 },\r\n { range: '11-20', min: 11, max: 20 },\r\n { range: '21-100', min: 21, max: 100 },\r\n];\r\n\r\nexport function analyzeQueryRankings(queries: GscQueryData[]): RankingAnalysis {\r\n if (queries.length === 0) {\r\n return { totalQueries: 0, buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })), strikingDistance: [] };\r\n }\r\n\r\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\r\n const matching = queries.filter(\r\n (q) => q.position >= range.min && q.position <= range.max,\r\n );\r\n return {\r\n range: range.range,\r\n count: matching.length,\r\n queries: matching,\r\n };\r\n });\r\n\r\n // Striking distance: position 4-20, sorted by impressions descending\r\n const strikingDistance = queries\r\n .filter((q) => q.position >= 4 && q.position <= 20)\r\n .sort((a, b) => b.impressions - a.impressions);\r\n\r\n return {\r\n totalQueries: queries.length,\r\n buckets,\r\n strikingDistance,\r\n };\r\n}\r\n\r\nexport function trackPositionChanges(\r\n current: GscQueryData[],\r\n previous: GscQueryData[],\r\n): PositionChange[] {\r\n if (current.length === 0 && previous.length === 0) {\r\n return [];\r\n }\r\n\r\n const prevMap = new Map<string, GscQueryData>();\r\n for (const q of previous) {\r\n prevMap.set(q.query, q);\r\n }\r\n\r\n const changes: PositionChange[] = [];\r\n\r\n for (const curr of current) {\r\n const prev = prevMap.get(curr.query);\r\n if (prev) {\r\n changes.push({\r\n query: curr.query,\r\n previousPosition: prev.position,\r\n currentPosition: curr.position,\r\n change: prev.position - curr.position, // positive = improvement\r\n impressionChange: curr.impressions - prev.impressions,\r\n });\r\n }\r\n }\r\n\r\n return changes;\r\n}\r\n","// ============================================================================\r\n// @power-seo/analytics — Dashboard Data Builder\r\n// ============================================================================\r\n\r\nimport type { DashboardInput, DashboardData, DashboardOverview } from './types.js';\r\nimport { buildTrendLines } from './trends.js';\r\n\r\nexport function buildDashboardData(input: DashboardInput): DashboardData {\r\n const { gscPages = [], gscQueries = [], auditResults = [], auditHistory = [] } = input;\r\n\r\n // Overview metrics\r\n const totalClicks = gscPages.reduce((sum, p) => sum + p.clicks, 0);\r\n const totalImpressions = gscPages.reduce((sum, p) => sum + p.impressions, 0);\r\n const averageCtr = gscPages.length > 0\r\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\r\n : 0;\r\n const averagePosition = gscPages.length > 0\r\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\r\n : 0;\r\n const averageAuditScore = auditResults.length > 0\r\n ? Math.round(auditResults.reduce((sum, r) => sum + r.score, 0) / auditResults.length)\r\n : 0;\r\n const totalPages = Math.max(gscPages.length, auditResults.length);\r\n\r\n const overview: DashboardOverview = {\r\n totalClicks,\r\n totalImpressions,\r\n averageCtr,\r\n averagePosition,\r\n averageAuditScore,\r\n totalPages,\r\n };\r\n\r\n // Top pages by clicks\r\n const topPages = [...gscPages].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\r\n\r\n // Top queries by clicks\r\n const topQueries = [...gscQueries].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\r\n\r\n // Trend lines from audit history\r\n const trendLines = buildTrendLines(auditHistory);\r\n\r\n // Collect issues from audit results\r\n const issues: string[] = [];\r\n for (const result of auditResults) {\r\n issues.push(...result.recommendations);\r\n }\r\n // Deduplicate and limit\r\n const uniqueIssues = [...new Set(issues)].slice(0, 20);\r\n\r\n return {\r\n overview,\r\n topPages,\r\n topQueries,\r\n trendLines,\r\n issues: uniqueIssues,\r\n };\r\n}\r\n"]}
{"version":3,"sources":["../src/merge.ts","../src/trends.ts","../src/rankings.ts","../src/dashboard.ts"],"names":["normalizeUrl"],"mappings":"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","file":"index.cjs","sourcesContent":["// ============================================================================\n// @power-seo/analytics — Merge GSC + Audit Data\n// ============================================================================\n\nimport { normalizeUrl } from '@power-seo/core';\nimport type { GscPageData, PageInsight, AuditCategory, CategoryResult } from './types.js';\n\ninterface AuditData {\n url: string;\n score: number;\n categories: Record<AuditCategory, CategoryResult>;\n recommendations: string[];\n}\n\nexport function mergeGscWithAudit(\n gscData: GscPageData[],\n auditResults: AuditData[],\n): PageInsight[] {\n const auditMap = new Map<string, AuditData>();\n for (const result of auditResults) {\n auditMap.set(normalizeUrl(result.url), result);\n }\n\n const gscMap = new Map<string, GscPageData>();\n for (const page of gscData) {\n gscMap.set(normalizeUrl(page.url), page);\n }\n\n const allUrls = new Set([...auditMap.keys(), ...gscMap.keys()]);\n const insights: PageInsight[] = [];\n\n for (const url of allUrls) {\n const gsc = gscMap.get(url);\n const audit = auditMap.get(url);\n const opportunities: string[] = [];\n\n if (gsc && audit) {\n if (gsc.clicks > 50 && audit.score < 70) {\n opportunities.push(`High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`);\n }\n if (gsc.position > 10 && gsc.impressions > 100) {\n opportunities.push(`Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`);\n }\n if (audit.recommendations.length > 0) {\n opportunities.push(...audit.recommendations.slice(0, 3));\n }\n } else if (gsc && !audit) {\n opportunities.push('Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.');\n } else if (!gsc && audit) {\n if (audit.score < 50) {\n opportunities.push(`Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`);\n }\n }\n\n insights.push({\n url,\n gscMetrics: gsc ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position } : undefined,\n auditScore: audit?.score,\n auditCategories: audit?.categories,\n opportunities,\n });\n }\n\n return insights;\n}\n\nexport function correlateScoreAndTraffic(\n insights: PageInsight[],\n): { correlation: number; topOpportunities: PageInsight[] } {\n const paired = insights.filter((i) => i.gscMetrics && i.auditScore !== undefined);\n\n if (paired.length < 2) {\n return { correlation: 0, topOpportunities: [] };\n }\n\n const scores = paired.map((i) => i.auditScore!);\n const clicks = paired.map((i) => i.gscMetrics!.clicks);\n\n const n = scores.length;\n const meanScore = scores.reduce((a, b) => a + b, 0) / n;\n const meanClicks = clicks.reduce((a, b) => a + b, 0) / n;\n\n let numerator = 0;\n let denomScore = 0;\n let denomClicks = 0;\n\n for (let i = 0; i < n; i++) {\n const diffScore = (scores[i] ?? 0) - meanScore;\n const diffClicks = (clicks[i] ?? 0) - meanClicks;\n numerator += diffScore * diffClicks;\n denomScore += diffScore * diffScore;\n denomClicks += diffClicks * diffClicks;\n }\n\n const denominator = Math.sqrt(denomScore * denomClicks);\n const correlation = denominator === 0 ? 0 : numerator / denominator;\n\n // Top opportunities: high traffic, low score\n const topOpportunities = [...paired]\n .filter((i) => i.gscMetrics!.clicks > 0)\n .sort((a, b) => {\n const scoreA = (a.gscMetrics!.clicks / (a.auditScore! || 1));\n const scoreB = (b.gscMetrics!.clicks / (b.auditScore! || 1));\n return scoreB - scoreA;\n })\n .slice(0, 10);\n\n return { correlation: Math.round(correlation * 1000) / 1000, topOpportunities };\n}\n","// ============================================================================\n// @power-seo/analytics — Trend Analysis\n// ============================================================================\n\nimport type { TrendPoint, TrendDirection, TrendAnalysis, AuditSnapshot } from './types.js';\n\nexport function analyzeTrend(points: TrendPoint[], metric = 'value'): TrendAnalysis {\n if (points.length === 0) {\n return { metric, trend: 'stable', change: 0, points: [] };\n }\n\n if (points.length === 1) {\n return { metric, trend: 'stable', change: 0, points };\n }\n\n // Linear regression for slope\n const n = points.length;\n const xs = points.map((_, i) => i);\n const ys = points.map((p) => p.value);\n\n const meanX = xs.reduce((a, b) => a + b, 0) / n;\n const meanY = ys.reduce((a, b) => a + b, 0) / n;\n\n let numerator = 0;\n let denominator = 0;\n for (let i = 0; i < n; i++) {\n const xi = xs[i] ?? 0;\n const yi = ys[i] ?? 0;\n numerator += (xi - meanX) * (yi - meanY);\n denominator += (xi - meanX) * (xi - meanX);\n }\n\n const slope = denominator === 0 ? 0 : numerator / denominator;\n\n // Percentage change first→last\n const first = points[0]!.value;\n const last = points[points.length - 1]!.value;\n const change = first === 0 ? 0 : Math.round(((last - first) / Math.abs(first)) * 10000) / 100;\n\n // Classify trend based on slope relative to mean\n const threshold = Math.abs(meanY) * 0.02; // 2% of mean\n let trend: TrendDirection;\n if (slope > threshold) {\n trend = 'improving';\n } else if (slope < -threshold) {\n trend = 'declining';\n } else {\n trend = 'stable';\n }\n\n return { metric, trend, change, points };\n}\n\nexport function buildTrendLines(\n snapshots: AuditSnapshot[],\n): Record<string, TrendAnalysis> {\n if (snapshots.length === 0) {\n return {};\n }\n\n // Sort by date\n const sorted = [...snapshots].sort((a, b) => a.date.localeCompare(b.date));\n\n // Overall score trend\n const overallPoints: TrendPoint[] = sorted.map((s) => ({ date: s.date, value: s.score }));\n const result: Record<string, TrendAnalysis> = {\n overall: analyzeTrend(overallPoints, 'overall'),\n };\n\n // Per-category trends\n const categories = Object.keys(sorted[0]!.categories) as Array<keyof typeof sorted[0]['categories']>;\n for (const category of categories) {\n const categoryPoints: TrendPoint[] = sorted.map((s) => ({\n date: s.date,\n value: s.categories[category],\n }));\n result[category] = analyzeTrend(categoryPoints, category);\n }\n\n return result;\n}\n\nexport function detectAnomalies(points: TrendPoint[], threshold = 2): TrendPoint[] {\n if (points.length < 3) {\n return [];\n }\n\n const values = points.map((p) => p.value);\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / values.length;\n const stdDev = Math.sqrt(variance);\n\n if (stdDev === 0) {\n return [];\n }\n\n return points.filter((p) => Math.abs(p.value - mean) > threshold * stdDev);\n}\n","// ============================================================================\n// @power-seo/analytics — Query Ranking Analysis\n// ============================================================================\n\nimport type { GscQueryData, RankingAnalysis, RankingBucket, PositionChange } from './types.js';\n\nconst BUCKET_RANGES = [\n { range: '1-3', min: 1, max: 3 },\n { range: '4-10', min: 4, max: 10 },\n { range: '11-20', min: 11, max: 20 },\n { range: '21-100', min: 21, max: 100 },\n];\n\nexport function analyzeQueryRankings(queries: GscQueryData[]): RankingAnalysis {\n if (queries.length === 0) {\n return { totalQueries: 0, buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })), strikingDistance: [] };\n }\n\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\n const matching = queries.filter(\n (q) => q.position >= range.min && q.position <= range.max,\n );\n return {\n range: range.range,\n count: matching.length,\n queries: matching,\n };\n });\n\n // Striking distance: position 4-20, sorted by impressions descending\n const strikingDistance = queries\n .filter((q) => q.position >= 4 && q.position <= 20)\n .sort((a, b) => b.impressions - a.impressions);\n\n return {\n totalQueries: queries.length,\n buckets,\n strikingDistance,\n };\n}\n\nexport function trackPositionChanges(\n current: GscQueryData[],\n previous: GscQueryData[],\n): PositionChange[] {\n if (current.length === 0 && previous.length === 0) {\n return [];\n }\n\n const prevMap = new Map<string, GscQueryData>();\n for (const q of previous) {\n prevMap.set(q.query, q);\n }\n\n const changes: PositionChange[] = [];\n\n for (const curr of current) {\n const prev = prevMap.get(curr.query);\n if (prev) {\n changes.push({\n query: curr.query,\n previousPosition: prev.position,\n currentPosition: curr.position,\n change: prev.position - curr.position, // positive = improvement\n impressionChange: curr.impressions - prev.impressions,\n });\n }\n }\n\n return changes;\n}\n","// ============================================================================\n// @power-seo/analytics — Dashboard Data Builder\n// ============================================================================\n\nimport type { DashboardInput, DashboardData, DashboardOverview } from './types.js';\nimport { buildTrendLines } from './trends.js';\n\nexport function buildDashboardData(input: DashboardInput): DashboardData {\n const { gscPages = [], gscQueries = [], auditResults = [], auditHistory = [] } = input;\n\n // Overview metrics\n const totalClicks = gscPages.reduce((sum, p) => sum + p.clicks, 0);\n const totalImpressions = gscPages.reduce((sum, p) => sum + p.impressions, 0);\n const averageCtr = gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\n : 0;\n const averagePosition = gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\n : 0;\n const averageAuditScore = auditResults.length > 0\n ? Math.round(auditResults.reduce((sum, r) => sum + r.score, 0) / auditResults.length)\n : 0;\n const totalPages = Math.max(gscPages.length, auditResults.length);\n\n const overview: DashboardOverview = {\n totalClicks,\n totalImpressions,\n averageCtr,\n averagePosition,\n averageAuditScore,\n totalPages,\n };\n\n // Top pages by clicks\n const topPages = [...gscPages].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\n\n // Top queries by clicks\n const topQueries = [...gscQueries].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\n\n // Trend lines from audit history\n const trendLines = buildTrendLines(auditHistory);\n\n // Collect issues from audit results\n const issues: string[] = [];\n for (const result of auditResults) {\n issues.push(...result.recommendations);\n }\n // Deduplicate and limit\n const uniqueIssues = [...new Set(issues)].slice(0, 20);\n\n return {\n overview,\n topPages,\n topQueries,\n trendLines,\n issues: uniqueIssues,\n };\n}\n"]}

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/merge.ts","../src/trends.ts","../src/rankings.ts","../src/dashboard.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ============================================================================\r\n// @power-seo/analytics — Merge GSC + Audit Data\r\n// ============================================================================\r\n\r\nimport { normalizeUrl } from '@power-seo/core';\r\nimport type { GscPageData, PageInsight, AuditCategory, CategoryResult } from './types.js';\r\n\r\ninterface AuditData {\r\n url: string;\r\n score: number;\r\n categories: Record<AuditCategory, CategoryResult>;\r\n recommendations: string[];\r\n}\r\n\r\nexport function mergeGscWithAudit(\r\n gscData: GscPageData[],\r\n auditResults: AuditData[],\r\n): PageInsight[] {\r\n const auditMap = new Map<string, AuditData>();\r\n for (const result of auditResults) {\r\n auditMap.set(normalizeUrl(result.url), result);\r\n }\r\n\r\n const gscMap = new Map<string, GscPageData>();\r\n for (const page of gscData) {\r\n gscMap.set(normalizeUrl(page.url), page);\r\n }\r\n\r\n const allUrls = new Set([...auditMap.keys(), ...gscMap.keys()]);\r\n const insights: PageInsight[] = [];\r\n\r\n for (const url of allUrls) {\r\n const gsc = gscMap.get(url);\r\n const audit = auditMap.get(url);\r\n const opportunities: string[] = [];\r\n\r\n if (gsc && audit) {\r\n if (gsc.clicks > 50 && audit.score < 70) {\r\n opportunities.push(`High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`);\r\n }\r\n if (gsc.position > 10 && gsc.impressions > 100) {\r\n opportunities.push(`Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`);\r\n }\r\n if (audit.recommendations.length > 0) {\r\n opportunities.push(...audit.recommendations.slice(0, 3));\r\n }\r\n } else if (gsc && !audit) {\r\n opportunities.push('Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.');\r\n } else if (!gsc && audit) {\r\n if (audit.score < 50) {\r\n opportunities.push(`Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`);\r\n }\r\n }\r\n\r\n insights.push({\r\n url,\r\n gscMetrics: gsc ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position } : undefined,\r\n auditScore: audit?.score,\r\n auditCategories: audit?.categories,\r\n opportunities,\r\n });\r\n }\r\n\r\n return insights;\r\n}\r\n\r\nexport function correlateScoreAndTraffic(\r\n insights: PageInsight[],\r\n): { correlation: number; topOpportunities: PageInsight[] } {\r\n const paired = insights.filter((i) => i.gscMetrics && i.auditScore !== undefined);\r\n\r\n if (paired.length < 2) {\r\n return { correlation: 0, topOpportunities: [] };\r\n }\r\n\r\n const scores = paired.map((i) => i.auditScore!);\r\n const clicks = paired.map((i) => i.gscMetrics!.clicks);\r\n\r\n const n = scores.length;\r\n const meanScore = scores.reduce((a, b) => a + b, 0) / n;\r\n const meanClicks = clicks.reduce((a, b) => a + b, 0) / n;\r\n\r\n let numerator = 0;\r\n let denomScore = 0;\r\n let denomClicks = 0;\r\n\r\n for (let i = 0; i < n; i++) {\r\n const diffScore = (scores[i] ?? 0) - meanScore;\r\n const diffClicks = (clicks[i] ?? 0) - meanClicks;\r\n numerator += diffScore * diffClicks;\r\n denomScore += diffScore * diffScore;\r\n denomClicks += diffClicks * diffClicks;\r\n }\r\n\r\n const denominator = Math.sqrt(denomScore * denomClicks);\r\n const correlation = denominator === 0 ? 0 : numerator / denominator;\r\n\r\n // Top opportunities: high traffic, low score\r\n const topOpportunities = [...paired]\r\n .filter((i) => i.gscMetrics!.clicks > 0)\r\n .sort((a, b) => {\r\n const scoreA = (a.gscMetrics!.clicks / (a.auditScore! || 1));\r\n const scoreB = (b.gscMetrics!.clicks / (b.auditScore! || 1));\r\n return scoreB - scoreA;\r\n })\r\n .slice(0, 10);\r\n\r\n return { correlation: Math.round(correlation * 1000) / 1000, topOpportunities };\r\n}\r\n","// ============================================================================\r\n// @power-seo/analytics — Trend Analysis\r\n// ============================================================================\r\n\r\nimport type { TrendPoint, TrendDirection, TrendAnalysis, AuditSnapshot } from './types.js';\r\n\r\nexport function analyzeTrend(points: TrendPoint[], metric = 'value'): TrendAnalysis {\r\n if (points.length === 0) {\r\n return { metric, trend: 'stable', change: 0, points: [] };\r\n }\r\n\r\n if (points.length === 1) {\r\n return { metric, trend: 'stable', change: 0, points };\r\n }\r\n\r\n // Linear regression for slope\r\n const n = points.length;\r\n const xs = points.map((_, i) => i);\r\n const ys = points.map((p) => p.value);\r\n\r\n const meanX = xs.reduce((a, b) => a + b, 0) / n;\r\n const meanY = ys.reduce((a, b) => a + b, 0) / n;\r\n\r\n let numerator = 0;\r\n let denominator = 0;\r\n for (let i = 0; i < n; i++) {\r\n const xi = xs[i] ?? 0;\r\n const yi = ys[i] ?? 0;\r\n numerator += (xi - meanX) * (yi - meanY);\r\n denominator += (xi - meanX) * (xi - meanX);\r\n }\r\n\r\n const slope = denominator === 0 ? 0 : numerator / denominator;\r\n\r\n // Percentage change first→last\r\n const first = points[0]!.value;\r\n const last = points[points.length - 1]!.value;\r\n const change = first === 0 ? 0 : Math.round(((last - first) / Math.abs(first)) * 10000) / 100;\r\n\r\n // Classify trend based on slope relative to mean\r\n const threshold = Math.abs(meanY) * 0.02; // 2% of mean\r\n let trend: TrendDirection;\r\n if (slope > threshold) {\r\n trend = 'improving';\r\n } else if (slope < -threshold) {\r\n trend = 'declining';\r\n } else {\r\n trend = 'stable';\r\n }\r\n\r\n return { metric, trend, change, points };\r\n}\r\n\r\nexport function buildTrendLines(\r\n snapshots: AuditSnapshot[],\r\n): Record<string, TrendAnalysis> {\r\n if (snapshots.length === 0) {\r\n return {};\r\n }\r\n\r\n // Sort by date\r\n const sorted = [...snapshots].sort((a, b) => a.date.localeCompare(b.date));\r\n\r\n // Overall score trend\r\n const overallPoints: TrendPoint[] = sorted.map((s) => ({ date: s.date, value: s.score }));\r\n const result: Record<string, TrendAnalysis> = {\r\n overall: analyzeTrend(overallPoints, 'overall'),\r\n };\r\n\r\n // Per-category trends\r\n const categories = Object.keys(sorted[0]!.categories) as Array<keyof typeof sorted[0]['categories']>;\r\n for (const category of categories) {\r\n const categoryPoints: TrendPoint[] = sorted.map((s) => ({\r\n date: s.date,\r\n value: s.categories[category],\r\n }));\r\n result[category] = analyzeTrend(categoryPoints, category);\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport function detectAnomalies(points: TrendPoint[], threshold = 2): TrendPoint[] {\r\n if (points.length < 3) {\r\n return [];\r\n }\r\n\r\n const values = points.map((p) => p.value);\r\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\r\n const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / values.length;\r\n const stdDev = Math.sqrt(variance);\r\n\r\n if (stdDev === 0) {\r\n return [];\r\n }\r\n\r\n return points.filter((p) => Math.abs(p.value - mean) > threshold * stdDev);\r\n}\r\n","// ============================================================================\r\n// @power-seo/analytics — Query Ranking Analysis\r\n// ============================================================================\r\n\r\nimport type { GscQueryData, RankingAnalysis, RankingBucket, PositionChange } from './types.js';\r\n\r\nconst BUCKET_RANGES = [\r\n { range: '1-3', min: 1, max: 3 },\r\n { range: '4-10', min: 4, max: 10 },\r\n { range: '11-20', min: 11, max: 20 },\r\n { range: '21-100', min: 21, max: 100 },\r\n];\r\n\r\nexport function analyzeQueryRankings(queries: GscQueryData[]): RankingAnalysis {\r\n if (queries.length === 0) {\r\n return { totalQueries: 0, buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })), strikingDistance: [] };\r\n }\r\n\r\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\r\n const matching = queries.filter(\r\n (q) => q.position >= range.min && q.position <= range.max,\r\n );\r\n return {\r\n range: range.range,\r\n count: matching.length,\r\n queries: matching,\r\n };\r\n });\r\n\r\n // Striking distance: position 4-20, sorted by impressions descending\r\n const strikingDistance = queries\r\n .filter((q) => q.position >= 4 && q.position <= 20)\r\n .sort((a, b) => b.impressions - a.impressions);\r\n\r\n return {\r\n totalQueries: queries.length,\r\n buckets,\r\n strikingDistance,\r\n };\r\n}\r\n\r\nexport function trackPositionChanges(\r\n current: GscQueryData[],\r\n previous: GscQueryData[],\r\n): PositionChange[] {\r\n if (current.length === 0 && previous.length === 0) {\r\n return [];\r\n }\r\n\r\n const prevMap = new Map<string, GscQueryData>();\r\n for (const q of previous) {\r\n prevMap.set(q.query, q);\r\n }\r\n\r\n const changes: PositionChange[] = [];\r\n\r\n for (const curr of current) {\r\n const prev = prevMap.get(curr.query);\r\n if (prev) {\r\n changes.push({\r\n query: curr.query,\r\n previousPosition: prev.position,\r\n currentPosition: curr.position,\r\n change: prev.position - curr.position, // positive = improvement\r\n impressionChange: curr.impressions - prev.impressions,\r\n });\r\n }\r\n }\r\n\r\n return changes;\r\n}\r\n","// ============================================================================\r\n// @power-seo/analytics — Dashboard Data Builder\r\n// ============================================================================\r\n\r\nimport type { DashboardInput, DashboardData, DashboardOverview } from './types.js';\r\nimport { buildTrendLines } from './trends.js';\r\n\r\nexport function buildDashboardData(input: DashboardInput): DashboardData {\r\n const { gscPages = [], gscQueries = [], auditResults = [], auditHistory = [] } = input;\r\n\r\n // Overview metrics\r\n const totalClicks = gscPages.reduce((sum, p) => sum + p.clicks, 0);\r\n const totalImpressions = gscPages.reduce((sum, p) => sum + p.impressions, 0);\r\n const averageCtr = gscPages.length > 0\r\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\r\n : 0;\r\n const averagePosition = gscPages.length > 0\r\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\r\n : 0;\r\n const averageAuditScore = auditResults.length > 0\r\n ? Math.round(auditResults.reduce((sum, r) => sum + r.score, 0) / auditResults.length)\r\n : 0;\r\n const totalPages = Math.max(gscPages.length, auditResults.length);\r\n\r\n const overview: DashboardOverview = {\r\n totalClicks,\r\n totalImpressions,\r\n averageCtr,\r\n averagePosition,\r\n averageAuditScore,\r\n totalPages,\r\n };\r\n\r\n // Top pages by clicks\r\n const topPages = [...gscPages].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\r\n\r\n // Top queries by clicks\r\n const topQueries = [...gscQueries].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\r\n\r\n // Trend lines from audit history\r\n const trendLines = buildTrendLines(auditHistory);\r\n\r\n // Collect issues from audit results\r\n const issues: string[] = [];\r\n for (const result of auditResults) {\r\n issues.push(...result.recommendations);\r\n }\r\n // Deduplicate and limit\r\n const uniqueIssues = [...new Set(issues)].slice(0, 20);\r\n\r\n return {\r\n overview,\r\n topPages,\r\n topQueries,\r\n trendLines,\r\n issues: uniqueIssues,\r\n };\r\n}\r\n"]}
{"version":3,"sources":["../src/merge.ts","../src/trends.ts","../src/rankings.ts","../src/dashboard.ts"],"names":[],"mappings":";;;AAcO,SAAS,iBAAA,CACd,SACA,YAAA,EACe;AACf,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAuB;AAC5C,EAAA,KAAA,MAAW,UAAU,YAAA,EAAc;AACjC,IAAA,QAAA,CAAS,GAAA,CAAI,YAAA,CAAa,MAAA,CAAO,GAAG,GAAG,MAAM,CAAA;AAAA,EAC/C;AAEA,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAyB;AAC5C,EAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,IAAA,MAAA,CAAO,GAAA,CAAI,YAAA,CAAa,IAAA,CAAK,GAAG,GAAG,IAAI,CAAA;AAAA,EACzC;AAEA,EAAA,MAAM,OAAA,mBAAU,IAAI,GAAA,CAAI,CAAC,GAAG,QAAA,CAAS,IAAA,EAAK,EAAG,GAAG,MAAA,CAAO,IAAA,EAAM,CAAC,CAAA;AAC9D,EAAA,MAAM,WAA0B,EAAC;AAEjC,EAAA,KAAA,MAAW,OAAO,OAAA,EAAS;AACzB,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,GAAA,CAAI,GAAG,CAAA;AAC9B,IAAA,MAAM,gBAA0B,EAAC;AAEjC,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,IAAI,GAAA,CAAI,MAAA,GAAS,EAAA,IAAM,KAAA,CAAM,QAAQ,EAAA,EAAI;AACvC,QAAA,aAAA,CAAc,KAAK,CAAA,mBAAA,EAAsB,GAAA,CAAI,MAAM,CAAA,+BAAA,EAAkC,KAAA,CAAM,KAAK,CAAA,+DAAA,CAAiE,CAAA;AAAA,MACnK;AACA,MAAA,IAAI,GAAA,CAAI,QAAA,GAAW,EAAA,IAAM,GAAA,CAAI,cAAc,GAAA,EAAK;AAC9C,QAAA,aAAA,CAAc,IAAA,CAAK,CAAA,SAAA,EAAY,GAAA,CAAI,WAAW,CAAA,yBAAA,EAA4B,IAAI,QAAA,CAAS,OAAA,CAAQ,CAAC,CAAC,CAAA,uDAAA,CAAyD,CAAA;AAAA,MAC5J;AACA,MAAA,IAAI,KAAA,CAAM,eAAA,CAAgB,MAAA,GAAS,CAAA,EAAG;AACpC,QAAA,aAAA,CAAc,KAAK,GAAG,KAAA,CAAM,gBAAgB,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,MACzD;AAAA,IACF,CAAA,MAAA,IAAW,GAAA,IAAO,CAAC,KAAA,EAAO;AACxB,MAAA,aAAA,CAAc,KAAK,4GAA4G,CAAA;AAAA,IACjI,CAAA,MAAA,IAAW,CAAC,GAAA,IAAO,KAAA,EAAO;AACxB,MAAA,IAAI,KAAA,CAAM,QAAQ,EAAA,EAAI;AACpB,QAAA,aAAA,CAAc,IAAA,CAAK,CAAA,4BAAA,EAA+B,KAAA,CAAM,KAAK,CAAA,iEAAA,CAAmE,CAAA;AAAA,MAClI;AAAA,IACF;AAEA,IAAA,QAAA,CAAS,IAAA,CAAK;AAAA,MACZ,GAAA;AAAA,MACA,UAAA,EAAY,GAAA,GAAM,EAAE,MAAA,EAAQ,IAAI,MAAA,EAAQ,WAAA,EAAa,GAAA,CAAI,WAAA,EAAa,KAAK,GAAA,CAAI,GAAA,EAAK,QAAA,EAAU,GAAA,CAAI,UAAS,GAAI,MAAA;AAAA,MAC/G,YAAY,KAAA,EAAO,KAAA;AAAA,MACnB,iBAAiB,KAAA,EAAO,UAAA;AAAA,MACxB;AAAA,KACD,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,QAAA;AACT;AAEO,SAAS,yBACd,QAAA,EAC0D;AAC1D,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,UAAA,IAAc,CAAA,CAAE,UAAA,KAAe,MAAS,CAAA;AAEhF,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,IAAA,OAAO,EAAE,WAAA,EAAa,CAAA,EAAG,gBAAA,EAAkB,EAAC,EAAE;AAAA,EAChD;AAEA,EAAA,MAAM,SAAS,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,UAAW,CAAA;AAC9C,EAAA,MAAM,SAAS,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,WAAY,MAAM,CAAA;AAErD,EAAA,MAAM,IAAI,MAAA,CAAO,MAAA;AACjB,EAAA,MAAM,SAAA,GAAY,OAAO,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,CAAA;AACtD,EAAA,MAAM,UAAA,GAAa,OAAO,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,CAAA;AAEvD,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,IAAI,UAAA,GAAa,CAAA;AACjB,EAAA,IAAI,WAAA,GAAc,CAAA;AAElB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,SAAA,GAAA,CAAa,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA,IAAK,SAAA;AACrC,IAAA,MAAM,UAAA,GAAA,CAAc,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA,IAAK,UAAA;AACtC,IAAA,SAAA,IAAa,SAAA,GAAY,UAAA;AACzB,IAAA,UAAA,IAAc,SAAA,GAAY,SAAA;AAC1B,IAAA,WAAA,IAAe,UAAA,GAAa,UAAA;AAAA,EAC9B;AAEA,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,IAAA,CAAK,UAAA,GAAa,WAAW,CAAA;AACtD,EAAA,MAAM,WAAA,GAAc,WAAA,KAAgB,CAAA,GAAI,CAAA,GAAI,SAAA,GAAY,WAAA;AAGxD,EAAA,MAAM,mBAAmB,CAAC,GAAG,MAAM,CAAA,CAChC,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAY,SAAS,CAAC,CAAA,CACtC,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AACd,IAAA,MAAM,MAAA,GAAU,CAAA,CAAE,UAAA,CAAY,MAAA,IAAU,EAAE,UAAA,IAAe,CAAA,CAAA;AACzD,IAAA,MAAM,MAAA,GAAU,CAAA,CAAE,UAAA,CAAY,MAAA,IAAU,EAAE,UAAA,IAAe,CAAA,CAAA;AACzD,IAAA,OAAO,MAAA,GAAS,MAAA;AAAA,EAClB,CAAC,CAAA,CACA,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAEd,EAAA,OAAO,EAAE,aAAa,IAAA,CAAK,KAAA,CAAM,cAAc,GAAI,CAAA,GAAI,KAAM,gBAAA,EAAiB;AAChF;;;ACtGO,SAAS,YAAA,CAAa,MAAA,EAAsB,MAAA,GAAS,OAAA,EAAwB;AAClF,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAE,QAAQ,KAAA,EAAO,QAAA,EAAU,QAAQ,CAAA,EAAG,MAAA,EAAQ,EAAC,EAAE;AAAA,EAC1D;AAEA,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAU,MAAA,EAAQ,GAAG,MAAA,EAAO;AAAA,EACtD;AAGA,EAAA,MAAM,IAAI,MAAA,CAAO,MAAA;AACjB,EAAA,MAAM,KAAK,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,EAAG,MAAM,CAAC,CAAA;AACjC,EAAA,MAAM,KAAK,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,KAAK,CAAA;AAEpC,EAAA,MAAM,KAAA,GAAQ,GAAG,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,CAAA;AAC9C,EAAA,MAAM,KAAA,GAAQ,GAAG,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,CAAA;AAE9C,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,EAAA,GAAK,EAAA,CAAG,CAAC,CAAA,IAAK,CAAA;AACpB,IAAA,MAAM,EAAA,GAAK,EAAA,CAAG,CAAC,CAAA,IAAK,CAAA;AACpB,IAAA,SAAA,IAAA,CAAc,EAAA,GAAK,UAAU,EAAA,GAAK,KAAA,CAAA;AAClC,IAAA,WAAA,IAAA,CAAgB,EAAA,GAAK,UAAU,EAAA,GAAK,KAAA,CAAA;AAAA,EACtC;AAEA,EAAA,MAAM,KAAA,GAAQ,WAAA,KAAgB,CAAA,GAAI,CAAA,GAAI,SAAA,GAAY,WAAA;AAGlD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,CAAC,CAAA,CAAG,KAAA;AACzB,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA,CAAG,KAAA;AACxC,EAAA,MAAM,MAAA,GAAS,KAAA,KAAU,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,KAAA,CAAA,CAAQ,IAAA,GAAO,KAAA,IAAS,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA,GAAK,GAAK,CAAA,GAAI,GAAA;AAG1F,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA,GAAI,IAAA;AACpC,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI,QAAQ,SAAA,EAAW;AACrB,IAAA,KAAA,GAAQ,WAAA;AAAA,EACV,CAAA,MAAA,IAAW,KAAA,GAAQ,CAAC,SAAA,EAAW;AAC7B,IAAA,KAAA,GAAQ,WAAA;AAAA,EACV,CAAA,MAAO;AACL,IAAA,KAAA,GAAQ,QAAA;AAAA,EACV;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAO;AACzC;AAEO,SAAS,gBACd,SAAA,EAC+B;AAC/B,EAAA,IAAI,SAAA,CAAU,WAAW,CAAA,EAAG;AAC1B,IAAA,OAAO,EAAC;AAAA,EACV;AAGA,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,SAAS,EAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,aAAA,CAAc,CAAA,CAAE,IAAI,CAAC,CAAA;AAGzE,EAAA,MAAM,aAAA,GAA8B,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM,CAAE,CAAA;AACxF,EAAA,MAAM,MAAA,GAAwC;AAAA,IAC5C,OAAA,EAAS,YAAA,CAAa,aAAA,EAAe,SAAS;AAAA,GAChD;AAGA,EAAA,MAAM,aAAa,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,CAAC,EAAG,UAAU,CAAA;AACpD,EAAA,KAAA,MAAW,YAAY,UAAA,EAAY;AACjC,IAAA,MAAM,cAAA,GAA+B,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,MACtD,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,KAAA,EAAO,CAAA,CAAE,UAAA,CAAW,QAAQ;AAAA,KAC9B,CAAE,CAAA;AACF,IAAA,MAAA,CAAO,QAAQ,CAAA,GAAI,YAAA,CAAa,cAAA,EAAgB,QAAQ,CAAA;AAAA,EAC1D;AAEA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,eAAA,CAAgB,MAAA,EAAsB,SAAA,GAAY,CAAA,EAAiB;AACjF,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,SAAS,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,KAAK,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,EAAG,MAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,MAAA,CAAO,MAAA;AACxD,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAA,CAAO,CAAA,GAAI,IAAA,KAAS,CAAA,EAAG,CAAC,CAAA,GAAI,MAAA,CAAO,MAAA;AAC9E,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA;AAEjC,EAAA,IAAI,WAAW,CAAA,EAAG;AAChB,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAA,GAAQ,IAAI,CAAA,GAAI,SAAA,GAAY,MAAM,CAAA;AAC3E;;;AC3FA,IAAM,aAAA,GAAgB;AAAA,EACpB,EAAE,KAAA,EAAO,KAAA,EAAO,GAAA,EAAK,CAAA,EAAG,KAAK,CAAA,EAAE;AAAA,EAC/B,EAAE,KAAA,EAAO,MAAA,EAAQ,GAAA,EAAK,CAAA,EAAG,KAAK,EAAA,EAAG;AAAA,EACjC,EAAE,KAAA,EAAO,OAAA,EAAS,GAAA,EAAK,EAAA,EAAI,KAAK,EAAA,EAAG;AAAA,EACnC,EAAE,KAAA,EAAO,QAAA,EAAU,GAAA,EAAK,EAAA,EAAI,KAAK,GAAA;AACnC,CAAA;AAEO,SAAS,qBAAqB,OAAA,EAA0C;AAC7E,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,OAAO,EAAE,cAAc,CAAA,EAAG,OAAA,EAAS,cAAc,GAAA,CAAI,CAAC,OAAO,EAAE,KAAA,EAAO,EAAE,KAAA,EAAO,KAAA,EAAO,GAAG,OAAA,EAAS,IAAG,CAAE,CAAA,EAAG,gBAAA,EAAkB,EAAC,EAAE;AAAA,EACjI;AAEA,EAAA,MAAM,OAAA,GAA2B,aAAA,CAAc,GAAA,CAAI,CAAC,KAAA,KAAU;AAC5D,IAAA,MAAM,WAAW,OAAA,CAAQ,MAAA;AAAA,MACvB,CAAC,MAAM,CAAA,CAAE,QAAA,IAAY,MAAM,GAAA,IAAO,CAAA,CAAE,YAAY,KAAA,CAAM;AAAA,KACxD;AACA,IAAA,OAAO;AAAA,MACL,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,OAAO,QAAA,CAAS,MAAA;AAAA,MAChB,OAAA,EAAS;AAAA,KACX;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,MAAM,mBAAmB,OAAA,CACtB,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,YAAY,CAAA,IAAK,CAAA,CAAE,YAAY,EAAE,CAAA,CACjD,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,WAAA,GAAc,EAAE,WAAW,CAAA;AAE/C,EAAA,OAAO;AAAA,IACL,cAAc,OAAA,CAAQ,MAAA;AAAA,IACtB,OAAA;AAAA,IACA;AAAA,GACF;AACF;AAEO,SAAS,oBAAA,CACd,SACA,QAAA,EACkB;AAClB,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,IAAK,QAAA,CAAS,WAAW,CAAA,EAAG;AACjD,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,OAAA,uBAAc,GAAA,EAA0B;AAC9C,EAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,KAAA,EAAO,CAAC,CAAA;AAAA,EACxB;AAEA,EAAA,MAAM,UAA4B,EAAC;AAEnC,EAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA;AACnC,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,kBAAkB,IAAA,CAAK,QAAA;AAAA,QACvB,iBAAiB,IAAA,CAAK,QAAA;AAAA,QACtB,MAAA,EAAQ,IAAA,CAAK,QAAA,GAAW,IAAA,CAAK,QAAA;AAAA;AAAA,QAC7B,gBAAA,EAAkB,IAAA,CAAK,WAAA,GAAc,IAAA,CAAK;AAAA,OAC3C,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;;;AC/DO,SAAS,mBAAmB,KAAA,EAAsC;AACvE,EAAA,MAAM,EAAE,QAAA,GAAW,EAAC,EAAG,UAAA,GAAa,EAAC,EAAG,YAAA,GAAe,EAAC,EAAG,YAAA,GAAe,IAAG,GAAI,KAAA;AAGjF,EAAA,MAAM,WAAA,GAAc,SAAS,MAAA,CAAO,CAAC,KAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAA;AACjE,EAAA,MAAM,gBAAA,GAAmB,SAAS,MAAA,CAAO,CAAC,KAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,WAAA,EAAa,CAAC,CAAA;AAC3E,EAAA,MAAM,UAAA,GAAa,SAAS,MAAA,GAAS,CAAA,GACjC,KAAK,KAAA,CAAO,QAAA,CAAS,OAAO,CAAC,GAAA,EAAK,MAAM,GAAA,GAAM,CAAA,CAAE,KAAK,CAAC,CAAA,GAAI,SAAS,MAAA,GAAU,GAAK,IAAI,GAAA,GACtF,CAAA;AACJ,EAAA,MAAM,eAAA,GAAkB,SAAS,MAAA,GAAS,CAAA,GACtC,KAAK,KAAA,CAAO,QAAA,CAAS,OAAO,CAAC,GAAA,EAAK,MAAM,GAAA,GAAM,CAAA,CAAE,UAAU,CAAC,CAAA,GAAI,SAAS,MAAA,GAAU,EAAE,IAAI,EAAA,GACxF,CAAA;AACJ,EAAA,MAAM,oBAAoB,YAAA,CAAa,MAAA,GAAS,IAC5C,IAAA,CAAK,KAAA,CAAM,aAAa,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,MAAM,CAAA,CAAE,KAAA,EAAO,CAAC,CAAA,GAAI,YAAA,CAAa,MAAM,CAAA,GAClF,CAAA;AACJ,EAAA,MAAM,aAAa,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,MAAA,EAAQ,aAAa,MAAM,CAAA;AAEhE,EAAA,MAAM,QAAA,GAA8B;AAAA,IAClC,WAAA;AAAA,IACA,gBAAA;AAAA,IACA,UAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA;AAAA,IACA;AAAA,GACF;AAGA,EAAA,MAAM,WAAW,CAAC,GAAG,QAAQ,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,SAAS,CAAA,CAAE,MAAM,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAG9E,EAAA,MAAM,aAAa,CAAC,GAAG,UAAU,CAAA,CAAE,KAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,SAAS,CAAA,CAAE,MAAM,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AAGlF,EAAA,MAAM,UAAA,GAAa,gBAAgB,YAAY,CAAA;AAG/C,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,MAAW,UAAU,YAAA,EAAc;AACjC,IAAA,MAAA,CAAO,IAAA,CAAK,GAAG,MAAA,CAAO,eAAe,CAAA;AAAA,EACvC;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,GAAG,IAAI,GAAA,CAAI,MAAM,CAAC,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAErD,EAAA,OAAO;AAAA,IACL,QAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA,MAAA,EAAQ;AAAA,GACV;AACF","file":"index.js","sourcesContent":["// ============================================================================\n// @power-seo/analytics — Merge GSC + Audit Data\n// ============================================================================\n\nimport { normalizeUrl } from '@power-seo/core';\nimport type { GscPageData, PageInsight, AuditCategory, CategoryResult } from './types.js';\n\ninterface AuditData {\n url: string;\n score: number;\n categories: Record<AuditCategory, CategoryResult>;\n recommendations: string[];\n}\n\nexport function mergeGscWithAudit(\n gscData: GscPageData[],\n auditResults: AuditData[],\n): PageInsight[] {\n const auditMap = new Map<string, AuditData>();\n for (const result of auditResults) {\n auditMap.set(normalizeUrl(result.url), result);\n }\n\n const gscMap = new Map<string, GscPageData>();\n for (const page of gscData) {\n gscMap.set(normalizeUrl(page.url), page);\n }\n\n const allUrls = new Set([...auditMap.keys(), ...gscMap.keys()]);\n const insights: PageInsight[] = [];\n\n for (const url of allUrls) {\n const gsc = gscMap.get(url);\n const audit = auditMap.get(url);\n const opportunities: string[] = [];\n\n if (gsc && audit) {\n if (gsc.clicks > 50 && audit.score < 70) {\n opportunities.push(`High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`);\n }\n if (gsc.position > 10 && gsc.impressions > 100) {\n opportunities.push(`Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`);\n }\n if (audit.recommendations.length > 0) {\n opportunities.push(...audit.recommendations.slice(0, 3));\n }\n } else if (gsc && !audit) {\n opportunities.push('Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.');\n } else if (!gsc && audit) {\n if (audit.score < 50) {\n opportunities.push(`Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`);\n }\n }\n\n insights.push({\n url,\n gscMetrics: gsc ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position } : undefined,\n auditScore: audit?.score,\n auditCategories: audit?.categories,\n opportunities,\n });\n }\n\n return insights;\n}\n\nexport function correlateScoreAndTraffic(\n insights: PageInsight[],\n): { correlation: number; topOpportunities: PageInsight[] } {\n const paired = insights.filter((i) => i.gscMetrics && i.auditScore !== undefined);\n\n if (paired.length < 2) {\n return { correlation: 0, topOpportunities: [] };\n }\n\n const scores = paired.map((i) => i.auditScore!);\n const clicks = paired.map((i) => i.gscMetrics!.clicks);\n\n const n = scores.length;\n const meanScore = scores.reduce((a, b) => a + b, 0) / n;\n const meanClicks = clicks.reduce((a, b) => a + b, 0) / n;\n\n let numerator = 0;\n let denomScore = 0;\n let denomClicks = 0;\n\n for (let i = 0; i < n; i++) {\n const diffScore = (scores[i] ?? 0) - meanScore;\n const diffClicks = (clicks[i] ?? 0) - meanClicks;\n numerator += diffScore * diffClicks;\n denomScore += diffScore * diffScore;\n denomClicks += diffClicks * diffClicks;\n }\n\n const denominator = Math.sqrt(denomScore * denomClicks);\n const correlation = denominator === 0 ? 0 : numerator / denominator;\n\n // Top opportunities: high traffic, low score\n const topOpportunities = [...paired]\n .filter((i) => i.gscMetrics!.clicks > 0)\n .sort((a, b) => {\n const scoreA = (a.gscMetrics!.clicks / (a.auditScore! || 1));\n const scoreB = (b.gscMetrics!.clicks / (b.auditScore! || 1));\n return scoreB - scoreA;\n })\n .slice(0, 10);\n\n return { correlation: Math.round(correlation * 1000) / 1000, topOpportunities };\n}\n","// ============================================================================\n// @power-seo/analytics — Trend Analysis\n// ============================================================================\n\nimport type { TrendPoint, TrendDirection, TrendAnalysis, AuditSnapshot } from './types.js';\n\nexport function analyzeTrend(points: TrendPoint[], metric = 'value'): TrendAnalysis {\n if (points.length === 0) {\n return { metric, trend: 'stable', change: 0, points: [] };\n }\n\n if (points.length === 1) {\n return { metric, trend: 'stable', change: 0, points };\n }\n\n // Linear regression for slope\n const n = points.length;\n const xs = points.map((_, i) => i);\n const ys = points.map((p) => p.value);\n\n const meanX = xs.reduce((a, b) => a + b, 0) / n;\n const meanY = ys.reduce((a, b) => a + b, 0) / n;\n\n let numerator = 0;\n let denominator = 0;\n for (let i = 0; i < n; i++) {\n const xi = xs[i] ?? 0;\n const yi = ys[i] ?? 0;\n numerator += (xi - meanX) * (yi - meanY);\n denominator += (xi - meanX) * (xi - meanX);\n }\n\n const slope = denominator === 0 ? 0 : numerator / denominator;\n\n // Percentage change first→last\n const first = points[0]!.value;\n const last = points[points.length - 1]!.value;\n const change = first === 0 ? 0 : Math.round(((last - first) / Math.abs(first)) * 10000) / 100;\n\n // Classify trend based on slope relative to mean\n const threshold = Math.abs(meanY) * 0.02; // 2% of mean\n let trend: TrendDirection;\n if (slope > threshold) {\n trend = 'improving';\n } else if (slope < -threshold) {\n trend = 'declining';\n } else {\n trend = 'stable';\n }\n\n return { metric, trend, change, points };\n}\n\nexport function buildTrendLines(\n snapshots: AuditSnapshot[],\n): Record<string, TrendAnalysis> {\n if (snapshots.length === 0) {\n return {};\n }\n\n // Sort by date\n const sorted = [...snapshots].sort((a, b) => a.date.localeCompare(b.date));\n\n // Overall score trend\n const overallPoints: TrendPoint[] = sorted.map((s) => ({ date: s.date, value: s.score }));\n const result: Record<string, TrendAnalysis> = {\n overall: analyzeTrend(overallPoints, 'overall'),\n };\n\n // Per-category trends\n const categories = Object.keys(sorted[0]!.categories) as Array<keyof typeof sorted[0]['categories']>;\n for (const category of categories) {\n const categoryPoints: TrendPoint[] = sorted.map((s) => ({\n date: s.date,\n value: s.categories[category],\n }));\n result[category] = analyzeTrend(categoryPoints, category);\n }\n\n return result;\n}\n\nexport function detectAnomalies(points: TrendPoint[], threshold = 2): TrendPoint[] {\n if (points.length < 3) {\n return [];\n }\n\n const values = points.map((p) => p.value);\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / values.length;\n const stdDev = Math.sqrt(variance);\n\n if (stdDev === 0) {\n return [];\n }\n\n return points.filter((p) => Math.abs(p.value - mean) > threshold * stdDev);\n}\n","// ============================================================================\n// @power-seo/analytics — Query Ranking Analysis\n// ============================================================================\n\nimport type { GscQueryData, RankingAnalysis, RankingBucket, PositionChange } from './types.js';\n\nconst BUCKET_RANGES = [\n { range: '1-3', min: 1, max: 3 },\n { range: '4-10', min: 4, max: 10 },\n { range: '11-20', min: 11, max: 20 },\n { range: '21-100', min: 21, max: 100 },\n];\n\nexport function analyzeQueryRankings(queries: GscQueryData[]): RankingAnalysis {\n if (queries.length === 0) {\n return { totalQueries: 0, buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })), strikingDistance: [] };\n }\n\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\n const matching = queries.filter(\n (q) => q.position >= range.min && q.position <= range.max,\n );\n return {\n range: range.range,\n count: matching.length,\n queries: matching,\n };\n });\n\n // Striking distance: position 4-20, sorted by impressions descending\n const strikingDistance = queries\n .filter((q) => q.position >= 4 && q.position <= 20)\n .sort((a, b) => b.impressions - a.impressions);\n\n return {\n totalQueries: queries.length,\n buckets,\n strikingDistance,\n };\n}\n\nexport function trackPositionChanges(\n current: GscQueryData[],\n previous: GscQueryData[],\n): PositionChange[] {\n if (current.length === 0 && previous.length === 0) {\n return [];\n }\n\n const prevMap = new Map<string, GscQueryData>();\n for (const q of previous) {\n prevMap.set(q.query, q);\n }\n\n const changes: PositionChange[] = [];\n\n for (const curr of current) {\n const prev = prevMap.get(curr.query);\n if (prev) {\n changes.push({\n query: curr.query,\n previousPosition: prev.position,\n currentPosition: curr.position,\n change: prev.position - curr.position, // positive = improvement\n impressionChange: curr.impressions - prev.impressions,\n });\n }\n }\n\n return changes;\n}\n","// ============================================================================\n// @power-seo/analytics — Dashboard Data Builder\n// ============================================================================\n\nimport type { DashboardInput, DashboardData, DashboardOverview } from './types.js';\nimport { buildTrendLines } from './trends.js';\n\nexport function buildDashboardData(input: DashboardInput): DashboardData {\n const { gscPages = [], gscQueries = [], auditResults = [], auditHistory = [] } = input;\n\n // Overview metrics\n const totalClicks = gscPages.reduce((sum, p) => sum + p.clicks, 0);\n const totalImpressions = gscPages.reduce((sum, p) => sum + p.impressions, 0);\n const averageCtr = gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\n : 0;\n const averagePosition = gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\n : 0;\n const averageAuditScore = auditResults.length > 0\n ? Math.round(auditResults.reduce((sum, r) => sum + r.score, 0) / auditResults.length)\n : 0;\n const totalPages = Math.max(gscPages.length, auditResults.length);\n\n const overview: DashboardOverview = {\n totalClicks,\n totalImpressions,\n averageCtr,\n averagePosition,\n averageAuditScore,\n totalPages,\n };\n\n // Top pages by clicks\n const topPages = [...gscPages].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\n\n // Top queries by clicks\n const topQueries = [...gscQueries].sort((a, b) => b.clicks - a.clicks).slice(0, 10);\n\n // Trend lines from audit history\n const trendLines = buildTrendLines(auditHistory);\n\n // Collect issues from audit results\n const issues: string[] = [];\n for (const result of auditResults) {\n issues.push(...result.recommendations);\n }\n // Deduplicate and limit\n const uniqueIssues = [...new Set(issues)].slice(0, 20);\n\n return {\n overview,\n topPages,\n topQueries,\n trendLines,\n issues: uniqueIssues,\n };\n}\n"]}
{
"name": "@power-seo/analytics",
"version": "1.0.0",
"version": "1.0.1",
"description": "Analytics data processing: merge GSC data with audit results, trend analysis, ranking insights",

@@ -9,5 +9,5 @@ "license": "MIT",

".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
"require": "./dist/index.cjs"
}

@@ -54,3 +54,3 @@ },

"type": "git",
"url": "https://github.com/cybercraftbd/ccbd-power-seo.git",
"url": "git+https://github.com/CyberCraftBD/power-seo.git",
"directory": "packages/analytics"

@@ -57,0 +57,0 @@ },

+121
-96

@@ -15,2 +15,8 @@ # @power-seo/analytics — SEO Analytics Engine for GSC Data, Trend Analysis, and Ranking Insights

## Documentation
- **Package docs:** [`apps/docs/src/content/docs/packages/analytics.mdx`](../../apps/docs/src/content/docs/packages/analytics.mdx)
- **Ecosystem overview:** [`README.md`](../../README.md)
- **Contributing guide:** [`CONTRIBUTING.md`](../../CONTRIBUTING.md)
## Features

@@ -66,9 +72,9 @@

gscPages: [
{ url: '/blog/react-seo', clicks: 1240, impressions: 18500, ctr: 0.067, position: 4.2 },
{ url: '/blog/meta-tags', clicks: 380, impressions: 9200, ctr: 0.041, position: 8.7 },
{ url: '/blog/seo-audit', clicks: 55, impressions: 3100, ctr: 0.018, position: 19.1 },
{ url: '/blog/react-seo', clicks: 1240, impressions: 18500, ctr: 0.067, position: 4.2 },
{ url: '/blog/meta-tags', clicks: 380, impressions: 9200, ctr: 0.041, position: 8.7 },
{ url: '/blog/seo-audit', clicks: 55, impressions: 3100, ctr: 0.018, position: 19.1 },
],
gscQueries: [
{ query: 'react seo guide', clicks: 820, impressions: 9400, ctr: 0.087, position: 3.1 },
{ query: 'meta tags react', clicks: 290, impressions: 5800, ctr: 0.050, position: 7.4 },
{ query: 'meta tags react', clicks: 290, impressions: 5800, ctr: 0.05, position: 7.4 },
],

@@ -82,6 +88,6 @@ auditResults: [

console.log(dashboard.overview.totalClicks); // 1675
console.log(dashboard.overview.averagePosition); // 10.67
console.log(dashboard.overview.totalClicks); // 1675
console.log(dashboard.overview.averagePosition); // 10.67
console.log(dashboard.overview.averageAuditScore); // 67.7
console.log(dashboard.topPages[0].url); // '/blog/react-seo'
console.log(dashboard.topPages[0].url); // '/blog/react-seo'
```

@@ -100,4 +106,16 @@

const gscPages: GscPageData[] = [
{ url: 'https://example.com/blog/post-1', clicks: 850, impressions: 12000, ctr: 0.071, position: 5.3 },
{ url: 'https://example.com/blog/post-2', clicks: 220, impressions: 6500, ctr: 0.034, position: 12.1 },
{
url: 'https://example.com/blog/post-1',
clicks: 850,
impressions: 12000,
ctr: 0.071,
position: 5.3,
},
{
url: 'https://example.com/blog/post-2',
clicks: 220,
impressions: 6500,
ctr: 0.034,
position: 12.1,
},
];

@@ -107,3 +125,7 @@

{ url: '/blog/post-1', score: 91, issues: [] },
{ url: '/blog/post-2', score: 63, issues: [{ rule: 'meta-description', severity: 'error', message: '...' }] },
{
url: '/blog/post-2',
score: 63,
issues: [{ rule: 'meta-description', severity: 'error', message: '...' }],
},
];

@@ -154,5 +176,5 @@

const trend: TrendAnalysis = analyzeTrend(weeklyClicks);
console.log(trend.direction); // 'up' | 'down' | 'stable'
console.log(trend.rate); // % change per period, e.g. 5.8
console.log(trend.confidence); // 0-1, linearity confidence, e.g. 0.87
console.log(trend.direction); // 'up' | 'down' | 'stable'
console.log(trend.rate); // % change per period, e.g. 5.8
console.log(trend.confidence); // 0-1, linearity confidence, e.g. 0.87

@@ -176,3 +198,3 @@ // Build chart-ready trend line data

{ date: '2026-02-06', value: 9100 },
{ date: '2026-02-07', value: 2100 }, // drop — server issue?
{ date: '2026-02-07', value: 2100 }, // drop — server issue?
{ date: '2026-02-08', value: 8800 },

@@ -196,7 +218,7 @@ ];

const queries: GscQueryData[] = [
{ query: 'react seo', clicks: 820, impressions: 9400, ctr: 0.087, position: 2.1 },
{ query: 'seo audit tool', clicks: 340, impressions: 6200, ctr: 0.055, position: 6.8 },
{ query: 'meta tags guide', clicks: 180, impressions: 4800, ctr: 0.038, position: 14.3 },
{ query: 'sitemap generator', clicks: 30, impressions: 2100, ctr: 0.014, position: 28.7 },
{ query: 'seo typescript', clicks: 5, impressions: 1200, ctr: 0.004, position: 67.2 },
{ query: 'react seo', clicks: 820, impressions: 9400, ctr: 0.087, position: 2.1 },
{ query: 'seo audit tool', clicks: 340, impressions: 6200, ctr: 0.055, position: 6.8 },
{ query: 'meta tags guide', clicks: 180, impressions: 4800, ctr: 0.038, position: 14.3 },
{ query: 'sitemap generator', clicks: 30, impressions: 2100, ctr: 0.014, position: 28.7 },
{ query: 'seo typescript', clicks: 5, impressions: 1200, ctr: 0.004, position: 67.2 },
];

@@ -206,11 +228,14 @@

console.log('Position 1-3:', analysis.buckets['1-3'].length, 'queries');
console.log('Position 4-10:', analysis.buckets['4-10'].length, 'queries');
console.log('Position 1-3:', analysis.buckets['1-3'].length, 'queries');
console.log('Position 4-10:', analysis.buckets['4-10'].length, 'queries');
console.log('Position 11-20:', analysis.buckets['11-20'].length, 'queries');
console.log('Position 21-50:', analysis.buckets['21-50'].length, 'queries');
console.log('Position 50+:', analysis.buckets['50+'].length, 'queries');
console.log('Position 50+:', analysis.buckets['50+'].length, 'queries');
// Quick-win opportunities: ranked 11-20 with good impressions
const quickWins = analysis.buckets['11-20'].filter((q) => q.impressions > 2000);
console.log('Quick-win queries:', quickWins.map((q) => q.query));
console.log(
'Quick-win queries:',
quickWins.map((q) => q.query),
);
```

@@ -226,3 +251,3 @@

{ query: 'react seo guide', clicks: 320, impressions: 8200, ctr: 0.039, position: 8.4 },
{ query: 'seo audit', clicks: 45, impressions: 1900, ctr: 0.024, position: 22.0 },
{ query: 'seo audit', clicks: 45, impressions: 1900, ctr: 0.024, position: 22.0 },
];

@@ -232,4 +257,4 @@

{ query: 'react seo guide', clicks: 580, impressions: 9800, ctr: 0.059, position: 5.1 },
{ query: 'seo audit', clicks: 88, impressions: 2200, ctr: 0.040, position: 14.3 },
{ query: 'seo typescript', clicks: 12, impressions: 800, ctr: 0.015, position: 31.0 },
{ query: 'seo audit', clicks: 88, impressions: 2200, ctr: 0.04, position: 14.3 },
{ query: 'seo typescript', clicks: 12, impressions: 800, ctr: 0.015, position: 31.0 },
];

@@ -254,4 +279,4 @@

const dashboard: DashboardData = buildDashboardData({
gscPages: allGscPages,
gscQueries: allGscQueries,
gscPages: allGscPages,
gscQueries: allGscQueries,
auditResults: allAuditResults,

@@ -270,3 +295,3 @@ topN: 10,

dashboard.topPages.forEach(({ url, clicks, auditScore }) =>
console.log(`${url}: ${clicks} clicks, score=${auditScore ?? 'N/A'}`)
console.log(`${url}: ${clicks} clicks, score=${auditScore ?? 'N/A'}`),
);

@@ -276,3 +301,3 @@

dashboard.topQueries.forEach(({ query, clicks, position }) =>
console.log(`"${query}": ${clicks} clicks @ position ${position.toFixed(1)}`)
console.log(`"${query}": ${clicks} clicks @ position ${position.toFixed(1)}`),
);

@@ -285,3 +310,3 @@

dashboard.issues.forEach(({ rule, severity, affectedPages }) =>
console.log(`[${severity}] ${rule}: affects ${affectedPages} pages`)
console.log(`[${severity}] ${rule}: affects ${affectedPages} pages`),
);

@@ -294,6 +319,6 @@ ```

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `input.gscPages` | `GscPageData[]` | required | Google Search Console page performance data |
| `input.auditResults` | `AuditSnapshot[]` | required | Audit results with URL, score, and issues |
| Parameter | Type | Default | Description |
| -------------------- | ----------------- | -------- | ------------------------------------------- |
| `input.gscPages` | `GscPageData[]` | required | Google Search Console page performance data |
| `input.auditResults` | `AuditSnapshot[]` | required | Audit results with URL, score, and issues |

@@ -306,4 +331,4 @@ Returns `PageInsight[]` — merged records keyed by normalized URL.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| Parameter | Type | Default | Description |
| ---------- | --------------- | -------- | --------------------------------------------------------- |
| `insights` | `PageInsight[]` | required | Merged page insights with both audit score and click data |

@@ -317,5 +342,5 @@

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `points` | `TrendPoint[]` | required | Time-ordered `{ date: string; value: number }` array |
| Parameter | Type | Default | Description |
| --------- | -------------- | -------- | ---------------------------------------------------- |
| `points` | `TrendPoint[]` | required | Time-ordered `{ date: string; value: number }` array |

@@ -328,5 +353,5 @@ Returns `TrendAnalysis`: `{ direction: TrendDirection; rate: number; confidence: number }`.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `points` | `TrendPoint[]` | required | Time-ordered data points |
| Parameter | Type | Default | Description |
| --------- | -------------- | -------- | ------------------------ |
| `points` | `TrendPoint[]` | required | Time-ordered data points |

@@ -339,6 +364,6 @@ Returns `Array<{ date: string; actual: number; trend: number }>`.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `points` | `TrendPoint[]` | required | Time-ordered data points |
| `options.threshold` | `number` | `2.0` | Standard deviation multiplier for anomaly detection |
| Parameter | Type | Default | Description |
| ------------------- | -------------- | -------- | --------------------------------------------------- |
| `points` | `TrendPoint[]` | required | Time-ordered data points |
| `options.threshold` | `number` | `2.0` | Standard deviation multiplier for anomaly detection |

@@ -351,4 +376,4 @@ Returns `Array<{ date: string; value: number; type: 'spike' | 'drop'; delta: number }>`.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| Parameter | Type | Default | Description |
| --------- | ---------------- | -------- | ----------------------------------- |
| `queries` | `GscQueryData[]` | required | GSC query data with position values |

@@ -362,6 +387,6 @@

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `before` | `GscQueryData[]` | required | Ranking snapshot from the earlier period |
| `after` | `GscQueryData[]` | required | Ranking snapshot from the later period |
| Parameter | Type | Default | Description |
| --------- | ---------------- | -------- | ---------------------------------------- |
| `before` | `GscQueryData[]` | required | Ranking snapshot from the earlier period |
| `after` | `GscQueryData[]` | required | Ranking snapshot from the later period |

@@ -374,9 +399,9 @@ Returns `PositionChange[]`.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `input.gscPages` | `GscPageData[]` | required | GSC page performance data |
| `input.gscQueries` | `GscQueryData[]` | required | GSC query performance data |
| Parameter | Type | Default | Description |
| -------------------- | ----------------- | -------- | --------------------------------------------------- |
| `input.gscPages` | `GscPageData[]` | required | GSC page performance data |
| `input.gscQueries` | `GscQueryData[]` | required | GSC query performance data |
| `input.auditResults` | `AuditSnapshot[]` | required | Audit results for correlation and issue aggregation |
| `input.trendData` | `TrendPoint[]` | `[]` | Optional time-series data for trend charts |
| `input.topN` | `number` | `10` | Number of top pages/queries to include |
| `input.trendData` | `TrendPoint[]` | `[]` | Optional time-series data for trend charts |
| `input.topN` | `number` | `10` | Number of top pages/queries to include |

@@ -391,15 +416,15 @@ Returns `DashboardData`.

import type {
GscPageData, // { url, clicks, impressions, ctr, position }
GscQueryData, // { query, clicks, impressions, ctr, position }
AuditSnapshot, // { url, score, issues }
TrendPoint, // { date: string; value: number }
TrendDirection, // 'up' | 'down' | 'stable'
TrendAnalysis, // { direction, rate, confidence }
PageInsight, // Merged GscPageData + AuditSnapshot
RankingBucket, // '1-3' | '4-10' | '11-20' | '21-50' | '50+'
RankingAnalysis, // { buckets: Record<RankingBucket, GscQueryData[]>; totalQueries }
PositionChange, // { query, before?, after?, delta?, direction }
DashboardInput, // { gscPages, gscQueries, auditResults, trendData?, topN? }
DashboardOverview, // { totalClicks, totalImpressions, averageCtr, averagePosition, averageAuditScore, pagesWithErrors }
DashboardData, // { overview, topPages, topQueries, trendLines, issues }
GscPageData, // { url, clicks, impressions, ctr, position }
GscQueryData, // { query, clicks, impressions, ctr, position }
AuditSnapshot, // { url, score, issues }
TrendPoint, // { date: string; value: number }
TrendDirection, // 'up' | 'down' | 'stable'
TrendAnalysis, // { direction, rate, confidence }
PageInsight, // Merged GscPageData + AuditSnapshot
RankingBucket, // '1-3' | '4-10' | '11-20' | '21-50' | '50+'
RankingAnalysis, // { buckets: Record<RankingBucket, GscQueryData[]>; totalQueries }
PositionChange, // { query, before?, after?, delta?, direction }
DashboardInput, // { gscPages, gscQueries, auditResults, trendData?, topN? }
DashboardOverview, // { totalClicks, totalImpressions, averageCtr, averagePosition, averageAuditScore, pagesWithErrors }
DashboardData, // { overview, topPages, topQueries, trendLines, issues }
} from '@power-seo/analytics';

@@ -412,21 +437,21 @@ ```

| Package | Install | Description |
|---------|---------|-------------|
| [`@power-seo/core`](https://www.npmjs.com/package/@power-seo/core) | `npm i @power-seo/core` | Framework-agnostic utilities, types, validators, and constants |
| [`@power-seo/react`](https://www.npmjs.com/package/@power-seo/react) | `npm i @power-seo/react` | React SEO components — meta, Open Graph, Twitter Card, breadcrumbs |
| [`@power-seo/meta`](https://www.npmjs.com/package/@power-seo/meta) | `npm i @power-seo/meta` | SSR meta helpers for Next.js App Router, Remix v2, and generic SSR |
| [`@power-seo/schema`](https://www.npmjs.com/package/@power-seo/schema) | `npm i @power-seo/schema` | Type-safe JSON-LD structured data — 20 builders + 18 React components |
| [`@power-seo/content-analysis`](https://www.npmjs.com/package/@power-seo/content-analysis) | `npm i @power-seo/content-analysis` | Yoast-style SEO content scoring engine with React components |
| [`@power-seo/readability`](https://www.npmjs.com/package/@power-seo/readability) | `npm i @power-seo/readability` | Readability scoring — Flesch-Kincaid, Gunning Fog, Coleman-Liau, ARI |
| [`@power-seo/preview`](https://www.npmjs.com/package/@power-seo/preview) | `npm i @power-seo/preview` | SERP, Open Graph, and Twitter/X Card preview generators |
| [`@power-seo/sitemap`](https://www.npmjs.com/package/@power-seo/sitemap) | `npm i @power-seo/sitemap` | XML sitemap generation, streaming, index splitting, and validation |
| [`@power-seo/redirects`](https://www.npmjs.com/package/@power-seo/redirects) | `npm i @power-seo/redirects` | Redirect engine with Next.js, Remix, and Express adapters |
| [`@power-seo/links`](https://www.npmjs.com/package/@power-seo/links) | `npm i @power-seo/links` | Link graph analysis — orphan detection, suggestions, equity scoring |
| [`@power-seo/audit`](https://www.npmjs.com/package/@power-seo/audit) | `npm i @power-seo/audit` | Full SEO audit engine — meta, content, structure, performance rules |
| [`@power-seo/images`](https://www.npmjs.com/package/@power-seo/images) | `npm i @power-seo/images` | Image SEO — alt text, lazy loading, format analysis, image sitemaps |
| [`@power-seo/ai`](https://www.npmjs.com/package/@power-seo/ai) | `npm i @power-seo/ai` | LLM-agnostic AI prompt templates and parsers for SEO tasks |
| [`@power-seo/analytics`](https://www.npmjs.com/package/@power-seo/analytics) | `npm i @power-seo/analytics` | Merge GSC + audit data, trend analysis, ranking insights, dashboard |
| [`@power-seo/search-console`](https://www.npmjs.com/package/@power-seo/search-console) | `npm i @power-seo/search-console` | Google Search Console API — OAuth2, service account, URL inspection |
| [`@power-seo/integrations`](https://www.npmjs.com/package/@power-seo/integrations) | `npm i @power-seo/integrations` | Semrush and Ahrefs API clients with rate limiting and pagination |
| [`@power-seo/tracking`](https://www.npmjs.com/package/@power-seo/tracking) | `npm i @power-seo/tracking` | GA4, Clarity, PostHog, Plausible, Fathom — scripts + consent management |
| Package | Install | Description |
| ------------------------------------------------------------------------------------------ | ----------------------------------- | ----------------------------------------------------------------------- |
| [`@power-seo/core`](https://www.npmjs.com/package/@power-seo/core) | `npm i @power-seo/core` | Framework-agnostic utilities, types, validators, and constants |
| [`@power-seo/react`](https://www.npmjs.com/package/@power-seo/react) | `npm i @power-seo/react` | React SEO components — meta, Open Graph, Twitter Card, breadcrumbs |
| [`@power-seo/meta`](https://www.npmjs.com/package/@power-seo/meta) | `npm i @power-seo/meta` | SSR meta helpers for Next.js App Router, Remix v2, and generic SSR |
| [`@power-seo/schema`](https://www.npmjs.com/package/@power-seo/schema) | `npm i @power-seo/schema` | Type-safe JSON-LD structured data — 20 builders + 18 React components |
| [`@power-seo/content-analysis`](https://www.npmjs.com/package/@power-seo/content-analysis) | `npm i @power-seo/content-analysis` | Yoast-style SEO content scoring engine with React components |
| [`@power-seo/readability`](https://www.npmjs.com/package/@power-seo/readability) | `npm i @power-seo/readability` | Readability scoring — Flesch-Kincaid, Gunning Fog, Coleman-Liau, ARI |
| [`@power-seo/preview`](https://www.npmjs.com/package/@power-seo/preview) | `npm i @power-seo/preview` | SERP, Open Graph, and Twitter/X Card preview generators |
| [`@power-seo/sitemap`](https://www.npmjs.com/package/@power-seo/sitemap) | `npm i @power-seo/sitemap` | XML sitemap generation, streaming, index splitting, and validation |
| [`@power-seo/redirects`](https://www.npmjs.com/package/@power-seo/redirects) | `npm i @power-seo/redirects` | Redirect engine with Next.js, Remix, and Express adapters |
| [`@power-seo/links`](https://www.npmjs.com/package/@power-seo/links) | `npm i @power-seo/links` | Link graph analysis — orphan detection, suggestions, equity scoring |
| [`@power-seo/audit`](https://www.npmjs.com/package/@power-seo/audit) | `npm i @power-seo/audit` | Full SEO audit engine — meta, content, structure, performance rules |
| [`@power-seo/images`](https://www.npmjs.com/package/@power-seo/images) | `npm i @power-seo/images` | Image SEO — alt text, lazy loading, format analysis, image sitemaps |
| [`@power-seo/ai`](https://www.npmjs.com/package/@power-seo/ai) | `npm i @power-seo/ai` | LLM-agnostic AI prompt templates and parsers for SEO tasks |
| [`@power-seo/analytics`](https://www.npmjs.com/package/@power-seo/analytics) | `npm i @power-seo/analytics` | Merge GSC + audit data, trend analysis, ranking insights, dashboard |
| [`@power-seo/search-console`](https://www.npmjs.com/package/@power-seo/search-console) | `npm i @power-seo/search-console` | Google Search Console API — OAuth2, service account, URL inspection |
| [`@power-seo/integrations`](https://www.npmjs.com/package/@power-seo/integrations) | `npm i @power-seo/integrations` | Semrush and Ahrefs API clients with rate limiting and pagination |
| [`@power-seo/tracking`](https://www.npmjs.com/package/@power-seo/tracking) | `npm i @power-seo/tracking` | GA4, Clarity, PostHog, Plausible, Fathom — scripts + consent management |

@@ -439,9 +464,9 @@ ---

| | |
|---|---|
| **Website** | [ccbd.dev](https://ccbd.dev) |
| **GitHub** | [github.com/cybercraftbd](https://github.com/cybercraftbd) |
| | |
| -------------------- | -------------------------------------------------------------- |
| **Website** | [ccbd.dev](https://ccbd.dev) |
| **GitHub** | [github.com/cybercraftbd](https://github.com/cybercraftbd) |
| **npm Organization** | [npmjs.com/org/power-seo](https://www.npmjs.com/org/power-seo) |
| **Email** | [info@ccbd.dev](mailto:info@ccbd.dev) |
| **Email** | [info@ccbd.dev](mailto:info@ccbd.dev) |
© 2026 CyberCraft Bangladesh · Released under the [MIT License](../../LICENSE)