@shopify/hydrogen 0.17.1 → 0.18.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.
Files changed (150) hide show
  1. package/CHANGELOG.md +136 -1
  2. package/config.js +1 -0
  3. package/dist/esnext/client.d.ts +2 -0
  4. package/dist/esnext/client.js +2 -0
  5. package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +2 -2
  6. package/dist/esnext/components/CartProvider/CartProvider.client.js +15 -14
  7. package/dist/esnext/components/CartProvider/{hooks.d.ts → hooks.client.d.ts} +0 -0
  8. package/dist/esnext/components/CartProvider/{hooks.js → hooks.client.js} +0 -0
  9. package/dist/esnext/components/CartProvider/index.d.ts +1 -1
  10. package/dist/esnext/components/CartProvider/index.js +1 -1
  11. package/dist/esnext/components/{DevTools.d.ts → DevTools.client.d.ts} +0 -0
  12. package/dist/esnext/components/{DevTools.js → DevTools.client.js} +3 -2
  13. package/dist/esnext/components/Image/Image.js +2 -0
  14. package/dist/esnext/components/Link/Link.client.js +11 -2
  15. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +1 -1
  16. package/dist/esnext/components/Metafield/Metafield.client.js +4 -5
  17. package/dist/esnext/components/ModelViewer/ModelViewer.client.d.ts +1 -1
  18. package/dist/esnext/components/ModelViewer/ModelViewer.client.js +2 -2
  19. package/dist/esnext/components/Money/Money.client.d.ts +5 -1
  20. package/dist/esnext/components/Money/Money.client.js +16 -3
  21. package/dist/esnext/components/ProductMetafield/ProductMetafield.client.js +1 -1
  22. package/dist/esnext/components/ProductProvider/ProductOptionsProvider.client.js +1 -1
  23. package/dist/esnext/components/ProductProvider/ProductProvider.client.d.ts +7 -3
  24. package/dist/esnext/components/ProductProvider/ProductProvider.client.js +1 -1
  25. package/dist/esnext/components/ShopPayButton/ShopPayButton.client.js +6 -2
  26. package/dist/esnext/components/Video/Video.js +3 -1
  27. package/dist/esnext/config.d.ts +3 -0
  28. package/dist/esnext/config.js +1 -0
  29. package/dist/esnext/constants.js +1 -1
  30. package/dist/esnext/entry-client.js +3 -1
  31. package/dist/esnext/entry-server.d.ts +2 -2
  32. package/dist/esnext/entry-server.js +59 -56
  33. package/dist/esnext/foundation/Analytics/ClientAnalytics.d.ts +1 -0
  34. package/dist/esnext/foundation/Analytics/ClientAnalytics.js +7 -1
  35. package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.client.d.ts +7 -0
  36. package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.client.js +64 -0
  37. package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.server.d.ts +1 -0
  38. package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.server.js +24 -0
  39. package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetricsDebug.client.d.ts +1 -0
  40. package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetricsDebug.client.js +23 -0
  41. package/dist/esnext/foundation/Analytics/const.d.ts +1 -0
  42. package/dist/esnext/foundation/Analytics/const.js +1 -0
  43. package/dist/esnext/foundation/Cookie/Cookie.js +2 -1
  44. package/dist/esnext/foundation/FileRoutes/FileRoutes.server.d.ts +4 -4
  45. package/dist/esnext/foundation/FileRoutes/FileRoutes.server.js +18 -21
  46. package/dist/esnext/foundation/FileSessionStorage/FileSessionStorage.js +2 -1
  47. package/dist/esnext/foundation/Redirect/Redirect.client.js +1 -0
  48. package/dist/esnext/foundation/Route/Route.server.js +1 -10
  49. package/dist/esnext/foundation/Router/BrowserRouter.client.js +34 -5
  50. package/dist/esnext/foundation/ServerPropsProvider/ServerPropsProvider.js +5 -3
  51. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +2 -2
  52. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +7 -2
  53. package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.js +6 -1
  54. package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.d.ts +8 -1
  55. package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +31 -5
  56. package/dist/esnext/foundation/ShopifyProvider/types.d.ts +3 -4
  57. package/dist/esnext/foundation/fetchSync/client/fetchSync.js +2 -1
  58. package/dist/esnext/foundation/fetchSync/server/fetchSync.js +4 -2
  59. package/dist/esnext/foundation/ssr-interop.js +1 -1
  60. package/dist/esnext/foundation/useQuery/hooks.d.ts +1 -1
  61. package/dist/esnext/foundation/useQuery/hooks.js +2 -2
  62. package/dist/esnext/foundation/useShop/use-shop.d.ts +3 -1
  63. package/dist/esnext/foundation/useShop/use-shop.js +3 -1
  64. package/dist/esnext/foundation/useUrl/useUrl.js +7 -4
  65. package/dist/esnext/framework/Hydration/Html.js +1 -1
  66. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.d.ts +3 -2
  67. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.js +16 -7
  68. package/dist/esnext/framework/middleware.d.ts +3 -4
  69. package/dist/esnext/framework/middleware.js +4 -4
  70. package/dist/esnext/framework/plugin.d.ts +2 -2
  71. package/dist/esnext/framework/plugin.js +3 -3
  72. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +1 -1
  73. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +2 -2
  74. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +59 -4
  75. package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +2 -2
  76. package/dist/esnext/hooks/useLoadScript/index.d.ts +1 -1
  77. package/dist/esnext/hooks/useLoadScript/index.js +1 -1
  78. package/dist/esnext/hooks/useLoadScript/{useLoadScript.d.ts → useLoadScript.client.d.ts} +0 -0
  79. package/dist/esnext/hooks/useLoadScript/{useLoadScript.js → useLoadScript.client.js} +2 -1
  80. package/dist/esnext/hooks/useMoney/hooks.d.ts +13 -1
  81. package/dist/esnext/hooks/useMoney/hooks.js +25 -1
  82. package/dist/esnext/hooks/useParsedMetafields/useParsedMetafields.js +0 -2
  83. package/dist/esnext/hooks/useProduct/useProduct.js +1 -1
  84. package/dist/esnext/hooks/useProductOptions/index.d.ts +1 -1
  85. package/dist/esnext/hooks/useProductOptions/index.js +1 -1
  86. package/dist/esnext/hooks/useProductOptions/{useProductOptions.d.ts → useProductOptions.client.d.ts} +0 -0
  87. package/dist/esnext/hooks/useProductOptions/{useProductOptions.js → useProductOptions.client.js} +6 -23
  88. package/dist/esnext/hooks/useShopQuery/hooks.js +15 -4
  89. package/dist/esnext/index.d.ts +1 -0
  90. package/dist/esnext/index.js +1 -0
  91. package/dist/esnext/storefront-api-types.d.ts +60 -6
  92. package/dist/esnext/storefront-api-types.js +6 -2
  93. package/dist/esnext/types.d.ts +11 -4
  94. package/dist/esnext/utilities/apiRoutes.d.ts +4 -3
  95. package/dist/esnext/utilities/apiRoutes.js +51 -33
  96. package/dist/esnext/utilities/bot-ua.js +3 -0
  97. package/dist/esnext/utilities/empty-hydrogen-config.d.ts +2 -0
  98. package/dist/esnext/utilities/empty-hydrogen-config.js +2 -0
  99. package/dist/esnext/utilities/findRoutePrefix.d.ts +1 -0
  100. package/dist/esnext/utilities/findRoutePrefix.js +17 -0
  101. package/dist/esnext/utilities/log/utils.js +1 -1
  102. package/dist/esnext/utilities/parse.d.ts +1 -0
  103. package/dist/esnext/utilities/parse.js +9 -0
  104. package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.js +2 -1
  105. package/dist/esnext/utilities/storefrontApi.js +1 -0
  106. package/dist/esnext/version.d.ts +1 -1
  107. package/dist/esnext/version.js +1 -1
  108. package/dist/node/constants.js +1 -1
  109. package/dist/node/entry-server.d.ts +2 -2
  110. package/dist/node/entry-server.js +59 -56
  111. package/dist/node/foundation/Analytics/ClientAnalytics.d.ts +1 -0
  112. package/dist/node/foundation/Analytics/ClientAnalytics.js +7 -1
  113. package/dist/node/foundation/Analytics/const.d.ts +1 -0
  114. package/dist/node/foundation/Analytics/const.js +1 -0
  115. package/dist/node/foundation/Redirect/Redirect.client.js +1 -0
  116. package/dist/node/foundation/Router/BrowserRouter.client.js +34 -5
  117. package/dist/node/foundation/ServerPropsProvider/ServerPropsProvider.js +5 -3
  118. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +2 -2
  119. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +7 -2
  120. package/dist/node/foundation/ShopifyProvider/types.d.ts +3 -4
  121. package/dist/node/foundation/ssr-interop.js +1 -1
  122. package/dist/node/framework/Hydration/Html.js +1 -1
  123. package/dist/node/framework/Hydration/ServerComponentRequest.server.d.ts +3 -2
  124. package/dist/node/framework/Hydration/ServerComponentRequest.server.js +16 -7
  125. package/dist/node/framework/middleware.d.ts +3 -4
  126. package/dist/node/framework/middleware.js +4 -4
  127. package/dist/node/framework/plugin.d.ts +2 -2
  128. package/dist/node/framework/plugin.js +3 -3
  129. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +1 -1
  130. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +2 -2
  131. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +58 -3
  132. package/dist/node/framework/plugins/vite-plugin-platform-entry.js +2 -2
  133. package/dist/node/storefront-api-types.d.ts +60 -6
  134. package/dist/node/storefront-api-types.js +6 -2
  135. package/dist/node/types.d.ts +11 -4
  136. package/dist/node/utilities/apiRoutes.d.ts +4 -3
  137. package/dist/node/utilities/apiRoutes.js +53 -34
  138. package/dist/node/utilities/bot-ua.js +3 -0
  139. package/dist/node/utilities/findRoutePrefix.d.ts +1 -0
  140. package/dist/node/utilities/findRoutePrefix.js +21 -0
  141. package/dist/node/utilities/log/utils.js +1 -1
  142. package/dist/node/utilities/parse.d.ts +1 -0
  143. package/dist/node/utilities/parse.js +13 -0
  144. package/dist/node/utilities/parseMetafieldValue/parseMetafieldValue.js +2 -1
  145. package/dist/node/utilities/storefrontApi.js +1 -0
  146. package/dist/node/version.d.ts +1 -1
  147. package/dist/node/version.js +1 -1
  148. package/package.json +9 -7
  149. package/dist/esnext/foundation/Boomerang/Boomerang.client.d.ts +0 -9
  150. package/dist/esnext/foundation/Boomerang/Boomerang.client.js +0 -66
