@shopify/hydrogen 0.12.0 → 0.13.2

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 (264) hide show
  1. package/CHANGELOG.md +331 -27
  2. package/dist/esnext/client.d.ts +2 -0
  3. package/dist/esnext/client.js +2 -0
  4. package/dist/esnext/components/CartLineProvider/context.d.ts +10 -10
  5. package/dist/esnext/components/CartProvider/CartProvider.client.d.ts +1 -1
  6. package/dist/esnext/components/CartProvider/CartProvider.client.js +2 -1
  7. package/dist/esnext/components/CartProvider/cart-queries.d.ts +9 -0
  8. package/dist/esnext/components/CartProvider/cart-queries.js +876 -0
  9. package/dist/esnext/components/CartProvider/graphql/CartAttributesUpdateMutation.d.ts +1 -1
  10. package/dist/esnext/components/CartProvider/graphql/CartBuyerIdentityUpdateMutation.d.ts +1 -1
  11. package/dist/esnext/components/CartProvider/graphql/CartCreateMutation.d.ts +1 -1
  12. package/dist/esnext/components/CartProvider/graphql/CartDiscountCodesUpdateMutation.d.ts +1 -1
  13. package/dist/esnext/components/CartProvider/graphql/CartFragment.d.ts +1 -1
  14. package/dist/esnext/components/CartProvider/graphql/CartLineAddMutation.d.ts +1 -1
  15. package/dist/esnext/components/CartProvider/graphql/CartLineRemoveMutation.d.ts +1 -1
  16. package/dist/esnext/components/CartProvider/graphql/CartLineUpdateMutation.d.ts +1 -1
  17. package/dist/esnext/components/CartProvider/graphql/CartNoteUpdateMutation.d.ts +1 -1
  18. package/dist/esnext/components/CartProvider/graphql/CartQuery.d.ts +1 -1
  19. package/dist/esnext/components/CartProvider/hooks.d.ts +1 -1
  20. package/dist/esnext/components/CartProvider/hooks.js +4 -1
  21. package/dist/esnext/components/CartProvider/types.d.ts +1 -1
  22. package/dist/esnext/components/ExternalVideo/ExternalVideo.d.ts +6 -5
  23. package/dist/esnext/components/ExternalVideo/ExternalVideo.js +5 -2
  24. package/dist/esnext/components/Image/Image.d.ts +14 -12
  25. package/dist/esnext/components/Image/Image.js +17 -14
  26. package/dist/esnext/components/Link/Link.client.d.ts +4 -5
  27. package/dist/esnext/components/Link/Link.client.js +5 -4
  28. package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +1 -3
  29. package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -1
  30. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +2 -2
  31. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +15 -4
  32. package/dist/esnext/components/LocalizationProvider/LocalizationQuery.d.ts +1 -8
  33. package/dist/esnext/components/LocalizationProvider/index.d.ts +0 -1
  34. package/dist/esnext/components/LocalizationProvider/index.js +0 -1
  35. package/dist/esnext/components/MediaFile/MediaFile.d.ts +4 -3
  36. package/dist/esnext/components/Metafield/Metafield.client.d.ts +2 -2
  37. package/dist/esnext/components/Metafield/Metafield.client.js +8 -5
  38. package/dist/esnext/components/Metafield/types.d.ts +1 -1
  39. package/dist/esnext/components/ModelViewer/ModelViewer.client.d.ts +57 -56
  40. package/dist/esnext/components/ModelViewer/ModelViewer.client.js +10 -4
  41. package/dist/esnext/components/Money/Money.client.d.ts +5 -4
  42. package/dist/esnext/components/Money/Money.client.js +1 -1
  43. package/dist/esnext/components/ProductDescription/ProductDescription.client.d.ts +9 -4
  44. package/dist/esnext/components/ProductDescription/ProductDescription.client.js +4 -3
  45. package/dist/esnext/components/ProductMetafield/ProductMetafield.client.js +3 -3
  46. package/dist/esnext/components/ProductPrice/ProductPrice.client.js +2 -2
  47. package/dist/esnext/components/ProductProvider/ProductProvider.client.d.ts +3 -2
  48. package/dist/esnext/components/ProductProvider/ProductProvider.client.js +1 -0
  49. package/dist/esnext/components/ProductProvider/context.d.ts +23 -14
  50. package/dist/esnext/components/Seo/CollectionSeo.client.d.ts +3 -2
  51. package/dist/esnext/components/Seo/CollectionSeo.client.js +2 -2
  52. package/dist/esnext/components/Seo/DefaultPageSeo.client.d.ts +3 -2
  53. package/dist/esnext/components/Seo/DescriptionSeo.client.d.ts +2 -2
  54. package/dist/esnext/components/Seo/HomePageSeo.client.d.ts +1 -1
  55. package/dist/esnext/components/Seo/ImageSeo.client.d.ts +3 -2
  56. package/dist/esnext/components/Seo/ImageSeo.client.js +1 -1
  57. package/dist/esnext/components/Seo/PageSeo.client.d.ts +3 -2
  58. package/dist/esnext/components/Seo/ProductSeo.client.d.ts +3 -3
  59. package/dist/esnext/components/Seo/ProductSeo.client.js +10 -5
  60. package/dist/esnext/components/Seo/Seo.client.d.ts +10 -7
  61. package/dist/esnext/components/Seo/TitleSeo.client.d.ts +3 -4
  62. package/dist/esnext/components/Seo/TwitterSeo.client.d.ts +1 -1
  63. package/dist/esnext/components/Seo/seo-types.d.ts +17 -0
  64. package/dist/esnext/components/{ExternalVideo/ExternalVideoFragment.js → Seo/seo-types.js} +0 -0
  65. package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +7 -6
  66. package/dist/esnext/components/UnitPrice/UnitPrice.client.js +1 -1
  67. package/dist/esnext/components/Video/Video.d.ts +5 -4
  68. package/dist/esnext/components/Video/Video.js +10 -2
  69. package/dist/esnext/components/index.d.ts +0 -3
  70. package/dist/esnext/components/index.js +0 -3
  71. package/dist/esnext/entry-client.js +9 -4
  72. package/dist/esnext/entry-server.d.ts +1 -0
  73. package/dist/esnext/entry-server.js +101 -88
  74. package/dist/esnext/foundation/FileRoutes/FileRoutes.server.d.ts +22 -0
  75. package/dist/esnext/foundation/{Router/FileRoutes.js → FileRoutes/FileRoutes.server.js} +20 -10
  76. package/dist/esnext/foundation/Redirect/Redirect.client.d.ts +5 -0
  77. package/dist/esnext/foundation/Redirect/Redirect.client.js +14 -0
  78. package/dist/esnext/foundation/Route/Route.server.d.ts +12 -0
  79. package/dist/esnext/foundation/Route/Route.server.js +33 -0
  80. package/dist/esnext/foundation/Router/{Router.d.ts → BrowserRouter.client.d.ts} +3 -2
  81. package/dist/esnext/foundation/Router/{Router.js → BrowserRouter.client.js} +7 -5
  82. package/dist/esnext/foundation/Router/Router.server.d.ts +5 -3
  83. package/dist/esnext/foundation/Router/Router.server.js +7 -22
  84. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +19 -24
  85. package/dist/esnext/foundation/ShopifyProvider/index.d.ts +0 -1
  86. package/dist/esnext/foundation/ShopifyProvider/index.js +0 -1
  87. package/dist/esnext/foundation/index.d.ts +0 -1
  88. package/dist/esnext/foundation/index.js +0 -1
  89. package/dist/esnext/{hooks → foundation}/useNavigate/useNavigate.d.ts +6 -3
  90. package/dist/esnext/{hooks → foundation}/useNavigate/useNavigate.js +4 -1
  91. package/dist/esnext/foundation/useQuery/hooks.d.ts +5 -4
  92. package/dist/esnext/foundation/useQuery/hooks.js +13 -4
  93. package/dist/esnext/foundation/useRouteParams/RouteParamsProvider.client.d.ts +9 -0
  94. package/dist/esnext/foundation/useRouteParams/RouteParamsProvider.client.js +7 -0
  95. package/dist/esnext/foundation/useRouteParams/useRouteParams.d.ts +4 -0
  96. package/dist/esnext/foundation/useRouteParams/useRouteParams.js +9 -0
  97. package/dist/esnext/foundation/useUrl/useUrl.js +1 -1
  98. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.d.ts +13 -0
  99. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.js +28 -7
  100. package/dist/esnext/framework/Hydration/ServerComponentResponse.server.d.ts +4 -1
  101. package/dist/esnext/framework/Hydration/ServerComponentResponse.server.js +5 -0
  102. package/dist/esnext/framework/cache/in-memory.d.ts +1 -0
  103. package/dist/esnext/framework/cache/in-memory.js +15 -5
  104. package/dist/esnext/framework/middleware.js +25 -3
  105. package/dist/esnext/framework/plugin.js +6 -1
  106. package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.d.ts +2 -0
  107. package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.js +28 -0
  108. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +61 -75
  109. package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +1 -1
  110. package/dist/esnext/hooks/index.d.ts +0 -1
  111. package/dist/esnext/hooks/index.js +0 -1
  112. package/dist/esnext/hooks/useCartLine/useCartLine.d.ts +10 -10
  113. package/dist/esnext/hooks/useCountry/useCountry.d.ts +4 -4
  114. package/dist/esnext/hooks/useMoney/hooks.d.ts +3 -3
  115. package/dist/esnext/hooks/useMoney/hooks.js +2 -2
  116. package/dist/esnext/hooks/useParsedMetafields/useParsedMetafields.d.ts +17 -2
  117. package/dist/esnext/hooks/useParsedMetafields/useParsedMetafields.js +7 -3
  118. package/dist/esnext/hooks/useProduct/useProduct.d.ts +34 -96
  119. package/dist/esnext/hooks/useProductOptions/helpers.d.ts +6 -4
  120. package/dist/esnext/hooks/useProductOptions/helpers.js +13 -6
  121. package/dist/esnext/hooks/useProductOptions/types.d.ts +15 -35
  122. package/dist/esnext/hooks/useProductOptions/useProductOptions.d.ts +6 -5
  123. package/dist/esnext/hooks/useProductOptions/useProductOptions.js +13 -3
  124. package/dist/esnext/hooks/useShopQuery/hooks.js +68 -15
  125. package/dist/esnext/index.d.ts +7 -5
  126. package/dist/esnext/index.js +7 -5
  127. package/dist/esnext/platforms/node.d.ts +2 -3
  128. package/dist/esnext/platforms/node.js +5 -3
  129. package/dist/esnext/platforms/worker-event.d.ts +0 -8
  130. package/dist/esnext/platforms/worker-event.js +2 -23
  131. package/dist/esnext/platforms/worker.d.ts +14 -0
  132. package/dist/esnext/platforms/worker.js +25 -0
  133. package/dist/esnext/{graphql/types/types.d.ts → storefront-api-types.d.ts} +389 -32
  134. package/dist/esnext/{graphql/types/types.js → storefront-api-types.js} +326 -30
  135. package/dist/esnext/streaming.server.d.ts +9 -5
  136. package/dist/esnext/streaming.server.js +2 -18
  137. package/dist/esnext/types.d.ts +1 -16
  138. package/dist/esnext/utilities/apiRoutes.d.ts +5 -1
  139. package/dist/esnext/utilities/apiRoutes.js +5 -4
  140. package/dist/esnext/utilities/devtools.d.ts +11 -0
  141. package/dist/esnext/utilities/devtools.js +11 -0
  142. package/dist/esnext/utilities/fetch.d.ts +7 -1
  143. package/dist/esnext/utilities/fetch.js +9 -10
  144. package/dist/esnext/utilities/flattenConnection/flattenConnection.d.ts +3 -2
  145. package/dist/esnext/utilities/flattenConnection/flattenConnection.js +6 -2
  146. package/dist/esnext/utilities/graphql-tracker.d.ts +17 -0
  147. package/dist/esnext/utilities/graphql-tracker.js +119 -0
  148. package/dist/esnext/utilities/image_size.d.ts +5 -4
  149. package/dist/esnext/utilities/log/log-query-timeline.d.ts +1 -1
  150. package/dist/esnext/utilities/log/log-query-timeline.js +1 -2
  151. package/dist/esnext/utilities/log/log.d.ts +1 -0
  152. package/dist/esnext/utilities/log/utils.js +3 -0
  153. package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.d.ts +3 -2
  154. package/dist/esnext/version.d.ts +1 -1
  155. package/dist/esnext/version.js +1 -1
  156. package/dist/node/entry-server.d.ts +1 -0
  157. package/dist/node/entry-server.js +106 -89
  158. package/dist/node/foundation/Redirect/Redirect.client.d.ts +5 -0
  159. package/dist/node/foundation/Redirect/Redirect.client.js +17 -0
  160. package/dist/node/foundation/Router/BrowserRouter.client.d.ts +13 -0
  161. package/dist/node/foundation/Router/BrowserRouter.client.js +77 -0
  162. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +24 -25
  163. package/dist/node/foundation/ServerRequestProvider/index.js +5 -1
  164. package/dist/node/foundation/ServerStateProvider/ServerStateProvider.js +5 -1
  165. package/dist/node/foundation/ssr-interop.d.ts +29 -0
  166. package/dist/node/foundation/ssr-interop.js +39 -0
  167. package/dist/node/foundation/useNavigate/useNavigate.d.ts +13 -0
  168. package/dist/node/foundation/useNavigate/useNavigate.js +18 -0
  169. package/dist/node/foundation/useServerState/index.d.ts +1 -0
  170. package/dist/node/foundation/useServerState/index.js +5 -0
  171. package/dist/node/foundation/useServerState/use-server-state.d.ts +16 -0
  172. package/dist/node/foundation/useServerState/use-server-state.js +24 -0
  173. package/dist/node/framework/Hydration/ServerComponentRequest.server.d.ts +13 -0
  174. package/dist/node/framework/Hydration/ServerComponentRequest.server.js +28 -7
  175. package/dist/node/framework/Hydration/ServerComponentResponse.server.d.ts +4 -1
  176. package/dist/node/framework/Hydration/ServerComponentResponse.server.js +8 -0
  177. package/dist/node/framework/cache/in-memory.d.ts +1 -0
  178. package/dist/node/framework/cache/in-memory.js +15 -5
  179. package/dist/node/framework/middleware.js +30 -4
  180. package/dist/node/framework/plugin.js +11 -2
  181. package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.d.ts +2 -0
  182. package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.js +31 -0
  183. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +61 -75
  184. package/dist/node/framework/plugins/vite-plugin-platform-entry.js +1 -1
  185. package/dist/node/{graphql/types/types.d.ts → storefront-api-types.d.ts} +389 -32
  186. package/dist/node/{graphql/types/types.js → storefront-api-types.js} +327 -31
  187. package/dist/node/streaming.server.d.ts +9 -5
  188. package/dist/node/streaming.server.js +2 -18
  189. package/dist/node/types.d.ts +1 -16
  190. package/dist/node/utilities/apiRoutes.d.ts +5 -1
  191. package/dist/node/utilities/apiRoutes.js +5 -4
  192. package/dist/node/utilities/fetch.d.ts +7 -1
  193. package/dist/node/utilities/fetch.js +9 -10
  194. package/dist/node/utilities/log/log-query-timeline.d.ts +1 -1
  195. package/dist/node/utilities/log/log-query-timeline.js +1 -2
  196. package/dist/node/utilities/log/log.d.ts +1 -0
  197. package/dist/node/utilities/log/utils.js +3 -0
  198. package/dist/node/utilities/web-api-polyfill.js +5 -1
  199. package/dist/node/version.d.ts +1 -1
  200. package/dist/node/version.js +1 -1
  201. package/package.json +9 -12
  202. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +43 -104
  203. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.browser.development.server.js +1566 -848
  204. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.browser.production.min.server.js +36 -421
  205. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.node.development.server.js +1523 -864
  206. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-writer.node.production.min.server.js +35 -437
  207. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite.development.js +507 -517
  208. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite.production.min.js +10 -246
  209. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-client-proxy.js +16 -23
  210. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +47 -108
  211. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js +1033 -306
  212. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.node.server.js +965 -293
  213. package/vendor/react-server-dom-vite/esm/react-server-dom-vite.js +98 -108
  214. package/vendor/react-server-dom-vite/package.json +0 -2
  215. package/dist/esnext/components/ExternalVideo/ExternalVideoFragment.d.ts +0 -8
  216. package/dist/esnext/components/Image/ImageFragment.d.ts +0 -8
  217. package/dist/esnext/components/Image/ImageFragment.js +0 -1
  218. package/dist/esnext/components/MediaFile/MediaFileFragment.d.ts +0 -36
  219. package/dist/esnext/components/MediaFile/MediaFileFragment.js +0 -1
  220. package/dist/esnext/components/Metafield/MetafieldFragment.d.ts +0 -22
  221. package/dist/esnext/components/Metafield/MetafieldFragment.js +0 -1
  222. package/dist/esnext/components/ModelViewer/Model3DFragment.d.ts +0 -15
  223. package/dist/esnext/components/ModelViewer/Model3DFragment.js +0 -1
  224. package/dist/esnext/components/Money/MoneyFragment.d.ts +0 -8
  225. package/dist/esnext/components/Money/MoneyFragment.js +0 -1
  226. package/dist/esnext/components/ProductProvider/ProductProviderFragment.d.ts +0 -247
  227. package/dist/esnext/components/ProductProvider/ProductProviderFragment.js +0 -1
  228. package/dist/esnext/components/ProductProvider/types.d.ts +0 -19
  229. package/dist/esnext/components/ProductProvider/types.js +0 -1
  230. package/dist/esnext/components/RawHtml/RawHtml.d.ts +0 -17
  231. package/dist/esnext/components/RawHtml/RawHtml.js +0 -21
  232. package/dist/esnext/components/RawHtml/index.d.ts +0 -1
  233. package/dist/esnext/components/RawHtml/index.js +0 -1
  234. package/dist/esnext/components/Seo/SeoFragment.d.ts +0 -66
  235. package/dist/esnext/components/Seo/SeoFragment.js +0 -1
  236. package/dist/esnext/components/Seo/types.d.ts +0 -15
  237. package/dist/esnext/components/Seo/types.js +0 -1
  238. package/dist/esnext/components/UnitPrice/UnitPriceFragment.d.ts +0 -15
  239. package/dist/esnext/components/UnitPrice/UnitPriceFragment.js +0 -1
  240. package/dist/esnext/components/Video/VideoFragment.d.ts +0 -15
  241. package/dist/esnext/components/Video/VideoFragment.js +0 -1
  242. package/dist/esnext/foundation/Router/FileRoutes.d.ts +0 -18
  243. package/dist/esnext/foundation/Router/Route.server.d.ts +0 -9
  244. package/dist/esnext/foundation/Router/Route.server.js +0 -6
  245. package/dist/esnext/foundation/Router/useParams.d.ts +0 -1
  246. package/dist/esnext/foundation/Router/useParams.js +0 -5
  247. package/dist/esnext/fragments.d.ts +0 -20
  248. package/dist/esnext/fragments.js +0 -10
  249. package/dist/esnext/graphql/graphql-constants.d.ts +0 -1756
  250. package/dist/esnext/graphql/graphql-constants.js +0 -3447
  251. package/dist/esnext/hooks/useAvailableCountries/index.d.ts +0 -1
  252. package/dist/esnext/hooks/useAvailableCountries/index.js +0 -1
  253. package/dist/esnext/hooks/useAvailableCountries/useAvailableCountries.d.ts +0 -11
  254. package/dist/esnext/hooks/useAvailableCountries/useAvailableCountries.js +0 -17
  255. package/dist/esnext/hooks/useNavigate/index.d.ts +0 -1
  256. package/dist/esnext/hooks/useNavigate/index.js +0 -1
  257. package/dist/esnext/hooks/useProductOptions/SellingPlanFragment.d.ts +0 -31
  258. package/dist/esnext/hooks/useProductOptions/SellingPlanFragment.js +0 -1
  259. package/dist/esnext/hooks/useProductOptions/SellingPlanGroupsFragment.d.ts +0 -46
  260. package/dist/esnext/hooks/useProductOptions/SellingPlanGroupsFragment.js +0 -1
  261. package/dist/esnext/hooks/useProductOptions/VariantFragment.d.ts +0 -106
  262. package/dist/esnext/hooks/useProductOptions/VariantFragment.js +0 -1
  263. package/fragments.d.ts +0 -1
  264. package/fragments.js +0 -1
