File size: 2,039 Bytes
9d2d895
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { getRpcBaseUrl } from '@/services/rpc-client';
import type { ArxivPaper, GithubRepo, HackernewsItem } from '@/generated/client/worldmonitor/research/v1/service_client';
import { createCircuitBreaker } from '@/utils';
import { ResearchServiceClient } from '@/services/generated-rpc-clients';

// Re-export proto types (no legacy mapping needed -- proto types are clean)
export type { ArxivPaper, GithubRepo, HackernewsItem };

const client = new ResearchServiceClient(getRpcBaseUrl(), { fetch: (...args) => globalThis.fetch(...args) });

const arxivBreaker = createCircuitBreaker<ArxivPaper[]>({ name: 'ArXiv Papers', cacheTtlMs: 10 * 60 * 1000, persistCache: true });
const trendingBreaker = createCircuitBreaker<GithubRepo[]>({ name: 'GitHub Trending', cacheTtlMs: 10 * 60 * 1000, persistCache: true });
const hnBreaker = createCircuitBreaker<HackernewsItem[]>({ name: 'Hacker News', cacheTtlMs: 10 * 60 * 1000, persistCache: true });

export async function fetchArxivPapers(
  category = 'cs.AI',
  query = '',
  pageSize = 50,
): Promise<ArxivPaper[]> {
  return arxivBreaker.execute(async () => {
    const resp = await client.listArxivPapers({
      category,
      query,
      pageSize,
      cursor: '',
    });
    return resp.papers;
  }, [], { cacheKey: `${category}:${query}:${pageSize}` });
}

export async function fetchTrendingRepos(
  language = 'python',
  period = 'daily',
  pageSize = 50,
): Promise<GithubRepo[]> {
  return trendingBreaker.execute(async () => {
    const resp = await client.listTrendingRepos({
      language,
      period,
      pageSize,
      cursor: '',
    });
    return resp.repos;
  }, [], { cacheKey: `${language}:${period}:${pageSize}` });
}

export async function fetchHackernewsItems(
  feedType = 'top',
  pageSize = 30,
): Promise<HackernewsItem[]> {
  return hnBreaker.execute(async () => {
    const resp = await client.listHackernewsItems({
      feedType,
      pageSize,
      cursor: '',
    });
    return resp.items;
  }, [], { cacheKey: `${feedType}:${pageSize}` });
}