@@ -1,13 +1,19 @@
1
- import { loadEnv } from 'vite';
1
+ import { loadEnv, normalizePath } from 'vite';
2
2
  import bodyParser from 'body-parser';
3
3
  import path from 'path';
4
4
  import { promises as fs } from 'fs';
5
5
  import { hydrogenMiddleware, graphiqlMiddleware } from '../middleware';
6
6
  import { InMemoryCache } from '../cache/in-memory';
7
7
  export const HYDROGEN_DEFAULT_SERVER_ENTRY = '/src/App.server';
8
- export default (shopifyConfig, pluginOptions) => {
8
+ const virtualModuleId = 'virtual:hydrogen-config';
9
+ const virtualProxyModuleId = virtualModuleId + ':proxy';
10
+ export default (pluginOptions) => {
11
+ let config;
9
12
  return {
10
13
  name: 'vite-plugin-hydrogen-middleware',
14
+ configResolved(_config) {
15
+ config = _config;
16
+ },
11
17
  /**
12
18
  * By adding a middleware to the Vite dev server, we can handle SSR without needing
13
19
  * a custom node script. It works by handling any requests for `text/html` documents,
@@ -24,13 +30,27 @@ export default (shopifyConfig, pluginOptions) => {
24
30
  // The default vite middleware rewrites the URL `/graphqil` to `/index.html`
25
31
  // By running this middleware first, we avoid that.
26
32
  server.middlewares.use(graphiqlMiddleware({
27
- shopifyConfig,
28
33
  dev: true,
34
+ getShopifyConfig: async (incomingMessage) => {
35
+ var _a;
36
+ const { default: hydrogenConfig } = await server.ssrLoadModule('virtual:hydrogen-config:proxy');
37
+ // @ts-ignore
38
+ const { address = 'localhost', port = '3000' } = ((_a = server.httpServer) === null || _a === void 0 ? void 0 : _a.address()) || {};
39
+ const url = new URL(`http://${address}:${port}${incomingMessage.url}`);
40
+ const request = new Request(url.toString(), {
41
+ headers: incomingMessage.headers,
42
+ });
43
+ // @ts-expect-error Manually set `normalizedUrl` which a developer expects to be available
44
+ // via `ServerComponentRequest` during production runtime.
45
+ request.normalizedUrl = request.url;
46
+ return typeof hydrogenConfig.shopify === 'function'
47
+ ? hydrogenConfig.shopify(request)
48
+ : hydrogenConfig.shopify;
49
+ },
29
50
  }));
30
51
  server.middlewares.use(bodyParser.raw({ type: '*/*' }));
31
52
  return () => server.middlewares.use(hydrogenMiddleware({
32
53
  dev: true,
33
- shopifyConfig,
34
54
  indexTemplate: getIndexTemplate,
35
55
  getServerEntrypoint: () => server.ssrLoadModule(process.env.HYDROGEN_SERVER_ENTRY ||
36
56
  HYDROGEN_DEFAULT_SERVER_ENTRY),
@@ -40,6 +60,26 @@ export default (shopifyConfig, pluginOptions) => {
40
60
  : undefined,
41
61
  }));
42
62
  },
63
+ async resolveId(source, importer) {
64
+ if (source === virtualModuleId) {
65
+ const configPath = await findHydrogenConfigPath(config.root, pluginOptions.configPath);
66
+ return this.resolve(configPath, importer, {
67
+ skipSelf: true,
68
+ });
69
+ }
70
+ if (source === virtualProxyModuleId) {
71
+ // Virtual modules convention
72
+ // https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention
73
+ return '\0' + virtualProxyModuleId;
74
+ }
75
+ },
76
+ async load(id) {
77
+ if (id === '\0' + virtualProxyModuleId) {
78
+ // Likely due to a bug in Vite, but the config cannot be loaded
79
+ // directly using ssrLoadModule. It needs to be proxied as follows:
80
+ return `import hc from 'virtual:hydrogen-config'; export default hc;`;
81
+ }
82
+ },
43
83
  };
44
84
  };
45
85
  async function polyfillOxygenEnv(config) {
@@ -54,3 +94,18 @@ async function polyfillOxygenEnv(config) {
54
94
  }
55
95
  globalThis.Oxygen = { env };
56
96
  }
97
+ async function findHydrogenConfigPath(root, userProvidedPath) {
98
+ let configPath = userProvidedPath;
99
+ if (!configPath) {
100
+ // Find the config file in the project root
101
+ const files = await fs.readdir(root);
102
+ configPath = files.find((file) => /^hydrogen\.config\.[jt]s$/.test(file));
103
+ }
104
+ if (configPath) {
105
+ configPath = normalizePath(configPath);
106
+ if (!configPath.startsWith('/'))
107
+ configPath = path.resolve(root, configPath);
108
+ }
109
+ return (configPath ||
110
+ require.resolve('@shopify/hydrogen/dist/esnext/utilities/empty-hydrogen-config.js'));
111
+ }
@@ -19,7 +19,7 @@ export default () => {
19
19
  }
20
20
  },