@@ -0,0 +1,17 @@
1
+ import type { Scalars, Shop as ShopType, Seo as SeoType } from '../../storefront-api-types';
2
+ export interface Twitter {
3
+ site: string;
4
+ title: SeoType['title'];
5
+ description: SeoType['description'];
6
+ }
7
+ export interface HomePage {
8
+ description: ShopType['description'];
9
+ title: ShopType['name'];
10
+ url: Scalars['URL'];
11
+ }
12
+ export interface DefaultPage extends ShopType {
13
+ title: ShopType['name'];
14
+ url: Scalars['URL'];
15
+ titleTemplate?: string;
16
+ lang?: string;
17
+ }
@@ -1,14 +1,15 @@
1
- import type { UnitPriceFragmentFragment } from './UnitPriceFragment';
1
+ import type { UnitPriceMeasurement, MoneyV2 } from '../../storefront-api-types';
2
+ import type { PartialDeep } from 'type-fest';
2
3
  export interface UnitPriceProps<TTag> {
3
- /** A [`MoneyV2` object](/api/storefront/reference/common-objects/moneyv2). */
4
- data: UnitPriceFragmentFragment['unitPrice'];
5
- /** A [`UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement). */
6
- measurement: UnitPriceFragmentFragment['unitPriceMeasurement'];
4
+ /** An object with fields that correspond to the Storefront API's [MoneyV2 object](/api/storefront/reference/common-objects/moneyv2). */
5
+ data: PartialDeep<MoneyV2>;
6
+ /** A [UnitPriceMeasurement object](/api/storefront/reference/products/unitpricemeasurement). */
7
+ measurement: PartialDeep<UnitPriceMeasurement>;
7
8
  /** An HTML tag to be rendered as the base element wrapper. The default is `div`. */
8
9
  as?: TTag;
9
10
  }
