@shopbb/helium 0.5.10 → 0.6.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/cache/withCache.d.ts +49 -0
- package/dist/cache/withCache.d.ts.map +1 -0
- package/dist/cache/withCache.js +117 -0
- package/dist/cache/withCache.js.map +1 -0
- package/dist/components/AddToCartButton.d.ts +28 -22
- package/dist/components/AddToCartButton.d.ts.map +1 -1
- package/dist/components/AddToCartButton.js +36 -47
- package/dist/components/AddToCartButton.js.map +1 -1
- package/dist/components/BuyNowButton.d.ts +45 -0
- package/dist/components/BuyNowButton.d.ts.map +1 -0
- package/dist/components/BuyNowButton.js +49 -0
- package/dist/components/BuyNowButton.js.map +1 -0
- package/dist/components/CartCheckoutButton.d.ts +39 -0
- package/dist/components/CartCheckoutButton.d.ts.map +1 -0
- package/dist/components/CartCheckoutButton.js +32 -0
- package/dist/components/CartCheckoutButton.js.map +1 -0
- package/dist/components/CartCost.d.ts +43 -0
- package/dist/components/CartCost.d.ts.map +1 -0
- package/dist/components/CartCost.js +34 -0
- package/dist/components/CartCost.js.map +1 -0
- package/dist/components/CartForm.d.ts +201 -0
- package/dist/components/CartForm.d.ts.map +1 -0
- package/dist/components/CartForm.js +213 -0
- package/dist/components/CartForm.js.map +1 -0
- package/dist/components/CartLineProvider.d.ts +78 -0
- package/dist/components/CartLineProvider.d.ts.map +1 -0
- package/dist/components/CartLineProvider.js +46 -0
- package/dist/components/CartLineProvider.js.map +1 -0
- package/dist/components/CartLineQuantity.d.ts +24 -0
- package/dist/components/CartLineQuantity.d.ts.map +1 -0
- package/dist/components/CartLineQuantity.js +9 -0
- package/dist/components/CartLineQuantity.js.map +1 -0
- package/dist/components/DiscountSelector.d.ts.map +1 -1
- package/dist/components/DiscountSelector.js +8 -19
- package/dist/components/DiscountSelector.js.map +1 -1
- package/dist/components/Image.d.ts +18 -0
- package/dist/components/Image.d.ts.map +1 -1
- package/dist/components/Image.js +26 -0
- package/dist/components/Image.js.map +1 -1
- package/dist/components/Pagination.d.ts +82 -0
- package/dist/components/Pagination.d.ts.map +1 -0
- package/dist/components/Pagination.js +84 -0
- package/dist/components/Pagination.js.map +1 -0
- package/dist/components/RichText.d.ts +78 -0
- package/dist/components/RichText.d.ts.map +1 -0
- package/dist/components/RichText.js +93 -0
- package/dist/components/RichText.js.map +1 -0
- package/dist/components/Seo.d.ts +25 -0
- package/dist/components/Seo.d.ts.map +1 -0
- package/dist/components/Seo.js +54 -0
- package/dist/components/Seo.js.map +1 -0
- package/dist/components/hooks/useMoney.d.ts +40 -0
- package/dist/components/hooks/useMoney.d.ts.map +1 -0
- package/dist/components/hooks/useMoney.js +60 -0
- package/dist/components/hooks/useMoney.js.map +1 -0
- package/dist/components/hooks/useOptimisticCart.d.ts +50 -0
- package/dist/components/hooks/useOptimisticCart.d.ts.map +1 -0
- package/dist/components/hooks/useOptimisticCart.js +138 -0
- package/dist/components/hooks/useOptimisticCart.js.map +1 -0
- package/dist/components/index.d.ts +28 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +21 -0
- package/dist/components/index.js.map +1 -1
- package/dist/createCartHandler.d.ts.map +1 -1
- package/dist/createCartHandler.js +57 -0
- package/dist/createCartHandler.js.map +1 -1
- package/dist/csp/csp.d.ts +57 -0
- package/dist/csp/csp.d.ts.map +1 -0
- package/dist/csp/csp.js +73 -0
- package/dist/csp/csp.js.map +1 -0
- package/dist/customer/createCustomerAccountClient.d.ts +43 -0
- package/dist/customer/createCustomerAccountClient.d.ts.map +1 -0
- package/dist/customer/createCustomerAccountClient.js +68 -0
- package/dist/customer/createCustomerAccountClient.js.map +1 -0
- package/dist/handleCartFormAction.d.ts +39 -0
- package/dist/handleCartFormAction.d.ts.map +1 -0
- package/dist/handleCartFormAction.js +103 -0
- package/dist/handleCartFormAction.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/routing/storefrontRedirect.d.ts +37 -0
- package/dist/routing/storefrontRedirect.d.ts.map +1 -0
- package/dist/routing/storefrontRedirect.js +64 -0
- package/dist/routing/storefrontRedirect.js.map +1 -0
- package/dist/seo/getSeoMeta.d.ts +68 -0
- package/dist/seo/getSeoMeta.d.ts.map +1 -0
- package/dist/seo/getSeoMeta.js +89 -0
- package/dist/seo/getSeoMeta.js.map +1 -0
- package/dist/sitemap/sitemap.d.ts +55 -0
- package/dist/sitemap/sitemap.d.ts.map +1 -0
- package/dist/sitemap/sitemap.js +93 -0
- package/dist/sitemap/sitemap.js.map +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/flattenConnection.d.ts +25 -0
- package/dist/utils/flattenConnection.d.ts.map +1 -0
- package/dist/utils/flattenConnection.js +25 -0
- package/dist/utils/flattenConnection.js.map +1 -0
- package/dist/utils/parseGid.d.ts +17 -0
- package/dist/utils/parseGid.d.ts.map +1 -0
- package/dist/utils/parseGid.js +19 -0
- package/dist/utils/parseGid.js.map +1 -0
- package/package.json +1 -1
- package/src/cache/withCache.ts +144 -0
- package/src/components/AddToCartButton.tsx +94 -56
- package/src/components/BuyNowButton.tsx +135 -0
- package/src/components/CartCheckoutButton.tsx +97 -0
- package/src/components/CartCost.tsx +65 -0
- package/src/components/CartForm.tsx +311 -0
- package/src/components/CartLineProvider.tsx +77 -0
- package/src/components/CartLineQuantity.tsx +37 -0
- package/src/components/DiscountSelector.tsx +34 -45
- package/src/components/Image.tsx +27 -0
- package/src/components/Pagination.tsx +139 -0
- package/src/components/RichText.tsx +122 -0
- package/src/components/Seo.tsx +61 -0
- package/src/components/hooks/useMoney.ts +87 -0
- package/src/components/hooks/useOptimisticCart.ts +173 -0
- package/src/components/index.ts +44 -0
- package/src/createCartHandler.ts +71 -0
- package/src/csp/csp.tsx +119 -0
- package/src/customer/createCustomerAccountClient.ts +89 -0
- package/src/handleCartFormAction.ts +129 -0
- package/src/index.ts +24 -0
- package/src/routing/storefrontRedirect.ts +86 -0
- package/src/seo/getSeoMeta.ts +125 -0
- package/src/sitemap/sitemap.ts +121 -0
- package/src/types.ts +12 -1
- package/src/utils/flattenConnection.ts +33 -0
- package/src/utils/parseGid.ts +25 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getSeoMeta + <Seo> — 对齐 Hydrogen 的 SEO 工具
|
|
3
|
+
*
|
|
4
|
+
* Hydrogen 通过 Remix `meta` export 返回 SeoConfig;我们这里因不绑 Remix,
|
|
5
|
+
* 提供一个 `getSeoMeta(config)` 函数返回 HTML `<meta>` 字符串,供 SSR
|
|
6
|
+
* 服务端拼到 `<head>` 里。也提供 `<Seo data={config} />` 客户端组件
|
|
7
|
+
* (hydrate 阶段更新 document title / meta),用作 SPA 路由切换。
|
|
8
|
+
*
|
|
9
|
+
* 用法(服务端):
|
|
10
|
+
*
|
|
11
|
+
* const seo = getSeoMeta({
|
|
12
|
+
* title: product.title,
|
|
13
|
+
* description: product.description,
|
|
14
|
+
* image: product.featuredImage?.url,
|
|
15
|
+
* url: 'https://shop/products/xxx',
|
|
16
|
+
* type: 'product',
|
|
17
|
+
* });
|
|
18
|
+
* // seo = { title, htmlTags: '<title>...</title><meta ...>' }
|
|
19
|
+
* const html = `<head>${seo.htmlTags}...</head>`;
|
|
20
|
+
*/
|
|
21
|
+
function escapeHtml(s) {
|
|
22
|
+
return String(s).replace(/[<>&"']/g, (c) => ({ '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[c]));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 根据 config 生成 <head> 该有的全部 SEO 标签字符串。
|
|
26
|
+
*/
|
|
27
|
+
export function getSeoMeta(config) {
|
|
28
|
+
const { title, titleTemplate, description = '', url, image, type = 'website', twitterCard = 'summary_large_image', og = {}, robots, jsonLd, } = config;
|
|
29
|
+
const fullTitle = title
|
|
30
|
+
? (titleTemplate ? `${title} · ${titleTemplate}` : title)
|
|
31
|
+
: (titleTemplate || '');
|
|
32
|
+
const imgUrl = typeof image === 'string' ? image : image?.url;
|
|
33
|
+
const imgAlt = typeof image === 'object' ? image?.altText : undefined;
|
|
34
|
+
const imgW = typeof image === 'object' ? image?.width : undefined;
|
|
35
|
+
const imgH = typeof image === 'object' ? image?.height : undefined;
|
|
36
|
+
const meta = [];
|
|
37
|
+
if (description)
|
|
38
|
+
meta.push({ name: 'description', content: description });
|
|
39
|
+
if (robots)
|
|
40
|
+
meta.push({ name: 'robots', content: robots });
|
|
41
|
+
if (fullTitle)
|
|
42
|
+
meta.push({ property: 'og:title', content: fullTitle });
|
|
43
|
+
if (description)
|
|
44
|
+
meta.push({ property: 'og:description', content: description });
|
|
45
|
+
if (url)
|
|
46
|
+
meta.push({ property: 'og:url', content: url });
|
|
47
|
+
meta.push({ property: 'og:type', content: type });
|
|
48
|
+
if (imgUrl)
|
|
49
|
+
meta.push({ property: 'og:image', content: imgUrl });
|
|
50
|
+
if (imgAlt)
|
|
51
|
+
meta.push({ property: 'og:image:alt', content: imgAlt });
|
|
52
|
+
if (imgW)
|
|
53
|
+
meta.push({ property: 'og:image:width', content: String(imgW) });
|
|
54
|
+
if (imgH)
|
|
55
|
+
meta.push({ property: 'og:image:height', content: String(imgH) });
|
|
56
|
+
for (const [k, v] of Object.entries(og)) {
|
|
57
|
+
meta.push({ property: k.startsWith('og:') ? k : `og:${k}`, content: v });
|
|
58
|
+
}
|
|
59
|
+
meta.push({ name: 'twitter:card', content: twitterCard });
|
|
60
|
+
if (fullTitle)
|
|
61
|
+
meta.push({ name: 'twitter:title', content: fullTitle });
|
|
62
|
+
if (description)
|
|
63
|
+
meta.push({ name: 'twitter:description', content: description });
|
|
64
|
+
if (imgUrl)
|
|
65
|
+
meta.push({ name: 'twitter:image', content: imgUrl });
|
|
66
|
+
const parts = [];
|
|
67
|
+
if (fullTitle)
|
|
68
|
+
parts.push(`<title>${escapeHtml(fullTitle)}</title>`);
|
|
69
|
+
if (url)
|
|
70
|
+
parts.push(`<link rel="canonical" href="${escapeHtml(url)}" />`);
|
|
71
|
+
for (const m of meta) {
|
|
72
|
+
const attr = m.name ? `name="${m.name}"` : `property="${m.property}"`;
|
|
73
|
+
parts.push(`<meta ${attr} content="${escapeHtml(m.content)}" />`);
|
|
74
|
+
}
|
|
75
|
+
if (jsonLd) {
|
|
76
|
+
const data = Array.isArray(jsonLd) ? jsonLd : [jsonLd];
|
|
77
|
+
for (const d of data) {
|
|
78
|
+
parts.push(`<script type="application/ld+json">${JSON.stringify(d).replace(/</g, '\\u003c')}</script>`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
title: fullTitle,
|
|
83
|
+
description,
|
|
84
|
+
meta,
|
|
85
|
+
fullTitle,
|
|
86
|
+
htmlTags: parts.join('\n'),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=getSeoMeta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getSeoMeta.js","sourceRoot":"","sources":["../../src/seo/getSeoMeta.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getSitemap + getSitemapIndex — 对齐 Hydrogen
|
|
3
|
+
*
|
|
4
|
+
* 生成 XML sitemap,让搜索引擎能爬到商品 / 集合 / 页面。
|
|
5
|
+
*
|
|
6
|
+
* 用法(服务端 GET /sitemap.xml):
|
|
7
|
+
*
|
|
8
|
+
* const xml = await getSitemap({
|
|
9
|
+
* storefront,
|
|
10
|
+
* request,
|
|
11
|
+
* types: ['products', 'collections', 'pages'],
|
|
12
|
+
* getLink: ({ type, baseUrl, handle }) => `${baseUrl}/${type}/${handle}`,
|
|
13
|
+
* });
|
|
14
|
+
* return new Response(xml, { headers: { 'Content-Type': 'application/xml' } });
|
|
15
|
+
*
|
|
16
|
+
* 大店铺:一个 sitemap 装不下时分多个:
|
|
17
|
+
*
|
|
18
|
+
* // GET /sitemap.xml
|
|
19
|
+
* const indexXml = await getSitemapIndex({
|
|
20
|
+
* baseUrl: 'https://shop',
|
|
21
|
+
* sitemaps: ['products-1.xml', 'collections.xml'],
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
export interface SitemapResource {
|
|
25
|
+
url: string;
|
|
26
|
+
lastmod?: string;
|
|
27
|
+
changefreq?: 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never' | 'always' | 'hourly';
|
|
28
|
+
priority?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface GetSitemapOptions {
|
|
31
|
+
storefront: {
|
|
32
|
+
query: (q: string, opts?: any) => Promise<any>;
|
|
33
|
+
};
|
|
34
|
+
request: Request;
|
|
35
|
+
/** 拉哪些类型 */
|
|
36
|
+
types: Array<'products' | 'collections' | 'pages' | 'articles' | 'blogs'>;
|
|
37
|
+
/** 每页最多多少(GraphQL connection pageSize),默认 250 */
|
|
38
|
+
pageSize?: number;
|
|
39
|
+
/** 自定义 link 构造:({type, baseUrl, handle}) => url。默认 baseUrl + /type + /handle */
|
|
40
|
+
getLink?: (args: {
|
|
41
|
+
type: string;
|
|
42
|
+
baseUrl: string;
|
|
43
|
+
handle: string;
|
|
44
|
+
}) => string;
|
|
45
|
+
/** 强制 base URL(不传则从 request 推导) */
|
|
46
|
+
baseUrl?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function getSitemap(options: GetSitemapOptions): Promise<string>;
|
|
49
|
+
export interface GetSitemapIndexOptions {
|
|
50
|
+
baseUrl: string;
|
|
51
|
+
sitemaps: string[];
|
|
52
|
+
lastmod?: string;
|
|
53
|
+
}
|
|
54
|
+
export declare function getSitemapIndex(options: GetSitemapIndexOptions): string;
|
|
55
|
+
//# sourceMappingURL=sitemap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/sitemap/sitemap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;KAAE,CAAC;IAC/D,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY;IACZ,KAAK,EAAE,KAAK,CAAC,UAAU,GAAG,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC,CAAC;IAC1E,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;IAC9E,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAkBD,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuC5E;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAavE"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* getSitemap + getSitemapIndex — 对齐 Hydrogen
|
|
3
|
+
*
|
|
4
|
+
* 生成 XML sitemap,让搜索引擎能爬到商品 / 集合 / 页面。
|
|
5
|
+
*
|
|
6
|
+
* 用法(服务端 GET /sitemap.xml):
|
|
7
|
+
*
|
|
8
|
+
* const xml = await getSitemap({
|
|
9
|
+
* storefront,
|
|
10
|
+
* request,
|
|
11
|
+
* types: ['products', 'collections', 'pages'],
|
|
12
|
+
* getLink: ({ type, baseUrl, handle }) => `${baseUrl}/${type}/${handle}`,
|
|
13
|
+
* });
|
|
14
|
+
* return new Response(xml, { headers: { 'Content-Type': 'application/xml' } });
|
|
15
|
+
*
|
|
16
|
+
* 大店铺:一个 sitemap 装不下时分多个:
|
|
17
|
+
*
|
|
18
|
+
* // GET /sitemap.xml
|
|
19
|
+
* const indexXml = await getSitemapIndex({
|
|
20
|
+
* baseUrl: 'https://shop',
|
|
21
|
+
* sitemaps: ['products-1.xml', 'collections.xml'],
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
const Q_PRODUCTS = `query SitemapProducts($first:Int!,$after:String){products(first:$first,after:$after){edges{cursor node{handle updatedAt}} pageInfo{hasNextPage endCursor}}}`;
|
|
25
|
+
const Q_COLLECTIONS = `query SitemapCollections($first:Int!,$after:String){collections(first:$first,after:$after){edges{cursor node{handle updatedAt}} pageInfo{hasNextPage endCursor}}}`;
|
|
26
|
+
function escapeXml(s) {
|
|
27
|
+
return s.replace(/[<>&'"]/g, (c) => ({ '<': '<', '>': '>', '&': '&', "'": ''', '"': '"' }[c]));
|
|
28
|
+
}
|
|
29
|
+
function urlEntry(r) {
|
|
30
|
+
const parts = [`<url>`, ` <loc>${escapeXml(r.url)}</loc>`];
|
|
31
|
+
if (r.lastmod)
|
|
32
|
+
parts.push(` <lastmod>${r.lastmod}</lastmod>`);
|
|
33
|
+
if (r.changefreq)
|
|
34
|
+
parts.push(` <changefreq>${r.changefreq}</changefreq>`);
|
|
35
|
+
if (r.priority != null)
|
|
36
|
+
parts.push(` <priority>${r.priority}</priority>`);
|
|
37
|
+
parts.push('</url>');
|
|
38
|
+
return parts.join('\n');
|
|
39
|
+
}
|
|
40
|
+
export async function getSitemap(options) {
|
|
41
|
+
const { storefront, request, types, pageSize = 250, getLink, baseUrl: baseUrlOverride } = options;
|
|
42
|
+
const url = new URL(request.url);
|
|
43
|
+
const baseUrl = (baseUrlOverride || `${url.protocol}//${url.host}`).replace(/\/$/, '');
|
|
44
|
+
const linker = getLink || (({ type, baseUrl, handle }) => `${baseUrl}/${type}/${handle}`);
|
|
45
|
+
const entries = [];
|
|
46
|
+
for (const type of types) {
|
|
47
|
+
let cursor = null;
|
|
48
|
+
let hasNext = true;
|
|
49
|
+
const query = type === 'products' ? Q_PRODUCTS : type === 'collections' ? Q_COLLECTIONS : null;
|
|
50
|
+
if (!query)
|
|
51
|
+
continue;
|
|
52
|
+
while (hasNext) {
|
|
53
|
+
const data = await storefront.query(query, { variables: { first: pageSize, after: cursor } });
|
|
54
|
+
const conn = data[type];
|
|
55
|
+
if (!conn)
|
|
56
|
+
break;
|
|
57
|
+
for (const e of conn.edges) {
|
|
58
|
+
const node = e.node;
|
|
59
|
+
entries.push({
|
|
60
|
+
url: linker({ type, baseUrl, handle: node.handle }),
|
|
61
|
+
lastmod: node.updatedAt,
|
|
62
|
+
changefreq: 'daily',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
hasNext = conn.pageInfo.hasNextPage;
|
|
66
|
+
cursor = conn.pageInfo.endCursor;
|
|
67
|
+
// safety break — 单次请求最多 50 page
|
|
68
|
+
if (entries.length > pageSize * 50)
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return [
|
|
73
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
74
|
+
`<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`,
|
|
75
|
+
...entries.map(urlEntry),
|
|
76
|
+
`</urlset>`,
|
|
77
|
+
].join('\n');
|
|
78
|
+
}
|
|
79
|
+
export function getSitemapIndex(options) {
|
|
80
|
+
const { baseUrl, sitemaps, lastmod } = options;
|
|
81
|
+
const base = baseUrl.replace(/\/$/, '');
|
|
82
|
+
const items = sitemaps.map((s) => {
|
|
83
|
+
const loc = /^https?:\/\//.test(s) ? s : `${base}/${s.replace(/^\//, '')}`;
|
|
84
|
+
return `<sitemap><loc>${escapeXml(loc)}</loc>${lastmod ? `<lastmod>${lastmod}</lastmod>` : ''}</sitemap>`;
|
|
85
|
+
});
|
|
86
|
+
return [
|
|
87
|
+
`<?xml version="1.0" encoding="UTF-8"?>`,
|
|
88
|
+
`<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">`,
|
|
89
|
+
...items,
|
|
90
|
+
`</sitemapindex>`,
|
|
91
|
+
].join('\n');
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=sitemap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../../src/sitemap/sitemap.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -74,10 +74,22 @@ export interface CartHandler<TCart = any> {
|
|
|
74
74
|
setCartId(cartId: string): void;
|
|
75
75
|
create(input?: {
|
|
76
76
|
lines?: CartLineInput[];
|
|
77
|
+
discountCodes?: string[];
|
|
77
78
|
}): Promise<CartResult<TCart>>;
|
|
78
79
|
addLines(lines: CartLineInput[]): Promise<CartResult<TCart>>;
|
|
79
80
|
updateLines(lines: CartLineUpdateInput[]): Promise<CartResult<TCart>>;
|
|
80
81
|
removeLines(lineIds: string[]): Promise<CartResult<TCart>>;
|
|
82
|
+
/** 替换 cart 上的优惠码列表(对齐 Hydrogen cart.updateDiscountCodes) */
|
|
83
|
+
updateDiscountCodes(discountCodes: string[]): Promise<CartResult<TCart>>;
|
|
84
|
+
/**
|
|
85
|
+
* shopbb-extension:买家从已领的 claim 中选一张(不是输入 code)。
|
|
86
|
+
* 服务端把 selected_claim_id 写到 cart DO;下次 resolveCart 时优先用该 claim。
|
|
87
|
+
*
|
|
88
|
+
* Hydrogen 没这个 API;这是 shopbb W5 的优惠券模型(claim-based)专属能力。
|
|
89
|
+
*/
|
|
90
|
+
selectDiscount(claimId: string): Promise<CartResult<TCart>>;
|
|
91
|
+
/** 清掉显式选择,回到"服务端自动选最佳"模式 */
|
|
92
|
+
clearDiscount(): Promise<CartResult<TCart>>;
|
|
81
93
|
}
|
|
82
94
|
export interface HeliumContextOptions {
|
|
83
95
|
request: Request;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flattenConnection — 对齐 Hydrogen React 同名工具
|
|
3
|
+
*
|
|
4
|
+
* GraphQL Connection 类型常见两种形态:
|
|
5
|
+
* { edges: [{node: T}, ...] }
|
|
6
|
+
* { nodes: [T, ...] }
|
|
7
|
+
*
|
|
8
|
+
* 此函数把两种统一拍平成 T[],让消费方写法一致。
|
|
9
|
+
*
|
|
10
|
+
* 用法:
|
|
11
|
+
* const products = flattenConnection(data.products);
|
|
12
|
+
* products.forEach(p => ...);
|
|
13
|
+
*/
|
|
14
|
+
interface ConnectionWithEdges<T> {
|
|
15
|
+
edges: Array<{
|
|
16
|
+
node: T;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
interface ConnectionWithNodes<T> {
|
|
20
|
+
nodes: T[];
|
|
21
|
+
}
|
|
22
|
+
export type Connection<T> = ConnectionWithEdges<T> | ConnectionWithNodes<T> | null | undefined;
|
|
23
|
+
export declare function flattenConnection<T = any>(connection: Connection<T>): T[];
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=flattenConnection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenConnection.d.ts","sourceRoot":"","sources":["../../src/utils/flattenConnection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,UAAU,mBAAmB,CAAC,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;CAC3B;AACD,UAAU,mBAAmB,CAAC,CAAC;IAC7B,KAAK,EAAE,CAAC,EAAE,CAAC;CACZ;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,mBAAmB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/F,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CASzE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* flattenConnection — 对齐 Hydrogen React 同名工具
|
|
3
|
+
*
|
|
4
|
+
* GraphQL Connection 类型常见两种形态:
|
|
5
|
+
* { edges: [{node: T}, ...] }
|
|
6
|
+
* { nodes: [T, ...] }
|
|
7
|
+
*
|
|
8
|
+
* 此函数把两种统一拍平成 T[],让消费方写法一致。
|
|
9
|
+
*
|
|
10
|
+
* 用法:
|
|
11
|
+
* const products = flattenConnection(data.products);
|
|
12
|
+
* products.forEach(p => ...);
|
|
13
|
+
*/
|
|
14
|
+
export function flattenConnection(connection) {
|
|
15
|
+
if (!connection)
|
|
16
|
+
return [];
|
|
17
|
+
if ('nodes' in connection && Array.isArray(connection.nodes)) {
|
|
18
|
+
return connection.nodes;
|
|
19
|
+
}
|
|
20
|
+
if ('edges' in connection && Array.isArray(connection.edges)) {
|
|
21
|
+
return connection.edges.map((e) => e.node);
|
|
22
|
+
}
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=flattenConnection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flattenConnection.js","sourceRoot":"","sources":["../../src/utils/flattenConnection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAWH,MAAM,UAAU,iBAAiB,CAAU,UAAyB;IAClE,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAC3B,IAAI,OAAO,IAAI,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO,UAAU,CAAC,KAAK,CAAC;IAC1B,CAAC;IACD,IAAI,OAAO,IAAI,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parseGid — 对齐 Hydrogen React 同名工具
|
|
3
|
+
*
|
|
4
|
+
* 把 GraphQL global ID 拆成 { id, resource }:
|
|
5
|
+
* "gid://shopbb/Product/prod_123" → { id: "prod_123", resource: "Product" }
|
|
6
|
+
* "gid://shopify/CartLine/abc" → { id: "abc", resource: "CartLine" }
|
|
7
|
+
*
|
|
8
|
+
* 找不到合法格式 → 返回 { id: gid, resource: null }(保留原值,便于兜底渲染)
|
|
9
|
+
*/
|
|
10
|
+
export interface ParsedGid {
|
|
11
|
+
id: string;
|
|
12
|
+
resource: string | null;
|
|
13
|
+
/** 完整原始 gid,便于回填 */
|
|
14
|
+
raw: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function parseGid(gid: string | null | undefined): ParsedGid;
|
|
17
|
+
//# sourceMappingURL=parseGid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseGid.d.ts","sourceRoot":"","sources":["../../src/utils/parseGid.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAID,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,CAKlE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parseGid — 对齐 Hydrogen React 同名工具
|
|
3
|
+
*
|
|
4
|
+
* 把 GraphQL global ID 拆成 { id, resource }:
|
|
5
|
+
* "gid://shopbb/Product/prod_123" → { id: "prod_123", resource: "Product" }
|
|
6
|
+
* "gid://shopify/CartLine/abc" → { id: "abc", resource: "CartLine" }
|
|
7
|
+
*
|
|
8
|
+
* 找不到合法格式 → 返回 { id: gid, resource: null }(保留原值,便于兜底渲染)
|
|
9
|
+
*/
|
|
10
|
+
const GID_PATTERN = /^gid:\/\/[^/]+\/([^/]+)\/(.+)$/;
|
|
11
|
+
export function parseGid(gid) {
|
|
12
|
+
if (!gid)
|
|
13
|
+
return { id: '', resource: null, raw: '' };
|
|
14
|
+
const m = gid.match(GID_PATTERN);
|
|
15
|
+
if (!m)
|
|
16
|
+
return { id: gid, resource: null, raw: gid };
|
|
17
|
+
return { id: m[2], resource: m[1], raw: gid };
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=parseGid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseGid.js","sourceRoot":"","sources":["../../src/utils/parseGid.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,WAAW,GAAG,gCAAgC,CAAC;AAErD,MAAM,UAAU,QAAQ,CAAC,GAA8B;IACrD,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IACrD,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACjC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACrD,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAChD,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createWithCache + InMemoryCache — 对齐 Hydrogen
|
|
3
|
+
*
|
|
4
|
+
* Hydrogen 的 `createWithCache({cache, waitUntil})` 返回一个高阶函数,
|
|
5
|
+
* 用 `withCache.run(strategy, cacheKey, fn)` 包裹任意异步函数,自动加 cache。
|
|
6
|
+
*
|
|
7
|
+
* 在 Cloudflare Workers 上 cache 可以是:
|
|
8
|
+
* - `caches.default` / `caches.open(...)` (Cache API — 真正的 edge cache)
|
|
9
|
+
* - `InMemoryCache` (本 worker 实例内存,per-instance;轻量缓存)
|
|
10
|
+
*
|
|
11
|
+
* 用法:
|
|
12
|
+
*
|
|
13
|
+
* const withCache = createWithCache({ cache: await caches.open('helium'), waitUntil });
|
|
14
|
+
*
|
|
15
|
+
* const products = await withCache.run(
|
|
16
|
+
* CacheLong(),
|
|
17
|
+
* ['products', 'page', '1'],
|
|
18
|
+
* async () => storefront.query(PRODUCTS_QUERY, { variables }),
|
|
19
|
+
* );
|
|
20
|
+
*
|
|
21
|
+
* 简化点(vs Hydrogen):
|
|
22
|
+
* - 不实现 stale-while-revalidate 后台 revalidate(Workers 内复杂,先做基础)
|
|
23
|
+
* - 不实现 stale-if-error
|
|
24
|
+
* - 提供 InMemoryCache 兜底(test / 没 caches.open 的环境)
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { CacheStrategy } from '../types';
|
|
28
|
+
|
|
29
|
+
// 对齐 Hydrogen 命名 (CachingStrategy)
|
|
30
|
+
export type CachingStrategy = CacheStrategy;
|
|
31
|
+
|
|
32
|
+
export type CacheKey = string | (string | number)[];
|
|
33
|
+
|
|
34
|
+
export interface WithCacheOptions {
|
|
35
|
+
cache: Cache | InMemoryCache;
|
|
36
|
+
waitUntil?: (p: Promise<any>) => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface WithCache {
|
|
40
|
+
/** 用 cache 包裹异步函数。命中 cache 直接返回;未命中执行 fn 写入 */
|
|
41
|
+
run<T>(strategy: CachingStrategy, key: CacheKey, fn: () => Promise<T>): Promise<T>;
|
|
42
|
+
/** 直接读 cache(不执行 fn) */
|
|
43
|
+
get<T>(key: CacheKey): Promise<T | null>;
|
|
44
|
+
/** 写 cache */
|
|
45
|
+
set<T>(strategy: CachingStrategy, key: CacheKey, value: T): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function toCacheKey(key: CacheKey): string {
|
|
49
|
+
if (typeof key === 'string') return key;
|
|
50
|
+
return key.map(String).join(':');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildCacheControl(strategy: CachingStrategy): string {
|
|
54
|
+
const dirs: string[] = [];
|
|
55
|
+
if (strategy.mode === 'NONE') return 'no-store';
|
|
56
|
+
if (strategy.mode === 'PUBLIC') dirs.push('public');
|
|
57
|
+
if (strategy.maxAge != null) dirs.push(`max-age=${strategy.maxAge}`);
|
|
58
|
+
if (strategy.staleWhileRevalidate != null) dirs.push(`stale-while-revalidate=${strategy.staleWhileRevalidate}`);
|
|
59
|
+
return dirs.join(', ');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createWithCache(opts: WithCacheOptions): WithCache {
|
|
63
|
+
const { cache, waitUntil } = opts;
|
|
64
|
+
|
|
65
|
+
async function get<T>(key: CacheKey): Promise<T | null> {
|
|
66
|
+
const cacheKey = toCacheKey(key);
|
|
67
|
+
if (cache instanceof InMemoryCache) {
|
|
68
|
+
return cache.get<T>(cacheKey);
|
|
69
|
+
}
|
|
70
|
+
const req = new Request(`https://helium.cache/${encodeURIComponent(cacheKey)}`);
|
|
71
|
+
const cached = await cache.match(req);
|
|
72
|
+
if (!cached) return null;
|
|
73
|
+
try {
|
|
74
|
+
return (await cached.json()) as T;
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function set<T>(strategy: CachingStrategy, key: CacheKey, value: T): Promise<void> {
|
|
81
|
+
if (strategy.mode === 'NONE') return;
|
|
82
|
+
const cacheKey = toCacheKey(key);
|
|
83
|
+
if (cache instanceof InMemoryCache) {
|
|
84
|
+
cache.set(cacheKey, value, strategy.maxAge ?? 0);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const req = new Request(`https://helium.cache/${encodeURIComponent(cacheKey)}`);
|
|
88
|
+
const res = new Response(JSON.stringify(value), {
|
|
89
|
+
headers: {
|
|
90
|
+
'Content-Type': 'application/json',
|
|
91
|
+
'Cache-Control': buildCacheControl(strategy),
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
const p = cache.put(req, res);
|
|
95
|
+
if (waitUntil) waitUntil(p); else await p;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function run<T>(strategy: CachingStrategy, key: CacheKey, fn: () => Promise<T>): Promise<T> {
|
|
99
|
+
if (strategy.mode === 'NONE') return fn();
|
|
100
|
+
const cached = await get<T>(key);
|
|
101
|
+
if (cached !== null) return cached;
|
|
102
|
+
const value = await fn();
|
|
103
|
+
await set(strategy, key, value);
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return { run, get, set };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================
|
|
111
|
+
// InMemoryCache —— 进程内 cache(轻量)
|
|
112
|
+
// ============================================================
|
|
113
|
+
|
|
114
|
+
interface MemEntry<T = any> {
|
|
115
|
+
value: T;
|
|
116
|
+
expiresAt: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export class InMemoryCache {
|
|
120
|
+
private store = new Map<string, MemEntry>();
|
|
121
|
+
|
|
122
|
+
get<T = any>(key: string): T | null {
|
|
123
|
+
const e = this.store.get(key);
|
|
124
|
+
if (!e) return null;
|
|
125
|
+
if (e.expiresAt > 0 && Date.now() > e.expiresAt) {
|
|
126
|
+
this.store.delete(key);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
return e.value as T;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
set<T = any>(key: string, value: T, maxAgeSeconds: number): void {
|
|
133
|
+
const expiresAt = maxAgeSeconds > 0 ? Date.now() + maxAgeSeconds * 1000 : 0;
|
|
134
|
+
this.store.set(key, { value, expiresAt });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
delete(key: string): boolean {
|
|
138
|
+
return this.store.delete(key);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
clear(): void {
|
|
142
|
+
this.store.clear();
|
|
143
|
+
}
|
|
144
|
+
}
|