| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- import { cookies } from "next/headers";
- import { auth } from "@/utils/auth/auth-helper";
- import { print, DocumentNode } from "graphql";
- import {
- GRAPHQL_URL,
- REST_API_URL,
- } from "@/utils/constants/server";
- import {
- GUEST_CART_TOKEN,
- CURRENT_CURRENCY,
- CURRENT_LOCAL,
- CURRENT_CHANNEL,
- } from "@/utils/constants";
- import {
- GET_FOOTER,
- PAGE_BY_URL_KEY,
- } from "@/graphql";
- import { SUBSCRIBE_TO_NEWSLETTER } from "@/graphql/theme/mutations";
- import { cachedGraphQLRequest } from "@/utils/hooks/useCache";
- import {
- GetFooterResponse,
- ThemeCustomizationResult,
- PageData,
- } from "@/types/theme/theme-customization";
- import {FetchGraphqlResult} from "@/types/graphqlFetch/type";
- type ExtractVariables<T> = T extends { variables: object }
- ? T["variables"]
- : any;
- type ExtractRestFulData<T> = T extends { data: infer D } ? D : any;
- type ExtractGraphqlData<T> = T extends { data: infer D } ? { data: D } : any;
- interface PageByUrlKeyResponse {
- pageByUrlKeypages?: PageData[];
- }
- const STOREFRONT_KEY = process.env.NEXT_PUBLIC_BAGISTO_STOREFRONT_KEY;
- async function getBaseHeader() {
- /**
- * Headers:
- * X-LOCALE — locale code, e.g. "en", "fr", "ar"
- * X-CHANNEL — channel code, e.g. "default"
- * X-CURRENCY — currency code, e.g. "USD", "EUR", "INR"
- * */
-
- if(!STOREFRONT_KEY) {
- throw new Error("STOREFRONT_KEY must be configed!");
- }
- const cookieStore = await cookies();
- const xCurrency = cookieStore.get(CURRENT_CURRENCY)?.value; // 在proxy.ts中已经设置过值了
- const xLocal = cookieStore.get(CURRENT_LOCAL)?.value; // 在proxy.ts中已经设置过值了
- const xChannel = cookieStore.get(CURRENT_CHANNEL)?.value; // 在proxy.ts中已经设置过值了
- const baseHeaders: Record<string, string> = {
- "Content-Type": "application/json",
- "X-STOREFRONT-KEY": STOREFRONT_KEY,
-
- };
- if(xCurrency) {
- baseHeaders["X-Currency"] = xCurrency;
- }
- if(xLocal) {
- baseHeaders["X-Local"] = xLocal;
- }
- if(xChannel) {
- baseHeaders["X-Channel"] = xChannel;
- }
- return baseHeaders;
- }
- export async function getAuthorizationToken(): Promise<{token: string | null; isGuest: boolean;}> {
-
- // 登录用户从nextAuth里获取
- /*
- const tokenCookie =
- cookieStore.get("next-auth.session-token")
- ?? cookieStore.get("__Secure-next-auth.session-token");
- if (tokenCookie?.value) {
- const token = await decode({
- token: tokenCookie.value,
- secret: process.env.NEXTAUTH_SECRET!,
- });
- console.log('getAuthorizationToken decode ===============',token);
- return {
- token: token?.accessToken ?? '',
- isGuest: false,
- };
- }
- */
- const authSession = await auth();
- const accessToken = authSession?.user?.accessToken;
- if (accessToken) {
- return {
- token: accessToken,
- isGuest: false,
- };
- }
- // 游客从cookie里获取
- const cookieStore = await cookies();
- const guestToken = cookieStore.get(GUEST_CART_TOKEN)?.value;
-
- return {
- token: guestToken || null,
- isGuest: true
- };
- }
- // rest api fetch
- export async function restApiFetch<T>({
- api,
- method,
- cache = "force-cache",
- headers,
- tags,
- variables,
- isRoute = true,
- revalidate = 60,
- takeAuthorization = true, // 是否携带token,默认携带
- }: {
- api: string;
- method: "POST" | "GET" | "PUT" | "DELETE";
- cache?: RequestCache;
- headers?: HeadersInit | Record<string, string>;
- tags?: string[];
- variables?: ExtractVariables<T>;
- isRoute?: boolean; // 是否是在route handle中调用
- guestToken?: string;
- revalidate?: number;
- takeAuthorization?: boolean;
- }): Promise<{ status: number; body: ExtractRestFulData<T> } | never> {
- try {
- const apiUrl = api.startsWith("http") ? api : `${REST_API_URL}${api}`;
- const url = new URL(apiUrl);
-
- const headerRes = await getBaseHeader();
- const baseHeaders: Record<string, string> = {...headerRes};
- if(takeAuthorization) {
- const tokenRes = await getAuthorizationToken();
- if (tokenRes.token) {
- baseHeaders.Authorization = `Bearer ${tokenRes.token}`;
- }
- }
- if (headers) {
- if (headers instanceof Headers) {
- headers.forEach((value, key) => (baseHeaders[key] = value));
- } else {
- Object.assign(baseHeaders, headers);
- }
- }
- console.log('restApiFetch --- baseHeaders:', baseHeaders)
- const param: RequestInit = {
- method: method,
- headers: baseHeaders,
- cache,
- next: {
- revalidate: cache === "no-store" ? 0 : revalidate || 60,
- ...(tags && { tags }),
- },
- };
- if(variables && method === "POST") {
- param.body = JSON.stringify({...variables});
- }
- if(variables && method === "GET") {
- const entries = Object.entries(variables as Record<string, unknown>);
- for (const [key, val] of entries) {
- if (val !== undefined && val !== null) {
- url.searchParams.set(key, String(val));
- }
- }
- }
- const result = await fetch(url, param);
- const body = await result.json();
- console.log('restApiFetch --- body:', body)
- if(!isRoute) {
- if(result.status === 401) {
- const err = new Error('Authorization Bearer token is required. Please Login.');//new Error(body.message || 'Authorization Bearer token is required');
- err.name = "UnauthorizedError";
- throw err;
- }
-
- }
- return { status: result.status, body };
- } catch (e) {
- throw e;
- }
- }
- // graphql fetch use for server side
- export async function serverGraphqlFetch<
- TData,
- TVariables = Record<string, never>
- >({
- cache = "no-store",
- headers,
- query,
- tags,
- variables,
- revalidate = 0,
- takeAuthorization = true, // 是否携带token,默认携带
- }: {
- cache?: RequestCache;
- headers?: HeadersInit | Record<string, string>;
- query: string | DocumentNode;
- tags?: string[];
- variables?: TVariables;
- revalidate?: number;
- takeAuthorization?: boolean;
- }): Promise<FetchGraphqlResult<TData>> {
- try {
- const queryString = typeof query === "string" ? query : print(query);
-
- const headerRes = await getBaseHeader();
- const baseHeaders: Record<string, string> = {...headerRes};
-
- if(takeAuthorization) {
- const tokenRes = await getAuthorizationToken();
- if (tokenRes.token) {
- baseHeaders['Authorization'] = `Bearer ${tokenRes.token}`;
- }
- }
- if (headers) {
- if (headers instanceof Headers) {
- headers.forEach((value, key) => (baseHeaders[key] = value));
- } else {
- Object.assign(baseHeaders, headers);
- }
- }
- console.log('serverGraphqlFetch --- baseHeaders:', baseHeaders);
- const result = await fetch(GRAPHQL_URL, {
- method: "POST",
- headers: baseHeaders,
- body: JSON.stringify({
- query: queryString,
- ...(variables && { variables }),
- }),
- cache,
- next: {
- revalidate: cache === "no-store" ? 0 : revalidate || 60,
- ...(tags && { tags }),
- },
- });
- const body = await result.json();
- const err = body.errors?.[0] ?? null;
- if(err && err.extensions.status === 401) {
- // "UNAUTHENTICATED"
- const err = new Error('Authorization Bearer token is required. Please Login.');
- err.name = "UnauthorizedError";
- throw err;
- }
- return {
- status:result.status,
- data:body.data || null,
- error: err
- }
- } catch (e) {
- console.error( "GraphQL request failed", e );
- throw e;
- }
- }
- // graphql fetch use for route handler
- export async function bagistoFetch<T>({
- cache = "force-cache",
- headers,
- query,
- tags,
- variables,
- // isCookies = true,
- // guestToken,
- takeAuthorization = true, // 是否携带token,默认携带
- revalidate = 60,
- }: {
- cache?: RequestCache;
- headers?: HeadersInit | Record<string, string>;
- query: string | DocumentNode;
- tags?: string[];
- variables?: ExtractVariables<T>;
- // isCookies?: boolean;
- // guestToken?: string;
- takeAuthorization?: boolean;
- revalidate?: number;
- }): Promise<{ status: number; body: ExtractGraphqlData<T> } | never> {
- try {
- const queryString =
- typeof query === "string" ? query : print(query);
-
- const headerRes = await getBaseHeader();
- const baseHeaders: Record<string, string> = {...headerRes};
- if(takeAuthorization) {
- const tokenRes = await getAuthorizationToken();
- if (tokenRes.token) {
- baseHeaders.Authorization = `Bearer ${tokenRes.token}`;
- }
- }
-
-
- if (headers) {
- if (headers instanceof Headers) {
- headers.forEach((value, key) => (baseHeaders[key] = value));
- } else {
- Object.assign(baseHeaders, headers);
- }
- }
- // let cc = await cookies();
- // console.log('bagistoFetch --- url:', GRAPHQL_URL,isCookies);
- // console.log('bagistoFetch --- queryString:', queryString);
- console.log('bagistoFetch --- baseHeaders:', baseHeaders);
- // console.log('bagistoFetch --- cookies:', cc.getAll());
- // console.log('bagistoFetch --- variables:', variables);
- const result = await fetch(GRAPHQL_URL, {
- method: "POST",
- headers: baseHeaders,
- body: JSON.stringify({
- query: queryString,
- ...(variables && { variables }),
- }),
- cache,
- next: {
- revalidate: cache === "no-store" ? 0 : revalidate || 60,
- ...(tags && { tags }),
- },
- });
- const body = await result.json();
- console.log('bagistoFetch --- body:',body);
- return { status: result.status, body };
- } catch (e) {
- throw e;
- }
- }
- export async function subscribeUser(
- input: Record<string, unknown>,
- ): Promise<unknown> {
- try {
- return await bagistoFetch<{
- data: unknown;
- variables: Record<string, unknown>;
- }>({
- query: SUBSCRIBE_TO_NEWSLETTER,
- variables: {
- ...input,
- },
- cache: "no-store",
- });
- } catch (error) {
- return error;
- }
- }
- export async function getThemeCustomization(): Promise<ThemeCustomizationResult> {
- try {
- const [{data: footerRes}, {data:servicesRes}] = await Promise.all([
- cachedGraphQLRequest<GetFooterResponse>("static", GET_FOOTER, {
- type: "footer_links",
- }),
- cachedGraphQLRequest<GetFooterResponse>("static", GET_FOOTER, {
- type: "services_content",
- }),
- ]);
- return {
- footer_links: footerRes,
- services_content: servicesRes,
- };
- } catch (err) {
- console.error("ThemeCustomization Error:", err);
- }
- return {
- footer_links: null,
- services_content: null,
- };
- }
- export async function getPage(input: { urlKey: string }): Promise<PageData[]> {
- const res = await bagistoFetch<{
- data: PageByUrlKeyResponse;
- variables: { pageByUrlKey: string };
- }>({
- query: PAGE_BY_URL_KEY,
- cache: "no-store",
- // isCookies: false,
- variables: { pageByUrlKey: input.urlKey },
- });
- return res.body.data?.pageByUrlKeypages || [];
- }
|