10
11
  /**
11
12
  * The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
12
- * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
13
+ * Storefront API's [MoneyV2 object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the Storefront API's [UnitPriceMeasurement object](/api/storefront/reference/products/unitpricemeasurement).
13
14
  */
14
15
  export declare function UnitPrice<TTag extends keyof JSX.IntrinsicElements = 'div'>(props: JSX.IntrinsicElements[TTag] & UnitPriceProps<TTag>): JSX.Element | null;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { Money } from '../Money';
3
3
  /**
4
4
  * The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
5
- * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
5
+ * Storefront API's [MoneyV2 object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the Storefront API's [UnitPriceMeasurement object](/api/storefront/reference/products/unitpricemeasurement).
6
6
  */
7
7
  export function UnitPrice(props) {
8
8
  const { data, measurement, as, ...passthroughProps } = props;
@@ -1,13 +1,14 @@
1
1
  import { ImageSizeOptions } from '../../utilities';
2
- import type { VideoFragmentFragment } from './VideoFragment';
2
+ import type { Video as VideoType } from '../../storefront-api-types';
3
+ import type { PartialDeep } from 'type-fest';
3
4
  interface VideoProps {
4
- /** An object corresponding to the [GraphQL fragment](#graphql-fragment). */
5
- data: VideoFragmentFragment;
5
+ /** An object with fields that correspond to the Storefront API's [Video object](/api/storefront/latest/objects/video). */
6
+ data: PartialDeep<VideoType>;
6
7
  /** An object of image size options for the video's `previewImage`. */
7
8
  options?: ImageSizeOptions;
8
9
  }
9
10
  /**
10
- * The `Video` component renders a `video` for the Storefront API's [`Video` object](/api/storefront/reference/products/video).
11
+ * The `Video` component renders a `video` for the Storefront API's [Video object](/api/storefront/reference/products/video).
11
12
  */
12
13
  export declare function Video(props: JSX.IntrinsicElements['video'] & VideoProps): JSX.Element;
13
14
  export {};
@@ -1,11 +1,19 @@
1
1
  import React from 'react';
2
2
  import { useImageUrl } from '../../utilities';
3
3
  /**
4
- * The `Video` component renders a `video` for the Storefront API's [`Video` object](/api/storefront/reference/products/video).
4
+ * The `Video` component renders a `video` for the Storefront API's [Video object](/api/storefront/reference/products/video).
5
5
  */
6
6
  export function Video(props) {
7
7
  var _a;
8
8
  const { data, options, id = data.id, playsInline = true, controls = true, ...passthroughProps } = props;
9
9
  const posterUrl = useImageUrl((_a = data.previewImage) === null || _a === void 0 ? void 0 : _a.url, options);
10
- return (React.createElement("video", { ...passthroughProps, id: id, playsInline: playsInline, controls: controls, poster: posterUrl }, data.sources.map((source) => (React.createElement("source", { key: source.url, src: source.url, type: source.mimeType })))));
10
+ if (!data.sources) {
11
+ throw new Error(`<Video/> requires a 'data.sources' array`);
12
+ }
13
+ return (React.createElement("video", { ...passthroughProps, id: id, playsInline: playsInline, controls: controls, poster: posterUrl }, data.sources.map((source) => {
14
+ if (!((source === null || source === void 0 ? void 0 : source.url) && (source === null || source === void 0 ? void 0 : source.mimeType))) {
15
+ throw new Error(`<Video/> needs 'source.url' and 'source.mimeType'`);
16
+ }
17
+ return (React.createElement("source", { key: source.url, src: source.url, type: source.mimeType }));
18
+ })));
11
19
  }
@@ -3,7 +3,6 @@ export { MediaFile } from './MediaFile';
3
3
  export { Video } from './Video';
4
4
  export { Image } from './Image';
5
5
  export { ExternalVideo } from './ExternalVideo';
6
- export { RawHtml } from './RawHtml';
7
6
  export { AddToCartButton } from './AddToCartButton';
8
7
  export { ModelViewer } from './ModelViewer';
9
8
  export { Money } from './Money';
@@ -28,7 +27,5 @@ export { ProductPrice } from './ProductPrice';
28
27
  export { ProductMetafield } from './ProductMetafield';
29
28
  export { BuyNowButton } from './BuyNowButton';
30
29
  export { ShopPayButton } from './ShopPayButton';
31
- export { useAvailableCountries } from '../hooks/useAvailableCountries';
32
30
  export { useCountry } from '../hooks/useCountry';
33
31
  export { Seo } from './Seo';
34
- export { useNavigate } from '../hooks/useNavigate';
@@ -3,7 +3,6 @@ export { MediaFile } from './MediaFile';
3
3
  export { Video } from './Video';
4
4
  export { Image } from './Image';
5
5
  export { ExternalVideo } from './ExternalVideo';
6
- export { RawHtml } from './RawHtml';
7
6
  export { AddToCartButton } from './AddToCartButton';
8
7
  export { ModelViewer } from './ModelViewer';
9
8
  export { Money } from './Money';
@@ -26,7 +25,5 @@ export { ProductPrice } from './ProductPrice';
26
25
  export { ProductMetafield } from './ProductMetafield';
27
26
  export { BuyNowButton } from './BuyNowButton';
28
27
  export { ShopPayButton } from './ShopPayButton';
29
- export { useAvailableCountries } from '../hooks/useAvailableCountries';
30
28
  export { useCountry } from '../hooks/useCountry';
31
29
  export { Seo } from './Seo';
32
- export { useNavigate } from '../hooks/useNavigate';
@@ -1,16 +1,22 @@
1
1
  import React, { Suspense, useState, StrictMode, Fragment, } from 'react';
2
2
  // @ts-expect-error hydrateRoot isn't on the TS types yet, but we're using React 18 so it exists
3
- import { hydrateRoot } from 'react-dom';
3
+ import { hydrateRoot } from 'react-dom/client';
4
4
  import { ErrorBoundary } from 'react-error-boundary';
5
5
  import { useServerResponse } from './framework/Hydration/rsc';
6
6
  import { ServerStateProvider } from './foundation/ServerStateProvider';
7
- import { Router } from './foundation/Router/Router';
8
7
  const renderHydrogen = async (ClientWrapper, config) => {
9
8
  const root = document.getElementById('root');
10
9
  if (!root) {
11
10
  console.error(`Could not find a root element <div id="root"></div> to render.`);
12
11
  return;
13
12
  }
13
+ if (import.meta.hot) {
14
+ import.meta.hot.on('hydrogen', ({ type, data }) => {
15
+ if (type === 'warn') {
16
+ console.warn(data);
17
+ }
18
+ });
19
+ }
14
20
  // default to StrictMode on, unless explicitly turned off
15
21
  const RootComponent = (config === null || config === void 0 ? void 0 : config.strictMode) !== false ? StrictMode : Fragment;
16
22
  hydrateRoot(root, React.createElement(RootComponent, null,
@@ -26,8 +32,7 @@ function Content({ clientWrapper: ClientWrapper = ({ children }) => children, })
26
32
  });
27
33
  const response = useServerResponse(serverState);
28
34
  return (React.createElement(ServerStateProvider, { serverState: serverState, setServerState: setServerState },
29
- React.createElement(Router, null,
30
- React.createElement(ClientWrapper, null, response.readRoot()))));
35
+ React.createElement(ClientWrapper, null, response.readRoot())));
31
36
  }
