Skip to content

Commit 8b2719c

Browse files
committed
feat: added all endpoints
1 parent 0682c73 commit 8b2719c

File tree

10 files changed

+117
-78
lines changed

10 files changed

+117
-78
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { NextResponse } from "next/server";
2+
import { stringify } from "superjson";
3+
4+
import { getFeeds } from '../../../../../server/pyth/get-feeds';
5+
import { Cluster } from "../../../../../services/pyth";
6+
7+
export const GET = async (request: Request, { params }: { params: Promise<{ publisher: string }> }) => {
8+
const { publisher } = await params;
9+
// get cluster from query params
10+
const { searchParams } = new URL(request.url);
11+
const cluster = Number.parseInt(searchParams.get("cluster") ?? Cluster.Pythnet.toString()) as Cluster;
12+
// check if cluster is valid
13+
if (cluster && !Object.values(Cluster).includes(cluster)) {
14+
return NextResponse.json({ error: "Invalid cluster" }, { status: 400 });
15+
}
16+
if (!publisher) {
17+
return NextResponse.json({ error: "Publisher is required" }, { status: 400 });
18+
}
19+
const feeds = await getFeeds(cluster);
20+
const filteredFeeds = feeds.filter((feed) => feed.price.priceComponents.some((c) => c.publisher === publisher));
21+
22+
return new Response(stringify(filteredFeeds), {
23+
headers: {
24+
'Content-Type': 'application/json',
25+
},
26+
});
27+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { NextResponse } from "next/server";
2+
3+
import { getPublishersForCluster } from "../../../../../server/pyth/get-publishers-for-cluster";
4+
import { Cluster } from "../../../../../services/pyth";
5+
6+
export const GET = async (request: Request, { params }: { params: Promise<{ symbol: string }> }) => {
7+
const { symbol } = await params;
8+
// get cluster from query params
9+
const { searchParams } = new URL(request.url);
10+
const cluster = Number.parseInt(searchParams.get("cluster") ?? Cluster.Pythnet.toString()) as Cluster;
11+
// check if cluster is valid
12+
if (cluster && !Object.values(Cluster).includes(cluster)) {
13+
return NextResponse.json({ error: "Invalid cluster" }, { status: 400 });
14+
}
15+
if (!symbol) {
16+
return NextResponse.json({ error: "Symbol is required" }, { status: 400 });
17+
}
18+
const map = await getPublishersForCluster(cluster);
19+
return NextResponse.json(map[symbol] ?? []);
20+
};

apps/insights/src/app/api/pyth/get-publishers/route.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

apps/insights/src/components/PriceFeed/publishers.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export const Publishers = async ({ params }: Props) => {
9191
export const PublishersLoading = () => <PublishersCard isLoading />;
9292

9393
const getPublishers = async (cluster: Cluster, symbol: string) => {
94+
9495
const [publishers, rankings] = await Promise.all([
9596
getPublishersForFeedCached(cluster, symbol),
9697
getRankingsBySymbolCached(symbol),

apps/insights/src/components/Publishers/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export const Publishers = async () => {
3131
getPublishersCached(Cluster.PythtestConformance),
3232
getOisStats(),
3333
]);
34-
3534
const rankingTime = pythnetPublishers[0]?.timestamp;
3635
const scoreTime = pythnetPublishers[0]?.scoreTime;
3736

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,47 @@
11
import { getPublisherAverageScoreHistory, getPublisherRankingHistory, getPublishers, getRankingsByPublisher, getRankingsBySymbol } from "../services/clickhouse";
2-
import { Cluster } from "../services/pyth";
2+
import { redisCache } from '../utils/cache';
33

4-
export const getRankingsBySymbolCached = async (symbol: string) => {
5-
return getRankingsBySymbol(symbol);
6-
};
4+
export const getRankingsBySymbolCached = redisCache.define(
5+
"getRankingsBySymbol",
6+
{
7+
ttl: 1000 * 60 * 60 * 24,
8+
},
9+
getRankingsBySymbol,
10+
).getRankingsBySymbol;
711

8-
export const getRankingsByPublisherCached = async (publisherKey: string) => {
9-
return getRankingsByPublisher(publisherKey);
10-
};
12+
export const getRankingsByPublisherCached = redisCache.define(
13+
"getRankingsByPublisher",
14+
{
15+
ttl: 1000 * 60 * 60 * 24,
16+
},
17+
getRankingsByPublisher,
18+
).getRankingsByPublisher;
1119

12-
export const getPublisherAverageScoreHistoryCached = async (cluster: Cluster, key: string) => {
13-
return getPublisherAverageScoreHistory(cluster, key);
14-
};
1520

16-
export const getPublisherRankingHistoryCached = async (cluster: Cluster, key: string) => {
17-
return getPublisherRankingHistory(cluster, key);
18-
};
21+
export const getPublishersCached = redisCache.define(
22+
"getPublishers",
23+
{
24+
ttl: 1000 * 60 * 60 * 24,
25+
},
26+
getPublishers,
27+
).getPublishers;
1928

20-
export const getPublishersCached = async (cluster: Cluster) => {
21-
return getPublishers(cluster);
22-
}
29+
export const getPublisherAverageScoreHistoryCached = redisCache.define(
30+
"getPublisherAverageScoreHistory",
31+
{
32+
ttl: 1000 * 60 * 60 * 24,
33+
},
34+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
35+
// @ts-expect-error
36+
getPublisherAverageScoreHistory,
37+
).getPublisherAverageScoreHistory as typeof getPublisherAverageScoreHistory;
38+
39+
export const getPublisherRankingHistoryCached = redisCache.define(
40+
"getPublisherRankingHistory",
41+
{
42+
ttl: 1000 * 60 * 60 * 24,
43+
},
44+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
45+
// @ts-expect-error
46+
getPublisherRankingHistory,
47+
).getPublisherRankingHistory as typeof getPublisherRankingHistory;

apps/insights/src/server/pyth.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,37 @@
1+
import { parse, } from "superjson";
2+
import { z } from "zod";
3+
4+
import { PUBLIC_URL, VERCEL_AUTOMATION_BYPASS_SECRET } from '../config/server';
15
import { Cluster, priceFeedsSchema } from "../services/pyth";
2-
import { getFeeds } from './pyth/get-feeds';
3-
import { getPublishersForCluster } from './pyth/get-publishers-for-cluster';
46

57
// Convenience helpers matching your previous functions
68
export async function getPublishersForFeedCached(
79
cluster: Cluster,
810
symbol: string
911
) {
10-
const map = await getPublishersForCluster(cluster);
11-
return map[symbol] ?? [];
12+
const data = await fetch(`${PUBLIC_URL}/api/pyth/get-publishers/${encodeURIComponent(symbol)}?cluster=${cluster.toString()}`, {
13+
next: {
14+
revalidate: 1000 * 60 * 60 * 24,
15+
},
16+
headers: {
17+
'x-vercel-protection-bypass': VERCEL_AUTOMATION_BYPASS_SECRET,
18+
},
19+
});
20+
return data.json() as Promise<string[]>;
1221
}
1322

1423
export async function getFeedsForPublisherCached(
1524
cluster: Cluster,
1625
publisher: string
1726
) {
18-
// eslint-disable-next-line no-console
19-
console.log('getFeedsForPublisherCached');
20-
const data = await getFeeds(cluster);
21-
return priceFeedsSchema.parse(
22-
data.filter(({ price }) =>
23-
price.priceComponents.some((c) => c.publisher === publisher)
24-
)
25-
);
27+
const data = await fetch(`${PUBLIC_URL}/api/pyth/get-feeds-for-publisher/${encodeURIComponent(publisher)}?cluster=${cluster.toString()}`, {
28+
next: {
29+
revalidate: 1000 * 60 * 60 * 24,
30+
},
31+
headers: {
32+
'x-vercel-protection-bypass': VERCEL_AUTOMATION_BYPASS_SECRET,
33+
},
34+
});
35+
const rawData = await data.text();
36+
return parse<z.infer<typeof priceFeedsSchema>>(rawData);
2637
}
Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
1-
// disable file
2-
// @typescript-eslint/no-unused-vars
31
import { z } from 'zod';
42

5-
63
import { getPythMetadata } from './get-metadata';
74
import { Cluster, priceFeedsSchema } from "../../services/pyth";
85
import { redisCache } from '../../utils/cache';
96

10-
11-
/**
12-
* Prepare a JSON-serializable version for Redis (strip Maps / transform).
13-
* This is what we actually persist in L2 (Redis).
14-
*/
157
const _getFeeds = async (cluster: Cluster) => {
168
const unfilteredData = await getPythMetadata(cluster);
179
const filtered = unfilteredData.symbols
@@ -45,24 +37,6 @@ export const getFeedsCached = redisCache.define(
4537
_getFeeds,
4638
).getFeeds;
4739

48-
49-
50-
5140
export const getFeeds = async (cluster: Cluster): Promise<z.infer<typeof priceFeedsSchema>> => {
52-
// eslint-disable-next-line no-console
53-
console.log('getFeeds function called');
5441
return getFeedsCached(cluster);
5542
};
56-
57-
// const _getFeedsBySymbol = async (cluster: Cluster, symbol: string) => {
58-
// const feeds = await getFeeds(cluster);
59-
// return feeds.find((feed) => feed.symbol === symbol);
60-
// };
61-
62-
// export const getFeedsBySymbol = redisCache.define(
63-
// "getFeedsBySymbol",
64-
// {
65-
// ttl: 1000 * 60 * 60 * 24,
66-
// },
67-
// _getFeedsBySymbol,
68-
// ).getFeedsBySymbol;

apps/insights/src/server/pyth/get-publishers-for-cluster.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { getPythMetadata } from './get-metadata';
22
import { Cluster } from '../../services/pyth';
33
import { redisCache } from '../../utils/cache';
44

5-
6-
// Publishers map (plain JSON) → good candidate for Redis
75
const _computePublishers = async (cluster: Cluster) => {
86
const data = await getPythMetadata(cluster);
97
const result: Record<string, string[]> = {};

apps/insights/src/utils/cache.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import type { Cache as ACDCache } from "async-cache-dedupe";
22
import { createCache } from "async-cache-dedupe";
3+
import { serialize, deserialize } from "superjson";
34

45
import { getRedis } from '../config/server';
56

67
// L2-backed cache: in-memory LRU (L1) + Redis (L2)
78
export const redisCache: ACDCache = createCache({
9+
transformer: {
10+
serialize,
11+
deserialize,
12+
},
813
storage: {
914
type: "redis",
1015
options: {

0 commit comments

Comments
 (0)