Skip to content

Commit adc0b8d

Browse files
committed
修改跨域
1 parent 6f6ba2c commit adc0b8d

3 files changed

Lines changed: 132 additions & 0 deletions

File tree

src/app/api/azuro-graphql/route.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
3+
/**
4+
* 与 @azuro-org/toolkit 中一致的 chainId -> 子路径映射
5+
* 用于服务端转发到正确的 GraphQL 端点,避免浏览器直连时的 CORS
6+
*/
7+
const ENDPOINT_NAME_BY_CHAIN_ID: Record<number, string> = {
8+
100: 'gnosis', // gnosis
9+
137: 'polygon', // polygon
10+
80002: 'polygon-amoy-dev', // polygonAmoy
11+
88882: 'chiliz', // chiliz
12+
88888: 'chiliz-spicy-dev', // spicy
13+
8453: 'base', // base
14+
84532: 'base-sepolia-dev', // baseSepolia
15+
97: 'bsc-dev', // bscTestnet
16+
56: 'bsc', // bsc
17+
}
18+
19+
const DEV_CHAIN_IDS = new Set([80002, 88888, 84532, 97])
20+
21+
function getFeedGraphqlEndpoint(chainId: number): string {
22+
const name = ENDPOINT_NAME_BY_CHAIN_ID[chainId]
23+
if (!name) throw new Error(`Unsupported chainId for feed: ${chainId}`)
24+
return `https://thegraph-1.chainfeedon.com/subgraphs/name/azuro-protocol/azuro-data-feed-${name}`
25+
}
26+
27+
function getBetsGraphqlEndpoint(chainId: number): string {
28+
const name = ENDPOINT_NAME_BY_CHAIN_ID[chainId]
29+
if (!name) throw new Error(`Unsupported chainId for bets: ${chainId}`)
30+
return `https://thegraph.chainfeedon.com/subgraphs/name/azuro-protocol/azuro-api-${name}-v3`
31+
}
32+
33+
function getLegacyLiveGraphqlEndpoint(chainId: number): string {
34+
if (DEV_CHAIN_IDS.has(chainId)) {
35+
return 'https://thegraph.chainfeedon.com/subgraphs/name/azuro-protocol/azuro-api-live-data-feed-dev'
36+
}
37+
return 'https://thegraph.chainfeedon.com/subgraphs/name/azuro-protocol/azuro-api-live-data-feed'
38+
}
39+
40+
function getTargetUrl(chainId: number, type: 'feed' | 'bets' | 'legacyLive'): string {
41+
switch (type) {
42+
case 'feed':
43+
return getFeedGraphqlEndpoint(chainId)
44+
case 'bets':
45+
return getBetsGraphqlEndpoint(chainId)
46+
case 'legacyLive':
47+
return getLegacyLiveGraphqlEndpoint(chainId)
48+
default:
49+
throw new Error(`Unknown type: ${type}`)
50+
}
51+
}
52+
53+
export async function POST(request: NextRequest) {
54+
try {
55+
const { searchParams } = new URL(request.url)
56+
const chainIdStr = searchParams.get('chainId')
57+
const type = (searchParams.get('type') || 'feed') as 'feed' | 'bets' | 'legacyLive'
58+
59+
if (!chainIdStr) {
60+
return NextResponse.json(
61+
{ error: 'Missing query param: chainId' },
62+
{ status: 400 }
63+
)
64+
}
65+
66+
const chainId = parseInt(chainIdStr, 10)
67+
if (Number.isNaN(chainId) || !ENDPOINT_NAME_BY_CHAIN_ID[chainId]) {
68+
return NextResponse.json(
69+
{ error: `Unsupported or invalid chainId: ${chainIdStr}` },
70+
{ status: 400 }
71+
)
72+
}
73+
74+
const targetUrl = getTargetUrl(chainId, type)
75+
const body = await request.json()
76+
77+
const forwardParams = new URLSearchParams(searchParams)
78+
forwardParams.delete('chainId')
79+
forwardParams.delete('type')
80+
const queryString = forwardParams.toString()
81+
const url = queryString ? `${targetUrl}?${queryString}` : targetUrl
82+
83+
const res = await fetch(url, {
84+
method: 'POST',
85+
headers: {
86+
'Content-Type': 'application/json',
87+
Accept: 'application/graphql-response+json',
88+
},
89+
body: JSON.stringify(body),
90+
cache: 'no-store',
91+
})
92+
93+
const data = await res.json()
94+
95+
if (!res.ok) {
96+
return NextResponse.json(data, { status: res.status })
97+
}
98+
99+
return NextResponse.json(data)
100+
} catch (err) {
101+
console.error('[azuro-graphql] proxy error:', err)
102+
return NextResponse.json(
103+
{ error: err instanceof Error ? err.message : 'Proxy failed' },
104+
{ status: 500 }
105+
)
106+
}
107+
}

src/compositions/Providers/Providers.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ import { SvgProvider, SvgSprite } from 'svg-provider'
99
import { AzuroSDKProvider, LiveProvider } from '@azuro-org/sdk'
1010
import { WagmiProvider } from 'wallet'
1111
import { DeviceProvider, LocaleProvider, OddsViewProvider } from 'contexts'
12+
import { patchAzuroChainsForCors } from 'helpers/patchAzuroChainsForCors'
1213
import type { Locale } from 'i18n/config'
1314

1415
import NewFreeBetsChecker from 'compositions/NewFreeBetsChecker/NewFreeBetsChecker'
1516

17+
// 将 Azuro GraphQL 请求改为走同源代理,避免 CORS
18+
patchAzuroChainsForCors()
19+
1620

1721
type Props = {
1822
locale: Locale
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* 在客户端将 Azuro GraphQL 请求改为走同源代理,避免直连 thegraph 时的 CORS。
3+
* 必须在 AzuroSDKProvider 使用 chainsData 之前执行(在 Providers 中引入即可)。
4+
*/
5+
import { chainsData } from '@azuro-org/toolkit'
6+
7+
const PROXY_PATH = '/api/azuro-graphql'
8+
9+
export function patchAzuroChainsForCors(): void {
10+
if (typeof window === 'undefined') return
11+
12+
Object.keys(chainsData).forEach((key) => {
13+
const chainId = Number(key)
14+
const chain = chainsData[chainId as keyof typeof chainsData]
15+
if (chain?.graphql) {
16+
chain.graphql.feed = `${PROXY_PATH}?chainId=${chainId}&type=feed`
17+
chain.graphql.bets = `${PROXY_PATH}?chainId=${chainId}&type=bets`
18+
chain.graphql.legacyLive = `${PROXY_PATH}?chainId=${chainId}&type=legacyLive`
19+
}
20+
})
21+
}

0 commit comments

Comments
 (0)