Explorar o código

环境变量配置修改(添加自定义环境变量区分开发,测试和生产)

zgl hai 1 día
pai
achega
72d03e2f99

+ 13 - 1
.env.example

@@ -1,8 +1,20 @@
+# 业务环境变量 development test production
+# 本地开发创建evn.local, 测试环境创建 env.test, 生产环境创建env.production
+# 服务端使用
+APP_ENV=development
+# 客户端使用
+NEXT_PUBLIC_APP_ENV=development
+
+# 前端项目部署的域名
+NEXT_PUBLIC_SITE_URL=http://localhost:3001
+
 # Bagisto API Configuration
+# 后端接口域名
 NEXT_PUBLIC_BAGISTO_ENDPOINT=https://your-bagisto-instance.com
+# 后端接口需要的key
 NEXT_PUBLIC_BAGISTO_STOREFRONT_KEY=your_storefront_key_here
 
-# NextAuth Configuration
+# NextAuth Configuration 测试环境和生产环境要写实际部署的域名
 NEXTAUTH_URL=http://localhost:3001
 # NextAuth 使用 secret(下面的值)对 session中的token 对象进行 签名 + 加密,生成一个 JWT 字符串,解密这个JWT字符串就可以还原token对象。
 NEXTAUTH_SECRET=9jstKgQ1Q22PlDDhPtXTZ6G4MEzHGDJIkebcd/5UyZ4=

+ 1 - 0
.gitignore

@@ -37,6 +37,7 @@ yarn-error.log*
 .env.local
 .env.development.local
 .env.test
+.env.test.local
 
 # vercel
 .vercel

+ 1 - 1
next.config.ts