32
37
  function Error({ error }) {
33
38
  if (import.meta.env.DEV) {
@@ -14,6 +14,7 @@ interface RequestHandlerOptions {
14
14
  dev?: boolean;
15
15
  context?: RuntimeContext;
16
16
  nonce?: string;
17
+ buyerIpHeader?: string;
17
18
  }
18
19
  export interface RequestHandler {
19
20
  (request: Request | IncomingMessage, options: RequestHandlerOptions): Promise<Response | undefined>;
@@ -15,10 +15,13 @@ import { setConfig } from './framework/config';
15
15
  import { ssrRenderToPipeableStream, ssrRenderToReadableStream, rscRenderToReadableStream, createFromReadableStream, isStreamingSupported, bufferReadableStream, } from './streaming.server';
16
16
  import { RSC_PATHNAME } from './constants';
17
17
  import { stripScriptsFromTemplate } from './utilities/template';
18
+ const DOCTYPE = '<!DOCTYPE html>';
19
+ const CONTENT_TYPE = 'Content-Type';
18
20
  const HTML_CONTENT_TYPE = 'text/html; charset=UTF-8';
19
21
  export const renderHydrogen = (App, { shopifyConfig, routes }) => {
20
- const handleRequest = async function (rawRequest, { indexTemplate, streamableResponse, dev, cache, context, nonce }) {
22
+ const handleRequest = async function (rawRequest, { indexTemplate, streamableResponse, dev, cache, context, nonce, buyerIpHeader, }) {
21
23
  const request = new ServerComponentRequest(rawRequest);
24
+ request.ctx.buyerIpHeader = buyerIpHeader;
22
25
  const url = new URL(request.url);
23
26
  const log = getLoggerWithContext(request);
24
27
  const componentResponse = new ServerComponentResponse();
@@ -92,9 +95,14 @@ async function render(url, { App, routes, request, componentResponse, log, templ
92
95
  routes,
93
96
  log,
94
97
  }, { template });
98
+ function onErrorShell(error) {
99
+ log.error(error);
100
+ componentResponse.writeHead({ status: 500 });
101
+ return template;
102
+ }
95
103
  let [html, flight] = await Promise.all([
96
- renderToBufferedString(AppSSR, { log, nonce }),
97
- bufferReadableStream(rscReadable.getReader()),
104
+ renderToBufferedString(AppSSR, { log, nonce }).catch(onErrorShell),
105
+ bufferReadableStream(rscReadable.getReader()).catch(() => null),
98
106
  ]);
99
107
  const { headers, status, statusText } = getResponseOptions(componentResponse);
100
108
  /**
@@ -111,7 +119,7 @@ async function render(url, { App, routes, request, componentResponse, log, templ
111
119
  headers,
112
120
  });
113
121
  }
114
- headers['Content-type'] = HTML_CONTENT_TYPE;
122
+ headers[CONTENT_TYPE] = HTML_CONTENT_TYPE;
115
123
  html = applyHtmlHead(html, request.ctx.head, template);
116
124
  if (flight) {
117
125
  html = html.replace('</body>', `${flightContainer({ init: true, nonce, chunk: flight })}</body>`);
@@ -128,6 +136,7 @@ async function render(url, { App, routes, request, componentResponse, log, templ
128
136
  * information, so this method should not be used by crawlers.
129
137
  */
130
138
  async function stream(url, { App, routes, request, response, componentResponse, log, template, nonce, dev, }) {
139
+ var _a;
131
140
  const state = { pathname: url.pathname, search: url.search };
132
141
  log.trace('start stream');
133
142
  const { noScriptTemplate, bootstrapScripts, bootstrapModules } = stripScriptsFromTemplate(template);
@@ -156,59 +165,66 @@ async function stream(url, { App, routes, request, response, componentResponse,
156
165
  });
157
166
  let didError;
158
167
  if (__WORKER__) {
159
- const deferredShouldReturnApp = defer();
168
+ const onCompleteAll = defer();
160
169
  const encoder = new TextEncoder();
161
170
  const transform = new TransformStream();
162
171
  const writable = transform.writable.getWriter();
163
172
  const responseOptions = {};
164
- const ssrReadable = ssrRenderToReadableStream(AppSSR, {
165
- nonce,
166
- bootstrapScripts,
167
- bootstrapModules,
168
- onCompleteShell() {
169
- log.trace('worker ready to stream');
170
- Object.assign(responseOptions, getResponseOptions(componentResponse, didError));
171
- /**
172
- * TODO: This assumes `response.cache()` has been called _before_ any
173
- * queries which might be caught behind Suspense. Clarify this or add
174
- * additional checks downstream?
175
- */
176
- responseOptions.headers[getCacheControlHeader({ dev })] =
177
- componentResponse.cacheControlHeader;
178
- if (isRedirect(responseOptions)) {
179
- // Return redirects early without further rendering/streaming
180
- return deferredShouldReturnApp.resolve(false);
181
- }
182
- if (!componentResponse.canStream())
183
- return;
184
- startWritingHtmlToStream(responseOptions, writable, encoder, dev ? didError : undefined);
185
- deferredShouldReturnApp.resolve(true);
186
- },
187
- async onCompleteAll() {
188
- log.trace('worker complete stream');
189
- if (componentResponse.canStream())
190
- return;
191
- Object.assign(responseOptions, getResponseOptions(componentResponse, didError));
192
- if (isRedirect(responseOptions)) {
193
- // Redirects found after any async code
194
- return deferredShouldReturnApp.resolve(false);
195
- }
173
+ let ssrReadable;
174
+ try {
175
+ ssrReadable = await ssrRenderToReadableStream(AppSSR, {
176
+ nonce,
177
+ bootstrapScripts,
178
+ bootstrapModules,
179
+ onError(error) {
180
+ didError = error;
181
+ if (dev && !writable.closed && !!responseOptions.status) {
182
+ writable.write(getErrorMarkup(error));
183
+ }
184
+ log.error(error);
185
+ },
186
+ });
187
+ }
188
+ catch (error) {
189
+ log.error(error);
190
+ return new Response(template + (dev ? getErrorMarkup(error) : ''), {
191
+ status: 500,
192
+ headers: { [CONTENT_TYPE]: HTML_CONTENT_TYPE },
193
+ });
194
+ }
195
+ log.trace('worker ready to stream');
196
+ ssrReadable.allReady.then(() => {
197
+ log.trace('worker complete stream');
198
+ onCompleteAll.resolve(true);
199
+ });
200
+ async function prepareForStreaming(flush) {
201
+ Object.assign(responseOptions, getResponseOptions(componentResponse, didError));
202
+ /**
203
+ * TODO: This assumes `response.cache()` has been called _before_ any
204
+ * queries which might be caught behind Suspense. Clarify this or add
205
+ * additional checks downstream?
206
+ */
207
+ responseOptions.headers[getCacheControlHeader({ dev })] =
208
+ componentResponse.cacheControlHeader;
209
+ if (isRedirect(responseOptions)) {
210
+ return false;
211
+ }
212
+ if (flush) {
196
213
  if (componentResponse.customBody) {
197
214
  writable.write(encoder.encode(await componentResponse.customBody));
198
- return deferredShouldReturnApp.resolve(false);
215
+ return false;
199
216
  }
200
- startWritingHtmlToStream(responseOptions, writable, encoder, dev ? didError : undefined);
201
- deferredShouldReturnApp.resolve(true);
202
- },
203
- onError(error) {
204
- didError = error;
205
- if (dev && deferredShouldReturnApp.status === 'pending') {
206
- writable.write(getErrorMarkup(error));
217
+ responseOptions.headers[CONTENT_TYPE] = HTML_CONTENT_TYPE;
218
+ writable.write(encoder.encode(DOCTYPE));
219
+ if (didError) {
220
+ // This error was delayed until the headers were properly sent.
221
+ writable.write(encoder.encode(getErrorMarkup(didError)));
207
222
  }
208
- log.error(error);
209
- },
210
- });
211
- if (await deferredShouldReturnApp.promise) {
223
+ return true;
224
+ }
225
+ }
226
+ const shouldReturnApp = (_a = (await prepareForStreaming(componentResponse.canStream()))) !== null && _a !== void 0 ? _a : (await onCompleteAll.promise.then(prepareForStreaming));
227
+ if (shouldReturnApp) {
212
228
  let bufferedSsr = '';
213
229
  let isPendingSsrWrite = false;
214
230
  const writingSSR = bufferReadableStream(ssrReadable.getReader(), (chunk) => {
@@ -245,12 +261,11 @@ async function stream(url, { App, routes, request, response, componentResponse,
245
261
  return new Response(bufferedBody, responseOptions);
246
262
  }
247
263
  else if (response) {
248
- response.socket.on('error', log.fatal);
249
264
  const { pipe } = ssrRenderToPipeableStream(AppSSR, {
250
265
  nonce,
251
266
  bootstrapScripts,
252
267
  bootstrapModules,
253
- onCompleteShell() {
268
+ onShellReady() {
254
269
  log.trace('node ready to stream');
255
270
  /**
256
271
  * TODO: This assumes `response.cache()` has been called _before_ any
@@ -275,7 +290,7 @@ async function stream(url, { App, routes, request, response, componentResponse,
275
290
  return response.write(chunk);
276
291
  });
277
292
  },
278
- async onCompleteAll() {
293
+ async onAllReady() {
279
294
  log.trace('node complete stream');
280
295
  if (componentResponse.canStream() || response.writableEnded) {
281
296
  postRequestTasks('str', response.statusCode, request, componentResponse);
@@ -298,6 +313,15 @@ async function stream(url, { App, routes, request, response, componentResponse,
298
313
  pipe(response);
299
314
  });
300
315
  },
316
+ onShellError(error) {
317
+ log.error(error);
318
+ if (!response.writableEnded) {
319
+ writeHeadToServerResponse(response, componentResponse, log, error);
320
+ startWritingHtmlToServerResponse(response, dev ? error : undefined);
321
+ response.write(template);
322
+ response.end();
323
+ }
324
+ },
301
325
  onError(error) {
302
326
  didError = error;
303
327
  if (dev && response.headersSent) {
@@ -335,7 +359,6 @@ async function hydrate(url, { App, routes, request, response, componentResponse,
335
359
  return new Response(bufferedBody);
336
360
  }
337
361
  else if (response) {
338
- response.socket.on('error', log.fatal);
339
362
  const rscWriter = await import(
340
363
  // @ts-ignore
341
364
  '@shopify/hydrogen/vendor/react-server-dom-vite/writer.node.server');
@@ -349,9 +372,11 @@ async function hydrate(url, { App, routes, request, response, componentResponse,
349
372
  }
350
373
  function buildAppRSC({ App, state, request, response, log, routes, }) {
351
374
  const hydrogenServerProps = { request, response, log };
375
+ const serverProps = { ...state, ...hydrogenServerProps, routes };
376
+ request.ctx.router.serverProps = serverProps;
352
377
  const AppRSC = (React.createElement(ServerRequestProvider, { request: request, isRSC: true },
353
378
  React.createElement(PreloadQueries, { request: request },
354
- React.createElement(App, { ...state, ...hydrogenServerProps, routes: routes }))));
379
+ React.createElement(App, { ...serverProps }))));
355
380
  return { AppRSC };
356
381
  }
357
382
  function buildAppSSR({ App, state, request, response, log, routes }, htmlOptions) {
@@ -382,25 +407,23 @@ function PreloadQueries({ request, children, }) {
382
407
  async function renderToBufferedString(ReactApp, { log, nonce }) {
383
408
  return new Promise(async (resolve, reject) => {
384
409
  if (__WORKER__) {
385
- const deferred = defer();
386
- const readable = ssrRenderToReadableStream(ReactApp, {
387
- nonce,
388
- onCompleteAll() {
389
- /**
390
- * We want to wait until `onCompleteAll` has been called before fetching the
391
- * stream body. Otherwise, React 18's streaming JS script/template tags
392
- * will be included in the output and cause issues when loading
393
- * the Client Components in the browser.
394
- */
395
- deferred.resolve(null);
396
- },
397
- onError(error) {
398
- log.error(error);
399
- deferred.reject(error);
400
- },
401
- });
402
- await deferred.promise.catch(reject);
403
- resolve(await bufferReadableStream(readable.getReader()));
410
+ try {
411
+ const ssrReadable = await ssrRenderToReadableStream(ReactApp, {
412
+ nonce,
413
+ onError: (error) => log.error(error),
414
+ });
415
+ /**
416
+ * We want to wait until `allReady` resolves before fetching the
417
+ * stream body. Otherwise, React 18's streaming JS script/template tags
418
+ * will be included in the output and cause issues when loading
419
+ * the Client Components in the browser.
420
+ */
421
+ await ssrReadable.allReady;
422
+ resolve(bufferReadableStream(ssrReadable.getReader()));
423
+ }
424
+ catch (error) {
425
+ reject(error);
426
+ }
404
427
  }
405
428
  else {
406
429
  const writer = await createNodeWriter();
@@ -410,7 +433,7 @@ async function renderToBufferedString(ReactApp, { log, nonce }) {
410
433
  * When hydrating, we have to wait until `onCompleteAll` to avoid having
411
434
  * `template` and `script` tags inserted and rendered as part of the hydration response.
412
435
  */
413
- onCompleteAll() {
436
+ onAllReady() {
414
437
  let data = '';
415
438
  writer.on('data', (chunk) => (data += chunk.toString()));
416
439
  writer.once('error', reject);
@@ -418,10 +441,8 @@ async function renderToBufferedString(ReactApp, { log, nonce }) {
418
441
  // Tell React to start writing to the writer
419
442
  pipe(writer);
420
443
  },
421
- onError(error) {
422
- log.error(error);
423
- reject(error);
424
- },
444
+ onShellError: reject,
445
+ onError: (error) => log.error(error),
425
446
  });
426
447
  }
427
448
  });
@@ -429,22 +450,14 @@ async function renderToBufferedString(ReactApp, { log, nonce }) {
429
450
  export default renderHydrogen;
430
451
  function startWritingHtmlToServerResponse(response, error) {
431
452
  if (!response.headersSent) {
432
- response.setHeader('Content-type', HTML_CONTENT_TYPE);
433
- response.write('<!DOCTYPE html>');
453
+ response.setHeader(CONTENT_TYPE, HTML_CONTENT_TYPE);
454
+ response.write(DOCTYPE);
434
455
  }
435
456
  if (error) {
436
457
  // This error was delayed until the headers were properly sent.
437
458
  response.write(getErrorMarkup(error));
438
459
  }
439
460
  }
440
- function startWritingHtmlToStream(responseOptions, writable, encoder, error) {
441
- responseOptions.headers['Content-type'] = HTML_CONTENT_TYPE;
442
- writable.write(encoder.encode('<!DOCTYPE html>'));
443
- if (error) {
444
- // This error was delayed until the headers were properly sent.
445
- writable.write(encoder.encode(getErrorMarkup(error)));
446
- }
447
- }
448
461
  function getResponseOptions({ headers, status, customStatus }, error) {
449
462
  var _a, _b;
450
463
  const responseInit = {};
@@ -0,0 +1,22 @@
1
+ import type { ImportGlobEagerOutput } from '../../types';
2
+ interface FileRoutesProps {
3
+ /** The routes defined by Vite's [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. */
4
+ routes: ImportGlobEagerOutput;
5
+ /** A path that's prepended to all file routes. You can modify `basePath` if you want to prefix all file routes. For example, you can prefix all file routes with a locale. */
6
+ basePath?: string;
7
+ /** The portion of the file route path that shouldn't be a part of the URL. You need to modify this if you want to import routes from a location other than the default `src/routes`. */
8
+ dirPrefix?: string;
9
+ }
10
+ /**
11
+ * The `FileRoutes` component builds a set of default Hydrogen routes based on the output provided by Vite's
12
+ * [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. You can have multiple
13
+ * instances of this component to source file routes from multiple locations.
14
+ */
15
+ export declare function FileRoutes({ routes, basePath, dirPrefix, }: FileRoutesProps): JSX.Element | null;
16
+ interface HydrogenRoute {
17
+ component: any;
18
+ path: string;
19
+ exact: boolean;
20
+ }
21
+ export declare function createPageRoutes(pages: ImportGlobEagerOutput, topLevelPath: string | undefined, dirPrefix: string): HydrogenRoute[];
22
+ export {};
@@ -1,15 +1,19 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { matchPath } from '../../utilities/matchPath';
3
3
  import { log } from '../../utilities/log';
4
+ import { useServerRequest } from '../ServerRequestProvider';
5
+ import { RouteParamsProvider } from '../useRouteParams/RouteParamsProvider.client';
4
6
  /**
5
- * Build a set of default Hydrogen routes based on the output provided by Vite's
6
- * import.meta.globEager method.
7
- *
8
- * @see https://vitejs.dev/guide/features.html#glob-import
7
+ * The `FileRoutes` component builds a set of default Hydrogen routes based on the output provided by Vite's
8
+ * [import.meta.globEager](https://vitejs.dev/guide/features.html#glob-import) method. You can have multiple
9
+ * instances of this component to source file routes from multiple locations.
9
10
  */
10
- export function FileRoutes({ routes, serverProps, }) {
11
- const basePath = '/';
12
- const pageRoutes = useMemo(() => createPageRoutes(routes, basePath), [routes, basePath]);
11
+ export function FileRoutes({ routes, basePath = '/', dirPrefix = './routes', }) {
12
+ const request = useServerRequest();
13
+ const { routeRendered, serverProps } = request.ctx.router;
14
+ if (routeRendered)
15
+ return null;
16
+ const pageRoutes = useMemo(() => createPageRoutes(routes, basePath, dirPrefix), [routes, basePath]);
13
17
  let foundRoute, foundRouteDetails;
14
18
  for (let i = 0; i < pageRoutes.length; i++) {
15
19
  foundRouteDetails = matchPath(serverProps.pathname, pageRoutes[i]);
@@ -18,14 +22,20 @@ export function FileRoutes({ routes, serverProps, }) {
18
22
  break;
19
23
  }
20
24
  }
21
- return foundRoute ? (React.createElement(foundRoute.component, { params: foundRouteDetails.params, ...serverProps })) : null;
25
+ if (foundRoute) {
26
+ request.ctx.router.routeRendered = true;
27
+ request.ctx.router.routeParams = foundRouteDetails.params;
28
+ return (React.createElement(RouteParamsProvider, { routeParams: foundRouteDetails.params },
29
+ React.createElement(foundRoute.component, { params: foundRouteDetails.params, ...serverProps })));
30
+ }
31
+ return null;
22
32
  }
23
- export function createPageRoutes(pages, topLevelPath = '*') {
33
+ export function createPageRoutes(pages, topLevelPath = '*', dirPrefix) {
24
34
  const topLevelPrefix = topLevelPath.replace('*', '').replace(/\/$/, '');
25
35
  const routes = Object.keys(pages)
26
36
  .map((key) => {
27
37
  let path = key
28
- .replace('./routes', '')
38
+ .replace(dirPrefix, '')
29
39
  .replace(/\.server\.(t|j)sx?$/, '')
30
40
  /**
31
41
  * Replace /index with /
@@ -0,0 +1,5 @@
1
+ declare type RedirectProps = {
2
+ to: string;
3
+ };
4
+ export default function Redirect({ to }: RedirectProps): null;
5
+ export {};
@@ -0,0 +1,14 @@
1
+ import { useEffect } from 'react';
2
+ import { useNavigate } from '../../foundation/useNavigate/useNavigate';
3
+ export default function Redirect({ to }) {
4
+ const navigate = useNavigate();
5
+ useEffect(() => {
6
+ if (to.startsWith('http')) {
7
+ window.location.href = to;
8
+ }
9
+ else {
10
+ navigate(to);
11
+ }
12
+ }, []);
13
+ return null;
14
+ }
@@ -0,0 +1,12 @@
1
+ import { ReactElement } from 'react';
2
+ export declare type RouteProps = {
3
+ /** The URL path where the route exists. The path can contain variables. For example, `/products/:handle`. */
4
+ path: string;
5
+ /** A reference to a React Server Component that's rendered when the route is active. */
6
+ page: ReactElement;
7
+ };
8
+ /**
9
+ * The `Route` component is used to set up a route in Hydrogen that's independent of the file system. Routes are
10
+ * matched in the order that they're defined.
11
+ */
12
+ export declare function Route({ path, page }: RouteProps): ReactElement | null;
@@ -0,0 +1,33 @@
1
+ import React, { cloneElement } from 'react';
2
+ import { useServerRequest } from '../ServerRequestProvider';
3
+ import { matchPath } from '../../utilities/matchPath';
4
+ import { Boomerang } from '../Boomerang/Boomerang.client';
5
+ import { RouteParamsProvider } from '../useRouteParams/RouteParamsProvider.client';
6
+ /**
7
+ * The `Route` component is used to set up a route in Hydrogen that's independent of the file system. Routes are
8
+ * matched in the order that they're defined.
9
+ */
10
+ export function Route({ path, page }) {
11
+ var _a;
12
+ const request = useServerRequest();
13
+ const { routeRendered, serverProps } = request.ctx.router;
14
+ if (routeRendered)
15
+ return null;
16
+ if (path === '*') {
17
+ request.ctx.router.routeRendered = true;
18
+ return cloneElement(page, serverProps);
19
+ }
20
+ const match = matchPath(serverProps.pathname, {
21
+ path,
22
+ exact: true,
23
+ });
24
+ if (match) {
25
+ request.ctx.router.routeRendered = true;
26
+ request.ctx.router.routeParams = match.params;
27
+ const name = (_a = page === null || page === void 0 ? void 0 : page.type) === null || _a === void 0 ? void 0 : _a.name;
28
+ return (React.createElement(RouteParamsProvider, { routeParams: match.params },
29
+ cloneElement(page, { params: match.params || {}, ...serverProps }),
30
+ name ? React.createElement(Boomerang, { pageTemplate: name }) : null));
31
+ }
32
+ return null;
33
+ }