mirror of
https://github.com/vercel/commerce.git
synced 2025-07-08 22:01:22 +00:00
Merge b9af6f6b9ae9c03b2c97e0e8216cc80244ee0343 into fa1306916c652ea5f820d5b400087bece13460fd
This commit is contained in:
commit
3e092c8d7d
@ -3,3 +3,4 @@ SITE_NAME="Next.js Commerce"
|
|||||||
SHOPIFY_REVALIDATION_SECRET=""
|
SHOPIFY_REVALIDATION_SECRET=""
|
||||||
SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
|
SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
|
||||||
SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com"
|
SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com"
|
||||||
|
SHOPIFY_STOREFRONT_API_VERSION= "2025-04"
|
||||||
|
@ -28,4 +28,4 @@ export const TAGS = {
|
|||||||
|
|
||||||
export const HIDDEN_PRODUCT_TAG = 'nextjs-frontend-hidden';
|
export const HIDDEN_PRODUCT_TAG = 'nextjs-frontend-hidden';
|
||||||
export const DEFAULT_OPTION = 'Default Title';
|
export const DEFAULT_OPTION = 'Default Title';
|
||||||
export const SHOPIFY_GRAPHQL_API_ENDPOINT = '/api/2023-01/graphql.json';
|
export const SHOPIFY_GRAPHQL_API_ENDPOINT = `/api/${process.env.SHOPIFY_STOREFRONT_API_VERSION}/graphql.json`;
|
||||||
|
@ -61,22 +61,25 @@ import {
|
|||||||
const domain = process.env.SHOPIFY_STORE_DOMAIN
|
const domain = process.env.SHOPIFY_STORE_DOMAIN
|
||||||
? ensureStartsWith(process.env.SHOPIFY_STORE_DOMAIN, 'https://')
|
? ensureStartsWith(process.env.SHOPIFY_STORE_DOMAIN, 'https://')
|
||||||
: '';
|
: '';
|
||||||
const endpoint = `${domain}${SHOPIFY_GRAPHQL_API_ENDPOINT}`;
|
|
||||||
const key = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!;
|
export const endpoint = `${domain}${SHOPIFY_GRAPHQL_API_ENDPOINT}`;
|
||||||
|
|
||||||
|
// Your Shopify Storefront access token
|
||||||
|
export const key = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN!;
|
||||||
|
|
||||||
type ExtractVariables<T> = T extends { variables: object }
|
type ExtractVariables<T> = T extends { variables: object }
|
||||||
? T['variables']
|
? T['variables']
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
export async function shopifyFetch<T>({
|
export async function shopifyFetch<T>({
|
||||||
headers,
|
headers,
|
||||||
query,
|
query,
|
||||||
variables
|
variables
|
||||||
}: {
|
}: {
|
||||||
headers?: HeadersInit;
|
headers?: HeadersInit;
|
||||||
query: string;
|
query: string;
|
||||||
variables?: ExtractVariables<T>;
|
variables?: ExtractVariables<T>;
|
||||||
}): Promise<{ status: number; body: T } | never> {
|
}): Promise<{ status: number; body: T }> {
|
||||||
try {
|
try {
|
||||||
const result = await fetch(endpoint, {
|
const result = await fetch(endpoint, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -93,28 +96,35 @@ export async function shopifyFetch<T>({
|
|||||||
|
|
||||||
const body = await result.json();
|
const body = await result.json();
|
||||||
|
|
||||||
|
// Handle API-level errors
|
||||||
if (body.errors) {
|
if (body.errors) {
|
||||||
throw body.errors[0];
|
console.error('[shopifyFetch] Shopify API error:', {
|
||||||
|
query,
|
||||||
|
status: result.status,
|
||||||
|
error: body.errors[0]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Throw a standard Error object (not a plain object)
|
||||||
|
throw new Error(
|
||||||
|
`Shopify API Error (${result.status}): ${body.errors[0].message}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: result.status,
|
status: result.status,
|
||||||
body
|
body
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (err: any) {
|
||||||
if (isShopifyError(e)) {
|
// Log full context for unknown or fetch-level errors
|
||||||
throw {
|
console.error('[shopifyFetch] Unexpected fetch error:', {
|
||||||
cause: e.cause?.toString() || 'unknown',
|
query,
|
||||||
status: e.status || 500,
|
error: err
|
||||||
message: e.message,
|
});
|
||||||
query
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
throw {
|
// Re-throw a standard Error to be caught elsewhere
|
||||||
error: e,
|
throw new Error(
|
||||||
query
|
`Unexpected error in shopifyFetch: ${err?.message ?? err}`
|
||||||
};
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,23 +274,29 @@ export async function updateCart(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getCart(): Promise<Cart | undefined> {
|
export async function getCart(): Promise<Cart | undefined> {
|
||||||
const cartId = (await cookies()).get('cartId')?.value;
|
try {
|
||||||
|
const cartId = (await cookies()).get('cartId')?.value;
|
||||||
|
|
||||||
if (!cartId) {
|
if (!cartId) {
|
||||||
|
console.warn('[getCart] No cartId in cookies');
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await shopifyFetch<ShopifyCartOperation>({
|
||||||
|
query: getCartQuery,
|
||||||
|
variables: { cartId }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.body?.data?.cart) {
|
||||||
|
console.warn('[getCart] Cart is null for cartId:', cartId);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reshapeCart(res.body.data.cart);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[getCart] Failed:', err);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await shopifyFetch<ShopifyCartOperation>({
|
|
||||||
query: getCartQuery,
|
|
||||||
variables: { cartId }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Old carts becomes `null` when you checkout.
|
|
||||||
if (!res.body.data.cart) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reshapeCart(res.body.data.cart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCollection(
|
export async function getCollection(
|
||||||
|
2143
package-lock.json
generated
Normal file
2143
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user