import { cookies } from 'next/headers' import { type DocumentNode } from "graphql"; import { type OperationVariables, ApolloClient } from "@apollo/client"; import {getClient} from "@/lib/ApolloClientServer"; import {IS_GUEST,GUEST_CART_TOKEN} from "@/utils/constants"; import { decodeJWT } from "@/utils/jwt-cookie"; /* 定义自己的context类型 import "@apollo/client"; import { HttpLink } from "@apollo/client"; declare module "@apollo/client" { interface DefaultContext extends HttpLink.ContextOptions {} } */ // Comprehensive error handling example. https://www.apollographql.com/docs/react/data/error-handling export interface GraphqlRequestResult { data: TData | null; error: string | undefined; } export type CacheLifePreset = | "seconds" | "minutes" | "hours" | "days" | "weeks" | "max"; export type CacheLifeOption = number | CacheLifePreset; export function getRevalidateTime( life?: CacheLifeOption ): number | false { if (!life) return false; if (typeof life === "number") return life; switch (life) { case "seconds": return 10; case "minutes": return 60; case "hours": return 3600; case "days": return 86400; case "weeks": return 604800; case "max": return false; default: return false; } } export function stableStringify(value: unknown): string { if (value === null || typeof value !== "object") { return JSON.stringify(value); } if (Array.isArray(value)) { return `[${value.map(stableStringify).join(",")}]`; } const obj = value as Record; return `{${Object.keys(obj) .sort() .map( (key) => `"${key}":${stableStringify(obj[key])}` ) .join(",")}}`; } export interface GraphQLRequestOptions { tags?: string[]; life?: CacheLifeOption; noCache?: boolean; context?: Record; fetchPolicy?: | "cache-first" | "network-only" | "no-cache" | "cache-only"; } export async function graphqlRequest< TData = unknown, TVariables extends OperationVariables = OperationVariables >( query: DocumentNode, variables?: TVariables, options?: GraphQLRequestOptions ): Promise> { const client = getClient(); let resData; const revalidate = getRevalidateTime(options?.life); let queryOption: ApolloClient.QueryOptions = { query, variables, fetchPolicy: "network-only", context: { fetchOptions: { next: { revalidate, tags: options?.tags, }, }, } }; if (options?.noCache) { /*** * client.query的参数是一个对象: * {query, variables, context, fetchPolicy, errorPolicy} * context.fetchOptions 可以设置nextjs fetch的缓存策略 https://www.apollographql.com/docs/react/integrations/nextjs * context: { fetchOptions: { next: { revalidate: 60, // 对应 life: 'minutes' tags: ['posts'], // 对应 tags 选项 }, }, }, */ queryOption = { query, variables, context: options?.context, fetchPolicy: "no-cache", // 跳过 apollo client 的缓存,直接调fetch }; } if (options?.context) { throw new Error( "graphqlRequest: Caching with `context` is unsafe. Use noCache instead." ); } try { // Promise-based APIs (e.g. client.query, client.mutate) - Errors either reject the promise or are returned in the result as the error field. // 如果错误被reject 则会进入catch const result: ApolloClient.QueryResult = await client.query(queryOption); resData = result.data || null; return {data: resData, error: result.error? result.error.message : '' }; } catch (error) { throw error; } } export async function graphqlRequestNoCache< TData = unknown, TVariables extends OperationVariables = OperationVariables >( query: DocumentNode, variables?: TVariables, options?: Omit< GraphQLRequestOptions, "noCache" | "tags" | "life" > ): Promise> { return graphqlRequest( query, variables, { ...options, noCache: true, } ); } export async function authorizationGraphqlRequest< TData = unknown, TVariables extends OperationVariables = OperationVariables >( query: DocumentNode, variables?: TVariables, ): Promise> { const cookieStore = await cookies(); const isGuest = cookieStore.get(IS_GUEST); const authToken = cookieStore.get(GUEST_CART_TOKEN); let token = ''; if(!authToken) { return {data: null, error: 'Authorization token not found!'}; } if(isGuest?.value === 'false') { // 登录用户 token = authToken.value; } else { // 游客 const jwtRes = decodeJWT<{ sessionToken: string; cartId: number; isGuest: boolean; }>(authToken.value, true); token = jwtRes?.sessionToken || ''; } const client = getClient(); try { const queryOption: ApolloClient.QueryOptions = { query, variables, fetchPolicy: "no-cache", context: { headers: { "Authorization": "Bearer " + token, }, fetchOptions: { cache: 'no-store', }, } }; const result: ApolloClient.QueryResult = await client.query(queryOption); console.log('authorizationGraphqlRequest result ---- ', result); const resData = result.data || null; return {data: resData, error: result.error? result.error.message : '' }; } catch (error) { throw error; } } export async function fullCacheGraphqlRequest< TData = unknown, TVariables extends OperationVariables = OperationVariables >( query: DocumentNode, variables?: TVariables, ): Promise> { const client = getClient(); try { const queryOption: ApolloClient.QueryOptions = { query, variables, fetchPolicy: "cache-first", context: { fetchOptions: { cache: 'force-cache', }, } }; const result: ApolloClient.QueryResult = await client.query(queryOption); console.log('authorizationGraphqlRequest result ---- ', result); const resData = result.data || null; return {data: resData, error: result.error? result.error.message : '' }; } catch (error) { throw error; } }