21
21
  resolveId(source, importer) {
22
- if (normalizePath(source).includes('@shopify/hydrogen/platforms/')) {
22
+ if (normalizePath(source).includes('/hydrogen/platforms/')) {
23
23
  const hydrogenPath = path.dirname(require.resolve('@shopify/hydrogen/package.json'));
24
24
  const platformEntryName = source.split(path.sep).pop() || '';
25
25
  const platformEntryPath = path.resolve(hydrogenPath, 'dist', 'esnext', 'platforms', platformEntryName);
@@ -30,7 +30,7 @@ export default () => {
30
30
  return null;
31
31
  },
32
32
  transform(code, id) {
33
- if (normalizePath(id).includes('@shopify/hydrogen/dist/esnext/platforms/')) {
33
+ if (normalizePath(id).includes('/hydrogen/dist/esnext/platforms/')) {
34
34
  code = code
35
35
  .replace('__SERVER_ENTRY__', process.env.HYDROGEN_SERVER_ENTRY || HYDROGEN_DEFAULT_SERVER_ENTRY)
36
36
  .replace('__INDEX_TEMPLATE__', normalizePath(path.resolve(config.root, config.build.outDir, '..', 'client', 'index.html')));
@@ -1 +1 @@
1
- export { useLoadScript } from './useLoadScript';
1
+ export { useLoadScript } from './useLoadScript.client';
@@ -1 +1 @@
1
- export { useLoadScript } from './useLoadScript';
1
+ export { useLoadScript } from './useLoadScript.client';
@@ -5,6 +5,7 @@ import { useState, useEffect } from 'react';
5
5
  */
6
6
  export function useLoadScript(url, options) {
7
7
  const [status, setStatus] = useState('loading');
8
+ const stringifiedOptions = JSON.stringify(options);
8
9
  useEffect(() => {
9
10
  async function loadScriptWrapper() {
10
11
  try {
@@ -17,6 +18,6 @@ export function useLoadScript(url, options) {
17
18
  }
18
19
  }
19
20
  loadScriptWrapper();
20
- }, [url, JSON.stringify(options)]);
21
+ }, [url, stringifiedOptions, options]);
21
22
  return status;
22
23
  }
@@ -26,13 +26,25 @@ export declare type UseMoneyValue = {
26
26
  parts: Intl.NumberFormatPart[];
27
27
  /**
28
28
  * A string returned by `new Intl.NumberFormat` for the amount and currency code,
29
- * using the `shopify.config.js` locale.
29
+ * using the `defaultLocale` value in [`hydrogenConfig.shopify`](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
30
30
  */
31
31
  localizedString: string;
32
32
  /**
33
33
  * The `MoneyV2` object provided as an argument to the hook.
34
34
  */
35
35
  original: MoneyV2;
36
+ /**
37
+ * A string with trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.
38
+ * For example, `$640.00` turns into `$640`.
39
+ * `$640.42` remains `$640.42`.
40
+ */
41
+ withoutTrailingZeros: string;
42
+ /**
43
+ * A string without currency and without trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.
44
+ * For example, `$640.00` turns into `640`.
45
+ * `$640.42` turns into `640.42`.
46
+ */
47
+ withoutTrailingZerosAndCurrency: string;
36
48
  };
37
49
  /**
38
50
  * The `useMoney` hook takes a [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) and returns a
@@ -22,6 +22,20 @@ export function useMoney(money) {
22
22
  ...options,
23
23
  currencyDisplay: 'narrowSymbol',
24
24
  }).formatToParts(amount);
25
+ const withoutTrailingZerosFormatter = new Intl.NumberFormat(locale, {
26
+ ...options,
27
+ minimumFractionDigits: 0,
28
+ maximumFractionDigits: 0,
29
+ });
30
+ const withoutCurrencyFormatter = new Intl.NumberFormat(locale);
31
+ const withoutTrailingZerosOrCurrencyFormatter = new Intl.NumberFormat(locale, {
32
+ minimumFractionDigits: 0,
33
+ maximumFractionDigits: 0,
34
+ });
35
+ const withoutTrailingZeros = amount % 1 === 0 ? withoutTrailingZerosFormatter.format(amount) : value;
36
+ const withoutTrailingZerosAndCurrency = amount % 1 === 0
37
+ ? withoutTrailingZerosOrCurrencyFormatter.format(amount)
38
+ : withoutCurrencyFormatter.format(amount);
25
39
  const moneyValue = useMemo(() => {
26
40
  var _a, _b, _c, _d, _e, _f;
27
41
  return ({
@@ -36,7 +50,17 @@ export function useMoney(money) {
36
50
  .map((part) => part.value)
37
51
  .join(''),
38
52
  original: money,
53
+ withoutTrailingZeros,
54
+ withoutTrailingZerosAndCurrency,
39
55
  });
40
- }, [baseParts, money, nameParts, narrowParts, value]);
56
+ }, [
57
+ baseParts,
58
+ money,
59
+ nameParts,
60
+ narrowParts,
61
+ value,
62
+ withoutTrailingZeros,
63
+ withoutTrailingZerosAndCurrency,
64
+ ]);
41
65
  return moneyValue;
42
66
  }
@@ -7,8 +7,6 @@ import { flattenConnection, parseMetafieldValue } from '../../utilities';
7
7
  export function useParsedMetafields(
8
8
  /** A [MetafieldConnection](https://shopify.dev/api/storefront/reference/common-objects/metafieldconnection). */
9
9
  metafields) {
10
- var _a, _b;
11
- (_b = (_a = metafields === null || metafields === void 0 ? void 0 : metafields.edges) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.node;
12
10
  return useMemo(() => {
13
11
  if (!metafields) {
14
12
  throw new Error(`'useParsedMetafields' needs metafields`);
@@ -9,7 +9,7 @@ export function useProduct() {
9
9
  const data = useContext(ProductContext);
10
10
  let state;
11
11
  try {
12
- state = (_a = useContext(ProductOptionsContext)) !== null && _a !== void 0 ? _a : { ...stateFallback };
12
+ state = (_a = useContext(ProductOptionsContext)) !== null && _a !== void 0 ? _a : { ...stateFallback }; // eslint-disable-line react-hooks/rules-of-hooks
13
13
  }
14
14
  catch (error) {
15
15
  // for server components which can't use state
@@ -1,2 +1,2 @@
1
- export { useProductOptions } from './useProductOptions';
1
+ export { useProductOptions } from './useProductOptions.client';
2
2
  export * from './types';
@@ -1,2 +1,2 @@
1
- export { useProductOptions } from './useProductOptions';
1
+ export { useProductOptions } from './useProductOptions.client';
2
2
  export * from './types';
@@ -39,35 +39,18 @@ export function useProductOptions({ variants: variantsConnection, sellingPlanGro
39
39
  * values.
40
40
  */
41
41
  useEffect(() => {
42
- setSelectedVariant(initialVariantId);
43
- const selectedOptions = (selectedVariant === null || selectedVariant === void 0 ? void 0 : selectedVariant.selectedOptions)
44
- ? selectedVariant.selectedOptions.reduce((memo, optionSet) => {
45
- var _a, _b;
46
- memo[(_a = optionSet === null || optionSet === void 0 ? void 0 : optionSet.name) !== null && _a !== void 0 ? _a : ''] = (_b = optionSet === null || optionSet === void 0 ? void 0 : optionSet.value) !== null && _b !== void 0 ? _b : '';
47
- return memo;
48
- }, {})
49
- : {};
50
- setSelectedOptions(selectedOptions);
51
- }, [initialVariantId, variants]);
42
+ const variant = getSelectedVariant(variants, selectedOptions);
43
+ setSelectedVariant(variant);
44
+ }, [selectedOptions, variants]);
52
45
  /**
53
46
  * Allow the developer to select an option.
54
47
  */
55
48
  const setSelectedOption = useCallback((name, value) => {
56
- const newSelectedOptions = {
49
+ setSelectedOptions((selectedOptions) => ({
57
50
  ...selectedOptions,
58
51
  [name]: value,
59
- };
60
- setSelectedOptions(newSelectedOptions);
61
- }, [selectedOptions]);
62
- useEffect(() => {
63
- /**
64
- * When selected options change, select the correct variant.
65
- */
66
- const variant = getSelectedVariant(variants, selectedOptions);
67
- if (variant) {
68
- setSelectedVariant(variant);
69
- }
70
- }, [variants, selectedOptions]);
52
+ }));
53
+ }, [setSelectedOptions]);
71
54
  const isOptionInStock = useCallback((option, value) => {
72
55
  var _a;
73
56
  const proposedVariant = getSelectedVariant(variants, {
@@ -8,9 +8,20 @@ import { sendMessageToClient } from '../../utilities/devtools';
8
8
  import { fetchSync } from '../../foundation/fetchSync/server/fetchSync';
9
9
  import { META_ENV_SSR } from '../../foundation/ssr-interop';
10
10
  import { getStorefrontApiRequestHeaders } from '../../utilities/storefrontApi';
11
+ import { parseJSON } from '../../utilities/parse';
11
12
  // Check if the response body has GraphQL errors
12
13
  // https://spec.graphql.org/June2018/#sec-Response-Format
13
- const shouldCacheResponse = ([body]) => { var _a; return !((_a = JSON.parse(body)) === null || _a === void 0 ? void 0 : _a.errors); };
14
+ const shouldCacheResponse = ([body]) => {
15
+ var _a;
16
+ try {
17
+ return !((_a = parseJSON(body)) === null || _a === void 0 ? void 0 : _a.errors);
18
+ }
19
+ catch (_b) {
20
+ // If we can't parse the response, then assume
21
+ // an error and don't cache the response
22
+ return false;
23
+ }
24
+ };
14
25
  /**
15
26
  * The `useShopQuery` hook allows you to make server-only GraphQL queries to the Storefront API. It must be a descendent of a `ShopifyProvider` component.
16
27
  */
@@ -25,10 +36,10 @@ export function useShopQuery({ query, variables = {}, cache, preload = false, })
25
36
  if (!META_ENV_SSR) {
26
37
  throw new Error('Shopify Storefront API requests should only be made from the server.');
27
38
  }
28
- const serverRequest = useServerRequest();
39
+ const serverRequest = useServerRequest(); // eslint-disable-line react-hooks/rules-of-hooks
29
40
  const log = getLoggerWithContext(serverRequest);
30
41
  const body = query ? graphqlRequestBody(query, variables) : '';
31
- const { url, requestInit } = useCreateShopRequest(body);
42
+ const { url, requestInit } = useCreateShopRequest(body); // eslint-disable-line react-hooks/rules-of-hooks
32
43
  let data;
33
44
  let useQueryError;
34
45
  try {
@@ -142,7 +153,7 @@ function createErrorMessage(fetchError) {
142
153
  return `An error occurred while fetching from the Storefront API. ${
143
154
  // 403s to the SF API (almost?) always mean that your Shopify credentials are bad/wrong
144
155
  fetchError.status === 403
145
- ? `You may have a bad value in 'shopify.config.js'`
156
+ ? `You may have a bad value in 'hydrogen.config.js'`
146
157
  : `${fetchError.statusText}`}`;
147
158
  }
148
159
  else {
@@ -15,6 +15,7 @@ export { CartQuery } from './components/CartProvider/cart-queries';
15
15
  export { generateCacheControlHeader, NoStore, CacheSeconds, CacheMinutes, CacheHours, CacheDays, CacheWeeks, CacheMonths, CacheCustom, } from './framework/CachingStrategy';
16
16
  export { fetchSync } from './foundation/fetchSync/server/fetchSync';
17
17
  export { useServerAnalytics } from './foundation/Analytics';
18
+ export * as PerformanceMetricsServerAnalyticsConnector from './foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.server';
18
19
  export { useSession } from './foundation/useSession/useSession';
19
20
  export { CookieSessionStorage } from './foundation/CookieSessionStorage/CookieSessionStorage';
20
21
  export { MemorySessionStorage } from './foundation/MemorySessionStorage/MemorySessionStorage';
@@ -19,6 +19,7 @@ export { CartQuery } from './components/CartProvider/cart-queries';
19
19
  export { generateCacheControlHeader, NoStore, CacheSeconds, CacheMinutes, CacheHours, CacheDays, CacheWeeks, CacheMonths, CacheCustom, } from './framework/CachingStrategy';
20
20
  export { fetchSync } from './foundation/fetchSync/server/fetchSync';
21
21
  export { useServerAnalytics } from './foundation/Analytics';
22
+ export * as PerformanceMetricsServerAnalyticsConnector from './foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.server';
22
23
  export { useSession } from './foundation/useSession/useSession';
23
24
  export { CookieSessionStorage } from './foundation/CookieSessionStorage/CookieSessionStorage';
24
25
  export { MemorySessionStorage } from './foundation/MemorySessionStorage/MemorySessionStorage';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * THIS FILE IS AUTO-GENERATED, DO NOT EDIT
3
- * Based on Storefront API 2022-04
3
+ * Based on Storefront API 2022-07
4
4
  * If changes need to happen to the types defined in this file, then generally the Storefront API needs to update, and then you can run `yarn graphql-types`
5
5
  * Except custom Scalars, which are defined in the `codegen.yml` file
6
6
  */
@@ -436,6 +436,8 @@ export declare type Cart = Node & {
436
436
  lines: CartLineConnection;
437
437
  /** A note that is associated with the cart. For example, the note can be a personalized message to the buyer. */
438
438
  note?: Maybe<Scalars['String']>;
439
+ /** The total number of items in the cart. */
440
+ totalQuantity: Scalars['Int'];
439
441
  /** The date and time when the cart was updated. */
440
442
  updatedAt: Scalars['DateTime'];
441
443
  };
@@ -694,6 +696,10 @@ export declare type CartLineEdge = {
694
696
  /** The estimated cost of the merchandise line that the buyer will pay at checkout. */
695
697
  export declare type CartLineEstimatedCost = {
696
698
  __typename?: 'CartLineEstimatedCost';
699
+ /** The amount of the merchandise line. */
700
+ amount: MoneyV2;
701
+ /** The compare at amount of the merchandise line. */
702
+ compareAtAmount: MoneyV2;
697
703
  /** The estimated cost of the merchandise line before discounts. */
698
704
  subtotalAmount: MoneyV2;
699
705
  /** The estimated total cost of the merchandise line. */
@@ -1660,7 +1666,7 @@ export declare type Country = {
1660
1666
  unitSystem: UnitSystem;
1661
1667
  };
1662
1668
  /**
1663
- * The code designating a country, which generally follows ISO 3166-1 alpha-2 guidelines.
1669
+ * The code designating a country/region, which generally follows ISO 3166-1 alpha-2 guidelines.
1664
1670
  * If a territory doesn't have a country code value in the `CountryCode` enum, it might be considered a subdivision
1665
1671
  * of another country. For example, the territories associated with Spain are represented by the country code `ES`,
1666
1672
  * and the territories associated with the United States of America are represented by the country code `US`.
@@ -2501,6 +2507,8 @@ export declare enum CurrencyCode {
2501
2507
  Ssp = "SSP",
2502
2508
  /** Sao Tome And Principe Dobra (STD). */
2503
2509
  Std = "STD",
2510
+ /** Sao Tome And Principe Dobra (STN). */
2511
+ Stn = "STN",
2504
2512
  /** Syrian Pound (SYP). */
2505
2513
  Syp = "SYP",
2506
2514
  /** Swazi Lilangeni (SZL). */
@@ -2533,6 +2541,8 @@ export declare enum CurrencyCode {
2533
2541
  Uyu = "UYU",
2534
2542
  /** Uzbekistan som (UZS). */
2535
2543
  Uzs = "UZS",
2544
+ /** Venezuelan Bolivares (VED). */
2545
+ Ved = "VED",
2536
2546
  /** Venezuelan Bolivares (VEF). */
2537
2547
  Vef = "VEF",
2538
2548
  /** Venezuelan Bolivares (VES). */
@@ -3394,7 +3404,7 @@ export declare type Language = {
3394
3404
  /** The name of the language in the current language. */
3395
3405
  name: Scalars['String'];
3396
3406
  };
3397
- /** ISO 369 language codes supported by Shopify. */
3407
+ /** ISO 639-1 language codes supported by Shopify. */
3398
3408
  export declare enum LanguageCode {
3399
3409
  /** Afrikaans. */
3400
3410
  Af = "AF",
@@ -4259,7 +4269,7 @@ export declare type Mutation = {
4259
4269
  checkoutDiscountCodeApply?: Maybe<CheckoutDiscountCodeApplyPayload>;
4260
4270
  /** Applies a discount to an existing checkout using a discount code. */
4261
4271
  checkoutDiscountCodeApplyV2?: Maybe<CheckoutDiscountCodeApplyV2Payload>;
4262
- /** Removes the applied discount from an existing checkout. */
4272
+ /** Removes the applied discounts from an existing checkout. */
4263
4273
  checkoutDiscountCodeRemove?: Maybe<CheckoutDiscountCodeRemovePayload>;
4264
4274
  /**
4265
4275
  * Updates the email on an existing checkout.
@@ -5576,9 +5586,9 @@ export declare type QueryRoot = {
5576
5586
  /** A storefront menu. */
5577
5587
  menu?: Maybe<Menu>;
5578
5588
  /** Returns a specific node by ID. */
5579
- node?: Maybe<AppliedGiftCard | Article | Blog | Cart | CartLine | Checkout | CheckoutLineItem | Collection | Comment | ExternalVideo | GenericFile | Location | MailingAddress | MediaImage | Menu | MenuItem | Metafield | Model3d | Order | Page | Payment | Product | ProductOption | ProductVariant | Shop | ShopPolicy | Video>;
5589
+ node?: Maybe<AppliedGiftCard | Article | Blog | Cart | CartLine | Checkout | CheckoutLineItem | Collection | Comment | ExternalVideo | GenericFile | Location | MailingAddress | MediaImage | Menu | MenuItem | Metafield | Model3d | Order | Page | Payment | Product | ProductOption | ProductVariant | Shop | ShopPolicy | UrlRedirect | Video>;
5580
5590
  /** Returns the list of nodes with the given IDs. */
5581
- nodes: Array<Maybe<AppliedGiftCard | Article | Blog | Cart | CartLine | Checkout | CheckoutLineItem | Collection | Comment | ExternalVideo | GenericFile | Location | MailingAddress | MediaImage | Menu | MenuItem | Metafield | Model3d | Order | Page | Payment | Product | ProductOption | ProductVariant | Shop | ShopPolicy | Video>>;
5591
+ nodes: Array<Maybe<AppliedGiftCard | Article | Blog | Cart | CartLine | Checkout | CheckoutLineItem | Collection | Comment | ExternalVideo | GenericFile | Location | MailingAddress | MediaImage | Menu | MenuItem | Metafield | Model3d | Order | Page | Payment | Product | ProductOption | ProductVariant | Shop | ShopPolicy | UrlRedirect | Video>>;
5582
5592
  /** Fetch a specific `Page` by one of its unique attributes. */
5583
5593
  page?: Maybe<Page>;
5584
5594
  /**
@@ -5616,6 +5626,8 @@ export declare type QueryRoot = {
5616
5626
  publicApiVersions: Array<ApiVersion>;
5617
5627
  /** The shop associated with the storefront access token. */
5618
5628
  shop: Shop;
5629
+ /** A list of redirects for a shop. */
5630
+ urlRedirects: UrlRedirectConnection;
5619
5631
  };
5620
5632
  /** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */
5621
5633
  export declare type QueryRootArticlesArgs = {
@@ -5745,6 +5757,14 @@ export declare type QueryRootProductsArgs = {
5745
5757
  reverse?: InputMaybe<Scalars['Boolean']>;
5746
5758
  sortKey?: InputMaybe<ProductSortKeys>;
5747
5759
  };
5760
+ /** The schema’s entry-point for queries. This acts as the public, top-level API from which all queries must start. */
5761
+ export declare type QueryRootUrlRedirectsArgs = {
5762
+ after?: InputMaybe<Scalars['String']>;
5763
+ before?: InputMaybe<Scalars['String']>;
5764
+ first?: InputMaybe<Scalars['Int']>;
5765
+ last?: InputMaybe<Scalars['Int']>;
5766
+ reverse?: InputMaybe<Scalars['Boolean']>;
5767
+ };
5748
5768
  /** SEO information. */
5749
5769
  export declare type Seo = {
5750
5770
  __typename?: 'SEO';
@@ -6293,6 +6313,40 @@ export declare enum UnitSystem {
6293
6313
  /** Metric system of weights and measures. */
6294
6314
  MetricSystem = "METRIC_SYSTEM"
6295
6315
  }
6316
+ /** A redirect on the online store. */
6317
+ export declare type UrlRedirect = Node & {
6318
+ __typename?: 'UrlRedirect';
6319
+ /** The ID of the URL redirect. */
6320
+ id: Scalars['ID'];
6321
+ /** The old path to be redirected from. When the user visits this path, they'll be redirected to the target location. */
6322
+ path: Scalars['String'];
6323
+ /** The target location where the user will be redirected to. */
6324
+ target: Scalars['String'];
6325
+ };
6326
+ /**
6327
+ * An auto-generated type for paginating through multiple UrlRedirects.
6328
+ *
6329
+ */
6330
+ export declare type UrlRedirectConnection = {
6331
+ __typename?: 'UrlRedirectConnection';
6332
+ /** A list of edges. */
6333
+ edges: Array<UrlRedirectEdge>;
6334
+ /** A list of the nodes contained in UrlRedirectEdge. */
6335
+ nodes: Array<UrlRedirect>;
6336
+ /** Information to aid in pagination. */
6337
+ pageInfo: PageInfo;
6338
+ };
6339
+ /**
6340
+ * An auto-generated type which holds one UrlRedirect and a cursor during pagination.
6341
+ *
6342
+ */
6343
+ export declare type UrlRedirectEdge = {
6344
+ __typename?: 'UrlRedirectEdge';
6345
+ /** A cursor for use in pagination. */
6346
+ cursor: Scalars['String'];
6347
+ /** The item at the end of UrlRedirectEdge. */
6348
+ node: UrlRedirect;
6349
+ };
6296
6350
  /** Represents an error in the input of a mutation. */
6297
6351
  export declare type UserError = DisplayableError & {
6298
6352
  __typename?: 'UserError';
@@ -171,7 +171,7 @@ export var CollectionSortKeys;
171
171
  CollectionSortKeys["UpdatedAt"] = "UPDATED_AT";
172
172
  })(CollectionSortKeys || (CollectionSortKeys = {}));
173
173
  /**
174
- * The code designating a country, which generally follows ISO 3166-1 alpha-2 guidelines.
174
+ * The code designating a country/region, which generally follows ISO 3166-1 alpha-2 guidelines.
175
175
  * If a territory doesn't have a country code value in the `CountryCode` enum, it might be considered a subdivision
176
176
  * of another country. For example, the territories associated with Spain are represented by the country code `ES`,
177
177
  * and the territories associated with the United States of America are represented by the country code `US`.
@@ -951,6 +951,8 @@ export var CurrencyCode;
951
951
  CurrencyCode["Ssp"] = "SSP";
952
952
  /** Sao Tome And Principe Dobra (STD). */
953
953
  CurrencyCode["Std"] = "STD";
954
+ /** Sao Tome And Principe Dobra (STN). */
955
+ CurrencyCode["Stn"] = "STN";
954
956
  /** Syrian Pound (SYP). */
955
957
  CurrencyCode["Syp"] = "SYP";
956
958
  /** Swazi Lilangeni (SZL). */
@@ -983,6 +985,8 @@ export var CurrencyCode;
983
985
  CurrencyCode["Uyu"] = "UYU";
984
986
  /** Uzbekistan som (UZS). */
985
987
  CurrencyCode["Uzs"] = "UZS";
988
+ /** Venezuelan Bolivares (VED). */
989
+ CurrencyCode["Ved"] = "VED";
986
990
  /** Venezuelan Bolivares (VEF). */
987
991
  CurrencyCode["Vef"] = "VEF";
988
992
  /** Venezuelan Bolivares (VES). */
@@ -1133,7 +1137,7 @@ export var ImageContentType;
1133
1137
  /** A WEBP image. */
1134
1138
  ImageContentType["Webp"] = "WEBP";
1135
1139
  })(ImageContentType || (ImageContentType = {}));
1136
- /** ISO 369 language codes supported by Shopify. */
1140
+ /** ISO 639-1 language codes supported by Shopify. */
1137
1141
  export var LanguageCode;
1138
1142
  (function (LanguageCode) {
1139
1143
  /** Afrikaans. */
@@ -36,17 +36,23 @@ export declare type Hook = (params: {
36
36
  url: URL;
37
37
  } & Record<string, any>) => any | Promise<any>;
38
38
  export declare type ImportGlobEagerOutput = Record<string, Record<'default' | 'api', any>>;
39
+ export declare type HydrogenConfigRoutes = ImportGlobEagerOutput | {
40
+ files: ImportGlobEagerOutput;
41
+ basePath?: string;
42
+ dirPrefix?: string;
43
+ };
44
+ declare type ConfigFetcher<T> = (request: ServerComponentRequest) => T | Promise<T>;
45
+ export declare type ShopifyConfigFetcher = ConfigFetcher<ShopifyConfig>;
39
46
  export declare type ServerAnalyticsConnector = {
40
47
  request: (request: Request, data?: any, contentType?: 'json' | 'text') => void;
41
48
  };
42
- export declare type ServerHandlerConfig = {
43
- routes?: ImportGlobEagerOutput;
44
- shopifyConfig: ShopifyConfig;
49
+ export declare type HydrogenConfig = {
50
+ routes?: HydrogenConfigRoutes;
51
+ shopify?: ShopifyConfig | ShopifyConfigFetcher;
45
52
  serverAnalyticsConnectors?: Array<ServerAnalyticsConnector>;
46
53
  session?: (log: Logger) => SessionStorageAdapter;
47
54
  };
48
55
  export declare type ClientHandlerConfig = {
49
- shopifyConfig: ShopifyConfig;
50
56
  /** React's StrictMode is on by default for your client side app; if you want to turn it off (not recommended), you can pass `false` */
51
57
  strictMode?: boolean;
52
58
  showDevTools?: boolean;
@@ -85,6 +91,7 @@ export declare type CachingStrategy = AllCacheOptions;
85
91
  export interface HydrogenVitePluginOptions {
86
92
  devCache?: boolean;
87
93
  purgeQueryCacheOnBuild?: boolean;
94
+ configPath?: string;
88
95
  }
89
96
  export declare type PreloadOptions = boolean | string;
90
97
  export {};
@@ -1,4 +1,4 @@
1
- import { ImportGlobEagerOutput, ShopifyConfig } from '../types';
1
+ import { HydrogenConfig, HydrogenConfigRoutes } from '../types';
2
2
  import type { ServerComponentRequest } from '../framework/Hydration/ServerComponentRequest.server';
3
3
  import type { ASTNode } from 'graphql';
4
4
  import { SessionApi, SessionStorageAdapter } from '../foundation/session/session';
@@ -19,7 +19,8 @@ export declare type ApiRouteMatch = {
19
19
  hasServerComponent: boolean;
20
20
  params: RouteParams;
21
21
  };
22
- export declare function getApiRoutes(pages: ImportGlobEagerOutput | undefined, topLevelPath?: string): Array<HydrogenApiRoute>;
22
+ export declare function extractPathFromRoutesKey(routesKey: string, dirPrefix: string | RegExp): string;
23
+ export declare function getApiRoutes(rawRoutes: HydrogenConfigRoutes): Array<HydrogenApiRoute>;
23
24
  export declare function getApiRouteFromURL(url: URL, routes: Array<HydrogenApiRoute>): ApiRouteMatch | null;
24
25
  /** The `queryShop` utility is a function that helps you query the Storefront API.
25
26
  * It's similar to the `useShopQuery` hook, which is available in server components.
@@ -33,5 +34,5 @@ interface QueryShopArgs {
33
34
  /** An object of the variables for the GraphQL query. */
34
35
  variables?: Record<string, any>;
35
36
  }
36
- export declare function renderApiRoute(request: ServerComponentRequest, route: ApiRouteMatch, shopifyConfig: ShopifyConfig, session?: SessionStorageAdapter): Promise<Response | Request>;
37
+ export declare function renderApiRoute(request: ServerComponentRequest, route: ApiRouteMatch, shopifyConfig: HydrogenConfig['shopify'], session?: SessionStorageAdapter): Promise<Response | Request>;
37
38
  export {};