@shopify/cli 3.90.1 → 3.91.1

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 (159) hide show
  1. package/dist/{acorn-45LE5Z2A.js → acorn-WDTBS4B3.js} +2 -2
  2. package/dist/{angular-Z5FPQPLR.js → angular-WLPEGHXZ.js} +4 -4
  3. package/dist/assets/hydrogen/starter/.graphqlrc.ts +4 -2
  4. package/dist/assets/hydrogen/starter/CHANGELOG.md +172 -0
  5. package/dist/assets/hydrogen/starter/app/components/CartLineItem.tsx +67 -38
  6. package/dist/assets/hydrogen/starter/app/components/CartMain.tsx +45 -7
  7. package/dist/assets/hydrogen/starter/app/components/CartSummary.tsx +20 -38
  8. package/dist/assets/hydrogen/starter/app/components/MockShopNotice.tsx +20 -0
  9. package/dist/assets/hydrogen/starter/app/entry.client.tsx +2 -3
  10. package/dist/assets/hydrogen/starter/app/lib/fragments.ts +8 -0
  11. package/dist/assets/hydrogen/starter/app/routes/_index.tsx +4 -5
  12. package/dist/assets/hydrogen/starter/app/routes/account.addresses.tsx +12 -12
  13. package/dist/assets/hydrogen/starter/app/routes/account.tsx +4 -7
  14. package/dist/assets/hydrogen/starter/app/routes/account_.login.tsx +10 -0
  15. package/dist/assets/hydrogen/starter/app/routes/blogs.$blogHandle._index.tsx +2 -9
  16. package/dist/assets/hydrogen/starter/app/routes/blogs._index.tsx +1 -4
  17. package/dist/assets/hydrogen/starter/app/routes/cart.tsx +3 -11
  18. package/dist/assets/hydrogen/starter/app/routes/collections.all.tsx +1 -3
  19. package/dist/assets/hydrogen/starter/app/routes/pages.$handle.tsx +2 -8
  20. package/dist/assets/hydrogen/starter/app/routes/policies.$handle.tsx +1 -4
  21. package/dist/assets/hydrogen/starter/app/routes/policies._index.tsx +1 -1
  22. package/dist/assets/hydrogen/starter/app/routes/products.$handle.tsx +2 -9
  23. package/dist/assets/hydrogen/starter/app/routes/search.tsx +18 -12
  24. package/dist/assets/hydrogen/starter/app/styles/app.css +72 -1
  25. package/dist/assets/hydrogen/starter/eslint.config.js +1 -0
  26. package/dist/assets/hydrogen/starter/guides/predictiveSearch/predictiveSearch.md +3 -3
  27. package/dist/assets/hydrogen/starter/guides/search/search.md +1 -1
  28. package/dist/assets/hydrogen/starter/package.json +14 -13
  29. package/dist/assets/hydrogen/starter/server.ts +5 -7
  30. package/dist/assets/hydrogen/starter/storefrontapi.generated.d.ts +89 -0
  31. package/dist/{babel-TRRZ6QQY.js → babel-LQYCV4NA.js} +2 -7
  32. package/dist/{brotli-2OKV26Y6.js → brotli-6CC7WD4Z.js} +1 -2
  33. package/dist/{chunk-SGU7BPE4.js → chunk-2EQNSO7C.js} +3 -3
  34. package/dist/{chunk-PAU7LKSJ.js → chunk-2YAGQHB2.js} +3 -3
  35. package/dist/{chunk-OZPZBNSB.js → chunk-463KYFYO.js} +2 -2
  36. package/dist/{chunk-IEPPQIPW.js → chunk-54FE2FGU.js} +2 -2
  37. package/dist/{chunk-EFOOQV72.js → chunk-56ELYGPH.js} +2 -2
  38. package/dist/{chunk-6ONJ77I7.js → chunk-5JYQJQ2E.js} +2 -2
  39. package/dist/chunk-5ZDTGPNX.js +28 -0
  40. package/dist/{chunk-6ONJEX7Y.js → chunk-6NVYATES.js} +2 -2
  41. package/dist/chunk-77BDQRQW.js +90 -0
  42. package/dist/{chunk-HMDWNGIV.js → chunk-A27P5CF7.js} +211 -103
  43. package/dist/{chunk-4BBQTKIZ.js → chunk-A2CZGTAP.js} +27763 -25681
  44. package/dist/{chunk-TIYR37XP.js → chunk-ATQVKUJC.js} +4 -4
  45. package/dist/{chunk-3GXB4ZRP.js → chunk-CE4S2SGM.js} +10 -10
  46. package/dist/{chunk-WC5EDB4Z.js → chunk-CEUL3KX5.js} +1190 -144
  47. package/dist/{chunk-2TMOMDXO.js → chunk-DR5R5UTE.js} +6 -6
  48. package/dist/{chunk-IYNLJNFT.js → chunk-DUNGALP3.js} +3 -3
  49. package/dist/{chunk-TGDLXF4K.js → chunk-E44JKFB6.js} +2 -2
  50. package/dist/{chunk-5SJCPOBW.js → chunk-E4GUDBAR.js} +417 -387
  51. package/dist/{chunk-C5STUYKR.js → chunk-FKP67FZI.js} +3 -3
  52. package/dist/{chunk-ZZNQWJUM.js → chunk-HAG3HJ2V.js} +10 -10
  53. package/dist/{chunk-PUMWL67K.js → chunk-HOIU6WRE.js} +3 -3
  54. package/dist/{chunk-GPKHDSF5.js → chunk-HTGTTXQL.js} +24 -26
  55. package/dist/{chunk-3VKS4374.js → chunk-I23GZAC4.js} +15 -17
  56. package/dist/chunk-ITTNM7I4.js +23 -0
  57. package/dist/chunk-IUKBWIQY.js +39 -0
  58. package/dist/{chunk-H3SSAPRP.js → chunk-K45ALTZ7.js} +3 -3
  59. package/dist/chunk-K52ORY26.js +78 -0
  60. package/dist/{prettier-2ITB6I34.js → chunk-KV3364EL.js} +43 -42
  61. package/dist/{chunk-4TOZOCIV.js → chunk-LFMBIRVC.js} +3 -3
  62. package/dist/{chunk-OTD3FRPC.js → chunk-NYP3N62G.js} +2 -2
  63. package/dist/chunk-OIUDJFV2.js +309 -0
  64. package/dist/{chunk-HV4MPORZ.js → chunk-PCNR4TMY.js} +5 -5
  65. package/dist/{chunk-SG2A4CTL.js → chunk-QFO7QSBW.js} +4 -4
  66. package/dist/{chunk-UHBL2XEG.js → chunk-R622IPZN.js} +3 -3
  67. package/dist/{chunk-X7CGUWBF.js → chunk-RKFRXKFE.js} +3 -3
  68. package/dist/{chunk-WYVKPOTO.js → chunk-RLJICWO6.js} +4 -4
  69. package/dist/chunk-SJXHR42U.js +36 -0
  70. package/dist/{chunk-CYPBBNM2.js → chunk-SUFC4ISB.js} +6 -6
  71. package/dist/{chunk-3AF66HDC.js → chunk-SVV4RJVX.js} +4 -4
  72. package/dist/chunk-TH7ZYYDZ.js +20868 -0
  73. package/dist/{chunk-J2CFMYG5.js → chunk-TY5YKCUW.js} +5 -5
  74. package/dist/{chunk-XD3LXUGW.js → chunk-VBBBCVMH.js} +2 -2
  75. package/dist/chunk-VRUH5BDH.js +51 -0
  76. package/dist/{chunk-7FIBLDM2.js → chunk-VUYVHHZY.js} +3 -3
  77. package/dist/{chunk-KC6KOCJ5.js → chunk-WDYPK6VH.js} +7 -7
  78. package/dist/{chunk-JRFL7VGC.js → chunk-XDCBS7SY.js} +3 -3
  79. package/dist/{chunk-6MYWZ7MP.js → chunk-Z5FK5H2M.js} +8 -27
  80. package/dist/{chunk-RHYTM4FE.js → chunk-ZLV2A27J.js} +2 -2
  81. package/dist/cli/commands/auth/login.js +14 -16
  82. package/dist/cli/commands/auth/login.test.js +16 -18
  83. package/dist/cli/commands/auth/logout.js +14 -16
  84. package/dist/cli/commands/auth/logout.test.js +17 -19
  85. package/dist/cli/commands/cache/clear.js +15 -16
  86. package/dist/cli/commands/debug/command-flags.js +14 -16
  87. package/dist/cli/commands/docs/generate.js +14 -16
  88. package/dist/cli/commands/docs/generate.test.js +15 -17
  89. package/dist/cli/commands/doctor-release/doctor-release.d.ts +6 -0
  90. package/dist/cli/commands/doctor-release/doctor-release.js +27 -0
  91. package/dist/cli/commands/doctor-release/theme/index.d.ts +14 -0
  92. package/dist/cli/commands/doctor-release/theme/index.js +33 -0
  93. package/dist/cli/commands/help.js +14 -16
  94. package/dist/cli/commands/kitchen-sink/async.js +15 -17
  95. package/dist/cli/commands/kitchen-sink/async.test.js +16 -18
  96. package/dist/cli/commands/kitchen-sink/index.js +17 -19
  97. package/dist/cli/commands/kitchen-sink/index.test.js +20 -22
  98. package/dist/cli/commands/kitchen-sink/prompts.js +15 -17
  99. package/dist/cli/commands/kitchen-sink/prompts.test.js +16 -18
  100. package/dist/cli/commands/kitchen-sink/static.js +15 -17
  101. package/dist/cli/commands/kitchen-sink/static.test.js +16 -18
  102. package/dist/cli/commands/notifications/generate.js +15 -17
  103. package/dist/cli/commands/notifications/list.js +15 -17
  104. package/dist/cli/commands/search.js +15 -17
  105. package/dist/cli/commands/upgrade.js +15 -17
  106. package/dist/cli/commands/upgrade.test.js +1 -1
  107. package/dist/cli/commands/version.js +15 -17
  108. package/dist/cli/commands/version.test.js +16 -18
  109. package/dist/cli/services/commands/notifications.js +14 -14
  110. package/dist/cli/services/commands/search.js +8 -9
  111. package/dist/cli/services/commands/search.test.js +9 -10
  112. package/dist/cli/services/commands/version.js +9 -10
  113. package/dist/cli/services/commands/version.test.js +11 -12
  114. package/dist/cli/services/doctor-release/context.d.ts +16 -0
  115. package/dist/cli/services/doctor-release/context.js +9 -0
  116. package/dist/cli/services/doctor-release/theme/runner.d.ts +7 -0
  117. package/dist/cli/services/doctor-release/theme/runner.js +24 -0
  118. package/dist/cli/services/doctor-release/theme/tests/init.d.ts +11 -0
  119. package/dist/cli/services/doctor-release/theme/tests/init.js +21 -0
  120. package/dist/cli/services/doctor-release/theme/tests/push.d.ts +10 -0
  121. package/dist/cli/services/doctor-release/theme/tests/push.js +21 -0
  122. package/dist/cli/services/kitchen-sink/async.js +8 -9
  123. package/dist/cli/services/kitchen-sink/prompts.js +8 -9
  124. package/dist/cli/services/kitchen-sink/static.js +8 -9
  125. package/dist/cli/services/upgrade.js +9 -10
  126. package/dist/cli/services/upgrade.test.js +11 -12
  127. package/dist/{custom-oclif-loader-RINU7HR3.js → custom-oclif-loader-AAJZ7WBW.js} +8 -9
  128. package/dist/{del-E4LJOSMR.js → del-63DSU6FP.js} +7 -7
  129. package/dist/{devtools-D47L6HIC.js → devtools-4MXU7BNJ.js} +2 -2
  130. package/dist/{devtools-2SG3BFWJ.js → devtools-BAOTGU3O.js} +2 -2
  131. package/dist/{error-handler-CWNDOJLB.js → error-handler-GSQRFK57.js} +12 -14
  132. package/dist/{estree-PY6WKTNG.js → estree-U57GTUKI.js} +14 -35
  133. package/dist/{flow-YN54TSCB.js → flow-CBPGBIW5.js} +2 -4
  134. package/dist/{glimmer-RMPUUUDS.js → glimmer-VWCK7UCR.js} +2 -6
  135. package/dist/{graphql-PPLVYWBL.js → graphql-2HHXB4VZ.js} +3 -5
  136. package/dist/hooks/postrun.js +13 -13
  137. package/dist/hooks/prerun.js +14 -14
  138. package/dist/{html-3U6QZZZ4.js → html-ST4I6M3K.js} +4 -6
  139. package/dist/index.js +143537 -8573
  140. package/dist/{lib-XGN4IWQ3.js → lib-HAW436ZI.js} +3 -4
  141. package/dist/{local-FQVEYJ4K.js → local-GOP2BHNI.js} +10 -11
  142. package/dist/{markdown-RHRQTUMC.js → markdown-NVTT3U3H.js} +4 -13
  143. package/dist/{meriyah-7MIMHTWQ.js → meriyah-H6RUUN2F.js} +2 -9
  144. package/dist/{morph-37GC7LQM.js → morph-7WAMUK6I.js} +68 -143
  145. package/dist/{multipart-parser-IYYNISJK.js → multipart-parser-WKKMXACL.js} +2 -2
  146. package/dist/{node-package-manager-XIE2HZEQ.js → node-package-manager-W4R4DUTE.js} +9 -10
  147. package/dist/{npa-E675GQOI.js → npa-GRSJKUWS.js} +5 -7
  148. package/dist/{postcss-MSOPGY7M.js → postcss-LKRKUSYR.js} +4 -6
  149. package/dist/prettier-5ODD6NHV.js +36 -0
  150. package/dist/{source-map-UFUVQCYE.js → source-map-KSW2YKNC.js} +2 -2
  151. package/dist/tsconfig.tsbuildinfo +1 -1
  152. package/dist/{ui-UAEFJEFY.js → ui-VRLRLHWH.js} +8 -9
  153. package/dist/{workerd-EPURL4IC.js → workerd-AO3T6IIJ.js} +19 -22
  154. package/dist/{yaml-6GALFXQY.js → yaml-54MHMX7H.js} +6 -9
  155. package/oclif.manifest.json +128 -9
  156. package/package.json +8 -8
  157. package/dist/chunk-DOZD5WAI.js +0 -153039
  158. package/dist/chunk-EZQWZ57B.js +0 -53
  159. package/dist/chunk-W65CJE3X.js +0 -2238
