Skip to content

Commit 57c5060

Browse files
committed
remove legacy npm stats workflow
1 parent 4d7c43a commit 57c5060

13 files changed

Lines changed: 460 additions & 2851 deletions

src/db/schema.ts

Lines changed: 0 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -336,122 +336,6 @@ export const docsArtifactCache = pgTable(
336336
}),
337337
)
338338

339-
// NPM Packages table (combines registry and stats cache)
340-
export const npmPackages = pgTable(
341-
'npm_packages',
342-
{
343-
id: uuid('id').primaryKey().defaultRandom(),
344-
// Package name (e.g., "@tanstack/react-query")
345-
packageName: varchar('package_name', { length: 255 }).notNull().unique(),
346-
347-
// Package metadata (from npm registry)
348-
githubRepo: varchar('github_repo', { length: 255 }),
349-
libraryId: varchar('library_id', { length: 255 }),
350-
isLegacy: boolean('is_legacy').default(false),
351-
metadataCheckedAt: timestamp('metadata_checked_at', {
352-
withTimezone: true,
353-
mode: 'date',
354-
}),
355-
356-
// Stats cache (from npm downloads API)
357-
downloads: bigint('downloads', { mode: 'number' }),
358-
ratePerDay: real('rate_per_day'), // Growth rate in downloads per day (for animation)
359-
statsExpiresAt: timestamp('stats_expires_at', {
360-
withTimezone: true,
361-
mode: 'date',
362-
}),
363-
364-
createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' })
365-
.notNull()
366-
.defaultNow(),
367-
updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' })
368-
.notNull()
369-
.defaultNow(),
370-
},
371-
(table) => ({
372-
packageNameIdx: index('npm_packages_package_name_idx').on(
373-
table.packageName,
374-
),
375-
githubRepoIdx: index('npm_packages_github_repo_idx').on(table.githubRepo),
376-
libraryIdIdx: index('npm_packages_library_id_idx').on(table.libraryId),
377-
statsExpiresAtIdx: index('npm_packages_stats_expires_at_idx').on(
378-
table.statsExpiresAt,
379-
),
380-
}),
381-
)
382-
383-
export type NpmPackage = InferSelectModel<typeof npmPackages>
384-
export type NewNpmPackage = InferInsertModel<typeof npmPackages>
385-
386-
// NPM Org Stats cache table (for pre-aggregated org-level stats)
387-
export const npmOrgStatsCache = pgTable(
388-
'npm_org_stats_cache',
389-
{
390-
id: uuid('id').primaryKey().defaultRandom(),
391-
// Organization name (e.g., "tanstack")
392-
orgName: varchar('org_name', { length: 255 }).notNull().unique(),
393-
// Pre-aggregated total downloads
394-
totalDownloads: bigint('total_downloads', { mode: 'number' }).notNull(),
395-
// Per-package stats breakdown (JSON) - needed for per-package rate info
396-
packageStats: jsonb('package_stats').notNull(),
397-
// When this cache entry expires (should refresh after this)
398-
expiresAt: timestamp('expires_at', {
399-
withTimezone: true,
400-
mode: 'date',
401-
}).notNull(),
402-
createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' })
403-
.notNull()
404-
.defaultNow(),
405-
updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' })
406-
.notNull()
407-
.defaultNow(),
408-
},
409-
(table) => ({
410-
orgNameIdx: index('npm_org_stats_cache_org_name_idx').on(table.orgName),
411-
expiresAtIdx: index('npm_org_stats_cache_expires_at_idx').on(
412-
table.expiresAt,
413-
),
414-
}),
415-
)
416-
417-
export type NpmOrgStatsCache = InferSelectModel<typeof npmOrgStatsCache>
418-
export type NewNpmOrgStatsCache = InferInsertModel<typeof npmOrgStatsCache>
419-
420-
// NPM Library Stats cache table (for pre-aggregated library-level stats)
421-
export const npmLibraryStatsCache = pgTable(
422-
'npm_library_stats_cache',
423-
{
424-
id: uuid('id').primaryKey().defaultRandom(),
425-
// Library ID (e.g., "query", "table")
426-
libraryId: varchar('library_id', { length: 255 }).notNull().unique(),
427-
// Pre-aggregated total downloads for this library
428-
totalDownloads: bigint('total_downloads', { mode: 'number' }).notNull(),
429-
// Previous total downloads (for calculating rate of change)
430-
previousTotalDownloads: bigint('previous_total_downloads', {
431-
mode: 'number',
432-
}),
433-
// Package count
434-
packageCount: integer('package_count').notNull(),
435-
// When this cache entry was last updated
436-
updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' })
437-
.notNull()
438-
.defaultNow(),
439-
createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' })
440-
.notNull()
441-
.defaultNow(),
442-
},
443-
(table) => ({
444-
libraryIdIdx: index('npm_library_stats_cache_library_id_idx').on(
445-
table.libraryId,
446-
),
447-
}),
448-
)
449-
450-
export type NpmLibraryStatsCache = InferSelectModel<typeof npmLibraryStatsCache>
451-
export type NewNpmLibraryStatsCache = InferInsertModel<
452-
typeof npmLibraryStatsCache
453-
>
454-
455339
export const ossStatsCache = pgTable(
456340
'oss_stats_cache',
457341
{

src/mcp/tools/npm-stats.ts

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { z } from 'zod'
2+
import { libraries } from '~/libraries'
23
import { getPopularComparisons } from '~/routes/stats/npm/-comparisons'
34
import { fetchNpmDownloadsBulk } from '~/utils/stats.server'
45

@@ -94,27 +95,21 @@ function extractPackageNames(
9495
}
9596

9697
async function getOrgStats() {
97-
const {
98-
getCachedNpmOrgStats,
99-
getExpiredNpmOrgStats,
100-
getAllCachedLibraryStats,
101-
} = await import('~/utils/stats-db.server')
102-
103-
const orgStats =
104-
(await getCachedNpmOrgStats('tanstack')) ??
105-
(await getExpiredNpmOrgStats('tanstack'))
106-
if (!orgStats) {
98+
const { getHomepageNpmStatsSummary } =
99+
await import('~/utils/homepage-npm-stats.server')
100+
const summary = await getHomepageNpmStatsSummary()
101+
102+
if (!summary) {
107103
throw new Error(
108104
'NPM stats not available. Stats are refreshed every 6 hours.',
109105
)
110106
}
111107

112-
const libraryStats = await getAllCachedLibraryStats()
113108
return {
114109
org: 'tanstack',
115-
totalDownloads: orgStats.totalDownloads,
116-
ratePerDay: orgStats.ratePerDay ?? 0,
117-
libraries: libraryStats
110+
totalDownloads: summary.totalDownloads,
111+
ratePerDay: summary.weeklyRatePerDay,
112+
libraries: summary.librarySummaries
118113
.map((lib) => ({
119114
id: lib.libraryId,
120115
downloads: lib.totalDownloads,
@@ -125,36 +120,31 @@ async function getOrgStats() {
125120
}
126121

127122
async function getLibraryStats(libraryId: string) {
128-
const {
129-
getCachedLibraryStats,
130-
getRegisteredPackages,
131-
getBatchCachedNpmPackageStats,
132-
} = await import('~/utils/stats-db.server')
133-
134-
const libraryStats = await getCachedLibraryStats(libraryId)
135-
if (!libraryStats) {
123+
const library = libraries.find((item) => item.id === libraryId)
124+
if (!library) {
136125
throw new Error(
137126
`Library "${libraryId}" not found. Use list_libraries to see available libraries.`,
138127
)
139128
}
140129

141-
const packageNames = await getRegisteredPackages(libraryId)
142-
const packageStats = await getBatchCachedNpmPackageStats(packageNames)
130+
const packageNames =
131+
library.npmPackageNames ??
132+
(library.corePackageName ? [library.corePackageName] : [])
143133

144-
const packages = packageNames
145-
.map((name) => {
146-
const stats = packageStats.get(name)
147-
return {
148-
name,
149-
downloads: stats?.downloads ?? 0,
150-
ratePerDay: stats?.ratePerDay ?? 0,
151-
}
152-
})
153-
.sort((a, b) => b.downloads - a.downloads)
134+
if (packageNames.length === 0) {
135+
throw new Error(`Library "${libraryId}" does not declare NPM packages.`)
136+
}
137+
138+
const comparison = await comparePackages(packageNames, 'all', 'monthly')
139+
const packages = comparison.packages.map((pkg) => ({
140+
name: pkg.name,
141+
downloads: pkg.total,
142+
ratePerDay: pkg.avgPerDay,
143+
}))
154144

155145
return {
156146
library: libraryId,
157-
totalDownloads: libraryStats.totalDownloads,
147+
totalDownloads: packages.reduce((sum, p) => sum + p.downloads, 0),
158148
ratePerDay: packages.reduce((sum, p) => sum + p.ratePerDay, 0),
159149
packages,
160150
}

0 commit comments

Comments
 (0)