@anker-in/shopify-sdk 0.1.1-beta.9 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.js +25 -8
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +25 -8
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.d.mts +8 -17
- package/dist/index.d.ts +8 -17
- package/dist/index.js +97 -100
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +97 -100
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/client/index.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/utils.ts
|
|
4
|
+
function addInContextDirective(query, country, language) {
|
|
5
|
+
if (!country || !language) {
|
|
6
|
+
return query;
|
|
7
|
+
}
|
|
8
|
+
const operationRegex = /((?:query|mutation)\s+\w+)(\s*\([^)]*\))?\s*(\{)/;
|
|
9
|
+
const match = query.match(operationRegex);
|
|
10
|
+
if (!match) {
|
|
11
|
+
const braceIndex = query.indexOf("{");
|
|
12
|
+
if (braceIndex === -1) return query;
|
|
13
|
+
const beforeBrace = query.substring(0, braceIndex).trim();
|
|
14
|
+
const afterBrace = query.substring(braceIndex);
|
|
15
|
+
return `${beforeBrace} @inContext(country: ${country}, language: ${language}) ${afterBrace}`;
|
|
16
|
+
}
|
|
17
|
+
const beforeDirective = match[1] + (match[2] || "");
|
|
18
|
+
const afterDirective = query.substring(match.index + match[0].length - 1);
|
|
19
|
+
return `${beforeDirective} @inContext(country: ${country}, language: ${language}) ${afterDirective}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
3
22
|
// src/client/client.ts
|
|
4
23
|
var ShopifyClient = class _ShopifyClient {
|
|
5
24
|
config;
|
|
@@ -12,8 +31,11 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
12
31
|
* Execute a GraphQL request
|
|
13
32
|
*/
|
|
14
33
|
async request(request, options = {}) {
|
|
15
|
-
|
|
34
|
+
let { query, variables, operationName } = request;
|
|
16
35
|
const { tags = [], ...fetchOptions } = options;
|
|
36
|
+
const country = this.config.getCountryCode(this.locale);
|
|
37
|
+
const language = this.config.getLanguageCode(this.locale);
|
|
38
|
+
query = addInContextDirective(query, country, language);
|
|
17
39
|
const apiUrl = this.config.getApiUrl(this.locale);
|
|
18
40
|
const token = this.config.getStorefrontToken(this.locale);
|
|
19
41
|
const headers = {
|
|
@@ -35,9 +57,7 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
35
57
|
...tags.length > 0 && { next: { tags } }
|
|
36
58
|
});
|
|
37
59
|
if (!response.ok) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`HTTP ${response.status}: ${response.statusText}`
|
|
40
|
-
);
|
|
60
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
41
61
|
}
|
|
42
62
|
const json = await response.json();
|
|
43
63
|
if (json.errors && json.errors.length > 0) {
|
|
@@ -53,10 +73,7 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
53
73
|
* Convenience method for simple queries
|
|
54
74
|
*/
|
|
55
75
|
async query(query, variables, options) {
|
|
56
|
-
const response = await this.request(
|
|
57
|
-
{ query, variables },
|
|
58
|
-
options
|
|
59
|
-
);
|
|
76
|
+
const response = await this.request({ query, variables }, options);
|
|
60
77
|
return response.data;
|
|
61
78
|
}
|
|
62
79
|
/**
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ShopifyConfig } from '@anker-in/shopify-core'\nimport type { GraphQLResponse, GraphQLRequest, FetchOptions } from './types'\n\n/**\n * Shopify GraphQL Client\n * Handles all GraphQL communication with Shopify Storefront API\n */\nexport class ShopifyClient {\n private config: ShopifyConfig\n private locale: string\n\n constructor(config: ShopifyConfig, locale: string) {\n this.config = config\n this.locale = locale\n }\n\n /**\n * Execute a GraphQL request\n */\n async request<T = any>(\n request: GraphQLRequest,\n options: FetchOptions = {}\n ): Promise<GraphQLResponse<T>> {\n const { query, variables, operationName } = request\n const { tags = [], ...fetchOptions } = options\n\n const apiUrl = this.config.getApiUrl(this.locale)\n const token = this.config.getStorefrontToken(this.locale)\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': token,\n ...(fetchOptions.headers || {}),\n }\n\n const body = JSON.stringify({\n query,\n variables,\n operationName,\n })\n\n try {\n const response = await fetch(apiUrl, {\n method: 'POST',\n headers,\n body,\n ...fetchOptions,\n ...(tags.length > 0 && { next: { tags } }),\n })\n\n if (!response.ok) {\n throw new Error(\n `HTTP ${response.status}: ${response.statusText}`\n )\n }\n\n const json: GraphQLResponse<T> = await response.json()\n\n if (json.errors && json.errors.length > 0) {\n console.error('GraphQL Errors:', json.errors)\n }\n\n return json\n } catch (error) {\n console.error('Shopify API Request Failed:', error)\n throw error\n }\n }\n\n /**\n * Convenience method for simple queries\n */\n async query<T = any>(\n query: string,\n variables?: Record<string, any>,\n options?: FetchOptions\n ): Promise<T | undefined> {\n const response = await this.request<T>(\n { query, variables },\n options\n )\n return response.data\n }\n\n /**\n * Get current locale\n */\n getLocale(): string {\n return this.locale\n }\n\n /**\n * Get config\n */\n getConfig(): ShopifyConfig {\n return this.config\n }\n\n /**\n * Get API URL\n */\n getApiUrl(): string {\n return this.config.getApiUrl(this.locale)\n }\n\n /**\n * Create a new client with different locale\n */\n withLocale(locale: string): ShopifyClient {\n return new ShopifyClient(this.config, locale)\n }\n}\n\n/**\n * Factory function to create a Shopify client\n */\nexport function createShopifyClient(\n config: ShopifyConfig,\n locale: string\n): ShopifyClient {\n return new ShopifyClient(config, locale)\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils.ts","../../src/client/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { HasMetafieldsIdentifier, Maybe, Metafield } from './shopify-types'\n\nexport type PartialRecord<K extends string | number | symbol, T> = Partial<Record<K, T>>\n\nexport type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type Replace<T, K extends keyof T, V> = Omit<T, K> & { [P in K]: V }\n\nexport enum HasMetafieldQueryRoot {\n Product = 'product',\n Variant = 'variant',\n Page = 'page',\n Article = 'article',\n Blog = 'blog',\n Collection = 'collection',\n Shop = 'shop',\n Cart = 'cart',\n Customer = 'customer',\n Location = 'location',\n Market = 'market',\n Order = 'order',\n}\n\n/**\n * 生成 metafieldIdentifiers 查询参数\n */\nexport function constructMetafieldIdentifiersQueryParams<T extends HasMetafieldQueryRoot>(\n metafieldIdentifiers: PartialRecord<T, HasMetafieldsIdentifier[]> = {},\n metafieldNamespacePrefix: string\n): PartialRecord<`${T}MetafieldIdentifiers`, HasMetafieldsIdentifier[]> {\n const identifiers = Object.entries(metafieldIdentifiers).reduce(\n (queryInput, [key, value]) => {\n const metafieldIdentifiers = value as HasMetafieldsIdentifier[]\n queryInput[`${key}MetafieldIdentifiers` as `${T}MetafieldIdentifiers`] =\n metafieldIdentifiers.map((item) => ({\n namespace: item.namespace,\n key: item.key,\n })) as HasMetafieldsIdentifier[]\n return queryInput\n },\n {} as PartialRecord<`${T}MetafieldIdentifiers`, HasMetafieldsIdentifier[]>\n )\n return identifiers\n}\n\nexport const parseMetafield = (item: Metafield, previewData?: any, resource_type?: string) => {\n const type = item?.type && item?.type.toLowerCase()\n if (\n item &&\n previewData &&\n previewData?.__preview_type === resource_type &&\n previewData[`${item?.namespace}${item?.key}`] !== undefined &&\n previewData[`${item?.namespace}${item?.key}`] !== null\n ) {\n return previewData[`${item.namespace}${item.key}`]\n }\n switch (type) {\n case 'json':\n case 'json_string':\n case 'rating':\n case 'volume':\n case 'weight':\n case 'dimension':\n return JSON.parse(item.value)\n default:\n return item?.value || item\n }\n}\n\nexport const normalizeMetafields = (metafields: Array<Maybe<Metafield>>): Record<string, any> => {\n return metafields?.reduce(\n (prev, cur) => {\n if (cur) {\n const namespace = cur.key\n prev[namespace] = prev[namespace] || {}\n const parsedMetafields: {\n [key: string]: Metafield\n } = parseMetafield(cur)\n if (parsedMetafields) {\n Object.entries(parsedMetafields).forEach(([key, innerMetafields]) => {\n prev[namespace][key] =\n prev[namespace][key] ?? (innerMetafields ? parseMetafield(innerMetafields) : null)\n })\n }\n }\n return prev\n },\n {} as Record<string, any>\n )\n}\n\n/**\n * Add @inContext directive to GraphQL query for single shop multi-language/currency support\n *\n * @param query - GraphQL query string\n * @param country - Country code (e.g., 'PL', 'CA', 'US')\n * @param language - Language code (e.g., 'PL', 'FR', 'EN')\n * @returns Modified query with @inContext directive, or original query if country/language not provided\n *\n * @example\n * ```typescript\n * const query = `query getCart($cartId: ID!) { cart(id: $cartId) { id } }`\n * const modifiedQuery = addInContextDirective(query, 'PL', 'PL')\n * // Result: query getCart($cartId: ID!) @inContext(country: PL, language: PL) { cart(id: $cartId) { id } }\n * ```\n */\nexport function addInContextDirective(\n query: string,\n country?: string,\n language?: string\n): string {\n // If no country or language, return original query\n if (!country || !language) {\n return query\n }\n\n // Match query/mutation declaration with optional parameters\n // e.g., \"query getCart(...)\" or \"mutation createCart\"\n const operationRegex = /((?:query|mutation)\\s+\\w+)(\\s*\\([^)]*\\))?\\s*(\\{)/\n const match = query.match(operationRegex)\n\n if (!match) {\n // Fallback: try to find first { if no operation found\n const braceIndex = query.indexOf('{')\n if (braceIndex === -1) return query\n\n const beforeBrace = query.substring(0, braceIndex).trim()\n const afterBrace = query.substring(braceIndex)\n return `${beforeBrace} @inContext(country: ${country}, language: ${language}) ${afterBrace}`\n }\n\n // Insert @inContext after operation declaration (and parameters if exist), before {\n const beforeDirective = match[1] + (match[2] || '') // e.g., \"query getCart($id: ID!)\"\n const afterDirective = query.substring(match.index! + match[0].length - 1) // Everything starting from {\n\n return `${beforeDirective} @inContext(country: ${country}, language: ${language}) ${afterDirective}`\n}\n","import type { ShopifyConfig } from '@anker-in/shopify-core'\nimport type { GraphQLResponse, GraphQLRequest, FetchOptions } from './types'\nimport { addInContextDirective } from '../utils'\n\n/**\n * Shopify GraphQL Client\n * Handles all GraphQL communication with Shopify Storefront API\n */\nexport class ShopifyClient {\n private config: ShopifyConfig\n private locale: string\n\n constructor(config: ShopifyConfig, locale: string) {\n this.config = config\n this.locale = locale\n }\n\n /**\n * Execute a GraphQL request\n */\n async request<T = any>(\n request: GraphQLRequest,\n options: FetchOptions = {}\n ): Promise<GraphQLResponse<T>> {\n let { query, variables, operationName } = request\n const { tags = [], ...fetchOptions } = options\n\n // Add @inContext directive if needed for single shop multi-language/currency\n const country = this.config.getCountryCode(this.locale)\n const language = this.config.getLanguageCode(this.locale)\n query = addInContextDirective(query, country, language)\n\n const apiUrl = this.config.getApiUrl(this.locale)\n const token = this.config.getStorefrontToken(this.locale)\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': token,\n ...(fetchOptions.headers || {}),\n }\n\n const body = JSON.stringify({\n query,\n variables,\n operationName,\n })\n\n try {\n const response = await fetch(apiUrl, {\n method: 'POST',\n headers,\n body,\n ...fetchOptions,\n ...(tags.length > 0 && { next: { tags } }),\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n const json: GraphQLResponse<T> = await response.json()\n\n if (json.errors && json.errors.length > 0) {\n console.error('GraphQL Errors:', json.errors)\n }\n\n return json\n } catch (error) {\n console.error('Shopify API Request Failed:', error)\n throw error\n }\n }\n\n /**\n * Convenience method for simple queries\n */\n async query<T = any>(\n query: string,\n variables?: Record<string, any>,\n options?: FetchOptions\n ): Promise<T | undefined> {\n const response = await this.request<T>({ query, variables }, options)\n return response.data\n }\n\n /**\n * Get current locale\n */\n getLocale(): string {\n return this.locale\n }\n\n /**\n * Get config\n */\n getConfig(): ShopifyConfig {\n return this.config\n }\n\n /**\n * Get API URL\n */\n getApiUrl(): string {\n return this.config.getApiUrl(this.locale)\n }\n\n /**\n * Create a new client with different locale\n */\n withLocale(locale: string): ShopifyClient {\n return new ShopifyClient(this.config, locale)\n }\n}\n\n/**\n * Factory function to create a Shopify client\n */\nexport function createShopifyClient(config: ShopifyConfig, locale: string): ShopifyClient {\n return new ShopifyClient(config, locale)\n}\n"]}
|
package/dist/client/index.mjs
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
function addInContextDirective(query, country, language) {
|
|
3
|
+
if (!country || !language) {
|
|
4
|
+
return query;
|
|
5
|
+
}
|
|
6
|
+
const operationRegex = /((?:query|mutation)\s+\w+)(\s*\([^)]*\))?\s*(\{)/;
|
|
7
|
+
const match = query.match(operationRegex);
|
|
8
|
+
if (!match) {
|
|
9
|
+
const braceIndex = query.indexOf("{");
|
|
10
|
+
if (braceIndex === -1) return query;
|
|
11
|
+
const beforeBrace = query.substring(0, braceIndex).trim();
|
|
12
|
+
const afterBrace = query.substring(braceIndex);
|
|
13
|
+
return `${beforeBrace} @inContext(country: ${country}, language: ${language}) ${afterBrace}`;
|
|
14
|
+
}
|
|
15
|
+
const beforeDirective = match[1] + (match[2] || "");
|
|
16
|
+
const afterDirective = query.substring(match.index + match[0].length - 1);
|
|
17
|
+
return `${beforeDirective} @inContext(country: ${country}, language: ${language}) ${afterDirective}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
1
20
|
// src/client/client.ts
|
|
2
21
|
var ShopifyClient = class _ShopifyClient {
|
|
3
22
|
config;
|
|
@@ -10,8 +29,11 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
10
29
|
* Execute a GraphQL request
|
|
11
30
|
*/
|
|
12
31
|
async request(request, options = {}) {
|
|
13
|
-
|
|
32
|
+
let { query, variables, operationName } = request;
|
|
14
33
|
const { tags = [], ...fetchOptions } = options;
|
|
34
|
+
const country = this.config.getCountryCode(this.locale);
|
|
35
|
+
const language = this.config.getLanguageCode(this.locale);
|
|
36
|
+
query = addInContextDirective(query, country, language);
|
|
15
37
|
const apiUrl = this.config.getApiUrl(this.locale);
|
|
16
38
|
const token = this.config.getStorefrontToken(this.locale);
|
|
17
39
|
const headers = {
|
|
@@ -33,9 +55,7 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
33
55
|
...tags.length > 0 && { next: { tags } }
|
|
34
56
|
});
|
|
35
57
|
if (!response.ok) {
|
|
36
|
-
throw new Error(
|
|
37
|
-
`HTTP ${response.status}: ${response.statusText}`
|
|
38
|
-
);
|
|
58
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
39
59
|
}
|
|
40
60
|
const json = await response.json();
|
|
41
61
|
if (json.errors && json.errors.length > 0) {
|
|
@@ -51,10 +71,7 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
51
71
|
* Convenience method for simple queries
|
|
52
72
|
*/
|
|
53
73
|
async query(query, variables, options) {
|
|
54
|
-
const response = await this.request(
|
|
55
|
-
{ query, variables },
|
|
56
|
-
options
|
|
57
|
-
);
|
|
74
|
+
const response = await this.request({ query, variables }, options);
|
|
58
75
|
return response.data;
|
|
59
76
|
}
|
|
60
77
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { ShopifyConfig } from '@anker-in/shopify-core'\nimport type { GraphQLResponse, GraphQLRequest, FetchOptions } from './types'\n\n/**\n * Shopify GraphQL Client\n * Handles all GraphQL communication with Shopify Storefront API\n */\nexport class ShopifyClient {\n private config: ShopifyConfig\n private locale: string\n\n constructor(config: ShopifyConfig, locale: string) {\n this.config = config\n this.locale = locale\n }\n\n /**\n * Execute a GraphQL request\n */\n async request<T = any>(\n request: GraphQLRequest,\n options: FetchOptions = {}\n ): Promise<GraphQLResponse<T>> {\n const { query, variables, operationName } = request\n const { tags = [], ...fetchOptions } = options\n\n const apiUrl = this.config.getApiUrl(this.locale)\n const token = this.config.getStorefrontToken(this.locale)\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': token,\n ...(fetchOptions.headers || {}),\n }\n\n const body = JSON.stringify({\n query,\n variables,\n operationName,\n })\n\n try {\n const response = await fetch(apiUrl, {\n method: 'POST',\n headers,\n body,\n ...fetchOptions,\n ...(tags.length > 0 && { next: { tags } }),\n })\n\n if (!response.ok) {\n throw new Error(\n `HTTP ${response.status}: ${response.statusText}`\n )\n }\n\n const json: GraphQLResponse<T> = await response.json()\n\n if (json.errors && json.errors.length > 0) {\n console.error('GraphQL Errors:', json.errors)\n }\n\n return json\n } catch (error) {\n console.error('Shopify API Request Failed:', error)\n throw error\n }\n }\n\n /**\n * Convenience method for simple queries\n */\n async query<T = any>(\n query: string,\n variables?: Record<string, any>,\n options?: FetchOptions\n ): Promise<T | undefined> {\n const response = await this.request<T>(\n { query, variables },\n options\n )\n return response.data\n }\n\n /**\n * Get current locale\n */\n getLocale(): string {\n return this.locale\n }\n\n /**\n * Get config\n */\n getConfig(): ShopifyConfig {\n return this.config\n }\n\n /**\n * Get API URL\n */\n getApiUrl(): string {\n return this.config.getApiUrl(this.locale)\n }\n\n /**\n * Create a new client with different locale\n */\n withLocale(locale: string): ShopifyClient {\n return new ShopifyClient(this.config, locale)\n }\n}\n\n/**\n * Factory function to create a Shopify client\n */\nexport function createShopifyClient(\n config: ShopifyConfig,\n locale: string\n): ShopifyClient {\n return new ShopifyClient(config, locale)\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils.ts","../../src/client/client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { HasMetafieldsIdentifier, Maybe, Metafield } from './shopify-types'\n\nexport type PartialRecord<K extends string | number | symbol, T> = Partial<Record<K, T>>\n\nexport type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>\n\nexport type Replace<T, K extends keyof T, V> = Omit<T, K> & { [P in K]: V }\n\nexport enum HasMetafieldQueryRoot {\n Product = 'product',\n Variant = 'variant',\n Page = 'page',\n Article = 'article',\n Blog = 'blog',\n Collection = 'collection',\n Shop = 'shop',\n Cart = 'cart',\n Customer = 'customer',\n Location = 'location',\n Market = 'market',\n Order = 'order',\n}\n\n/**\n * 生成 metafieldIdentifiers 查询参数\n */\nexport function constructMetafieldIdentifiersQueryParams<T extends HasMetafieldQueryRoot>(\n metafieldIdentifiers: PartialRecord<T, HasMetafieldsIdentifier[]> = {},\n metafieldNamespacePrefix: string\n): PartialRecord<`${T}MetafieldIdentifiers`, HasMetafieldsIdentifier[]> {\n const identifiers = Object.entries(metafieldIdentifiers).reduce(\n (queryInput, [key, value]) => {\n const metafieldIdentifiers = value as HasMetafieldsIdentifier[]\n queryInput[`${key}MetafieldIdentifiers` as `${T}MetafieldIdentifiers`] =\n metafieldIdentifiers.map((item) => ({\n namespace: item.namespace,\n key: item.key,\n })) as HasMetafieldsIdentifier[]\n return queryInput\n },\n {} as PartialRecord<`${T}MetafieldIdentifiers`, HasMetafieldsIdentifier[]>\n )\n return identifiers\n}\n\nexport const parseMetafield = (item: Metafield, previewData?: any, resource_type?: string) => {\n const type = item?.type && item?.type.toLowerCase()\n if (\n item &&\n previewData &&\n previewData?.__preview_type === resource_type &&\n previewData[`${item?.namespace}${item?.key}`] !== undefined &&\n previewData[`${item?.namespace}${item?.key}`] !== null\n ) {\n return previewData[`${item.namespace}${item.key}`]\n }\n switch (type) {\n case 'json':\n case 'json_string':\n case 'rating':\n case 'volume':\n case 'weight':\n case 'dimension':\n return JSON.parse(item.value)\n default:\n return item?.value || item\n }\n}\n\nexport const normalizeMetafields = (metafields: Array<Maybe<Metafield>>): Record<string, any> => {\n return metafields?.reduce(\n (prev, cur) => {\n if (cur) {\n const namespace = cur.key\n prev[namespace] = prev[namespace] || {}\n const parsedMetafields: {\n [key: string]: Metafield\n } = parseMetafield(cur)\n if (parsedMetafields) {\n Object.entries(parsedMetafields).forEach(([key, innerMetafields]) => {\n prev[namespace][key] =\n prev[namespace][key] ?? (innerMetafields ? parseMetafield(innerMetafields) : null)\n })\n }\n }\n return prev\n },\n {} as Record<string, any>\n )\n}\n\n/**\n * Add @inContext directive to GraphQL query for single shop multi-language/currency support\n *\n * @param query - GraphQL query string\n * @param country - Country code (e.g., 'PL', 'CA', 'US')\n * @param language - Language code (e.g., 'PL', 'FR', 'EN')\n * @returns Modified query with @inContext directive, or original query if country/language not provided\n *\n * @example\n * ```typescript\n * const query = `query getCart($cartId: ID!) { cart(id: $cartId) { id } }`\n * const modifiedQuery = addInContextDirective(query, 'PL', 'PL')\n * // Result: query getCart($cartId: ID!) @inContext(country: PL, language: PL) { cart(id: $cartId) { id } }\n * ```\n */\nexport function addInContextDirective(\n query: string,\n country?: string,\n language?: string\n): string {\n // If no country or language, return original query\n if (!country || !language) {\n return query\n }\n\n // Match query/mutation declaration with optional parameters\n // e.g., \"query getCart(...)\" or \"mutation createCart\"\n const operationRegex = /((?:query|mutation)\\s+\\w+)(\\s*\\([^)]*\\))?\\s*(\\{)/\n const match = query.match(operationRegex)\n\n if (!match) {\n // Fallback: try to find first { if no operation found\n const braceIndex = query.indexOf('{')\n if (braceIndex === -1) return query\n\n const beforeBrace = query.substring(0, braceIndex).trim()\n const afterBrace = query.substring(braceIndex)\n return `${beforeBrace} @inContext(country: ${country}, language: ${language}) ${afterBrace}`\n }\n\n // Insert @inContext after operation declaration (and parameters if exist), before {\n const beforeDirective = match[1] + (match[2] || '') // e.g., \"query getCart($id: ID!)\"\n const afterDirective = query.substring(match.index! + match[0].length - 1) // Everything starting from {\n\n return `${beforeDirective} @inContext(country: ${country}, language: ${language}) ${afterDirective}`\n}\n","import type { ShopifyConfig } from '@anker-in/shopify-core'\nimport type { GraphQLResponse, GraphQLRequest, FetchOptions } from './types'\nimport { addInContextDirective } from '../utils'\n\n/**\n * Shopify GraphQL Client\n * Handles all GraphQL communication with Shopify Storefront API\n */\nexport class ShopifyClient {\n private config: ShopifyConfig\n private locale: string\n\n constructor(config: ShopifyConfig, locale: string) {\n this.config = config\n this.locale = locale\n }\n\n /**\n * Execute a GraphQL request\n */\n async request<T = any>(\n request: GraphQLRequest,\n options: FetchOptions = {}\n ): Promise<GraphQLResponse<T>> {\n let { query, variables, operationName } = request\n const { tags = [], ...fetchOptions } = options\n\n // Add @inContext directive if needed for single shop multi-language/currency\n const country = this.config.getCountryCode(this.locale)\n const language = this.config.getLanguageCode(this.locale)\n query = addInContextDirective(query, country, language)\n\n const apiUrl = this.config.getApiUrl(this.locale)\n const token = this.config.getStorefrontToken(this.locale)\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'X-Shopify-Storefront-Access-Token': token,\n ...(fetchOptions.headers || {}),\n }\n\n const body = JSON.stringify({\n query,\n variables,\n operationName,\n })\n\n try {\n const response = await fetch(apiUrl, {\n method: 'POST',\n headers,\n body,\n ...fetchOptions,\n ...(tags.length > 0 && { next: { tags } }),\n })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n const json: GraphQLResponse<T> = await response.json()\n\n if (json.errors && json.errors.length > 0) {\n console.error('GraphQL Errors:', json.errors)\n }\n\n return json\n } catch (error) {\n console.error('Shopify API Request Failed:', error)\n throw error\n }\n }\n\n /**\n * Convenience method for simple queries\n */\n async query<T = any>(\n query: string,\n variables?: Record<string, any>,\n options?: FetchOptions\n ): Promise<T | undefined> {\n const response = await this.request<T>({ query, variables }, options)\n return response.data\n }\n\n /**\n * Get current locale\n */\n getLocale(): string {\n return this.locale\n }\n\n /**\n * Get config\n */\n getConfig(): ShopifyConfig {\n return this.config\n }\n\n /**\n * Get API URL\n */\n getApiUrl(): string {\n return this.config.getApiUrl(this.locale)\n }\n\n /**\n * Create a new client with different locale\n */\n withLocale(locale: string): ShopifyClient {\n return new ShopifyClient(this.config, locale)\n }\n}\n\n/**\n * Factory function to create a Shopify client\n */\nexport function createShopifyClient(config: ShopifyConfig, locale: string): ShopifyClient {\n return new ShopifyClient(config, locale)\n}\n"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -10230,6 +10230,7 @@ interface NormalizedLineItem {
|
|
|
10230
10230
|
totalAmount: number;
|
|
10231
10231
|
subtotalAmount: number;
|
|
10232
10232
|
discountAllocations: Array<{
|
|
10233
|
+
title: string;
|
|
10233
10234
|
code: string;
|
|
10234
10235
|
amount: number;
|
|
10235
10236
|
}>;
|
|
@@ -10280,6 +10281,7 @@ interface NormalizedCart {
|
|
|
10280
10281
|
code: string;
|
|
10281
10282
|
}>;
|
|
10282
10283
|
discountAllocations?: Array<{
|
|
10284
|
+
title: string;
|
|
10283
10285
|
code: string;
|
|
10284
10286
|
amount: number;
|
|
10285
10287
|
}>;
|
|
@@ -10400,6 +10402,8 @@ interface CreateCartOptions {
|
|
|
10400
10402
|
variant: HasMetafieldsIdentifier[];
|
|
10401
10403
|
product: HasMetafieldsIdentifier[];
|
|
10402
10404
|
};
|
|
10405
|
+
/** Whether to update the cookie * 默认不更新cookie/ 仅在需要更新cookie时设置为true */
|
|
10406
|
+
updateCookie?: boolean;
|
|
10403
10407
|
}
|
|
10404
10408
|
/**
|
|
10405
10409
|
* Create a new cart
|
|
@@ -10437,25 +10441,12 @@ declare function createCart(client: ShopifyClient, options?: CreateCartOptions):
|
|
|
10437
10441
|
*/
|
|
10438
10442
|
|
|
10439
10443
|
interface AddCartLinesOptions {
|
|
10440
|
-
/** Cart ID (
|
|
10441
|
-
cartId
|
|
10444
|
+
/** Cart ID (required) */
|
|
10445
|
+
cartId: string;
|
|
10442
10446
|
/** Lines to add */
|
|
10443
10447
|
lines: CartLineInput[];
|
|
10444
10448
|
/** Cookie adapter for managing cart ID */
|
|
10445
10449
|
cookieAdapter?: CartCookieAdapter;
|
|
10446
|
-
/** Current locale */
|
|
10447
|
-
/** Buyer identity for cart creation */
|
|
10448
|
-
buyerIdentity?: {
|
|
10449
|
-
email?: string;
|
|
10450
|
-
countryCode?: string;
|
|
10451
|
-
};
|
|
10452
|
-
/** Discount codes (only used when creating new cart) */
|
|
10453
|
-
discountCodes?: string[];
|
|
10454
|
-
/** Custom attributes (only used when creating new cart) */
|
|
10455
|
-
customAttributes?: Array<{
|
|
10456
|
-
key: string;
|
|
10457
|
-
value: string;
|
|
10458
|
-
}>;
|
|
10459
10450
|
/** Metafield identifiers */
|
|
10460
10451
|
metafieldIdentifiers?: {
|
|
10461
10452
|
variant: HasMetafieldsIdentifier[];
|
|
@@ -10463,7 +10454,7 @@ interface AddCartLinesOptions {
|
|
|
10463
10454
|
};
|
|
10464
10455
|
}
|
|
10465
10456
|
/**
|
|
10466
|
-
* Add lines to
|
|
10457
|
+
* Add lines to an existing cart
|
|
10467
10458
|
*
|
|
10468
10459
|
* @param client - Shopify GraphQL client
|
|
10469
10460
|
* @param options - Add cart lines options
|
|
@@ -10472,7 +10463,7 @@ interface AddCartLinesOptions {
|
|
|
10472
10463
|
* @example
|
|
10473
10464
|
* ```ts
|
|
10474
10465
|
* const cart = await addCartLines(client, {
|
|
10475
|
-
*
|
|
10466
|
+
* cartId: 'gid://shopify/Cart/xxx',
|
|
10476
10467
|
* lines: [{
|
|
10477
10468
|
* merchandiseId: 'gid://shopify/ProductVariant/123',
|
|
10478
10469
|
* quantity: 1
|
package/dist/index.d.ts
CHANGED
|
@@ -10230,6 +10230,7 @@ interface NormalizedLineItem {
|
|
|
10230
10230
|
totalAmount: number;
|
|
10231
10231
|
subtotalAmount: number;
|
|
10232
10232
|
discountAllocations: Array<{
|
|
10233
|
+
title: string;
|
|
10233
10234
|
code: string;
|
|
10234
10235
|
amount: number;
|
|
10235
10236
|
}>;
|
|
@@ -10280,6 +10281,7 @@ interface NormalizedCart {
|
|
|
10280
10281
|
code: string;
|
|
10281
10282
|
}>;
|
|
10282
10283
|
discountAllocations?: Array<{
|
|
10284
|
+
title: string;
|
|
10283
10285
|
code: string;
|
|
10284
10286
|
amount: number;
|
|
10285
10287
|
}>;
|
|
@@ -10400,6 +10402,8 @@ interface CreateCartOptions {
|
|
|
10400
10402
|
variant: HasMetafieldsIdentifier[];
|
|
10401
10403
|
product: HasMetafieldsIdentifier[];
|
|
10402
10404
|
};
|
|
10405
|
+
/** Whether to update the cookie * 默认不更新cookie/ 仅在需要更新cookie时设置为true */
|
|
10406
|
+
updateCookie?: boolean;
|
|
10403
10407
|
}
|
|
10404
10408
|
/**
|
|
10405
10409
|
* Create a new cart
|
|
@@ -10437,25 +10441,12 @@ declare function createCart(client: ShopifyClient, options?: CreateCartOptions):
|
|
|
10437
10441
|
*/
|
|
10438
10442
|
|
|
10439
10443
|
interface AddCartLinesOptions {
|
|
10440
|
-
/** Cart ID (
|
|
10441
|
-
cartId
|
|
10444
|
+
/** Cart ID (required) */
|
|
10445
|
+
cartId: string;
|
|
10442
10446
|
/** Lines to add */
|
|
10443
10447
|
lines: CartLineInput[];
|
|
10444
10448
|
/** Cookie adapter for managing cart ID */
|
|
10445
10449
|
cookieAdapter?: CartCookieAdapter;
|
|
10446
|
-
/** Current locale */
|
|
10447
|
-
/** Buyer identity for cart creation */
|
|
10448
|
-
buyerIdentity?: {
|
|
10449
|
-
email?: string;
|
|
10450
|
-
countryCode?: string;
|
|
10451
|
-
};
|
|
10452
|
-
/** Discount codes (only used when creating new cart) */
|
|
10453
|
-
discountCodes?: string[];
|
|
10454
|
-
/** Custom attributes (only used when creating new cart) */
|
|
10455
|
-
customAttributes?: Array<{
|
|
10456
|
-
key: string;
|
|
10457
|
-
value: string;
|
|
10458
|
-
}>;
|
|
10459
10450
|
/** Metafield identifiers */
|
|
10460
10451
|
metafieldIdentifiers?: {
|
|
10461
10452
|
variant: HasMetafieldsIdentifier[];
|
|
@@ -10463,7 +10454,7 @@ interface AddCartLinesOptions {
|
|
|
10463
10454
|
};
|
|
10464
10455
|
}
|
|
10465
10456
|
/**
|
|
10466
|
-
* Add lines to
|
|
10457
|
+
* Add lines to an existing cart
|
|
10467
10458
|
*
|
|
10468
10459
|
* @param client - Shopify GraphQL client
|
|
10469
10460
|
* @param options - Add cart lines options
|
|
@@ -10472,7 +10463,7 @@ interface AddCartLinesOptions {
|
|
|
10472
10463
|
* @example
|
|
10473
10464
|
* ```ts
|
|
10474
10465
|
* const cart = await addCartLines(client, {
|
|
10475
|
-
*
|
|
10466
|
+
* cartId: 'gid://shopify/Cart/xxx',
|
|
10476
10467
|
* lines: [{
|
|
10477
10468
|
* merchandiseId: 'gid://shopify/ProductVariant/123',
|
|
10478
10469
|
* quantity: 1
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,71 @@
|
|
|
2
2
|
|
|
3
3
|
var shopifyCore = require('@anker-in/shopify-core');
|
|
4
4
|
|
|
5
|
+
// src/utils.ts
|
|
6
|
+
function constructMetafieldIdentifiersQueryParams(metafieldIdentifiers = {}, metafieldNamespacePrefix) {
|
|
7
|
+
const identifiers = Object.entries(metafieldIdentifiers).reduce(
|
|
8
|
+
(queryInput, [key, value]) => {
|
|
9
|
+
const metafieldIdentifiers2 = value;
|
|
10
|
+
queryInput[`${key}MetafieldIdentifiers`] = metafieldIdentifiers2.map((item) => ({
|
|
11
|
+
namespace: item.namespace,
|
|
12
|
+
key: item.key
|
|
13
|
+
}));
|
|
14
|
+
return queryInput;
|
|
15
|
+
},
|
|
16
|
+
{}
|
|
17
|
+
);
|
|
18
|
+
return identifiers;
|
|
19
|
+
}
|
|
20
|
+
var parseMetafield = (item, previewData, resource_type) => {
|
|
21
|
+
const type = item?.type && item?.type.toLowerCase();
|
|
22
|
+
switch (type) {
|
|
23
|
+
case "json":
|
|
24
|
+
case "json_string":
|
|
25
|
+
case "rating":
|
|
26
|
+
case "volume":
|
|
27
|
+
case "weight":
|
|
28
|
+
case "dimension":
|
|
29
|
+
return JSON.parse(item.value);
|
|
30
|
+
default:
|
|
31
|
+
return item?.value || item;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var normalizeMetafields = (metafields) => {
|
|
35
|
+
return metafields?.reduce(
|
|
36
|
+
(prev, cur) => {
|
|
37
|
+
if (cur) {
|
|
38
|
+
const namespace = cur.key;
|
|
39
|
+
prev[namespace] = prev[namespace] || {};
|
|
40
|
+
const parsedMetafields = parseMetafield(cur);
|
|
41
|
+
if (parsedMetafields) {
|
|
42
|
+
Object.entries(parsedMetafields).forEach(([key, innerMetafields]) => {
|
|
43
|
+
prev[namespace][key] = prev[namespace][key] ?? (innerMetafields ? parseMetafield(innerMetafields) : null);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return prev;
|
|
48
|
+
},
|
|
49
|
+
{}
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
function addInContextDirective(query, country, language) {
|
|
53
|
+
if (!country || !language) {
|
|
54
|
+
return query;
|
|
55
|
+
}
|
|
56
|
+
const operationRegex = /((?:query|mutation)\s+\w+)(\s*\([^)]*\))?\s*(\{)/;
|
|
57
|
+
const match = query.match(operationRegex);
|
|
58
|
+
if (!match) {
|
|
59
|
+
const braceIndex = query.indexOf("{");
|
|
60
|
+
if (braceIndex === -1) return query;
|
|
61
|
+
const beforeBrace = query.substring(0, braceIndex).trim();
|
|
62
|
+
const afterBrace = query.substring(braceIndex);
|
|
63
|
+
return `${beforeBrace} @inContext(country: ${country}, language: ${language}) ${afterBrace}`;
|
|
64
|
+
}
|
|
65
|
+
const beforeDirective = match[1] + (match[2] || "");
|
|
66
|
+
const afterDirective = query.substring(match.index + match[0].length - 1);
|
|
67
|
+
return `${beforeDirective} @inContext(country: ${country}, language: ${language}) ${afterDirective}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
5
70
|
// src/client/client.ts
|
|
6
71
|
var ShopifyClient = class _ShopifyClient {
|
|
7
72
|
config;
|
|
@@ -14,8 +79,11 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
14
79
|
* Execute a GraphQL request
|
|
15
80
|
*/
|
|
16
81
|
async request(request, options = {}) {
|
|
17
|
-
|
|
82
|
+
let { query, variables, operationName } = request;
|
|
18
83
|
const { tags = [], ...fetchOptions } = options;
|
|
84
|
+
const country = this.config.getCountryCode(this.locale);
|
|
85
|
+
const language = this.config.getLanguageCode(this.locale);
|
|
86
|
+
query = addInContextDirective(query, country, language);
|
|
19
87
|
const apiUrl = this.config.getApiUrl(this.locale);
|
|
20
88
|
const token = this.config.getStorefrontToken(this.locale);
|
|
21
89
|
const headers = {
|
|
@@ -37,9 +105,7 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
37
105
|
...tags.length > 0 && { next: { tags } }
|
|
38
106
|
});
|
|
39
107
|
if (!response.ok) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
`HTTP ${response.status}: ${response.statusText}`
|
|
42
|
-
);
|
|
108
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
43
109
|
}
|
|
44
110
|
const json = await response.json();
|
|
45
111
|
if (json.errors && json.errors.length > 0) {
|
|
@@ -55,10 +121,7 @@ var ShopifyClient = class _ShopifyClient {
|
|
|
55
121
|
* Convenience method for simple queries
|
|
56
122
|
*/
|
|
57
123
|
async query(query, variables, options) {
|
|
58
|
-
const response = await this.request(
|
|
59
|
-
{ query, variables },
|
|
60
|
-
options
|
|
61
|
-
);
|
|
124
|
+
const response = await this.request({ query, variables }, options);
|
|
62
125
|
return response.data;
|
|
63
126
|
}
|
|
64
127
|
/**
|
|
@@ -1011,56 +1074,6 @@ var updateCartDeliveryOptionsMutation = (
|
|
|
1011
1074
|
${cartFragment}
|
|
1012
1075
|
`
|
|
1013
1076
|
);
|
|
1014
|
-
|
|
1015
|
-
// src/utils.ts
|
|
1016
|
-
function constructMetafieldIdentifiersQueryParams(metafieldIdentifiers = {}, metafieldNamespacePrefix) {
|
|
1017
|
-
const identifiers = Object.entries(metafieldIdentifiers).reduce(
|
|
1018
|
-
(queryInput, [key, value]) => {
|
|
1019
|
-
const metafieldIdentifiers2 = value;
|
|
1020
|
-
queryInput[`${key}MetafieldIdentifiers`] = metafieldIdentifiers2.map((item) => ({
|
|
1021
|
-
namespace: `${metafieldNamespacePrefix}combo`,
|
|
1022
|
-
key: item.namespace
|
|
1023
|
-
}));
|
|
1024
|
-
return queryInput;
|
|
1025
|
-
},
|
|
1026
|
-
{}
|
|
1027
|
-
);
|
|
1028
|
-
return identifiers;
|
|
1029
|
-
}
|
|
1030
|
-
var parseMetafield = (item, previewData, resource_type) => {
|
|
1031
|
-
const type = item?.type && item?.type.toLowerCase();
|
|
1032
|
-
switch (type) {
|
|
1033
|
-
case "json":
|
|
1034
|
-
case "json_string":
|
|
1035
|
-
case "rating":
|
|
1036
|
-
case "volume":
|
|
1037
|
-
case "weight":
|
|
1038
|
-
case "dimension":
|
|
1039
|
-
return JSON.parse(item.value);
|
|
1040
|
-
default:
|
|
1041
|
-
return item?.value || item;
|
|
1042
|
-
}
|
|
1043
|
-
};
|
|
1044
|
-
var normalizeMetafields = (metafields) => {
|
|
1045
|
-
return metafields?.reduce(
|
|
1046
|
-
(prev, cur) => {
|
|
1047
|
-
if (cur) {
|
|
1048
|
-
const namespace = cur.key;
|
|
1049
|
-
prev[namespace] = prev[namespace] || {};
|
|
1050
|
-
const parsedMetafields = parseMetafield(cur);
|
|
1051
|
-
if (parsedMetafields) {
|
|
1052
|
-
Object.entries(parsedMetafields).forEach(([key, innerMetafields]) => {
|
|
1053
|
-
prev[namespace][key] = prev[namespace][key] ?? (innerMetafields ? parseMetafield(innerMetafields) : null);
|
|
1054
|
-
});
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
return prev;
|
|
1058
|
-
},
|
|
1059
|
-
{}
|
|
1060
|
-
);
|
|
1061
|
-
};
|
|
1062
|
-
|
|
1063
|
-
// src/api/product/normalize.ts
|
|
1064
1077
|
var normalizeSellingPlan = ({ edges }) => {
|
|
1065
1078
|
return edges?.map(({ node }) => node);
|
|
1066
1079
|
};
|
|
@@ -1088,12 +1101,14 @@ function normalizeVariant(variant) {
|
|
|
1088
1101
|
amount: variant.compareAtPriceV2.amount,
|
|
1089
1102
|
currencyCode: variant.compareAtPriceV2.currencyCode
|
|
1090
1103
|
} : void 0;
|
|
1104
|
+
const isSoldOut = Number(price.amount) === shopifyCore.SOLD_OUT_PRICE;
|
|
1091
1105
|
const metafields = normalizeMetafields(variant.metafields || []);
|
|
1092
1106
|
return {
|
|
1093
1107
|
id: variant.id,
|
|
1094
1108
|
title: variant.title,
|
|
1095
1109
|
sku: variant.sku || "",
|
|
1096
|
-
|
|
1110
|
+
// 如果价格为售罄价格,强制设置 availableForSale 为 false
|
|
1111
|
+
availableForSale: isSoldOut ? false : variant.availableForSale || false,
|
|
1097
1112
|
quantityAvailable: variant.quantityAvailable,
|
|
1098
1113
|
selectedOptions: variant.selectedOptions || [],
|
|
1099
1114
|
price,
|
|
@@ -1367,7 +1382,8 @@ function normalizeLineItem(line) {
|
|
|
1367
1382
|
totalAmount: cost?.totalAmount?.amount || 0,
|
|
1368
1383
|
subtotalAmount: cost?.subtotalAmount?.amount || 0,
|
|
1369
1384
|
discountAllocations: discountAllocations?.map((item) => ({
|
|
1370
|
-
|
|
1385
|
+
title: item?.title || "",
|
|
1386
|
+
code: item?.code || "",
|
|
1371
1387
|
amount: item?.discountedAmount?.amount || 0
|
|
1372
1388
|
})) || [],
|
|
1373
1389
|
customAttributes: attributes?.filter((item) => item.key && item.value).map((item) => ({ key: item.key, value: item.value || "" })) || [],
|
|
@@ -1434,7 +1450,8 @@ function normalizeCart(cart) {
|
|
|
1434
1450
|
orderDiscounts,
|
|
1435
1451
|
discountCodes: cart.discountCodes || [],
|
|
1436
1452
|
discountAllocations: cart?.discountAllocations?.map((item) => ({
|
|
1437
|
-
|
|
1453
|
+
title: item?.title || "",
|
|
1454
|
+
code: item?.code || "",
|
|
1438
1455
|
amount: Number(item?.discountedAmount?.amount || 0)
|
|
1439
1456
|
})) || [],
|
|
1440
1457
|
// Map delivery amount from cart cost
|
|
@@ -1496,7 +1513,8 @@ async function createCart(client, options = {}) {
|
|
|
1496
1513
|
buyerIdentity,
|
|
1497
1514
|
discountCodes,
|
|
1498
1515
|
customAttributes,
|
|
1499
|
-
metafieldIdentifiers
|
|
1516
|
+
metafieldIdentifiers,
|
|
1517
|
+
updateCookie = false
|
|
1500
1518
|
} = options;
|
|
1501
1519
|
const locale = client.getLocale();
|
|
1502
1520
|
try {
|
|
@@ -1518,7 +1536,7 @@ async function createCart(client, options = {}) {
|
|
|
1518
1536
|
return void 0;
|
|
1519
1537
|
}
|
|
1520
1538
|
const normalizedCart = normalizeCart(cart);
|
|
1521
|
-
if (cookieAdapter && normalizedCart.id) {
|
|
1539
|
+
if (cookieAdapter && normalizedCart.id && updateCookie) {
|
|
1522
1540
|
cookieAdapter.setCartId(locale, normalizedCart.id);
|
|
1523
1541
|
}
|
|
1524
1542
|
return normalizedCart;
|
|
@@ -1530,46 +1548,22 @@ async function createCart(client, options = {}) {
|
|
|
1530
1548
|
|
|
1531
1549
|
// src/api/cart/add-cart-lines.ts
|
|
1532
1550
|
async function addCartLines(client, options) {
|
|
1533
|
-
const {
|
|
1534
|
-
cartId: providedCartId,
|
|
1535
|
-
lines,
|
|
1536
|
-
cookieAdapter,
|
|
1537
|
-
buyerIdentity,
|
|
1538
|
-
discountCodes,
|
|
1539
|
-
customAttributes,
|
|
1540
|
-
metafieldIdentifiers
|
|
1541
|
-
} = options;
|
|
1551
|
+
const { cartId, lines, cookieAdapter, metafieldIdentifiers } = options;
|
|
1542
1552
|
const locale = client.getLocale();
|
|
1543
|
-
const cartId = providedCartId || cookieAdapter?.getCartId(locale);
|
|
1544
1553
|
const normalizedMetafieldIdentifiers = constructMetafieldIdentifiersQueryParams(
|
|
1545
1554
|
metafieldIdentifiers,
|
|
1546
1555
|
client.getConfig().getMetafieldNamespacePrefix()
|
|
1547
1556
|
);
|
|
1548
1557
|
try {
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
if (data?.cartLinesAdd?.userErrors?.length) {
|
|
1557
|
-
console.error("[addCartLines] User errors:", data.cartLinesAdd.userErrors);
|
|
1558
|
-
}
|
|
1559
|
-
cart = data?.cartLinesAdd?.cart;
|
|
1560
|
-
} else {
|
|
1561
|
-
const data = await client.query(createCartMutation, {
|
|
1562
|
-
lines,
|
|
1563
|
-
buyerIdentity,
|
|
1564
|
-
discountCodes,
|
|
1565
|
-
attributes: customAttributes,
|
|
1566
|
-
...normalizedMetafieldIdentifiers
|
|
1567
|
-
});
|
|
1568
|
-
if (data?.cartCreate?.userErrors?.length) {
|
|
1569
|
-
console.error("[addCartLines] User errors:", data.cartCreate.userErrors);
|
|
1570
|
-
}
|
|
1571
|
-
cart = data?.cartCreate?.cart;
|
|
1558
|
+
const data = await client.query(addCartItemsMutation, {
|
|
1559
|
+
cartId,
|
|
1560
|
+
lines,
|
|
1561
|
+
...normalizedMetafieldIdentifiers
|
|
1562
|
+
});
|
|
1563
|
+
if (data?.cartLinesAdd?.userErrors?.length) {
|
|
1564
|
+
console.error("[addCartLines] User errors:", data.cartLinesAdd.userErrors);
|
|
1572
1565
|
}
|
|
1566
|
+
const cart = data?.cartLinesAdd?.cart;
|
|
1573
1567
|
if (!cart) {
|
|
1574
1568
|
return void 0;
|
|
1575
1569
|
}
|
|
@@ -1592,14 +1586,17 @@ async function updateCartLines(client, options) {
|
|
|
1592
1586
|
if (!cartId) {
|
|
1593
1587
|
throw new Error("Invalid input used for this operation: Miss cartId");
|
|
1594
1588
|
}
|
|
1589
|
+
const metafieldParams = constructMetafieldIdentifiersQueryParams(
|
|
1590
|
+
metafieldIdentifiers,
|
|
1591
|
+
client.getConfig().getMetafieldNamespacePrefix()
|
|
1592
|
+
);
|
|
1593
|
+
console.log("update-cart-lines metafieldIdentifiers:", metafieldIdentifiers);
|
|
1594
|
+
console.log("update-cart-lines metafieldParams:", metafieldParams);
|
|
1595
1595
|
try {
|
|
1596
1596
|
const data = await client.query(updateCartItemsMutation, {
|
|
1597
1597
|
cartId,
|
|
1598
1598
|
lines,
|
|
1599
|
-
...
|
|
1600
|
-
metafieldIdentifiers,
|
|
1601
|
-
client.getConfig().getMetafieldNamespacePrefix()
|
|
1602
|
-
)
|
|
1599
|
+
...metafieldParams
|
|
1603
1600
|
});
|
|
1604
1601
|
let maxNum;
|
|
1605
1602
|
if (data?.cartLinesUpdate?.userErrors?.length) {
|