@@ -1,8 +1,4 @@
1
- import {
2
- Await,
3
- useLoaderData,
4
- Link,
5
- } from 'react-router';
1
+ import {Await, useLoaderData, Link} from 'react-router';
6
2
  import type {Route} from './+types/_index';
7
3
  import {Suspense} from 'react';
8
4
  import {Image} from '@shopify/hydrogen';
@@ -11,6 +7,7 @@ import type {
11
7
  RecommendedProductsQuery,
12
8
  } from 'storefrontapi.generated';
13
9
  import {ProductItem} from '~/components/ProductItem';
10
+ import {MockShopNotice} from '~/components/MockShopNotice';
14
11
 
15
12
  export const meta: Route.MetaFunction = () => {
16
13
  return [{title: 'Hydrogen | Home'}];
@@ -37,6 +34,7 @@ async function loadCriticalData({context}: Route.LoaderArgs) {
37
34
  ]);
38
35
 
39
36
  return {
37
+ isShopLinked: Boolean(context.env.PUBLIC_STORE_DOMAIN),
40
38
  featuredCollection: collections.nodes[0],
41
39
  };
42
40
  }
@@ -64,6 +62,7 @@ export default function Homepage() {
64
62
  const data = useLoaderData<typeof loader>();
65
63
  return (
66
64
  <div className="home">
65
+ {data.isShopLinked ? null : <MockShopNotice />}
67
66
  <FeaturedCollection collection={data.featuredCollection} />
68
67
  <RecommendedProducts products={data.recommendedProducts} />
69
68
  </div>
@@ -264,23 +264,23 @@ export default function Addresses() {
264
264
  <div className="account-addresses">
265
265
  <h2>Addresses</h2>
266
266
  <br />
267
- {!addresses.nodes.length ? (
268
- <p>You have no addresses saved.</p>
269
- ) : (
267
+ <div>
270
268
  <div>
271
- <div>
272
- <legend>Create address</legend>
273
- <NewAddressForm />
274
- </div>
275
- <br />
276
- <hr />
277
- <br />
269
+ <legend>Create address</legend>
270
+ <NewAddressForm key={addresses.nodes.length} />
271
+ </div>
272
+ <br />
273
+ <hr />
274
+ <br />
275
+ {!addresses.nodes.length ? (
276
+ <p>You have no addresses saved.</p>
277
+ ) : (
278
278
  <ExistingAddresses
279
279
  addresses={addresses}
280
280
  defaultAddress={defaultAddress}
281
281
  />
282
- </div>
283
- )}
282
+ )}
283
+ </div>
284
284
  </div>
285
285
  );
286
286
  }
@@ -14,14 +14,11 @@ export function shouldRevalidate() {
14
14
 
15
15
  export async function loader({context}: Route.LoaderArgs) {
16
16
  const {customerAccount} = context;
17
- const {data, errors} = await customerAccount.query(
18
- CUSTOMER_DETAILS_QUERY,
19
- {
20
- variables: {
21
- language: customerAccount.i18n.language,
22
- },
17
+ const {data, errors} = await customerAccount.query(CUSTOMER_DETAILS_QUERY, {
18
+ variables: {
19
+ language: customerAccount.i18n.language,
23
20
  },
24
- );
21
+ });
25
22
 
26
23
  if (errors?.length || !data?.customer) {
27
24
  throw new Error('Customer not found');
@@ -1,7 +1,17 @@
1
1
  import type {Route} from './+types/account_.login';
2
2
 
3
3
  export async function loader({request, context}: Route.LoaderArgs) {
4
+ const url = new URL(request.url);
5
+ const acrValues = url.searchParams.get('acr_values') || undefined;
6
+ const loginHint = url.searchParams.get('login_hint') || undefined;
7
+ const loginHintMode = url.searchParams.get('login_hint_mode') || undefined;
8
+ const locale = url.searchParams.get('locale') || undefined;
9
+
4
10
  return context.customerAccount.login({
5
11
  countryCode: context.storefront.i18n.country,
12
+ acrValues,
13
+ loginHint,
14
+ loginHintMode,
15
+ locale,
6
16
  });
7
17
  }
@@ -1,7 +1,4 @@
1
- import {
2
- Link,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {Link, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/blogs.$blogHandle._index';
6
3
  import {Image, getPaginationVariables} from '@shopify/hydrogen';
7
4
  import type {ArticleItemFragment} from 'storefrontapi.generated';
@@ -26,11 +23,7 @@ export async function loader(args: Route.LoaderArgs) {
26
23
  * Load data necessary for rendering content above the fold. This is the critical data
27
24
  * needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
28
25
  */
29
- async function loadCriticalData({
30
- context,
31
- request,
32
- params,
33
- }: Route.LoaderArgs) {
26
+ async function loadCriticalData({context, request, params}: Route.LoaderArgs) {
34
27
  const paginationVariables = getPaginationVariables(request, {
35
28
  pageBy: 4,
36
29
  });
@@ -1,7 +1,4 @@
1
- import {
2
- Link,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {Link, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/blogs._index';
6
3
  import {getPaginationVariables} from '@shopify/hydrogen';
7
4
  import {PaginatedResourceSection} from '~/components/PaginatedResourceSection';
@@ -1,8 +1,4 @@
1
- import {
2
- useLoaderData,
3
- data,
4
- type HeadersFunction,
5
- } from 'react-router';
1
+ import {useLoaderData, data, type HeadersFunction} from 'react-router';
6
2
  import type {Route} from './+types/cart';
7
3
  import type {CartQueryDataReturn} from '@shopify/hydrogen';
8
4
  import {CartForm} from '@shopify/hydrogen';
@@ -52,18 +48,14 @@ export async function action({request, context}: Route.ActionArgs) {
52
48
  result = await cart.updateDiscountCodes(discountCodes);
53
49
  break;
54
50
  }
55
- case CartForm.ACTIONS.GiftCardCodesUpdate: {
51
+ case CartForm.ACTIONS.GiftCardCodesAdd: {
56
52
  const formGiftCardCode = inputs.giftCardCode;
57
53
 
58
- // User inputted gift card code
59
54
  const giftCardCodes = (
60
55
  formGiftCardCode ? [formGiftCardCode] : []
61
56
  ) as string[];
62
57
 
63
- // Combine gift card codes already applied on cart
64
- giftCardCodes.push(...inputs.giftCardCodes);
65
-
66
- result = await cart.updateGiftCardCodes(giftCardCodes);
58
+ result = await cart.addGiftCardCodes(giftCardCodes);
67
59
  break;
68
60
  }
69
61
  case CartForm.ACTIONS.GiftCardCodesRemove: {
@@ -1,7 +1,5 @@
1
1
  import type {Route} from './+types/collections.all';
2
- import {
3
- useLoaderData,
4
- } from 'react-router';
2
+ import {useLoaderData} from 'react-router';
5
3
  import {getPaginationVariables, Image, Money} from '@shopify/hydrogen';
6
4
  import {PaginatedResourceSection} from '~/components/PaginatedResourceSection';
7
5
  import {ProductItem} from '~/components/ProductItem';
@@ -1,6 +1,4 @@
1
- import {
2
- useLoaderData,
3
- } from 'react-router';
1
+ import {useLoaderData} from 'react-router';
4
2
  import type {Route} from './+types/pages.$handle';
5
3
  import {redirectIfHandleIsLocalized} from '~/lib/redirect';
6
4
 
@@ -22,11 +20,7 @@ export async function loader(args: Route.LoaderArgs) {
22
20
  * Load data necessary for rendering content above the fold. This is the critical data
23
21
  * needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
24
22
  */
25
- async function loadCriticalData({
26
- context,
27
- request,
28
- params,
29
- }: Route.LoaderArgs) {
23
+ async function loadCriticalData({context, request, params}: Route.LoaderArgs) {
30
24
  if (!params.handle) {
31
25
  throw new Error('Missing page handle');
32
26
  }
@@ -1,7 +1,4 @@
1
- import {
2
- Link,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {Link, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/policies.$handle';
6
3
  import {type Shop} from '@shopify/hydrogen/storefront-api-types';
7
4
 
@@ -4,7 +4,7 @@ import type {PoliciesQuery, PolicyItemFragment} from 'storefrontapi.generated';
4
4
 
5
5
  export async function loader({context}: Route.LoaderArgs) {
6
6
  const data: PoliciesQuery = await context.storefront.query(POLICIES_QUERY);
7
-
7
+
8
8
  const shopPolicies = data.shop;
9
9
  const policies: PolicyItemFragment[] = [
10
10
  shopPolicies?.privacyPolicy,
@@ -1,7 +1,4 @@
1
- import {
2
- redirect,
3
- useLoaderData,
4
- } from 'react-router';
1
+ import {redirect, useLoaderData} from 'react-router';
5
2
  import type {Route} from './+types/products.$handle';
6
3
  import {
7
4
  getSelectedProductOptions,
@@ -40,11 +37,7 @@ export async function loader(args: Route.LoaderArgs) {
40
37
  * Load data necessary for rendering content above the fold. This is the critical data
41
38
  * needed to render the page. If it's unavailable, the whole page should 400 or 500 error.
42
39
  */
43
- async function loadCriticalData({
44
- context,
45
- params,
46
- request,
47
- }: Route.LoaderArgs) {
40
+ async function loadCriticalData({context, params, request}: Route.LoaderArgs) {
48
41
  const {handle} = params;
49
42
  const {storefront} = context;
50
43
 
@@ -1,6 +1,4 @@
1
- import {
2
- useLoaderData,
3
- } from 'react-router';
1
+ import {useLoaderData} from 'react-router';
4
2
  import type {Route} from './+types/search';
5
3
  import {getPaginationVariables, Analytics} from '@shopify/hydrogen';
6
4
  import {SearchForm} from '~/components/SearchForm';
@@ -10,7 +8,10 @@ import {
10
8
  type PredictiveSearchReturn,
11
9
  getEmptyPredictiveSearchResult,
12
10
  } from '~/lib/search';
13
- import type {RegularSearchQuery, PredictiveSearchQuery} from 'storefrontapi.generated';
11
+ import type {
12
+ RegularSearchQuery,
13
+ PredictiveSearchQuery,
14
+ } from 'storefrontapi.generated';
14
15
 
15
16
  export const meta: Route.MetaFunction = () => {
16
17
  return [{title: `Hydrogen | Search`}];
@@ -225,9 +226,13 @@ async function regularSearch({
225
226
  const term = String(url.searchParams.get('q') || '');
226
227
 
227
228
  // Search articles, pages, and products for the `q` term
228
- const {errors, ...items}: {errors?: Array<{message: string}>} & RegularSearchQuery = await storefront.query(SEARCH_QUERY, {
229
- variables: {...variables, term},
230
- });
229
+ const {
230
+ errors,
231
+ ...items
232
+ }: {errors?: Array<{message: string}>} & RegularSearchQuery =
233
+ await storefront.query(SEARCH_QUERY, {
234
+ variables: {...variables, term},
235
+ });
231
236
 
232
237
  if (!items) {
233
238
  throw new Error('No search data returned from Shopify API');
@@ -389,17 +394,18 @@ async function predictiveSearch({
389
394
  if (!term) return {type, term, result: getEmptyPredictiveSearchResult()};
390
395
 
391
396
  // Predictively search articles, collections, pages, products, and queries (suggestions)
392
- const {predictiveSearch: items, errors}: PredictiveSearchQuery & {errors?: Array<{message: string}>} = await storefront.query(
393
- PREDICTIVE_SEARCH_QUERY,
394
- {
397
+ const {
398
+ predictiveSearch: items,
399
+ errors,
400
+ }: PredictiveSearchQuery & {errors?: Array<{message: string}>} =
401
+ await storefront.query(PREDICTIVE_SEARCH_QUERY, {
395
402
  variables: {
396
403
  // customize search options as needed
397
404
  limit,
398
405
  limitScope: 'EACH',
399
406
  term,
400
407
  },
401
- },
402
- );
408
+ });
403
409
 
404
410
  if (errors) {
405
411
  throw new Error(
@@ -22,6 +22,57 @@ img {
22
22
  cursor: pointer;
23
23
  }
24
24
 
25
+ /*
26
+ * --------------------------------------------------
27
+ * components/MockShopNotice
28
+ * --------------------------------------------------
29
+ */
30
+ .mock-shop-notice {
31
+ background: var(--color-light);
32
+ border: 1px solid var(--color-dark);
33
+ border-left-width: 0.5rem;
34
+ margin: 1rem 0;
35
+ padding: 0;
36
+
37
+ .inner {
38
+ padding: 0.875rem 1rem;
39
+ }
40
+
41
+ h2 {
42
+ font-size: 1.6rem;
43
+ font-weight: 700;
44
+ line-height: 1.4;
45
+ }
46
+
47
+ p {
48
+ font-size: 1rem;
49
+ line-height: 1.4;
50
+ margin-bottom: 0.5rem;
51
+ }
52
+
53
+ footer {
54
+ background: rgba(0, 0, 0, 0.06);
55
+ padding: 0.5rem 1rem;
56
+ }
57
+
58
+ .small {
59
+ font-size: 0.875rem;
60
+ line-height: 1.4;
61
+ margin-bottom: 0.5rem;
62
+ }
63
+
64
+ code {
65
+ background: rgba(0, 0, 0, 0.06);
66
+ border-radius: 0.25rem;
67
+ padding: 0.1em 0.3em;
68
+ }
69
+
70
+ a {
71
+ text-decoration: underline;
72
+ text-underline-offset: 6px;
73
+ }
74
+ }
75
+
25
76
  /*
26
77
  * --------------------------------------------------
27
78
  * components/Aside
@@ -90,6 +141,18 @@ aside li {
90
141
  margin-bottom: 0.125rem;
91
142
  }
92
143
 
144
+ .sr-only {
145
+ position: absolute;
146
+ width: 1px;
147
+ height: 1px;
148
+ padding: 0;
149
+ margin: -1px;
150
+ overflow: hidden;
151
+ clip-path: inset(50%);
152
+ white-space: nowrap;
153
+ border-width: 0;
154
+ }
155
+
93
156
  .overlay {
94
157
  background: rgba(0, 0, 0, 0.2);
95
158
  bottom: 0;
@@ -250,10 +313,13 @@ button.reset:hover:not(:has(> *)) {
250
313
  }
251
314
 
252
315
  .cart-line {
253
- display: flex;
254
316
  padding: 0.75rem 0;
255
317
  }
256
318
 
319
+ .cart-line-inner {
320
+ display: flex;
321
+ }
322
+
257
323
  .cart-line img {
258
324
  height: 100%;
259
325
  display: block;
@@ -277,6 +343,11 @@ button.reset:hover:not(:has(> *)) {
277
343
  display: flex;
278
344
  }
279
345
 
346
+ /* Child line components (warranties, gift wrapping, etc.) */
347
+ .cart-line-children {
348
+ padding-left: 2rem;
349
+ }
350
+
280
351
  .cart-discount {
281
352
  align-items: center;
282
353
  display: flex;
@@ -211,6 +211,7 @@ export default [
211
211
  '@typescript-eslint/no-floating-promises': 'error',
212
212
  '@typescript-eslint/no-misused-promises': 'error',
213
213
  'react/prop-types': 'off',
214
+ 'import/no-unresolved': ['error', {ignore: ['^virtual:']}],
214
215
  },
215
216
  },
216
217
  {
@@ -15,7 +15,7 @@ This integration uses the storefront API (SFAPI) [predictiveSearch](https://shop
15
15
 
16
16
  | File | Description |
17
17
  | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
18
- | [`app/components/SearchFormPredictive.tsx`](../../app/components/SearchFormPredictive.tsx) | A fully customizable form component configured to make form `GET` requests to the `/search` route. |
18
+ | [`app/components/SearchFormPredictive.tsx`](../../app/components/SearchFormPredictive.tsx) | A fully customizable form component configured to make form `GET` requests to the `/search` route. |
19
19
  | [`app/components/SearchResultsPredictive.tsx`](../../app/components/SearchResultsPredictive.tsx) | A fully customizable search results wrapper, that provides compound components to render `articles`, `pages`, `products`, `collections` and `queries`. |
20
20
 
21
21
  ## Instructions
@@ -217,10 +217,10 @@ export async function loader({request, context}: LoaderFunctionArgs) {
217
217
  const isPredictive = url.searchParams.has('predictive');
218
218
 
219
219
  if (!isPredictive) {
220
- return {}
220
+ return {};
221
221
  }
222
222
 
223
- const searchPromise = predictiveSearch({request, context})
223
+ const searchPromise = predictiveSearch({request, context});
224
224
 
225
225
  searchPromise.catch((error: Error) => {
226
226
  console.error(error);
@@ -212,7 +212,7 @@ export async function loader({request, context}: LoaderFunctionArgs) {
212
212
  const isRegular = !url.searchParams.has('predictive');
213
213
 
214
214
  if (!isRegular) {
215
- return {}
215
+ return {};
216
216
  }
217
217
 
218
218
  const searchPromise = regularSearch({request, context});
@@ -2,7 +2,7 @@
2
2
  "name": "skeleton",
3
3
  "private": true,
4
4
  "sideEffects": false,
5
- "version": "2025.7.0",
5
+ "version": "2026.1.1",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "build": "shopify hydrogen build --codegen",
@@ -14,31 +14,31 @@
14
14
  },
15
15
  "prettier": "@shopify/prettier-config",
16
16
  "dependencies": {
17
- "@shopify/hydrogen": "2025.7.0",
17
+ "@shopify/hydrogen": "*2026.1.1",
18
18
  "graphql": "^16.10.0",
19
19
  "graphql-tag": "^2.12.6",
20
20
  "isbot": "^5.1.22",
21
- "react": "18.3.1",
22
- "react-dom": "18.3.1",
23
- "react-router": "7.9.2",
24
- "react-router-dom": "7.9.2"
21
+ "react": "^18.3.1",
22
+ "react-dom": "^18.3.1",
23
+ "react-router": "7.12.0",
24
+ "react-router-dom": "7.12.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@eslint/compat": "^1.2.5",
28
28
  "@eslint/eslintrc": "^3.2.0",
29
29
  "@eslint/js": "^9.18.0",
30
30
  "@graphql-codegen/cli": "5.0.2",
31
- "@react-router/dev": "7.9.2",
32
- "@react-router/fs-routes": "7.9.2",
31
+ "@react-router/dev": "7.12.0",
32
+ "@react-router/fs-routes": "7.12.0",
33
33
  "@shopify/cli": "3.85.4",
34
- "@shopify/hydrogen-codegen": "^0.3.3",
35
- "@shopify/mini-oxygen": "^4.0.0",
34
+ "@shopify/hydrogen-codegen": "0.3.3",
35
+ "@shopify/mini-oxygen": "4.0.1",
36
36
  "@shopify/oxygen-workers-types": "^4.1.6",
37
37
  "@shopify/prettier-config": "^1.1.2",
38
38
  "@total-typescript/ts-reset": "^0.6.1",
39
39
  "@types/eslint": "^9.6.1",
40
- "@types/react": "^18.2.22",
41
- "@types/react-dom": "^18.2.7",
40
+ "@types/react": "^18.3.28",
41
+ "@types/react-dom": "^18.3.7",
42
42
  "@typescript-eslint/eslint-plugin": "^8.21.0",
43
43
  "@typescript-eslint/parser": "^8.21.0",
44
44
  "eslint": "^9.18.0",
@@ -51,12 +51,13 @@
51
51
  "eslint-plugin-react": "^7.37.4",
52
52
  "eslint-plugin-react-hooks": "^5.1.0",
53
53
  "globals": "^15.14.0",
54
+ "graphql-config": "^5.0.3",
54
55
  "prettier": "^3.4.2",
55
56
  "typescript": "^5.9.2",
56
57
  "vite": "^6.2.4",
57
58
  "vite-tsconfig-paths": "^4.3.1"
58
59
  },
59
60
  "engines": {
60
- "node": ">=18.0.0"
61
+ "node": "^22 || ^24"
61
62
  }
62
63
  }
@@ -1,6 +1,5 @@
1
- // Virtual entry point for the app
2
- import {storefrontRedirect} from '@shopify/hydrogen';
3
- import {createRequestHandler} from '@shopify/hydrogen/oxygen';
1
+ import * as serverBuild from 'virtual:react-router/server-build';
2
+ import {createRequestHandler, storefrontRedirect} from '@shopify/hydrogen';
4
3
  import {createHydrogenRouterContext} from '~/lib/context';
5
4
 
6
5
  /**
@@ -20,12 +19,11 @@ export default {
20
19
  );
21
20
 
22
21
  /**
23
- * Create a Remix request handler and pass
24
- * Hydrogen's Storefront client to the loader context.
22
+ * Create a Hydrogen request handler that internally
23
+ * delegates to React Router for routing and rendering.
25
24
  */
26
25
  const handleRequest = createRequestHandler({
27
- // eslint-disable-next-line import/no-unresolved
28
- build: await import('virtual:react-router/server-build'),
26
+ build: serverBuild,
29
27
  mode: process.env.NODE_ENV,
30
28
  getLoadContext: () => hydrogenContext,
31
29
  });
@@ -36,6 +36,9 @@ export type CartLineFragment = Pick<
36
36
  Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
37
37
  >;
38
38
  };
39
+ parentRelationship?: StorefrontAPI.Maybe<{
40
+ parent: Pick<StorefrontAPI.CartLine, 'id'>;
41
+ }>;
39
42
  };
40
43
 
41
44
  export type CartLineComponentFragment = Pick<
@@ -66,6 +69,46 @@ export type CartLineComponentFragment = Pick<
66
69
  Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
67
70
  >;
68
71
  };
72
+ lineComponents: Array<
73
+ Pick<StorefrontAPI.CartLine, 'id' | 'quantity'> & {
74
+ attributes: Array<Pick<StorefrontAPI.Attribute, 'key' | 'value'>>;
75
+ cost: {
76
+ totalAmount: Pick<StorefrontAPI.MoneyV2, 'currencyCode' | 'amount'>;
77
+ amountPerQuantity: Pick<
78
+ StorefrontAPI.MoneyV2,
79
+ 'currencyCode' | 'amount'
80
+ >;
81
+ compareAtAmountPerQuantity?: StorefrontAPI.Maybe<
82
+ Pick<StorefrontAPI.MoneyV2, 'currencyCode' | 'amount'>
83
+ >;
84
+ };
85
+ merchandise: Pick<
86
+ StorefrontAPI.ProductVariant,
87
+ 'id' | 'availableForSale' | 'requiresShipping' | 'title'
88
+ > & {
89
+ compareAtPrice?: StorefrontAPI.Maybe<
90
+ Pick<StorefrontAPI.MoneyV2, 'currencyCode' | 'amount'>
91
+ >;
92
+ price: Pick<StorefrontAPI.MoneyV2, 'currencyCode' | 'amount'>;
93
+ image?: StorefrontAPI.Maybe<
94
+ Pick<
95
+ StorefrontAPI.Image,
96
+ 'id' | 'url' | 'altText' | 'width' | 'height'
97
+ >
98
+ >;
99
+ product: Pick<
100
+ StorefrontAPI.Product,
101
+ 'handle' | 'title' | 'id' | 'vendor'
102
+ >;
103
+ selectedOptions: Array<
104
+ Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
105
+ >;
106
+ };
107
+ parentRelationship?: StorefrontAPI.Maybe<{
108
+ parent: Pick<StorefrontAPI.CartLine, 'id'>;
109
+ }>;
110
+ }
111
+ >;
69
112
  };
70
113
 
71
114
  export type CartApiQueryFragment = Pick<
@@ -124,6 +167,9 @@ export type CartApiQueryFragment = Pick<
124
167
  Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
125
168
  >;
126
169
  };
170
+ parentRelationship?: StorefrontAPI.Maybe<{
171
+ parent: Pick<StorefrontAPI.CartLine, 'id'>;
172
+ }>;
127
173
  })
128
174
  | (Pick<StorefrontAPI.ComponentizableCartLine, 'id' | 'quantity'> & {
129
175
  attributes: Array<Pick<StorefrontAPI.Attribute, 'key' | 'value'>>;
@@ -159,6 +205,49 @@ export type CartApiQueryFragment = Pick<
159
205
  Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
160
206
  >;
161
207
  };
208
+ lineComponents: Array<
209
+ Pick<StorefrontAPI.CartLine, 'id' | 'quantity'> & {
210
+ attributes: Array<Pick<StorefrontAPI.Attribute, 'key' | 'value'>>;
211
+ cost: {
212
+ totalAmount: Pick<
213
+ StorefrontAPI.MoneyV2,
214
+ 'currencyCode' | 'amount'
215
+ >;
216
+ amountPerQuantity: Pick<
217
+ StorefrontAPI.MoneyV2,
218
+ 'currencyCode' | 'amount'
219
+ >;
220
+ compareAtAmountPerQuantity?: StorefrontAPI.Maybe<
221
+ Pick<StorefrontAPI.MoneyV2, 'currencyCode' | 'amount'>
222
+ >;
223
+ };
224
+ merchandise: Pick<
225
+ StorefrontAPI.ProductVariant,
226
+ 'id' | 'availableForSale' | 'requiresShipping' | 'title'
227
+ > & {
228
+ compareAtPrice?: StorefrontAPI.Maybe<
229
+ Pick<StorefrontAPI.MoneyV2, 'currencyCode' | 'amount'>
230
+ >;
231
+ price: Pick<StorefrontAPI.MoneyV2, 'currencyCode' | 'amount'>;
232
+ image?: StorefrontAPI.Maybe<
233
+ Pick<
234
+ StorefrontAPI.Image,
235
+ 'id' | 'url' | 'altText' | 'width' | 'height'
236
+ >
237
+ >;
238
+ product: Pick<
239
+ StorefrontAPI.Product,
240
+ 'handle' | 'title' | 'id' | 'vendor'
241
+ >;
242
+ selectedOptions: Array<
243
+ Pick<StorefrontAPI.SelectedOption, 'name' | 'value'>
244
+ >;
245
+ };
246
+ parentRelationship?: StorefrontAPI.Maybe<{
247
+ parent: Pick<StorefrontAPI.CartLine, 'id'>;
248
+ }>;
249
+ }
250
+ >;
162
251
  })
163
252
  >;
164
253
  };