@power-seo/analytics
Advanced tools
+21
| MIT License | ||
| Copyright (c) 2026 CCBD SEO Contributors | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
+45
-14
@@ -1,14 +0,44 @@ | ||
| 'use strict'; | ||
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var core = require('@power-seo/core'); | ||
| // src/index.ts | ||
| var index_exports = {}; | ||
| __export(index_exports, { | ||
| analyzeQueryRankings: () => analyzeQueryRankings, | ||
| analyzeTrend: () => analyzeTrend, | ||
| buildDashboardData: () => buildDashboardData, | ||
| buildTrendLines: () => buildTrendLines, | ||
| correlateScoreAndTraffic: () => correlateScoreAndTraffic, | ||
| detectAnomalies: () => detectAnomalies, | ||
| mergeGscWithAudit: () => mergeGscWithAudit, | ||
| trackPositionChanges: () => trackPositionChanges | ||
| }); | ||
| module.exports = __toCommonJS(index_exports); | ||
| // src/merge.ts | ||
| var import_core = require("@power-seo/core"); | ||
| function mergeGscWithAudit(gscData, auditResults) { | ||
| const auditMap = /* @__PURE__ */ new Map(); | ||
| for (const result of auditResults) { | ||
| auditMap.set(core.normalizeUrl(result.url), result); | ||
| auditMap.set((0, import_core.normalizeUrl)(result.url), result); | ||
| } | ||
| const gscMap = /* @__PURE__ */ new Map(); | ||
| for (const page of gscData) { | ||
| gscMap.set(core.normalizeUrl(page.url), page); | ||
| gscMap.set((0, import_core.normalizeUrl)(page.url), page); | ||
| } | ||
@@ -243,12 +273,13 @@ const allUrls = /* @__PURE__ */ new Set([...auditMap.keys(), ...gscMap.keys()]); | ||
| } | ||
| exports.analyzeQueryRankings = analyzeQueryRankings; | ||
| exports.analyzeTrend = analyzeTrend; | ||
| exports.buildDashboardData = buildDashboardData; | ||
| exports.buildTrendLines = buildTrendLines; | ||
| exports.correlateScoreAndTraffic = correlateScoreAndTraffic; | ||
| exports.detectAnomalies = detectAnomalies; | ||
| exports.mergeGscWithAudit = mergeGscWithAudit; | ||
| exports.trackPositionChanges = trackPositionChanges; | ||
| //# sourceMappingURL=index.cjs.map | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| analyzeQueryRankings, | ||
| analyzeTrend, | ||
| buildDashboardData, | ||
| buildTrendLines, | ||
| correlateScoreAndTraffic, | ||
| detectAnomalies, | ||
| mergeGscWithAudit, | ||
| trackPositionChanges | ||
| }); | ||
| //# sourceMappingURL=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":["// ============================================================================\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(\n `High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`,\n );\n }\n if (gsc.position > 10 && gsc.impressions > 100) {\n opportunities.push(\n `Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`,\n );\n }\n if (audit.recommendations.length > 0) {\n opportunities.push(...audit.recommendations.slice(0, 3));\n }\n } else if (gsc && !audit) {\n opportunities.push(\n 'Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.',\n );\n } else if (!gsc && audit) {\n if (audit.score < 50) {\n opportunities.push(\n `Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`,\n );\n }\n }\n\n insights.push({\n url,\n gscMetrics: gsc\n ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position }\n : undefined,\n auditScore: audit?.score,\n auditCategories: audit?.categories,\n opportunities,\n });\n }\n\n return insights;\n}\n\nexport function correlateScoreAndTraffic(insights: PageInsight[]): {\n correlation: number;\n topOpportunities: PageInsight[];\n} {\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(snapshots: AuditSnapshot[]): 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<\n keyof (typeof sorted)[0]['categories']\n >;\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 {\n totalQueries: 0,\n buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })),\n strikingDistance: [],\n };\n }\n\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\n const matching = queries.filter((q) => q.position >= range.min && q.position <= range.max);\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 =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\n : 0;\n const averagePosition =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\n : 0;\n const averageAuditScore =\n 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"]} | ||
| {"version":3,"sources":["../src/index.ts","../src/merge.ts","../src/trends.ts","../src/rankings.ts","../src/dashboard.ts"],"sourcesContent":["// @power-seo/analytics — Public API\n// ----------------------------------------------------------------------------\n\nexport { mergeGscWithAudit, correlateScoreAndTraffic } from './merge.js';\nexport { analyzeTrend, buildTrendLines, detectAnomalies } from './trends.js';\nexport { analyzeQueryRankings, trackPositionChanges } from './rankings.js';\nexport { buildDashboardData } from './dashboard.js';\n\nexport type {\n GscPageData,\n GscQueryData,\n AuditSnapshot,\n TrendPoint,\n TrendDirection,\n TrendAnalysis,\n PageInsight,\n RankingBucket,\n RankingAnalysis,\n PositionChange,\n DashboardInput,\n DashboardOverview,\n DashboardData,\n AuditCategory,\n CategoryResult,\n PageAuditResult,\n} from './types.js';\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(\n `High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`,\n );\n }\n if (gsc.position > 10 && gsc.impressions > 100) {\n opportunities.push(\n `Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`,\n );\n }\n if (audit.recommendations.length > 0) {\n opportunities.push(...audit.recommendations.slice(0, 3));\n }\n } else if (gsc && !audit) {\n opportunities.push(\n 'Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.',\n );\n } else if (!gsc && audit) {\n if (audit.score < 50) {\n opportunities.push(\n `Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`,\n );\n }\n }\n\n insights.push({\n url,\n gscMetrics: gsc\n ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position }\n : undefined,\n auditScore: audit?.score,\n auditCategories: audit?.categories,\n opportunities,\n });\n }\n\n return insights;\n}\n\nexport function correlateScoreAndTraffic(insights: PageInsight[]): {\n correlation: number;\n topOpportunities: PageInsight[];\n} {\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","// @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(snapshots: AuditSnapshot[]): 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<\n keyof (typeof sorted)[0]['categories']\n >;\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","// @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 {\n totalQueries: 0,\n buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })),\n strikingDistance: [],\n };\n }\n\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\n const matching = queries.filter((q) => q.position >= range.min && q.position <= range.max);\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","// @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 =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\n : 0;\n const averagePosition =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\n : 0;\n const averageAuditScore =\n 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"],"mappings":"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","names":[]} |
+11
-5
@@ -1,4 +0,3 @@ | ||
| import { normalizeUrl } from '@power-seo/core'; | ||
| // src/merge.ts | ||
| import { normalizeUrl } from "@power-seo/core"; | ||
| function mergeGscWithAudit(gscData, auditResults) { | ||
@@ -241,5 +240,12 @@ const auditMap = /* @__PURE__ */ new Map(); | ||
| } | ||
| export { analyzeQueryRankings, analyzeTrend, buildDashboardData, buildTrendLines, correlateScoreAndTraffic, detectAnomalies, mergeGscWithAudit, trackPositionChanges }; | ||
| //# sourceMappingURL=index.js.map | ||
| export { | ||
| analyzeQueryRankings, | ||
| analyzeTrend, | ||
| buildDashboardData, | ||
| buildTrendLines, | ||
| correlateScoreAndTraffic, | ||
| detectAnomalies, | ||
| mergeGscWithAudit, | ||
| trackPositionChanges | ||
| }; | ||
| //# sourceMappingURL=index.js.map |
@@ -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":["// ============================================================================\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(\n `High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`,\n );\n }\n if (gsc.position > 10 && gsc.impressions > 100) {\n opportunities.push(\n `Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`,\n );\n }\n if (audit.recommendations.length > 0) {\n opportunities.push(...audit.recommendations.slice(0, 3));\n }\n } else if (gsc && !audit) {\n opportunities.push(\n 'Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.',\n );\n } else if (!gsc && audit) {\n if (audit.score < 50) {\n opportunities.push(\n `Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`,\n );\n }\n }\n\n insights.push({\n url,\n gscMetrics: gsc\n ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position }\n : undefined,\n auditScore: audit?.score,\n auditCategories: audit?.categories,\n opportunities,\n });\n }\n\n return insights;\n}\n\nexport function correlateScoreAndTraffic(insights: PageInsight[]): {\n correlation: number;\n topOpportunities: PageInsight[];\n} {\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(snapshots: AuditSnapshot[]): 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<\n keyof (typeof sorted)[0]['categories']\n >;\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 {\n totalQueries: 0,\n buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })),\n strikingDistance: [],\n };\n }\n\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\n const matching = queries.filter((q) => q.position >= range.min && q.position <= range.max);\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 =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\n : 0;\n const averagePosition =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\n : 0;\n const averageAuditScore =\n 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"]} | ||
| {"version":3,"sources":["../src/merge.ts","../src/trends.ts","../src/rankings.ts","../src/dashboard.ts"],"sourcesContent":["// @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(\n `High-traffic page (${gsc.clicks} clicks) with low audit score (${audit.score}). Fixing issues could significantly boost organic performance.`,\n );\n }\n if (gsc.position > 10 && gsc.impressions > 100) {\n opportunities.push(\n `Page has ${gsc.impressions} impressions at position ${gsc.position.toFixed(1)}. Improving to page 1 could unlock significant traffic.`,\n );\n }\n if (audit.recommendations.length > 0) {\n opportunities.push(...audit.recommendations.slice(0, 3));\n }\n } else if (gsc && !audit) {\n opportunities.push(\n 'Page receives search traffic but has not been audited. Run an audit to identify improvement opportunities.',\n );\n } else if (!gsc && audit) {\n if (audit.score < 50) {\n opportunities.push(\n `Page has a low audit score (${audit.score}) and no search traffic. Consider improving or removing the page.`,\n );\n }\n }\n\n insights.push({\n url,\n gscMetrics: gsc\n ? { clicks: gsc.clicks, impressions: gsc.impressions, ctr: gsc.ctr, position: gsc.position }\n : undefined,\n auditScore: audit?.score,\n auditCategories: audit?.categories,\n opportunities,\n });\n }\n\n return insights;\n}\n\nexport function correlateScoreAndTraffic(insights: PageInsight[]): {\n correlation: number;\n topOpportunities: PageInsight[];\n} {\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","// @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(snapshots: AuditSnapshot[]): 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<\n keyof (typeof sorted)[0]['categories']\n >;\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","// @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 {\n totalQueries: 0,\n buckets: BUCKET_RANGES.map((r) => ({ range: r.range, count: 0, queries: [] })),\n strikingDistance: [],\n };\n }\n\n const buckets: RankingBucket[] = BUCKET_RANGES.map((range) => {\n const matching = queries.filter((q) => q.position >= range.min && q.position <= range.max);\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","// @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 =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.ctr, 0) / gscPages.length) * 10000) / 10000\n : 0;\n const averagePosition =\n gscPages.length > 0\n ? Math.round((gscPages.reduce((sum, p) => sum + p.position, 0) / gscPages.length) * 10) / 10\n : 0;\n const averageAuditScore =\n 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"],"mappings":";AAGA,SAAS,oBAAoB;AAUtB,SAAS,kBACd,SACA,cACe;AACf,QAAM,WAAW,oBAAI,IAAuB;AAC5C,aAAW,UAAU,cAAc;AACjC,aAAS,IAAI,aAAa,OAAO,GAAG,GAAG,MAAM;AAAA,EAC/C;AAEA,QAAM,SAAS,oBAAI,IAAyB;AAC5C,aAAW,QAAQ,SAAS;AAC1B,WAAO,IAAI,aAAa,KAAK,GAAG,GAAG,IAAI;AAAA,EACzC;AAEA,QAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,SAAS,KAAK,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC;AAC9D,QAAM,WAA0B,CAAC;AAEjC,aAAW,OAAO,SAAS;AACzB,UAAM,MAAM,OAAO,IAAI,GAAG;AAC1B,UAAM,QAAQ,SAAS,IAAI,GAAG;AAC9B,UAAM,gBAA0B,CAAC;AAEjC,QAAI,OAAO,OAAO;AAChB,UAAI,IAAI,SAAS,MAAM,MAAM,QAAQ,IAAI;AACvC,sBAAc;AAAA,UACZ,sBAAsB,IAAI,MAAM,kCAAkC,MAAM,KAAK;AAAA,QAC/E;AAAA,MACF;AACA,UAAI,IAAI,WAAW,MAAM,IAAI,cAAc,KAAK;AAC9C,sBAAc;AAAA,UACZ,YAAY,IAAI,WAAW,4BAA4B,IAAI,SAAS,QAAQ,CAAC,CAAC;AAAA,QAChF;AAAA,MACF;AACA,UAAI,MAAM,gBAAgB,SAAS,GAAG;AACpC,sBAAc,KAAK,GAAG,MAAM,gBAAgB,MAAM,GAAG,CAAC,CAAC;AAAA,MACzD;AAAA,IACF,WAAW,OAAO,CAAC,OAAO;AACxB,oBAAc;AAAA,QACZ;AAAA,MACF;AAAA,IACF,WAAW,CAAC,OAAO,OAAO;AACxB,UAAI,MAAM,QAAQ,IAAI;AACpB,sBAAc;AAAA,UACZ,+BAA+B,MAAM,KAAK;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAEA,aAAS,KAAK;AAAA,MACZ;AAAA,MACA,YAAY,MACR,EAAE,QAAQ,IAAI,QAAQ,aAAa,IAAI,aAAa,KAAK,IAAI,KAAK,UAAU,IAAI,SAAS,IACzF;AAAA,MACJ,YAAY,OAAO;AAAA,MACnB,iBAAiB,OAAO;AAAA,MACxB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,SAAS,yBAAyB,UAGvC;AACA,QAAM,SAAS,SAAS,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,eAAe,MAAS;AAEhF,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO,EAAE,aAAa,GAAG,kBAAkB,CAAC,EAAE;AAAA,EAChD;AAEA,QAAM,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,UAAW;AAC9C,QAAM,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,WAAY,MAAM;AAErD,QAAM,IAAI,OAAO;AACjB,QAAM,YAAY,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI;AACtD,QAAM,aAAa,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI;AAEvD,MAAI,YAAY;AAChB,MAAI,aAAa;AACjB,MAAI,cAAc;AAElB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,aAAa,OAAO,CAAC,KAAK,KAAK;AACrC,UAAM,cAAc,OAAO,CAAC,KAAK,KAAK;AACtC,iBAAa,YAAY;AACzB,kBAAc,YAAY;AAC1B,mBAAe,aAAa;AAAA,EAC9B;AAEA,QAAM,cAAc,KAAK,KAAK,aAAa,WAAW;AACtD,QAAM,cAAc,gBAAgB,IAAI,IAAI,YAAY;AAGxD,QAAM,mBAAmB,CAAC,GAAG,MAAM,EAChC,OAAO,CAAC,MAAM,EAAE,WAAY,SAAS,CAAC,EACtC,KAAK,CAAC,GAAG,MAAM;AACd,UAAM,SAAS,EAAE,WAAY,UAAU,EAAE,cAAe;AACxD,UAAM,SAAS,EAAE,WAAY,UAAU,EAAE,cAAe;AACxD,WAAO,SAAS;AAAA,EAClB,CAAC,EACA,MAAM,GAAG,EAAE;AAEd,SAAO,EAAE,aAAa,KAAK,MAAM,cAAc,GAAI,IAAI,KAAM,iBAAiB;AAChF;;;ACjHO,SAAS,aAAa,QAAsB,SAAS,SAAwB;AAClF,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,EAAE,QAAQ,OAAO,UAAU,QAAQ,GAAG,QAAQ,CAAC,EAAE;AAAA,EAC1D;AAEA,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO,EAAE,QAAQ,OAAO,UAAU,QAAQ,GAAG,OAAO;AAAA,EACtD;AAGA,QAAM,IAAI,OAAO;AACjB,QAAM,KAAK,OAAO,IAAI,CAAC,GAAG,MAAM,CAAC;AACjC,QAAM,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK;AAEpC,QAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI;AAC9C,QAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI;AAE9C,MAAI,YAAY;AAChB,MAAI,cAAc;AAClB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,UAAM,KAAK,GAAG,CAAC,KAAK;AACpB,kBAAc,KAAK,UAAU,KAAK;AAClC,oBAAgB,KAAK,UAAU,KAAK;AAAA,EACtC;AAEA,QAAM,QAAQ,gBAAgB,IAAI,IAAI,YAAY;AAGlD,QAAM,QAAQ,OAAO,CAAC,EAAG;AACzB,QAAM,OAAO,OAAO,OAAO,SAAS,CAAC,EAAG;AACxC,QAAM,SAAS,UAAU,IAAI,IAAI,KAAK,OAAQ,OAAO,SAAS,KAAK,IAAI,KAAK,IAAK,GAAK,IAAI;AAG1F,QAAM,YAAY,KAAK,IAAI,KAAK,IAAI;AACpC,MAAI;AACJ,MAAI,QAAQ,WAAW;AACrB,YAAQ;AAAA,EACV,WAAW,QAAQ,CAAC,WAAW;AAC7B,YAAQ;AAAA,EACV,OAAO;AACL,YAAQ;AAAA,EACV;AAEA,SAAO,EAAE,QAAQ,OAAO,QAAQ,OAAO;AACzC;AAEO,SAAS,gBAAgB,WAA2D;AACzF,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,SAAS,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAGzE,QAAM,gBAA8B,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,MAAM,EAAE;AACxF,QAAM,SAAwC;AAAA,IAC5C,SAAS,aAAa,eAAe,SAAS;AAAA,EAChD;AAGA,QAAM,aAAa,OAAO,KAAK,OAAO,CAAC,EAAG,UAAU;AAGpD,aAAW,YAAY,YAAY;AACjC,UAAM,iBAA+B,OAAO,IAAI,CAAC,OAAO;AAAA,MACtD,MAAM,EAAE;AAAA,MACR,OAAO,EAAE,WAAW,QAAQ;AAAA,IAC9B,EAAE;AACF,WAAO,QAAQ,IAAI,aAAa,gBAAgB,QAAQ;AAAA,EAC1D;AAEA,SAAO;AACT;AAEO,SAAS,gBAAgB,QAAsB,YAAY,GAAiB;AACjF,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK;AACxC,QAAM,OAAO,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,OAAO;AACxD,QAAM,WAAW,OAAO,OAAO,CAAC,KAAK,MAAM,OAAO,IAAI,SAAS,GAAG,CAAC,IAAI,OAAO;AAC9E,QAAM,SAAS,KAAK,KAAK,QAAQ;AAEjC,MAAI,WAAW,GAAG;AAChB,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,OAAO,OAAO,CAAC,MAAM,KAAK,IAAI,EAAE,QAAQ,IAAI,IAAI,YAAY,MAAM;AAC3E;;;AC3FA,IAAM,gBAAgB;AAAA,EACpB,EAAE,OAAO,OAAO,KAAK,GAAG,KAAK,EAAE;AAAA,EAC/B,EAAE,OAAO,QAAQ,KAAK,GAAG,KAAK,GAAG;AAAA,EACjC,EAAE,OAAO,SAAS,KAAK,IAAI,KAAK,GAAG;AAAA,EACnC,EAAE,OAAO,UAAU,KAAK,IAAI,KAAK,IAAI;AACvC;AAEO,SAAS,qBAAqB,SAA0C;AAC7E,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO;AAAA,MACL,cAAc;AAAA,MACd,SAAS,cAAc,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,OAAO,GAAG,SAAS,CAAC,EAAE,EAAE;AAAA,MAC7E,kBAAkB,CAAC;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,UAA2B,cAAc,IAAI,CAAC,UAAU;AAC5D,UAAM,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,OAAO,EAAE,YAAY,MAAM,GAAG;AACzF,WAAO;AAAA,MACL,OAAO,MAAM;AAAA,MACb,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,IACX;AAAA,EACF,CAAC;AAGD,QAAM,mBAAmB,QACtB,OAAO,CAAC,MAAM,EAAE,YAAY,KAAK,EAAE,YAAY,EAAE,EACjD,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,WAAW;AAE/C,SAAO;AAAA,IACL,cAAc,QAAQ;AAAA,IACtB;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,qBACd,SACA,UACkB;AAClB,MAAI,QAAQ,WAAW,KAAK,SAAS,WAAW,GAAG;AACjD,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,UAAU,oBAAI,IAA0B;AAC9C,aAAW,KAAK,UAAU;AACxB,YAAQ,IAAI,EAAE,OAAO,CAAC;AAAA,EACxB;AAEA,QAAM,UAA4B,CAAC;AAEnC,aAAW,QAAQ,SAAS;AAC1B,UAAM,OAAO,QAAQ,IAAI,KAAK,KAAK;AACnC,QAAI,MAAM;AACR,cAAQ,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,QACZ,kBAAkB,KAAK;AAAA,QACvB,iBAAiB,KAAK;AAAA,QACtB,QAAQ,KAAK,WAAW,KAAK;AAAA;AAAA,QAC7B,kBAAkB,KAAK,cAAc,KAAK;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;;;ACjEO,SAAS,mBAAmB,OAAsC;AACvE,QAAM,EAAE,WAAW,CAAC,GAAG,aAAa,CAAC,GAAG,eAAe,CAAC,GAAG,eAAe,CAAC,EAAE,IAAI;AAGjF,QAAM,cAAc,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,QAAQ,CAAC;AACjE,QAAM,mBAAmB,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,aAAa,CAAC;AAC3E,QAAM,aACJ,SAAS,SAAS,IACd,KAAK,MAAO,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,KAAK,CAAC,IAAI,SAAS,SAAU,GAAK,IAAI,MACtF;AACN,QAAM,kBACJ,SAAS,SAAS,IACd,KAAK,MAAO,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,UAAU,CAAC,IAAI,SAAS,SAAU,EAAE,IAAI,KACxF;AACN,QAAM,oBACJ,aAAa,SAAS,IAClB,KAAK,MAAM,aAAa,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC,IAAI,aAAa,MAAM,IAClF;AACN,QAAM,aAAa,KAAK,IAAI,SAAS,QAAQ,aAAa,MAAM;AAEhE,QAAM,WAA8B;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,WAAW,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,EAAE;AAG9E,QAAM,aAAa,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,EAAE;AAGlF,QAAM,aAAa,gBAAgB,YAAY;AAG/C,QAAM,SAAmB,CAAC;AAC1B,aAAW,UAAU,cAAc;AACjC,WAAO,KAAK,GAAG,OAAO,eAAe;AAAA,EACvC;AAEA,QAAM,eAAe,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE;AAErD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,EACV;AACF;","names":[]} |
+23
-15
| { | ||
| "name": "@power-seo/analytics", | ||
| "version": "1.0.4", | ||
| "version": "1.0.7", | ||
| "description": "Analytics data processing: merge GSC data with audit results, trend analysis, ranking insights", | ||
@@ -20,18 +20,8 @@ "license": "MIT", | ||
| ], | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest", | ||
| "typecheck": "tsc --noEmit", | ||
| "lint": "eslint src/", | ||
| "lint:fix": "eslint src/ --fix", | ||
| "clean": "rimraf dist" | ||
| }, | ||
| "dependencies": { | ||
| "@power-seo/core": "workspace:*", | ||
| "@power-seo/audit": "workspace:*" | ||
| "@power-seo/core": "1.0.3", | ||
| "@power-seo/audit": "1.0.7" | ||
| }, | ||
| "devDependencies": { | ||
| "rimraf": "^6.0.0", | ||
| "rimraf": "^6.1.3", | ||
| "tsup": "^8.3.0", | ||
@@ -59,3 +49,21 @@ "typescript": "^5.7.0", | ||
| "access": "public" | ||
| }, | ||
| "bugs": { | ||
| "url": "https://github.com/CyberCraftBD/power-seo/issues" | ||
| }, | ||
| "homepage": "https://github.com/CyberCraftBD/power-seo/tree/main/packages/analytics#readme", | ||
| "funding": { | ||
| "type": "github", | ||
| "url": "https://github.com/sponsors/cybercraftbd" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "test": "vitest run", | ||
| "test:watch": "vitest", | ||
| "typecheck": "tsc --noEmit", | ||
| "lint": "eslint src/", | ||
| "lint:fix": "eslint src/ --fix", | ||
| "clean": "rimraf dist" | ||
| } | ||
| } | ||
| } |
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
9
12.5%633
6.75%0
-100%0
-100%88857
-5.53%+ Added
+ Added
+ Added
+ Added
Updated
Updated