Files
webapp/app/composables/useGraphQL.ts
2026-01-07 09:10:35 +07:00

120 lines
3.2 KiB
TypeScript

import type { TypedDocumentNode } from '@graphql-typed-document-node/core'
type Endpoint = 'user' | 'team' | 'public'
type Api = 'teams' | 'exchange' | 'kyc' | 'orders' | 'geo' | 'billing'
const RESOURCE_MAP: Record<Api, string> = {
teams: 'https://teams.optovia.ru',
orders: 'https://orders.optovia.ru',
kyc: 'https://kyc.optovia.ru',
exchange: 'https://exchange.optovia.ru',
geo: 'https://geo.optovia.ru',
billing: 'https://billing.optovia.ru'
}
const CLIENT_MAP: Record<string, string> = {
'public:exchange': 'default',
'public:geo': 'publicGeo',
'user:teams': 'teamsUser',
'user:kyc': 'kycUser',
'team:teams': 'teamsTeam',
'team:exchange': 'exchangeTeam',
'team:orders': 'ordersTeam',
'team:billing': 'billingTeam'
}
export const useGraphQL = () => {
const auth = useAuth()
const { activeLogtoOrgId } = useActiveTeam()
const getClientId = (endpoint: Endpoint, api: Api): string => {
return CLIENT_MAP[`${endpoint}:${api}`] || 'default'
}
const getTokenType = (endpoint: Endpoint): 'id' | 'access' | 'none' => {
if (endpoint === 'user') return 'id'
if (endpoint === 'team') return 'access'
return 'none'
}
const getAuthContext = async (endpoint: Endpoint, api: Api) => {
const tokenType = getTokenType(endpoint)
if (tokenType === 'none') return {}
let token: string | null = null
if (tokenType === 'id') {
try {
token = (await auth.getIdToken()) ?? null
}
catch (e) {
console.warn('Failed to get ID token:', e)
}
}
else if (tokenType === 'access') {
try {
token = await auth.getAccessToken(RESOURCE_MAP[api], activeLogtoOrgId.value || undefined)
}
catch (e) {
console.warn('Failed to get access token:', e)
}
}
if (!token) {
throw new Error('User not authenticated')
}
return { headers: { Authorization: `Bearer ${token}` } }
}
const execute = async <TResult, TVariables extends Record<string, unknown>>(
document: TypedDocumentNode<TResult, TVariables>,
variables: TVariables,
endpoint: Endpoint,
api: Api
): Promise<TResult> => {
const clientId = getClientId(endpoint, api)
const { client } = useApolloClient(clientId)
const context = await getAuthContext(endpoint, api)
const result = await client.query({
query: document,
variables,
context,
fetchPolicy: 'network-only'
})
if (result.errors?.length) {
throw new Error(result.errors[0]?.message || 'GraphQL error')
}
return result.data as TResult
}
const mutate = async <TResult, TVariables extends Record<string, unknown>>(
document: TypedDocumentNode<TResult, TVariables>,
variables: TVariables,
endpoint: Endpoint,
api: Api
): Promise<TResult> => {
const clientId = getClientId(endpoint, api)
const { client } = useApolloClient(clientId)
const context = await getAuthContext(endpoint, api)
const result = await client.mutate({
mutation: document,
variables,
context
})
if (result.errors?.length) {
throw new Error(result.errors[0]?.message || 'GraphQL error')
}
return result.data as TResult
}
return { execute, mutate }
}