60 lines
2.2 KiB
TypeScript
60 lines
2.2 KiB
TypeScript
/** Live, off-chain Wikipedia data. Text fields are plain strings, never HTML. */
|
|
export interface PageEnrichment {
|
|
pageId: number;
|
|
title: string;
|
|
description: string | null;
|
|
wikidataId: string | null;
|
|
revisionId: number;
|
|
pageBytes: number;
|
|
/** Number of returned interlanguage links (a lower bound when truncated). */
|
|
languageCount: number;
|
|
languagesTruncated: boolean;
|
|
categories: string[];
|
|
categoriesTruncated: boolean;
|
|
fetchedAt: string;
|
|
pageviews: {
|
|
status: 'available' | 'unavailable';
|
|
/** Six completed UTC months, oldest first, identified as YYYY-MM. */
|
|
months: { month: string; views: number }[];
|
|
latestMonth: string;
|
|
total: number | null;
|
|
/** Latest completed month's views divided by its actual UTC day count. */
|
|
dailyAverage: number | null;
|
|
trendPercent: number | null;
|
|
};
|
|
stats: { attention: number | null; depth: number; reach: number };
|
|
}
|
|
|
|
/** Immutable numeric Wikipedia metrics committed to a minted block. */
|
|
export type MintStatsSnapshot = {
|
|
capturedAt: string;
|
|
revisionId: number;
|
|
pageBytes: number;
|
|
languageCount: number;
|
|
languagesTruncated: boolean;
|
|
pageviews: PageEnrichment['pageviews'];
|
|
stats: PageEnrichment['stats'];
|
|
};
|
|
|
|
export function snapshotStats(data: PageEnrichment): MintStatsSnapshot {
|
|
return {
|
|
capturedAt: new Date().toISOString(),
|
|
revisionId: data.revisionId,
|
|
pageBytes: data.pageBytes,
|
|
languageCount: data.languageCount,
|
|
languagesTruncated: data.languagesTruncated,
|
|
pageviews: { ...data.pageviews, months: data.pageviews.months.map(item => ({ ...item })) },
|
|
stats: { ...data.stats },
|
|
};
|
|
}
|
|
|
|
/** Attention uses the latest completed month's views, not the six-month total. */
|
|
export function deriveStats(pageBytes: number, languageCount: number, monthlyViews: number | null): PageEnrichment['stats'] {
|
|
const score = (value: number, scale: number) => {
|
|
if (!Number.isFinite(value) || value < 0) throw new RangeError('Invalid enrichment score input');
|
|
return Math.min(100, Math.round(Math.log10(value + 1) / scale * 100));
|
|
};
|
|
return { attention: monthlyViews === null ? null : score(monthlyViews, 6),
|
|
depth: score(pageBytes, 6), reach: score(languageCount, 3) };
|
|
}
|