@@ -1,4 +1,4 @@
-import { configHeader } from '@/utils/constants';
+import { configHeader } from '@/utils/constants/server';
 import type { NextConfig } from "next";
 
 const nextConfig: NextConfig = {

+ 1 - 1
package.json

@@ -4,7 +4,7 @@
   "private": true,
   "scripts": {
     "dev": "next dev -p 3001",
-    "build": "cross-env NODE_ENV=production eslint . && next build",
+    "build": "eslint . && next build",
     "start": "next start -p 3001",
     "lint": "eslint .",
     "lint:fix": "next lint --fix",

+ 2 - 1
src/actions/switchCurrencyAction.ts

@@ -2,7 +2,8 @@
 
 import { cookies } from "next/headers";
 import { revalidatePath } from "next/cache";
-import {CURRENT_CURRENCY,currencyCookieOptions} from "@/utils/constants";
+import {CURRENT_CURRENCY} from "@/utils/constants";
+import {currencyCookieOptions} from "@/utils/constants/server";
 export async function switchCurrencyAction(currency: string) {
 
     const cookieStore = await cookies()

+ 2 - 2
src/app/(checkout)/checkout/_components/CheckoutPlaceOrder.tsx

@@ -1,7 +1,7 @@
 "use client";
 
 import { useRouter } from 'next/navigation'
-import { Payment } from "@airwallex/components-sdk";
+import {AirwallexCartNumberElementType} from "@/lib/Airwallex/airwallexInit";
 import PaypalButton from "./PaymentButton/PaypalButton";
 import { overlayLoading } from "@/components/theme/ui/kernel/loading/api";
 import { PlaceOrderFunction,KlarnaOtherData } from "@/types/checkout/type";
@@ -81,7 +81,7 @@ export default function CheckoutPlaceOrder({
             return;
         }
 
-        const placeOrderRes = await clickPlaceOrder<Payment.CardNumberElementType>();
+        const placeOrderRes = await clickPlaceOrder<AirwallexCartNumberElementType>();
         if(placeOrderRes.data !== null && placeOrderRes.otherData !== null) {
             const webOrderId = placeOrderRes.data.orderId;
             const cardNumberElement = placeOrderRes.otherData;

+ 2 - 4
src/app/(checkout)/checkout/_components/PaymentMethodCheckout.tsx

@@ -3,10 +3,8 @@
 import Image from "next/image";
 import { Ref, useImperativeHandle } from "react";
 import { useForm, get } from "react-hook-form";
-import {
-    CheckoutPaymentMethod,
-    AirwallexCardElements
-} from "@/types/checkout/type";
+import { CheckoutPaymentMethod } from "@/types/checkout/type";
+import { AirwallexCardElements } from "@/lib/Airwallex/airwallexInit";
 import { useCustomToast } from "@/utils/hooks/useToast";
 import AirwallexCardInput from "./PaymentMethodAdditional/AirwallexCardInput";
 import {useAirwallexCard} from "@/lib/Airwallex/useAirwallexCard";

+ 2 - 1
src/app/layout.tsx

@@ -51,7 +51,7 @@ export default async function RootLayout({
 }>) {
 
   let paypalClientId = process.env.PAYPAL_PRODUCTION_CLIENT_ID;
-  if (process.env.NODE_ENV !== "production") {
+  if (process.env.APP_ENV !== "production") {
     paypalClientId = process.env.PAYPAL_SANDBOX_CLIENT_ID;
   }
   if(paypalClientId === undefined) {
@@ -151,6 +151,7 @@ export default async function RootLayout({
         </main>
         <div id="modal-root"></div>
         <KernelProvider />
+        {process.env.NODE_ENV} / {process.env.APP_ENV}
         <span aria-hidden="true" data-nx-locale style={__srOnly}>{__lr}</span>
       </body>
     </html>

+ 3 - 1
src/app/robots.ts

@@ -1,5 +1,7 @@
 import type { MetadataRoute } from 'next'
  
+// src/app/robots.ts 是 Next.js App Router 中用于生成 `robots.txt 文件的特殊路由文件。
+// 它的作用是告诉 搜索引擎爬虫(Googlebot、Bingbot 等)哪些页面可以抓取,哪些页面不要抓取,同时可以声明网站的 sitemap 地址。
 export default function robots(): MetadataRoute.Robots {
   return {
     rules: {
@@ -7,6 +9,6 @@ export default function robots(): MetadataRoute.Robots {
       allow: '/',
       disallow:  ['/customer/*', '/checkout'],
     },
-    sitemap: `${process.env.NEXTAUTH_URL}/sitemap.xml`,
+    sitemap: `${process.env.NEXT_PUBLIC_SITE_URL}/sitemap.xml`,
   }
 }

+ 1 - 1
src/components/error/ErrorBoundary.tsx

@@ -59,7 +59,7 @@ export class ErrorBoundary extends Component<Props, State> {
               Try Again
             </button>
           </div>
-          {process.env.NODE_ENV === "development" && this.state.error && (
+          {process.env.NEXT_PUBLIC_APP_ENV !== "production" && this.state.error && (
             <details className="mt-6 w-full max-w-2xl">
               <summary className="cursor-pointer text-sm text-gray-500">
                 Error Details (Development Only)

+ 0 - 84
src/lib/Airwallex/airwallexCardManager.ts

@@ -1,84 +0,0 @@
-import { createElement, Payment } from "@airwallex/components-sdk";
-import { AirwallexCardElements } from "@/types/checkout/type";
-
-type ElementType =
-  | Payment.CardNumberElementType
-  | Payment.CvcElementType
-  | Payment.ExpiryDateElementType;
-
-
-class AirwallexManager {
-  private elements: AirwallexCardElements = {};
-
-  private listeners = new Map<ElementType, Map<Payment.SplitElementEventCode, boolean>>();
-
-  private created = false;
-
-  async init() {
-    if (this.created) return;
-    this.created = true;
-  }
-
-  async createElements() {
-    if (this.elements.cardNumber) return this.elements;
-
-    const cardNumber = await createElement("cardNumber");
-    const cvc = await createElement("cvc");
-    const expiry = await createElement("expiry");
-
-    this.elements = { cardNumber, cvc, expiry };
-
-    return this.elements;
-  }
-
-  mount(containerIds: {
-    cardNumber: string;
-    cvc: string;
-    expiry: string;
-  }) {
-    this.elements.cardNumber?.mount(containerIds.cardNumber);
-    this.elements.cvc?.mount(containerIds.cvc);
-    this.elements.expiry?.mount(containerIds.expiry);
-  }
-
-  unmount() {
-    this.elements.cardNumber?.unmount();
-    this.elements.cvc?.unmount();
-    this.elements.expiry?.unmount();
-  }
-
-  on<EventCode extends Payment.SplitElementEventCode>(el: ElementType, event: EventCode, handler: Payment.SplitElementEventHandler<EventCode>) {
-    let eventMap = this.listeners.get(el);
-    
-    if (!eventMap) {
-      eventMap = new Map<Payment.SplitElementEventCode, boolean>([[event, false]]);
-      this.listeners.set(el, eventMap);
-    }
-    if(eventMap.get(event)) return; // 注册过就返回
-
-    el.on(event, handler);
-
-    eventMap.set(event,true);
-    
-  }
-
-
-
-  destroy() {
-    const { cardNumber, cvc, expiry } = this.elements;
-
-    [cardNumber, cvc, expiry].forEach((el) => {
-      if (!el) return;
-      el.unmount();
-      el.destroy();
-    });
-
-    this.elements = {};
-  }
-
-  getElements() {
-    return this.elements;
-  }
-}
-
-export const airwallexManager = new AirwallexManager();

+ 142 - 17
src/lib/Airwallex/airwallexInit.ts

@@ -1,18 +1,143 @@
-import { init, Env } from '@airwallex/components-sdk';
-
-let initialized = false; // 全局标志,防止重复初始化
-
-const envMap = {
-    "production": "prod",
-    "development": "demo",
-    "test": "demo"
-};
-
-export async function airwallexInit() {
-  if (initialized) return;
-  await init({
-    env: envMap[process.env.NODE_ENV] as Env, // 生产环境为 'prod'
-    enabledElements: ['payments'],
-  });
-  initialized = true;
+import { init,InitResult,createElement, type Payment } from '@airwallex/components-sdk';
+
+// export {Payment};
+export type AirwallexCartNumberElementType = Payment.CardNumberElementType;
+export type AirwallexCvcElementType = Payment.CvcElementType;
+export type AirwallexExpiryDateElementType = Payment.ExpiryDateElementType;
+
+export interface AirwallexCardElements{
+  cardNumber?: AirwallexCartNumberElementType;
+  cvc?: AirwallexCvcElementType;
+  expiry?: AirwallexExpiryDateElementType;
+}
+
+type ElementType =
+  | AirwallexCartNumberElementType
+  | AirwallexCvcElementType
+  | AirwallexExpiryDateElementType;
+
+let initPromise: Promise<InitResult> | null = null;
+
+
+export function airwallexInit() {
+
+
+  if (!initPromise) {
+
+    initPromise = init({
+      env:
+        process.env.NEXT_PUBLIC_APP_ENV !== 'production'
+          ? 'demo'
+          : 'prod',
+
+      enabledElements: ['payments'],
+    });
+
+  }
+
+
+  return initPromise;
 }
+
+
+class AirwallexManager {
+  private elements: AirwallexCardElements = {};
+  private createPromise: Promise<AirwallexCardElements> | null = null;
+
+  private listeners = new Map<ElementType, Map<Payment.SplitElementEventCode, boolean>>();
+
+  // private created = false;
+
+  // async init() {
+  //   if (this.created) return;
+  //   this.created = true;
+  // }
+
+  async createElements() {
+
+    if (this.elements.cardNumber) {
+
+      return this.elements;
+    }
+
+    if (this.createPromise) {
+
+      return this.createPromise;
+    }
+
+
+
+    
+    this.createPromise = Promise.all([
+      createElement("cardNumber"),
+      createElement("cvc"),
+      createElement("expiry")
+    ]).then(([cardNumber,cvc,expiry]) => {
+
+      this.elements = {
+        cardNumber,
+        cvc,
+        expiry
+      };
+
+      return this.elements;
+
+    });
+
+
+    return this.createPromise;
+
+
+  }
+
+  mount(containerIds: {
+    cardNumber: string;
+    cvc: string;
+    expiry: string;
+  }) {
+    this.elements.cardNumber?.mount(containerIds.cardNumber);
+    this.elements.cvc?.mount(containerIds.cvc);
+    this.elements.expiry?.mount(containerIds.expiry);
+  }
+
+  unmount() {
+    this.elements.cardNumber?.unmount();
+    this.elements.cvc?.unmount();
+    this.elements.expiry?.unmount();
+  }
+
+  on<EventCode extends Payment.SplitElementEventCode>(el: ElementType, event: EventCode, handler: Payment.SplitElementEventHandler<EventCode>) {
+    let eventMap = this.listeners.get(el);
+    
+    if (!eventMap) {
+      eventMap = new Map<Payment.SplitElementEventCode, boolean>([[event, false]]);
+      this.listeners.set(el, eventMap);
+    }
+    if(eventMap.get(event)) return; // 注册过就返回
+
+    el.on(event, handler);
+
+    eventMap.set(event,true);
+    
+  }
+
+
+
+  destroy() {
+    const { cardNumber, cvc, expiry } = this.elements;
+
+    [cardNumber, cvc, expiry].forEach((el) => {
+      if (!el) return;
+      el.unmount();
+      el.destroy();
+    });
+
+    this.elements = {};
+  }
+
+  getElements() {
+    return this.elements;
+  }
+}
+
+export const airwallexManager = new AirwallexManager();

+ 38 - 19
src/lib/Airwallex/useAirwallexCard.ts

@@ -1,7 +1,11 @@
 import { useEffect, useRef, useReducer, useEffectEvent } from "react";
-import { airwallexManager } from "./airwallexCardManager";
-import { airwallexInit } from "@/lib/Airwallex/airwallexInit";
-import { Payment } from "@airwallex/components-sdk";
+import { 
+    airwallexInit,
+    airwallexManager,
+    AirwallexCartNumberElementType,
+    AirwallexCvcElementType,
+    AirwallexExpiryDateElementType
+} from "@/lib/Airwallex/airwallexInit";
 import { AirwallexCardStateType } from "@/types/checkout/type";
 
 interface EventCallback {
@@ -133,9 +137,9 @@ export function useAirwallexCard(
 
   const mountedRef = useRef(false);
   const elementRef = useRef<{
-    cardNumber?: Payment.CardNumberElementType;
-    cvc?: Payment.CvcElementType;
-    expiry?: Payment.ExpiryDateElementType;
+    cardNumber?: AirwallexCartNumberElementType;
+    cvc?: AirwallexCvcElementType;
+    expiry?: AirwallexExpiryDateElementType;
   }>({});
 
   useEffect(() => {
@@ -145,7 +149,7 @@ export function useAirwallexCard(
 
     const init = async () => {
       await airwallexInit();
-      await airwallexManager.init();
+    //   await airwallexManager.init();
 
       const els = await airwallexManager.createElements();
       elementRef.current = els;
@@ -193,20 +197,35 @@ function bindEvents(els: any,callback:EventCallback) {
   const { cardNumber, cvc, expiry } = els;
   const {focusCallback,blurCallback, changeCallback, readyCallback} = callback;
 
+  airwallexManager.on(cardNumber,"focus", focusCallback);
+  airwallexManager.on(cardNumber,"blur", blurCallback);
+  airwallexManager.on(cardNumber,"change", changeCallback);
+  airwallexManager.on(cardNumber,"ready", readyCallback);
+
+  airwallexManager.on(cvc,"focus", focusCallback);
+  airwallexManager.on(cvc,"blur", blurCallback);
+  airwallexManager.on(cvc,"change", changeCallback);
+  airwallexManager.on(cvc,"ready", readyCallback);
+
+  airwallexManager.on(expiry,"focus", focusCallback);
+  airwallexManager.on(expiry,"blur", blurCallback);
+  airwallexManager.on(expiry,"change", changeCallback);
+  airwallexManager.on(expiry,"ready", readyCallback);
+
   // ⚠️ 关键:绑定只发生一次(manager内部防重复)
-  cardNumber.on("focus", focusCallback);
-  cardNumber.on("blur", blurCallback);
-  cardNumber.on("change", changeCallback);
-  cardNumber.on("ready", readyCallback);
+//   cardNumber.on("focus", focusCallback);
+//   cardNumber.on("blur", blurCallback);
+//   cardNumber.on("change", changeCallback);
+//   cardNumber.on("ready", readyCallback);
 
 
-  cvc.on("focus", focusCallback);
-  cvc.on("blur", blurCallback);
-  cvc.on("change", changeCallback);
-  cvc.on("ready", readyCallback);
+//   cvc.on("focus", focusCallback);
+//   cvc.on("blur", blurCallback);
+//   cvc.on("change", changeCallback);
+//   cvc.on("ready", readyCallback);
 
-  expiry.on("focus", focusCallback);
-  expiry.on("blur", blurCallback);
-  expiry.on("change", changeCallback);
-  expiry.on("ready", readyCallback);
+//   expiry.on("focus", focusCallback);
+//   expiry.on("blur", blurCallback);
+//   expiry.on("change", changeCallback);
+//   expiry.on("ready", readyCallback);
 }

+ 1 - 1
src/lib/ApolloClientServer.ts

@@ -1,4 +1,4 @@
-import { GRAPHQL_URL } from "@/utils/constants";
+import { GRAPHQL_URL } from "@/utils/constants/server";
 import { HttpLink,ApolloLink } from "@apollo/client";
 import { SetContextLink } from "@apollo/client/link/context";
 import {

+ 1 - 1
src/providers/PaymentSDKProvider.tsx

@@ -23,7 +23,7 @@ interface PaymentContextProps {
 }
 
 const klarnaSDKURL = "https://x.klarnacdn.net/kp/lib/v1/api.js";
-const afterpaySDKURL = process.env.NODE_ENV === "production" ? "https://portal.afterpay.com/afterpay.js" : "https://portal.sandbox.afterpay.com/afterpay.js";
+const afterpaySDKURL = process.env.NEXT_PUBLIC_APP_ENV === "production" ? "https://portal.afterpay.com/afterpay.js" : "https://portal.sandbox.afterpay.com/afterpay.js";
 const applepaySDKURL = "https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js";
 
 const PaymentSDKContext = createContext<PaymentContextProps|null>(null);

+ 1 - 1
src/providers/PaypalWrapper.tsx

@@ -21,7 +21,7 @@ export function PayPalWrapper({
             "paypal-messages",
             "applepay-payments"
         ]}
-        environment={process.env.NODE_ENV === "production" ? "production" : "sandbox"} // 上线改为 "production"
+        environment={process.env.NEXT_PUBLIC_APP_ENV === "production" ? "production" : "sandbox"} // 上线改为 "production"
         pageType="checkout"
     >
         {children}

+ 2 - 1
src/proxy/currency.ts

@@ -1,6 +1,7 @@
 import type { NextRequest } from "next/server";
 import type { NextResponse } from "next/server";
-import {CURRENT_CURRENCY,CURRENT_LOCAL,CURRENT_CHANNEL,currencyCookieOptions} from "@/utils/constants";
+import {CURRENT_CURRENCY,CURRENT_LOCAL,CURRENT_CHANNEL} from "@/utils/constants";
+import {currencyCookieOptions} from "@/utils/constants/server";
 
 export function handleCurrency(
     request: NextRequest,

+ 0 - 8
src/types/checkout/type.ts

@@ -1,5 +1,4 @@
 import {CartDetail,CartAddress} from "@/types/cart/type";
-import { Payment } from '@airwallex/components-sdk';
 
 export type AddressType = "cart_billing" | "cart_shipping";
 
@@ -473,7 +472,6 @@ export interface CreatePaymentReplayVariables {
 
 
 // 结账页额外用到的类型
-export type AirwallexCadOtherData = Payment.CardNumberElementType;
 
 export type KlarnaOtherData = {
   billingAddress: CartAddress;
@@ -487,12 +485,6 @@ export interface PlaceOrderResult<T> {
 
 export type PlaceOrderFunction = <T = null>(params?: CreatePaymentInitiateVariables) => Promise<PlaceOrderResult<T>>
 
-export interface AirwallexCardElements{
-  cardNumber?: Payment.CardNumberElementType;
-  cvc?: Payment.CvcElementType;
-  expiry?: Payment.ExpiryDateElementType;
-}
-
 
 
 export interface AirwallexCardStateType {

+ 11 - 17
src/utils/bagisto/index.ts

@@ -9,9 +9,7 @@ import {
   ImageInfo,
 } from "@/types/types";
 import {
-  BAGISTO_SESSION,
   HIDDEN_PRODUCT_TAG,
-  STOREFRONT_KEY,
 } from "../constants";
 import { getServerSession } from "next-auth";
 import {
@@ -23,6 +21,8 @@ import { print, DocumentNode } from "graphql";
 import { 
   GRAPHQL_URL, 
   REST_API_URL,
+} from "@/utils/constants/server";
+import { 
   GUEST_CART_TOKEN,
   IS_GUEST,
   CURRENT_CURRENCY,
@@ -55,7 +55,7 @@ type ExtractVariables<T> = T extends { variables: object }
 interface PageByUrlKeyResponse {
   pageByUrlKeypages?: PageData[];
 }
-
+const STOREFRONT_KEY = process.env.NEXT_PUBLIC_BAGISTO_STOREFRONT_KEY;
 async function getBaseHeader() {
     /** 
      * Headers:
@@ -63,6 +63,10 @@ async function getBaseHeader() {
      *   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中已经设置过值了
@@ -109,12 +113,9 @@ export async function restApiFetch<T>({
 }): Promise<{ status: number; body: T } | never> {
   try {
     const apiUrl = api.startsWith("http") ? api : `${REST_API_URL}${api}`;
-    let bagistoCartId = "";
     let accessToken: string | undefined = undefined;
 
     if (isCookies) {
-      const cookieStore = await cookies();
-      bagistoCartId = cookieStore.get(BAGISTO_SESSION)?.value ?? "";
       const sessions = (await getServerSession(
         authOptions,
       )) as BagistoSession | null;
@@ -130,9 +131,6 @@ export async function restApiFetch<T>({
       baseHeaders.Authorization = `Bearer ${guestToken}`;
     }
 
-    if (bagistoCartId) {
-      baseHeaders.Cookie = `${BAGISTO_SESSION}=${bagistoCartId}`;
-    }
 
     if (isCookies && headers) {
       if (headers instanceof Headers) {
@@ -286,12 +284,11 @@ export async function bagistoFetch<T>({
     const queryString =
       typeof query === "string" ? query : print(query);
 
-    let bagistoCartId = "";
+
     let accessToken: string | undefined = undefined;
 
     if (isCookies) {
-      const cookieStore = await cookies();
-      bagistoCartId = cookieStore.get(BAGISTO_SESSION)?.value ?? "";
+
       const sessions = (await getServerSession(
         authOptions,
       )) as BagistoSession | null;
@@ -307,9 +304,7 @@ export async function bagistoFetch<T>({
       baseHeaders.Authorization = `Bearer ${guestToken}`;
     }
 
-    if (bagistoCartId) {
-      baseHeaders.Cookie = `${BAGISTO_SESSION}=${bagistoCartId}`;
-    }
+    
 
     if (isCookies && headers) {
       if (headers instanceof Headers) {
@@ -513,8 +508,7 @@ export async function logoutUser() {
       res?.body?.data?.createLogout?.logout?.message ?? "Logout executed";
 
 
-    const cookieStore = await cookies();
-    cookieStore.delete(BAGISTO_SESSION);
+
 
     return {
       success,

+ 2 - 148
src/utils/constants.ts

@@ -1,36 +1,7 @@
-// import { parseCsv } from './helper';
-import type { ResponseCookie } from "next/dist/compiled/@edge-runtime/cookies";
 
-export const CACHE_KEY = {
-  homeTheme: "collection-homepage",
-  headerMenus: "header-menus",
-  footerLink: "footer-link",
-};
-/**
- * Caching Tags for caching
- */
-export const TAGS = {
-  collections: "collections",
-  products: "products",
-  cart: "cart",
-  carDetail: "carDetail",
-  address: "address",
-  themeCustomize: "themeCustomize",
-  defaultChannel: "channel",
-};
-
-/**
- * Checkout Caching Tags
- */
-export const CHECKOUT = {
-  shipping: "collections",
-  method: "products",
-  cart: "cart",
-};
 export const HIDDEN_PRODUCT_TAG = "nextjs-frontend-hidden";
 export const DEFAULT_OPTION = "Default Title";
-export const BAGISTO_GRAPHQL_API_ENDPOINT = "/api/graphql";
-export const BAGISTO_REST_API_ENDPOINT = "/api";
+
 
 /**
  * productJsonLd constant
@@ -39,29 +10,14 @@ export const BASE_SCHEMA_URL = "https://schema.org";
 export const PRODUCT_TYPE = "Product";
 export const PRODUCT_OFFER_TYPE = "AggregateOffer";
 
-export const currencyCookieOptions = {
-    path: '/', // 该cookie对那些路径有效,/ 表示所有路径
-    maxAge: 60 * 60 * 24 * 365, // 过期时间 1年,到期后自动删除
-    sameSite: 'lax', // 第三方网站请求你的站点时,浏览器是否携带 Cookie。
-    secure: process.env.NODE_ENV === 'production' // true 表示这个 Cookie 是否只能通过 HTTPS 发送
-} satisfies Partial<ResponseCookie>;
 
 /**
  * cookies constant
  */
-export const BAGISTO_SESSION = process.env.BAGISTO_SESSION ?? "bagisto_session";
 export const TOKEN = "token";
-export const BASE_URL = process.env.NEXTAUTH_URL;
+export const BASE_URL = process.env.NEXT_PUBLIC_SITE_URL;
 export const baseUrl = process.env.NEXT_PUBLIC_BAGISTO_ENDPOINT;
-export const GRAPHQL_URL = `${(process.env.NEXT_PUBLIC_BAGISTO_ENDPOINT || '').replace(/\/$/, '')}${BAGISTO_GRAPHQL_API_ENDPOINT}`;
-export const REST_API_URL = `${(process.env.NEXT_PUBLIC_BAGISTO_ENDPOINT || '').replace(/\/$/, '')}${BAGISTO_REST_API_ENDPOINT}`;
-export const NEXT_AUTH_SECRET = process.env.NEXTAUTH_SECRET;
 
-// Server-only: Use non-public env var, fallback to public for backwards compatibility
-export const STOREFRONT_KEY = process.env.BAGISTO_STOREFRONT_KEY || process.env.NEXT_PUBLIC_BAGISTO_STOREFRONT_KEY || "";
-
-export const OPERATION_TO_ROUTE_MAP: Record<string, string> = {
-};
 
 // -----Pagination--------//
 export const PAGE = "page";
@@ -85,108 +41,6 @@ export const variants = {
 };
 
 
-export const configHeader = [
-  // Security headers for all routes
-  {
-    source: "/:path*",
-    headers: [
-      { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
-      { key: "X-Frame-Options", value: "DENY" },
-      { key: "X-Content-Type-Options", value: "nosniff" },
-      { key: "X-XSS-Protection", value: "1; mode=block" },
-      {
-        key: "Permissions-Policy",
-        value:
-          "camera=(), microphone=(), geolocation=(), browsing-topics=()",
-      },
-    ],
-  },
-  // Cache dynamic pages - shorter cache for frequently updated content
-  {
-    source: "/category/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "public, s-maxage=3600, stale-while-revalidate=86400",
-      },
-    ],
-  },
-  {
-    source: "/product/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "public, s-maxage=3600, stale-while-revalidate=86400",
-      },
-      {
-        key: "Vary",
-        value: "Accept-Encoding",
-      },
-    ],
-  },
-  {
-    source: "/checkout/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "private, no-cache, no-store, must-revalidate",
-      },
-    ],
-  },
-  {
-    source: "/customer/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "private, no-cache, no-store, must-revalidate",
-      },
-    ],
-  },
-  // Next.js static assets - long cache with immutable
-  {
-    source: "/_next/static/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "public, max-age=31536000, immutable",
-      },
-    ],
-  },
-  {
-    source: "/_next/image/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "public, max-age=31536000, immutable",
-      },
-    ],
-  },
-  // Public folder assets - long cache
-  {
-    source: "/image/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "public, max-age=31536000, immutable",
-      },
-    ],
-  },
-  {
-    source: "/fonts/:path*",
-    headers: [
-      {
-        key: "Cache-Control",
-        value: "public, max-age=31536000, immutable",
-      },
-    ],
-  },
-]
-
-
-export const imageProtocol = (process.env.NEXT_SERVER_MAGENTO_PROTOCOL ||
-  "https") as "http" | "https";
-
-
 
 export function getImageUrl(url?: string, baseUrl?: string, fallback: string = NOT_IMAGE) {
   if (!url) return fallback;

+ 0 - 0
src/utils/constants/client.ts


+ 110 - 0
src/utils/constants/server.ts

@@ -0,0 +1,110 @@
+import type { ResponseCookie } from "next/dist/compiled/@edge-runtime/cookies";
+export const BAGISTO_GRAPHQL_API_ENDPOINT = "/api/graphql";
+export const BAGISTO_REST_API_ENDPOINT = "/api";
+export const GRAPHQL_URL = `${(process.env.NEXT_PUBLIC_BAGISTO_ENDPOINT || '').replace(/\/$/, '')}${BAGISTO_GRAPHQL_API_ENDPOINT}`;
+export const REST_API_URL = `${(process.env.NEXT_PUBLIC_BAGISTO_ENDPOINT || '').replace(/\/$/, '')}${BAGISTO_REST_API_ENDPOINT}`;
+
+export const currencyCookieOptions = {
+    path: '/', // 该cookie对那些路径有效,/ 表示所有路径
+    maxAge: 60 * 60 * 24 * 365, // 过期时间 1年,到期后自动删除
+    sameSite: 'lax', // 第三方网站请求你的站点时,浏览器是否携带 Cookie。
+    secure: process.env.APP_ENV !== 'development' // true 表示这个 Cookie 是否只能通过 HTTPS 发送
+} satisfies Partial<ResponseCookie>;
+
+
+export const configHeader = [
+  // Security headers for all routes
+  {
+    source: "/:path*",
+    headers: [
+      { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
+      { key: "X-Frame-Options", value: "DENY" },
+      { key: "X-Content-Type-Options", value: "nosniff" },
+      { key: "X-XSS-Protection", value: "1; mode=block" },
+      {
+        key: "Permissions-Policy",
+        value:
+          "camera=(), microphone=(), geolocation=(), browsing-topics=()",
+      },
+    ],
+  },
+  // Cache dynamic pages - shorter cache for frequently updated content
+  {
+    source: "/category/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "public, s-maxage=3600, stale-while-revalidate=86400",
+      },
+    ],
+  },
+  {
+    source: "/product/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "public, s-maxage=3600, stale-while-revalidate=86400",
+      },
+      {
+        key: "Vary",
+        value: "Accept-Encoding",
+      },
+    ],
+  },
+  {
+    source: "/checkout/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "private, no-cache, no-store, must-revalidate",
+      },
+    ],
+  },
+  {
+    source: "/customer/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "private, no-cache, no-store, must-revalidate",
+      },
+    ],
+  },
+  // Next.js static assets - long cache with immutable
+  {
+    source: "/_next/static/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "public, max-age=31536000, immutable",
+      },
+    ],
+  },
+  {
+    source: "/_next/image/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "public, max-age=31536000, immutable",
+      },
+    ],
+  },
+  // Public folder assets - long cache
+  {
+    source: "/image/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "public, max-age=31536000, immutable",
+      },
+    ],
+  },
+  {
+    source: "/fonts/:path*",
+    headers: [
+      {
+        key: "Cache-Control",
+        value: "public, max-age=31536000, immutable",
+      },
+    ],
+  },
+];

+ 0 - 2
src/utils/jwt-cookie.ts

@@ -1,4 +1,3 @@
-// import { NEXT_AUTH_SECRET } from "./constants";
 // 把游客token编码
 export const encodeJWT = (payload: object): string => {
   try {
@@ -7,7 +6,6 @@ export const encodeJWT = (payload: object): string => {
 
     const header = btoa(JSON.stringify({ alg: "none", typ: "JWT" }));
 
-    // const token = `${header}.${encodedPayload}.${NEXT_AUTH_SECRET}`;
     const token = `${header}.${encodedPayload}`;
 
     return encodeURIComponent(token);