@shopify/hydrogen 0.17.3 → 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 (122) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/config.js +1 -0
  3. package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +2 -2
  4. package/dist/esnext/components/CartProvider/CartProvider.client.js +15 -14
  5. package/dist/esnext/components/CartProvider/{hooks.d.ts → hooks.client.d.ts} +0 -0
  6. package/dist/esnext/components/CartProvider/{hooks.js → hooks.client.js} +0 -0
  7. package/dist/esnext/components/CartProvider/index.d.ts +1 -1
  8. package/dist/esnext/components/CartProvider/index.js +1 -1
  9. package/dist/esnext/components/{DevTools.d.ts → DevTools.client.d.ts} +0 -0
  10. package/dist/esnext/components/{DevTools.js → DevTools.client.js} +3 -2
  11. package/dist/esnext/components/Image/Image.js +2 -0
  12. package/dist/esnext/components/Link/Link.client.js +11 -2
  13. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +1 -1
  14. package/dist/esnext/components/Metafield/Metafield.client.js +4 -5
  15. package/dist/esnext/components/ModelViewer/ModelViewer.client.js +1 -1
  16. package/dist/esnext/components/Money/Money.client.d.ts +5 -1
  17. package/dist/esnext/components/Money/Money.client.js +16 -3
  18. package/dist/esnext/components/ProductMetafield/ProductMetafield.client.js +1 -1
  19. package/dist/esnext/components/ProductProvider/ProductOptionsProvider.client.js +1 -1
  20. package/dist/esnext/components/ProductProvider/ProductProvider.client.d.ts +7 -3
  21. package/dist/esnext/components/ShopPayButton/ShopPayButton.client.js +6 -2
  22. package/dist/esnext/components/Video/Video.js +3 -1
  23. package/dist/esnext/config.d.ts +3 -0
  24. package/dist/esnext/config.js +1 -0
  25. package/dist/esnext/constants.js +1 -1
  26. package/dist/esnext/entry-client.js +3 -1
  27. package/dist/esnext/entry-server.d.ts +2 -2
  28. package/dist/esnext/entry-server.js +53 -48
  29. package/dist/esnext/foundation/Cookie/Cookie.js +2 -1
  30. package/dist/esnext/foundation/FileRoutes/FileRoutes.server.d.ts +4 -4
  31. package/dist/esnext/foundation/FileRoutes/FileRoutes.server.js +17 -4
  32. package/dist/esnext/foundation/FileSessionStorage/FileSessionStorage.js +2 -1
  33. package/dist/esnext/foundation/Redirect/Redirect.client.js +1 -0
  34. package/dist/esnext/foundation/Router/BrowserRouter.client.js +10 -1
  35. package/dist/esnext/foundation/ServerPropsProvider/ServerPropsProvider.js +5 -3
  36. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +2 -2
  37. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +7 -2
  38. package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.js +6 -1
  39. package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.d.ts +8 -1
  40. package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +31 -5
  41. package/dist/esnext/foundation/ShopifyProvider/types.d.ts +3 -4
  42. package/dist/esnext/foundation/fetchSync/client/fetchSync.js +2 -1
  43. package/dist/esnext/foundation/fetchSync/server/fetchSync.js +4 -2
  44. package/dist/esnext/foundation/ssr-interop.js +1 -1
  45. package/dist/esnext/foundation/useQuery/hooks.d.ts +1 -1
  46. package/dist/esnext/foundation/useQuery/hooks.js +2 -2
  47. package/dist/esnext/foundation/useShop/use-shop.d.ts +3 -1
  48. package/dist/esnext/foundation/useShop/use-shop.js +3 -1
  49. package/dist/esnext/foundation/useUrl/useUrl.js +7 -4
  50. package/dist/esnext/framework/Hydration/Html.js +1 -1
  51. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.d.ts +3 -2
  52. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.js +16 -7
  53. package/dist/esnext/framework/middleware.d.ts +3 -4
  54. package/dist/esnext/framework/middleware.js +4 -4
  55. package/dist/esnext/framework/plugin.d.ts +2 -2
  56. package/dist/esnext/framework/plugin.js +3 -3
  57. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +1 -1
  58. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +2 -2
  59. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +59 -4
  60. package/dist/esnext/hooks/useLoadScript/index.d.ts +1 -1
  61. package/dist/esnext/hooks/useLoadScript/index.js +1 -1
  62. package/dist/esnext/hooks/useLoadScript/{useLoadScript.d.ts → useLoadScript.client.d.ts} +0 -0
  63. package/dist/esnext/hooks/useLoadScript/{useLoadScript.js → useLoadScript.client.js} +2 -1
  64. package/dist/esnext/hooks/useMoney/hooks.d.ts +13 -1
  65. package/dist/esnext/hooks/useMoney/hooks.js +25 -1
  66. package/dist/esnext/hooks/useProduct/useProduct.js +1 -1
  67. package/dist/esnext/hooks/useProductOptions/index.d.ts +1 -1
  68. package/dist/esnext/hooks/useProductOptions/index.js +1 -1
  69. package/dist/esnext/hooks/useProductOptions/{useProductOptions.d.ts → useProductOptions.client.d.ts} +0 -0
  70. package/dist/esnext/hooks/useProductOptions/{useProductOptions.js → useProductOptions.client.js} +6 -23
  71. package/dist/esnext/hooks/useShopQuery/hooks.js +15 -4
  72. package/dist/esnext/storefront-api-types.d.ts +60 -6
  73. package/dist/esnext/storefront-api-types.js +6 -2
  74. package/dist/esnext/types.d.ts +11 -4
  75. package/dist/esnext/utilities/apiRoutes.d.ts +4 -4
  76. package/dist/esnext/utilities/apiRoutes.js +29 -16
  77. package/dist/esnext/utilities/empty-hydrogen-config.d.ts +2 -0
  78. package/dist/esnext/utilities/empty-hydrogen-config.js +2 -0
  79. package/dist/esnext/utilities/findRoutePrefix.d.ts +1 -0
  80. package/dist/esnext/utilities/findRoutePrefix.js +17 -0
  81. package/dist/esnext/utilities/log/utils.js +1 -1
  82. package/dist/esnext/utilities/parse.d.ts +1 -0
  83. package/dist/esnext/utilities/parse.js +9 -0
  84. package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.js +2 -1
  85. package/dist/esnext/utilities/storefrontApi.js +1 -0
  86. package/dist/esnext/version.d.ts +1 -1
  87. package/dist/esnext/version.js +1 -1
  88. package/dist/node/constants.js +1 -1
  89. package/dist/node/entry-server.d.ts +2 -2
  90. package/dist/node/entry-server.js +53 -48
  91. package/dist/node/foundation/Redirect/Redirect.client.js +1 -0
  92. package/dist/node/foundation/Router/BrowserRouter.client.js +10 -1
  93. package/dist/node/foundation/ServerPropsProvider/ServerPropsProvider.js +5 -3
  94. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +2 -2
  95. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +7 -2
  96. package/dist/node/foundation/ShopifyProvider/types.d.ts +3 -4
  97. package/dist/node/foundation/ssr-interop.js +1 -1
  98. package/dist/node/framework/Hydration/Html.js +1 -1
  99. package/dist/node/framework/Hydration/ServerComponentRequest.server.d.ts +3 -2
  100. package/dist/node/framework/Hydration/ServerComponentRequest.server.js +16 -7
  101. package/dist/node/framework/middleware.d.ts +3 -4
  102. package/dist/node/framework/middleware.js +4 -4
  103. package/dist/node/framework/plugin.d.ts +2 -2
  104. package/dist/node/framework/plugin.js +3 -3
  105. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +1 -1
  106. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +2 -2
  107. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +58 -3
  108. package/dist/node/storefront-api-types.d.ts +60 -6
  109. package/dist/node/storefront-api-types.js +6 -2
  110. package/dist/node/types.d.ts +11 -4
  111. package/dist/node/utilities/apiRoutes.d.ts +4 -4
  112. package/dist/node/utilities/apiRoutes.js +29 -16
  113. package/dist/node/utilities/findRoutePrefix.d.ts +1 -0
  114. package/dist/node/utilities/findRoutePrefix.js +21 -0
  115. package/dist/node/utilities/log/utils.js +1 -1
  116. package/dist/node/utilities/parse.d.ts +1 -0
  117. package/dist/node/utilities/parse.js +13 -0
  118. package/dist/node/utilities/parseMetafieldValue/parseMetafieldValue.js +2 -1
  119. package/dist/node/utilities/storefrontApi.js +1 -0
  120. package/dist/node/version.d.ts +1 -1
  121. package/dist/node/version.js +1 -1
  122. package/package.json +8 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,118 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1065](https://github.com/Shopify/hydrogen/pull/1065) [`81ae47fd`](https://github.com/Shopify/hydrogen/commit/81ae47fdb01be06af155a61e574d43c73122c414) Thanks [@frandiox](https://github.com/frandiox)! - A new config file `hydrogen.config.js` replaces the existing `shopify.config.js` in your Hydrogen app.
8
+
9
+ ## Introducing `hydrogen.config.js`
10
+
11
+ Hydrogen apps now expect a `hydrogen.config.js` in the root folder. This config file accepts Shopify storefront credentials, routes, session configuration, and more.
12
+
13
+ To migrate existing apps, you should create a `hydrogen.config.js` (or `hydrogen.config.ts`) file in your Hydrogen app:
14
+
15
+ ```js
16
+ import {defineConfig} from '@shopify/hydrogen/config';
17
+ import {
18
+ CookieSessionStorage,
19
+ PerformanceMetricsServerAnalyticsConnector,
20
+ } from '@shopify/hydrogen';
21
+
22
+ export default defineConfig({
23
+ routes: import.meta.globEager('./src/routes/**/*.server.[jt](s|sx)'),
24
+ shopify: {
25
+ storeDomain: 'YOUR_STORE.myshopify.com',
26
+ storefrontToken: 'YOUR_STOREFRONT_TOKEN',
27
+ storefrontApiVersion: '2022-07',
28
+ },
29
+ session: CookieSessionStorage('__session', {
30
+ path: '/',
31
+ httpOnly: true,
32
+ secure: process.env.NODE_ENV === 'production',
33
+ sameSite: 'strict',
34
+ maxAge: 60 * 60 * 24 * 30,
35
+ }),
36
+ serverAnalyticsConnectors: [PerformanceMetricsServerAnalyticsConnector],
37
+ });
38
+ ```
39
+
40
+ Then, update your `App.server.jsx` to remove previous arguments from `renderHydrogen()`:
41
+
42
+ ```diff
43
+ import renderHydrogen from '@shopify/hydrogen/entry-server';
44
+
45
+ -function App({routes}) {
46
+ +function App() {
47
+ return (
48
+ <Suspense fallback={<LoadingFallback />}>
49
+ - <ShopifyProvider shopifyConfig={shopifyConfig}>
50
+ + <ShopifyProvider>
51
+ <CartProvider>
52
+ <DefaultSeo />
53
+ <Router>
54
+ - <FileRoutes routes={routes} />
55
+ + <FileRoutes />
56
+ <Route path="*" page={<NotFound />} />
57
+ </Router>
58
+ </CartProvider>
59
+ <PerformanceMetrics />
60
+ {process.env.LOCAL_DEV && <PerformanceMetricsDebug />}
61
+ </ShopifyProvider>
62
+ </Suspense>
63
+ );
64
+ }
65
+
66
+ -const routes = import.meta.globEager('./routes/**/*.server.[jt](s|sx)');
67
+ -
68
+ -export default renderHydrogen(App, {
69
+ - routes,
70
+ - shopifyConfig,
71
+ - session: CookieSessionStorage('__session', {
72
+ - path: '/',
73
+ - httpOnly: true,
74
+ - secure: process.env.NODE_ENV === 'production',
75
+ - sameSite: 'strict',
76
+ - maxAge: 60 * 60 * 24 * 30,
77
+ - }),
78
+ - serverAnalyticsConnectors: [PerformanceMetricsServerAnalyticsConnector],
79
+ -});
80
+ +export default renderHydrogen(App);
81
+ ```
82
+
83
+ Next, update `vite.config.js` in your app to remove references to `shopifyConfig`:
84
+
85
+ ```diff
86
+ import {defineConfig} from 'vite';
87
+ import hydrogen from '@shopify/hydrogen/plugin';
88
+ -import shopifyConfig from './shopify.config';
89
+
90
+ // https://vitejs.dev/config/
91
+ export default defineConfig({
92
+ - plugins: [hydrogen(shopifyConfig)],
93
+ + plugins: [hydrogen()],
94
+ ```
95
+
96
+ Finally, delete `shopify.config.js` from your app.
97
+
98
+ [Read more about the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config)
99
+
100
+ * [#1214](https://github.com/Shopify/hydrogen/pull/1214) [`58ef6d69`](https://github.com/Shopify/hydrogen/commit/58ef6d69f1148e7bc8452fa77e7e8f54396c6105) Thanks [@frehner](https://github.com/frehner)! - Upgraded SFAPI version to 2022-07
101
+
102
+ - [#1232](https://github.com/Shopify/hydrogen/pull/1232) [`d3956d62`](https://github.com/Shopify/hydrogen/commit/d3956d623adb86371ab214b102b53c62ea9ce26c) Thanks [@arlyxiao](https://github.com/arlyxiao)! - Upgrade body-parser in hydrogen package
103
+
104
+ ### Patch Changes
105
+
106
+ - [#1211](https://github.com/Shopify/hydrogen/pull/1211) [`f3d26511`](https://github.com/Shopify/hydrogen/commit/f3d26511b1b0b94de1a43f76a0be9d99b5f2a8f7) Thanks [@wizardlyhel](https://github.com/wizardlyhel)! - Build chunks are inside assets folder
107
+
108
+ * [#1215](https://github.com/Shopify/hydrogen/pull/1215) [`a0ed7c06`](https://github.com/Shopify/hydrogen/commit/a0ed7c06d045a0063a356097dafcc25e5361aad1) Thanks [@frehner](https://github.com/frehner)! - `useMoney` now returns two additional properties: `withoutTrailingZeros` and `withoutTrailingZerosAndCurrency`
109
+
110
+ `<Money />` now has two additional and optional props: `withoutMoney` and `withoutCurrency`.
111
+
112
+ - [#1242](https://github.com/Shopify/hydrogen/pull/1242) [`c277c688`](https://github.com/Shopify/hydrogen/commit/c277c68836d6d75d509cc68c74e3ccd33706a0c7) Thanks [@blittle](https://github.com/blittle)! - Prevent JSON parsing from prototype poisoning vulnerabilities
113
+
114
+ * [#1210](https://github.com/Shopify/hydrogen/pull/1210) [`a844d26e`](https://github.com/Shopify/hydrogen/commit/a844d26ef258c28fded5293054389b719f0b86f4) Thanks [@blittle](https://github.com/blittle)! - Add eslint back and fix stale product options
115
+
3
116
  ## 0.17.3
4
117
 
5
118
  ### Patch Changes
package/config.js ADDED
@@ -0,0 +1 @@
1
+ export * from './dist/esnext/config';
@@ -27,9 +27,9 @@ export function AddToCartButton(props) {
27
27
  setAddingItem(true);
28
28
  linesAdd([
29
29
  {
30
- quantity: quantity,
30
+ quantity,
31
31
  merchandiseId: variantId,
32
- attributes: attributes,
32
+ attributes,
33
33
  },
34
34
  ]);
35
35
  } }, children),
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useCallback, useReducer, useMemo, useRef, } from 'react';
2
2
  import { flattenConnection } from '../../utilities';
3
3
  import { CartLineAdd, CartCreate, CartLineRemove, CartLineUpdate, CartNoteUpdate, CartBuyerIdentityUpdate, CartAttributesUpdate, CartDiscountCodesUpdate, CartQuery, } from './cart-queries';
4
- import { useCartFetch } from './hooks';
4
+ import { useCartFetch } from './hooks.client';
5
5
  import { CartContext } from './context';
6
6
  import { CART_ID_STORAGE_KEY } from './constants';
7
7
  import { useServerProps } from '../../foundation/useServerProps';
@@ -197,7 +197,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
197
197
  if (error) {
198
198
  dispatch({
199
199
  type: 'reject',
200
- error: error,
200
+ error,
201
201
  });
202
202
  }
203
203
  if ((_b = data === null || data === void 0 ? void 0 : data.cartCreate) === null || _b === void 0 ? void 0 : _b.cart) {
@@ -223,7 +223,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
223
223
  query: CartLineAdd,
224
224
  variables: {
225
225
  cartId: state.cart.id,
226
- lines: lines,
226
+ lines,
227
227
  numCartLines,
228
228
  country: countryCode,
229
229
  },
@@ -231,7 +231,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
231
231
  if (error) {
232
232
  dispatch({
233
233
  type: 'reject',
234
- error: error,
234
+ error,
235
235
  });
236
236
  }
237
237
  if ((_a = data === null || data === void 0 ? void 0 : data.cartLinesAdd) === null || _a === void 0 ? void 0 : _a.cart) {
@@ -255,7 +255,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
255
255
  query: CartLineRemove,
256
256
  variables: {
257
257
  cartId: state.cart.id,
258
- lines: lines,
258
+ lines,
259
259
  numCartLines,
260
260
  country: countryCode,
261
261
  },
@@ -287,7 +287,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
287
287
  query: CartLineUpdate,
288
288
  variables: {
289
289
  cartId: state.cart.id,
290
- lines: lines,
290
+ lines,
291
291
  numCartLines,
292
292
  country: countryCode,
293
293
  },
@@ -295,7 +295,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
295
295
  if (error) {
296
296
  dispatch({
297
297
  type: 'reject',
298
- error: error,
298
+ error,
299
299
  });
300
300
  }
301
301
  if ((_a = data === null || data === void 0 ? void 0 : data.cartLinesUpdate) === null || _a === void 0 ? void 0 : _a.cart) {
@@ -319,7 +319,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
319
319
  query: CartNoteUpdate,
320
320
  variables: {
321
321
  cartId: state.cart.id,
322
- note: note,
322
+ note,
323
323
  numCartLines,
324
324
  country: countryCode,
325
325
  },
@@ -327,7 +327,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
327
327
  if (error) {
328
328
  dispatch({
329
329
  type: 'reject',
330
- error: error,
330
+ error,
331
331
  });
332
332
  }
333
333
  if ((_a = data === null || data === void 0 ? void 0 : data.cartNoteUpdate) === null || _a === void 0 ? void 0 : _a.cart) {
@@ -355,7 +355,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
355
355
  if (error) {
356
356
  dispatch({
357
357
  type: 'reject',
358
- error: error,
358
+ error,
359
359
  });
360
360
  }
361
361
  if ((_a = data === null || data === void 0 ? void 0 : data.cartBuyerIdentityUpdate) === null || _a === void 0 ? void 0 : _a.cart) {
@@ -375,7 +375,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
375
375
  query: CartAttributesUpdate,
376
376
  variables: {
377
377
  cartId: state.cart.id,
378
- attributes: attributes,
378
+ attributes,
379
379
  numCartLines,
380
380
  country: countryCode,
381
381
  },
@@ -383,7 +383,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
383
383
  if (error) {
384
384
  dispatch({
385
385
  type: 'reject',
386
- error: error,
386
+ error,
387
387
  });
388
388
  }
389
389
  if ((_a = data === null || data === void 0 ? void 0 : data.cartAttributesUpdate) === null || _a === void 0 ? void 0 : _a.cart) {
@@ -403,7 +403,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
403
403
  query: CartDiscountCodesUpdate,
404
404
  variables: {
405
405
  cartId: state.cart.id,
406
- discountCodes: discountCodes,
406
+ discountCodes,
407
407
  numCartLines,
408
408
  country: countryCode,
409
409
  },
@@ -411,7 +411,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
411
411
  if (error) {
412
412
  dispatch({
413
413
  type: 'reject',
414
- error: error,
414
+ error,
415
415
  });
416
416
  }
417
417
  if ((_a = data === null || data === void 0 ? void 0 : data.cartDiscountCodesUpdate) === null || _a === void 0 ? void 0 : _a.cart) {
@@ -440,6 +440,7 @@ export function CartProvider({ children, numCartLines, onCreate, onLineAdd, onLi
440
440
  return;
441
441
  }
442
442
  buyerIdentityUpdate({ countryCode }, state);
443
+ // eslint-disable-next-line react-hooks/exhaustive-deps
443
444
  }, [countryCode]);
444
445
  const cartContextValue = useMemo(() => {
445
446
  return {
@@ -1,4 +1,4 @@
1
1
  export { CartProvider } from './CartProvider.client';
2
- export { useCartFetch, useInstantCheckout } from './hooks';
2
+ export { useCartFetch, useInstantCheckout } from './hooks.client';
3
3
  export { useCart } from '../../hooks/useCart';
4
4
  export type { State, Status, Cart, CartWithActions, CartAction } from './types';
@@ -1,3 +1,3 @@
1
1
  export { CartProvider } from './CartProvider.client';
2
- export { useCartFetch, useInstantCheckout } from './hooks';
2
+ export { useCartFetch, useInstantCheckout } from './hooks.client';
3
3
  export { useCart } from '../../hooks/useCart';
@@ -19,9 +19,9 @@ export default function DevTools() {
19
19
  const entry = perfData[0];
20
20
  let activePanelContent = null;
21
21
  switch (activePanel) {
22
- case 'warnings':
22
+ case 'warnings': {
23
23
  const warningsMarkup = warnings
24
- ? warnings.map((war, i) => React.createElement("li", { key: war + i }, war))
24
+ ? warnings.map((war, i) => React.createElement("li", { key: war + i }, war)) // eslint-disable-line react/no-array-index-key
25
25
  : null;
26
26
  activePanelContent = (React.createElement(React.Fragment, null,
27
27
  React.createElement(PanelHeading, null, "Overfetched graphQL fields"),
@@ -31,6 +31,7 @@ export default function DevTools() {
31
31
  fontSize: '0.9em',
32
32
  } }, warningsMarkup)));
33
33
  break;
34
+ }
34
35
  case 'network':
35
36
  activePanelContent = (React.createElement(React.Fragment, null,
36
37
  React.createElement(PanelHeading, null, "Metrics"),
@@ -34,7 +34,9 @@ export function Image(props) {
34
34
  const srcPath = imgProps.loader
35
35
  ? imgProps.loader({ src: imgProps.src, options: imgProps.loaderOptions })
36
36
  : imgProps.src;
37
+ /* eslint-disable hydrogen/prefer-image-component */
37
38
  return (React.createElement("img", { id: (_a = imgProps.id) !== null && _a !== void 0 ? _a : '', loading: "lazy", alt: (_b = imgProps.alt) !== null && _b !== void 0 ? _b : '', ...passthroughProps, src: srcPath, width: (_c = imgProps.width) !== null && _c !== void 0 ? _c : undefined, height: (_d = imgProps.height) !== null && _d !== void 0 ? _d : undefined }));
39
+ /* eslint-enable hydrogen/prefer-image-component */
38
40
  }
39
41
  function convertShopifyImageData({ data, options, loader, loaderOptions, id: propId, alt, }) {
40
42
  const { url: src, altText, id } = data;
@@ -30,12 +30,21 @@ export const Link = React.forwardRef(function Link(props, ref) {
30
30
  e.preventDefault();
31
31
  // If the URL hasn't changed, the regular <a> will do a replace
32
32
  const replace = !!_replace || createPath(location) === createPath({ pathname: to });
33
- navigate(props.to, {
33
+ navigate(to, {
34
34
  replace,
35
35
  clientState,
36
36
  });
37
37
  }
38
- }, [reloadDocument, target, _replace, to, clientState, onClick, location]);
38
+ }, [
39
+ reloadDocument,
40
+ target,
41
+ _replace,
42
+ to,
43
+ clientState,
44
+ onClick,
45
+ location,
46
+ navigate,
47
+ ]);
39
48
  const signalPrefetchIntent = () => {
40
49
  /**
41
50
  * startTransition to yield to more important updates
@@ -15,7 +15,7 @@ import { CacheDays } from '../../framework/CachingStrategy';
15
15
  export function LocalizationProvider(props) {
16
16
  const { languageCode } = useShop();
17
17
  const { data: { localization }, } = useShopQuery({
18
- query: query,
18
+ query,
19
19
  variables: { language: languageCode },
20
20
  cache: CacheDays(),
21
21
  preload: props.preload,
@@ -52,18 +52,17 @@ export function Metafield(props) {
52
52
  }
53
53
  case 'url':
54
54
  return (React.createElement("a", { href: data.value, ...passthroughProps }, data.value));
55
- case 'json':
55
+ case 'json': {
56
56
  const Wrapper = as !== null && as !== void 0 ? as : 'span';
57
57
  return (React.createElement(Wrapper, { ...passthroughProps }, JSON.stringify(data.value)));
58
+ }
58
59
  case 'file_reference': {
59
60
  if (((_a = data.reference) === null || _a === void 0 ? void 0 : _a.__typename) === 'MediaImage') {
60
61
  const ref = data.reference;
61
62
  return ref.image ? (React.createElement(Image, { data: ref.image, ...passthroughProps })) : null;
62
63
  }
63
64
  }
64
- default: {
65
- const Wrapper = as !== null && as !== void 0 ? as : 'span';
66
- return React.createElement(Wrapper, { ...passthroughProps }, data.value.toString());
67
- }
68
65
  }
66
+ const Wrapper = as !== null && as !== void 0 ? as : 'span';
67
+ return React.createElement(Wrapper, { ...passthroughProps }, data.value.toString());
69
68
  }
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect, useCallback, } from 'react';
2
- import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript';
2
+ import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript.client';
3
3
  /**
4
4
  * The `ModelViewer` component renders a 3D model (with the `model-viewer` tag) for
5
5
  * the Storefront API's [Model3d object](https://shopify.dev/api/storefront/reference/products/model3d).
@@ -5,11 +5,15 @@ interface MoneyProps<TTag> {
5
5
  as?: TTag;
6
6
  /** An object with fields that correspond to the Storefront API's [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2). */
7
7
  data: PartialDeep<MoneyV2>;
8
+ /** Whether to remove the currency symbol from the output. */
9
+ withoutCurrency?: boolean;
10
+ /** Whether to remove trailing zeros (fractional money) from the output. */
11
+ withoutTrailingZeros?: boolean;
8
12
  }
9
13
  /**
10
14
  * The `Money` component renders a string of the Storefront API's
11
15
  * [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the
12
- * `defaultLocale` in the `shopify.config.js` file.
16
+ * `defaultLocale` in [the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
13
17
  */
14
18
  export declare function Money<TTag extends keyof JSX.IntrinsicElements = 'div'>(props: JSX.IntrinsicElements[TTag] & MoneyProps<TTag>): JSX.Element;
15
19
  export {};
@@ -3,11 +3,24 @@ import { useMoney } from '../../hooks';
3
3
  /**
4
4
  * The `Money` component renders a string of the Storefront API's
5
5
  * [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the
6
- * `defaultLocale` in the `shopify.config.js` file.
6
+ * `defaultLocale` in [the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
7
7
  */
8
8
  export function Money(props) {
9
- const { data, as, ...passthroughProps } = props;
9
+ const { data, as, withoutCurrency, withoutTrailingZeros, ...passthroughProps } = props;
10
10
  const moneyObject = useMoney(data);
11
11
  const Wrapper = as !== null && as !== void 0 ? as : 'div';
12
- return React.createElement(Wrapper, { ...passthroughProps }, moneyObject.localizedString);
12
+ let output = moneyObject.localizedString;
13
+ if (withoutCurrency || withoutTrailingZeros) {
14
+ if (withoutCurrency && !withoutTrailingZeros) {
15
+ output = moneyObject.amount;
16
+ }
17
+ else if (!withoutCurrency && withoutTrailingZeros) {
18
+ output = moneyObject.withoutTrailingZeros;
19
+ }
20
+ else {
21
+ // both
22
+ output = moneyObject.withoutTrailingZerosAndCurrency;
23
+ }
24
+ }
25
+ return React.createElement(Wrapper, { ...passthroughProps }, output);
13
26
  }
@@ -26,7 +26,7 @@ export function ProductMetafield(props) {
26
26
  const message = 'does not have a value for metafield.';
27
27
  const productOrVariant = variantId ? `Variant` : 'Product';
28
28
  const logItems = {
29
- variantId: variantId,
29
+ variantId,
30
30
  ProductId: product.id,
31
31
  namespace,
32
32
  keyName,
@@ -6,7 +6,7 @@ export function ProductOptionsProvider({ children, initialVariantId, }) {
6
6
  const product = useProduct();
7
7
  const productOptions = useProductOptions({
8
8
  variants: product.variantsConnection,
9
- initialVariantId: initialVariantId,
9
+ initialVariantId,
10
10
  });
11
11
  return (React.createElement(ProductOptionsContext.Provider, { value: productOptions }, children));
12
12
  }
@@ -7,9 +7,13 @@ export interface ProductProviderProps {
7
7
  children: ReactNode;
8
8
  /** A [Product object](https://shopify.dev/api/storefront/reference/products/product). */
9
9
  data: PartialDeep<ProductType>;
10
- /** The initially selected variant. If this is missing, then `selectedVariantId`
11
- * in the returned `object` from the `useProduct` hook uses the first available variant
12
- * or the first variant (if none are available).
10
+ /** The initially selected variant.
11
+ * The following logic applies to `initialVariantId`:
12
+ * If `initialVariantId` is provided, then it's used, even if it's out of stock.
13
+ * If `initialVariantId` is provided, but is `null`, then no variant is used.
14
+ * If nothing is passed to `initialVariantId`, and you're in a `ProductProvider`, then `selectedVariant.id` is used.
15
+ * If nothing is passed to `initialVariantId` and you're not in a `ProductProvider`, then the first available or in-stock variant is used.
16
+ * If nothing is passed to `initialVariantId`, you're not in a `ProductProvider`, and no variants are in stock, then the first variant is used.
13
17
  */
14
18
  initialVariantId?: Parameters<typeof useProductOptions>['0']['initialVariantId'];
15
19
  }
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { useShop } from '../../foundation/useShop';
3
- import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript';
3
+ import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript.client';
4
4
  const URL = 'https://cdn.shopify.com/shopifycloud/shop-js/v0.8/client.js';
5
5
  /**
6
6
  * The `ShopPayButton` component renders a button that redirects to the Shop Pay checkout.
@@ -34,7 +34,11 @@ export function ShopPayButton({ variantIds, className, variantIdsAndQuantities,
34
34
  else {
35
35
  throw new Error(MissingPropsErrorMessage);
36
36
  }
37
- return (React.createElement("div", { className: className, tabIndex: 1 }, shopPayLoadedStatus === 'done' && (React.createElement("shop-pay-button", { "store-url": `https://${storeDomain}`, variants: ids.join(',') }))));
37
+ return (
38
+ /* eslint-disable jsx-a11y/no-noninteractive-tabindex */
39
+ React.createElement("div", { className: className, tabIndex: 0 }, shopPayLoadedStatus === 'done' && (React.createElement("shop-pay-button", { "store-url": `https://${storeDomain}`, variants: ids.join(',') })))
40
+ /* eslint-enable jsx-a11y/no-noninteractive-tabindex */
41
+ );
38
42
  }
39
43
  /**
40
44
  * Takes a string in the format of "gid://shopify/ProductVariant/41007289630776" and returns a string of the ID part at the end: "41007289630776"
@@ -10,7 +10,9 @@ export function Video(props) {
10
10
  if (!data.sources) {
11
11
  throw new Error(`<Video/> requires a 'data.sources' array`);
12
12
  }
13
- return (React.createElement("video", { ...passthroughProps, id: id, playsInline: playsInline, controls: controls, poster: posterUrl }, data.sources.map((source) => {
13
+ return (
14
+ // eslint-disable-next-line jsx-a11y/media-has-caption
15
+ React.createElement("video", { ...passthroughProps, id: id, playsInline: playsInline, controls: controls, poster: posterUrl }, data.sources.map((source) => {
14
16
  if (!((source === null || source === void 0 ? void 0 : source.url) && (source === null || source === void 0 ? void 0 : source.mimeType))) {
15
17
  throw new Error(`<Video/> needs 'source.url' and 'source.mimeType'`);
16
18
  }
@@ -0,0 +1,3 @@
1
+ import type { HydrogenConfig } from './types';
2
+ export declare const defineConfig: (params: HydrogenConfig) => HydrogenConfig;
3
+ export type { HydrogenConfig };
@@ -0,0 +1 @@
1
+ export const defineConfig = (params) => params;
@@ -1,6 +1,6 @@
1
1
  export const RSC_PATHNAME = '/__rsc';
2
2
  export const EVENT_PATHNAME = '/__event';
3
- export const EVENT_PATHNAME_REGEX = new RegExp(`^${EVENT_PATHNAME}\/`);
3
+ export const EVENT_PATHNAME_REGEX = new RegExp(`^${EVENT_PATHNAME}/`);
4
4
  export const OXYGEN_SECRET_TOKEN_ENVIRONMENT_VARIABLE = 'SHOPIFY_STOREFRONT_API_SECRET_TOKEN';
5
5
  export const STOREFRONT_API_SECRET_TOKEN_HEADER = 'Shopify-Storefront-Private-Token';
6
6
  export const STOREFRONT_API_PUBLIC_TOKEN_HEADER = 'X-Shopify-Storefront-Access-Token';
@@ -1,10 +1,11 @@
1
+ /* eslint-disable hydrogen/no-state-in-server-components */
1
2
  import React, { Suspense, useState, StrictMode, Fragment, } from 'react';
2
3
  // @ts-expect-error hydrateRoot isn't on the TS types yet, but we're using React 18 so it exists
3
4
  import { hydrateRoot } from 'react-dom/client';
4
5
  import { ErrorBoundary } from 'react-error-boundary';
5
6
  import { useServerResponse } from './framework/Hydration/rsc';
6
7
  import { ServerPropsProvider } from './foundation/ServerPropsProvider';
7
- const DevTools = React.lazy(() => import('./components/DevTools'));
8
+ const DevTools = React.lazy(() => import('./components/DevTools.client'));
8
9
  const renderHydrogen = async (ClientWrapper, config) => {
9
10
  const root = document.getElementById('root');
10
11
  if (!root) {
@@ -69,3 +70,4 @@ function Error({ error }) {
69
70
  React.createElement("a", { href: "/", style: { textDecoration: 'underline' } }, "home page"),
70
71
  "."))));
71
72
  }
73
+ /* eslint-enable hydrogen/no-state-in-server-components */
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { ServerHandlerConfig } from './types';
2
+ import type { HydrogenConfig } from './types';
3
3
  import type { ServerResponse, IncomingMessage } from 'http';
4
4
  import { RuntimeContext } from './framework/runtime';
5
5
  declare global {
@@ -19,5 +19,5 @@ interface RequestHandlerOptions {
19
19
  export interface RequestHandler {
20
20
  (request: Request | IncomingMessage, options: RequestHandlerOptions): Promise<Response | undefined>;
21
21
  }
22
- export declare const renderHydrogen: (App: any, { shopifyConfig, routes, serverAnalyticsConnectors, session, }: ServerHandlerConfig) => RequestHandler;
22
+ export declare const renderHydrogen: (App: any, hydrogenConfig?: HydrogenConfig | undefined) => RequestHandler;
23
23
  export default renderHydrogen;