@shopify/cli-hydrogen 3.26.0 → 4.0.0-alpha.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 (249) hide show
  1. package/dist/commands/hydrogen/build.js +89 -0
  2. package/dist/commands/hydrogen/dev.js +116 -0
  3. package/dist/commands/hydrogen/init.js +42 -0
  4. package/dist/commands/hydrogen/preview.js +34 -0
  5. package/dist/hooks/init.js +21 -0
  6. package/dist/templates/demo-store/.editorconfig +8 -0
  7. package/dist/templates/demo-store/.eslintignore +4 -0
  8. package/dist/templates/demo-store/.eslintrc.js +16 -0
  9. package/dist/templates/demo-store/.graphqlrc.yml +1 -0
  10. package/dist/templates/demo-store/.prettierignore +2 -0
  11. package/dist/templates/demo-store/.turbo/turbo-build.log +13 -0
  12. package/dist/templates/demo-store/app/components/AccountAddressBook.tsx +97 -0
  13. package/dist/templates/demo-store/app/components/AccountDetails.tsx +41 -0
  14. package/dist/templates/demo-store/app/components/AddToCartButton.tsx +42 -0
  15. package/dist/templates/demo-store/app/components/Breadcrumbs.tsx +36 -0
  16. package/dist/templates/demo-store/app/components/Button.tsx +56 -0
  17. package/dist/templates/demo-store/app/components/Cart.tsx +431 -0
  18. package/dist/templates/demo-store/app/components/CartLoading.tsx +50 -0
  19. package/dist/templates/demo-store/app/components/CountrySelector.tsx +180 -0
  20. package/dist/templates/demo-store/app/components/Drawer.tsx +115 -0
  21. package/dist/templates/demo-store/app/components/FeaturedCollections.tsx +54 -0
  22. package/dist/templates/demo-store/app/components/FeaturedProducts.tsx +116 -0
  23. package/dist/templates/demo-store/app/components/FeaturedSection.tsx +39 -0
  24. package/dist/templates/demo-store/app/components/GenericError.tsx +58 -0
  25. package/dist/templates/demo-store/app/components/Grid.tsx +44 -0
  26. package/dist/templates/demo-store/app/components/Hero.tsx +136 -0
  27. package/dist/templates/demo-store/app/components/Icon.tsx +253 -0
  28. package/dist/templates/demo-store/app/components/Input.tsx +24 -0
  29. package/dist/templates/demo-store/app/components/Layout.tsx +492 -0
  30. package/dist/templates/demo-store/app/components/Link.tsx +46 -0
  31. package/dist/templates/demo-store/app/components/Modal.tsx +46 -0
  32. package/dist/templates/demo-store/app/components/NotFound.tsx +22 -0
  33. package/dist/templates/demo-store/app/components/OrderCard.tsx +85 -0
  34. package/dist/templates/demo-store/app/components/Pagination.tsx +277 -0
  35. package/dist/templates/demo-store/app/components/ProductCard.tsx +146 -0
  36. package/dist/templates/demo-store/app/components/ProductGallery.tsx +114 -0
  37. package/dist/templates/demo-store/app/components/ProductGrid.tsx +93 -0
  38. package/dist/templates/demo-store/app/components/ProductSwimlane.tsx +30 -0
  39. package/dist/templates/demo-store/app/components/Skeleton.tsx +24 -0
  40. package/dist/templates/demo-store/app/components/SortFilter.tsx +411 -0
  41. package/dist/templates/demo-store/app/components/Text.tsx +192 -0
  42. package/dist/templates/demo-store/app/components/index.ts +28 -0
  43. package/dist/templates/demo-store/app/data/countries.ts +194 -0
  44. package/dist/templates/demo-store/app/data/index.ts +1037 -0
  45. package/dist/templates/demo-store/app/entry.client.tsx +4 -0
  46. package/dist/templates/demo-store/app/entry.server.tsx +26 -0
  47. package/dist/templates/demo-store/app/hooks/useCartFetchers.tsx +14 -0
  48. package/dist/templates/demo-store/app/hooks/useIsHydrated.tsx +12 -0
  49. package/dist/templates/demo-store/app/lib/const.ts +10 -0
  50. package/dist/templates/demo-store/app/lib/placeholders.ts +242 -0
  51. package/dist/templates/demo-store/app/lib/seo/common.tsx +324 -0
  52. package/dist/templates/demo-store/app/lib/seo/debugger.tsx +175 -0
  53. package/dist/templates/demo-store/app/lib/seo/image.tsx +32 -0
  54. package/dist/templates/demo-store/app/lib/seo/index.ts +4 -0
  55. package/dist/templates/demo-store/app/lib/seo/seo.tsx +24 -0
  56. package/dist/templates/demo-store/app/lib/seo/types.ts +70 -0
  57. package/dist/templates/demo-store/app/lib/session.server.ts +57 -0
  58. package/dist/templates/demo-store/app/lib/type.ts +21 -0
  59. package/dist/templates/demo-store/app/lib/utils.ts +310 -0
  60. package/dist/templates/demo-store/app/root.tsx +282 -0
  61. package/dist/templates/demo-store/app/routes/$.tsx +7 -0
  62. package/dist/templates/demo-store/app/routes/$lang/$.tsx +1 -0
  63. package/dist/templates/demo-store/app/routes/$lang/[robots.txt].tsx +1 -0
  64. package/dist/templates/demo-store/app/routes/$lang/[sitemap.xml].tsx +1 -0
  65. package/dist/templates/demo-store/app/routes/$lang/account/__private/address/$id.tsx +1 -0
  66. package/dist/templates/demo-store/app/routes/$lang/account/__private/edit.tsx +1 -0
  67. package/dist/templates/demo-store/app/routes/$lang/account/__private/logout.ts +1 -0
  68. package/dist/templates/demo-store/app/routes/$lang/account/__private/orders.$id.tsx +1 -0
  69. package/dist/templates/demo-store/app/routes/$lang/account/__public/activate.$id.$activationToken.tsx +6 -0
  70. package/dist/templates/demo-store/app/routes/$lang/account/__public/login.tsx +7 -0
  71. package/dist/templates/demo-store/app/routes/$lang/account/__public/recover.tsx +1 -0
  72. package/dist/templates/demo-store/app/routes/$lang/account/__public/register.tsx +6 -0
  73. package/dist/templates/demo-store/app/routes/$lang/account/__public/reset.$id.$resetToken.tsx +5 -0
  74. package/dist/templates/demo-store/app/routes/$lang/account.tsx +1 -0
  75. package/dist/templates/demo-store/app/routes/$lang/api/countries.tsx +1 -0
  76. package/dist/templates/demo-store/app/routes/$lang/api/products.tsx +1 -0
  77. package/dist/templates/demo-store/app/routes/$lang/cart.tsx +1 -0
  78. package/dist/templates/demo-store/app/routes/$lang/collections/$collectionHandle.tsx +6 -0
  79. package/dist/templates/demo-store/app/routes/$lang/collections/all.tsx +1 -0
  80. package/dist/templates/demo-store/app/routes/$lang/collections/index.tsx +1 -0
  81. package/dist/templates/demo-store/app/routes/$lang/featured-products.tsx +1 -0
  82. package/dist/templates/demo-store/app/routes/$lang/index.tsx +7 -0
  83. package/dist/templates/demo-store/app/routes/$lang/journal/$journalHandle.tsx +7 -0
  84. package/dist/templates/demo-store/app/routes/$lang/journal/index.tsx +1 -0
  85. package/dist/templates/demo-store/app/routes/$lang/og-image.tsx +1 -0
  86. package/dist/templates/demo-store/app/routes/$lang/pages/$pageHandle.tsx +1 -0
  87. package/dist/templates/demo-store/app/routes/$lang/policies/$policyHandle.tsx +1 -0
  88. package/dist/templates/demo-store/app/routes/$lang/policies/index.tsx +1 -0
  89. package/dist/templates/demo-store/app/routes/$lang/products/$productHandle.tsx +6 -0
  90. package/dist/templates/demo-store/app/routes/$lang/products/index.tsx +1 -0
  91. package/dist/templates/demo-store/app/routes/$lang/search.tsx +6 -0
  92. package/dist/templates/demo-store/app/routes/[robots.txt].tsx +40 -0
  93. package/dist/templates/demo-store/app/routes/[sitemap.xml].tsx +198 -0
  94. package/dist/templates/demo-store/app/routes/account/__private/address/$id.tsx +320 -0
  95. package/dist/templates/demo-store/app/routes/account/__private/edit.tsx +273 -0
  96. package/dist/templates/demo-store/app/routes/account/__private/logout.ts +29 -0
  97. package/dist/templates/demo-store/app/routes/account/__private/orders.$id.tsx +324 -0
  98. package/dist/templates/demo-store/app/routes/account/__public/activate.$id.$activationToken.tsx +218 -0
  99. package/dist/templates/demo-store/app/routes/account/__public/login.tsx +197 -0
  100. package/dist/templates/demo-store/app/routes/account/__public/recover.tsx +144 -0
  101. package/dist/templates/demo-store/app/routes/account/__public/register.tsx +184 -0
  102. package/dist/templates/demo-store/app/routes/account/__public/reset.$id.$resetToken.tsx +214 -0
  103. package/dist/templates/demo-store/app/routes/account.tsx +191 -0
  104. package/dist/templates/demo-store/app/routes/api/countries.tsx +22 -0
  105. package/dist/templates/demo-store/app/routes/api/products.tsx +116 -0
  106. package/dist/templates/demo-store/app/routes/cart.tsx +498 -0
  107. package/dist/templates/demo-store/app/routes/collections/$collectionHandle.tsx +308 -0
  108. package/dist/templates/demo-store/app/routes/collections/all.tsx +5 -0
  109. package/dist/templates/demo-store/app/routes/collections/index.tsx +195 -0
  110. package/dist/templates/demo-store/app/routes/discounts.$code.tsx +60 -0
  111. package/dist/templates/demo-store/app/routes/featured-products.tsx +58 -0
  112. package/dist/templates/demo-store/app/routes/index.tsx +254 -0
  113. package/dist/templates/demo-store/app/routes/journal/$journalHandle.tsx +147 -0
  114. package/dist/templates/demo-store/app/routes/journal/index.tsx +150 -0
  115. package/dist/templates/demo-store/app/routes/og-image.tsx +19 -0
  116. package/dist/templates/demo-store/app/routes/pages/$pageHandle.tsx +82 -0
  117. package/dist/templates/demo-store/app/routes/policies/$policyHandle.tsx +117 -0
  118. package/dist/templates/demo-store/app/routes/policies/index.tsx +104 -0
  119. package/dist/templates/demo-store/app/routes/products/$productHandle.tsx +561 -0
  120. package/dist/templates/demo-store/app/routes/products/index.tsx +155 -0
  121. package/dist/templates/demo-store/app/routes/search.tsx +205 -0
  122. package/dist/templates/demo-store/app/styles/custom-font.css +13 -0
  123. package/dist/templates/demo-store/package-lock.json +25515 -0
  124. package/dist/templates/demo-store/package.json +67 -0
  125. package/dist/templates/demo-store/playwright.config.ts +109 -0
  126. package/dist/templates/demo-store/postcss.config.js +10 -0
  127. package/dist/templates/demo-store/public/favicon.svg +28 -0
  128. package/dist/templates/demo-store/public/fonts/IBMPlexSerif-Text.woff2 +0 -0
  129. package/dist/templates/demo-store/public/fonts/IBMPlexSerif-TextItalic.woff2 +0 -0
  130. package/dist/templates/demo-store/remix.config.js +12 -0
  131. package/dist/templates/demo-store/remix.env.d.ts +34 -0
  132. package/dist/templates/demo-store/remix.init/index.ts +15 -0
  133. package/dist/templates/demo-store/remix.init/package.json +7 -0
  134. package/dist/templates/demo-store/server.ts +87 -0
  135. package/dist/templates/demo-store/styles/app.css +182 -0
  136. package/dist/templates/demo-store/tailwind.config.js +70 -0
  137. package/dist/templates/demo-store/tests/cart.test.ts +70 -0
  138. package/dist/templates/demo-store/tests/seo.test.ts +36 -0
  139. package/dist/templates/demo-store/tests/utils.ts +100 -0
  140. package/dist/templates/demo-store/tsconfig.json +26 -0
  141. package/dist/templates/hello-world/.eslintignore +4 -0
  142. package/dist/templates/hello-world/.eslintrc.js +6 -0
  143. package/dist/templates/hello-world/.graphqlrc.yml +1 -0
  144. package/dist/templates/hello-world/.turbo/turbo-build.log +9 -0
  145. package/dist/templates/hello-world/README.md +20 -0
  146. package/dist/templates/hello-world/app/components/Layout.tsx +15 -0
  147. package/dist/templates/hello-world/app/components/index.ts +1 -0
  148. package/dist/templates/hello-world/app/entry.client.tsx +4 -0
  149. package/dist/templates/hello-world/app/entry.server.tsx +21 -0
  150. package/dist/templates/hello-world/app/root.tsx +212 -0
  151. package/dist/templates/hello-world/app/routes/index.tsx +7 -0
  152. package/dist/templates/hello-world/app/styles/app.css +38 -0
  153. package/dist/templates/hello-world/package-lock.json +27641 -0
  154. package/dist/templates/hello-world/package.json +41 -0
  155. package/dist/templates/hello-world/public/favicon.svg +28 -0
  156. package/dist/templates/hello-world/remix.env.d.ts +29 -0
  157. package/dist/templates/hello-world/server.ts +127 -0
  158. package/dist/templates/hello-world/tsconfig.json +25 -0
  159. package/dist/utils/config.js +81 -0
  160. package/dist/utils/flags.js +15 -0
  161. package/dist/utils/log.js +20 -0
  162. package/dist/utils/mini-oxygen.js +70 -0
  163. package/package.json +27 -64
  164. package/tmp-create-app.mjs +29 -0
  165. package/LICENSE +0 -8
  166. package/README.md +0 -61
  167. package/dist/cli/commands/hydrogen/add/eslint.d.ts +0 -11
  168. package/dist/cli/commands/hydrogen/add/eslint.js +0 -26
  169. package/dist/cli/commands/hydrogen/add/eslint.js.map +0 -1
  170. package/dist/cli/commands/hydrogen/add/tailwind.d.ts +0 -11
  171. package/dist/cli/commands/hydrogen/add/tailwind.js +0 -26
  172. package/dist/cli/commands/hydrogen/add/tailwind.js.map +0 -1
  173. package/dist/cli/commands/hydrogen/build.d.ts +0 -14
  174. package/dist/cli/commands/hydrogen/build.js +0 -49
  175. package/dist/cli/commands/hydrogen/build.js.map +0 -1
  176. package/dist/cli/commands/hydrogen/deploy.d.ts +0 -19
  177. package/dist/cli/commands/hydrogen/deploy.js +0 -58
  178. package/dist/cli/commands/hydrogen/deploy.js.map +0 -1
  179. package/dist/cli/commands/hydrogen/dev.d.ts +0 -13
  180. package/dist/cli/commands/hydrogen/dev.js +0 -31
  181. package/dist/cli/commands/hydrogen/dev.js.map +0 -1
  182. package/dist/cli/commands/hydrogen/info.d.ts +0 -12
  183. package/dist/cli/commands/hydrogen/info.js +0 -28
  184. package/dist/cli/commands/hydrogen/info.js.map +0 -1
  185. package/dist/cli/commands/hydrogen/preview.d.ts +0 -13
  186. package/dist/cli/commands/hydrogen/preview.js +0 -46
  187. package/dist/cli/commands/hydrogen/preview.js.map +0 -1
  188. package/dist/cli/constants.d.ts +0 -15
  189. package/dist/cli/constants.js +0 -16
  190. package/dist/cli/constants.js.map +0 -1
  191. package/dist/cli/flags.d.ts +0 -4
  192. package/dist/cli/flags.js +0 -16
  193. package/dist/cli/flags.js.map +0 -1
  194. package/dist/cli/models/hydrogen.d.ts +0 -22
  195. package/dist/cli/models/hydrogen.js +0 -82
  196. package/dist/cli/models/hydrogen.js.map +0 -1
  197. package/dist/cli/prompts/git-init.d.ts +0 -1
  198. package/dist/cli/prompts/git-init.js +0 -16
  199. package/dist/cli/prompts/git-init.js.map +0 -1
  200. package/dist/cli/services/build/check-lockfile.d.ts +0 -3
  201. package/dist/cli/services/build/check-lockfile.js +0 -80
  202. package/dist/cli/services/build/check-lockfile.js.map +0 -1
  203. package/dist/cli/services/build.d.ts +0 -14
  204. package/dist/cli/services/build.js +0 -44
  205. package/dist/cli/services/build.js.map +0 -1
  206. package/dist/cli/services/deploy/config.d.ts +0 -4
  207. package/dist/cli/services/deploy/config.js +0 -49
  208. package/dist/cli/services/deploy/config.js.map +0 -1
  209. package/dist/cli/services/deploy/error.d.ts +0 -4
  210. package/dist/cli/services/deploy/error.js +0 -11
  211. package/dist/cli/services/deploy/error.js.map +0 -1
  212. package/dist/cli/services/deploy/graphql/create_deployment.d.ts +0 -10
  213. package/dist/cli/services/deploy/graphql/create_deployment.js +0 -15
  214. package/dist/cli/services/deploy/graphql/create_deployment.js.map +0 -1
  215. package/dist/cli/services/deploy/graphql/upload_deployment.d.ts +0 -1
  216. package/dist/cli/services/deploy/graphql/upload_deployment.js +0 -16
  217. package/dist/cli/services/deploy/graphql/upload_deployment.js.map +0 -1
  218. package/dist/cli/services/deploy/types.d.ts +0 -37
  219. package/dist/cli/services/deploy/types.js +0 -2
  220. package/dist/cli/services/deploy/types.js.map +0 -1
  221. package/dist/cli/services/deploy/upload.d.ts +0 -5
  222. package/dist/cli/services/deploy/upload.js +0 -81
  223. package/dist/cli/services/deploy/upload.js.map +0 -1
  224. package/dist/cli/services/deploy.d.ts +0 -2
  225. package/dist/cli/services/deploy.js +0 -103
  226. package/dist/cli/services/deploy.js.map +0 -1
  227. package/dist/cli/services/dev/check-version.d.ts +0 -1
  228. package/dist/cli/services/dev/check-version.js +0 -30
  229. package/dist/cli/services/dev/check-version.js.map +0 -1
  230. package/dist/cli/services/dev.d.ts +0 -10
  231. package/dist/cli/services/dev.js +0 -36
  232. package/dist/cli/services/dev.js.map +0 -1
  233. package/dist/cli/services/eslint.d.ts +0 -8
  234. package/dist/cli/services/eslint.js +0 -74
  235. package/dist/cli/services/eslint.js.map +0 -1
  236. package/dist/cli/services/info.d.ts +0 -7
  237. package/dist/cli/services/info.js +0 -131
  238. package/dist/cli/services/info.js.map +0 -1
  239. package/dist/cli/services/preview.d.ts +0 -12
  240. package/dist/cli/services/preview.js +0 -63
  241. package/dist/cli/services/preview.js.map +0 -1
  242. package/dist/cli/services/tailwind.d.ts +0 -9
  243. package/dist/cli/services/tailwind.js +0 -103
  244. package/dist/cli/services/tailwind.js.map +0 -1
  245. package/dist/cli/utilities/load-config.d.ts +0 -5
  246. package/dist/cli/utilities/load-config.js +0 -6
  247. package/dist/cli/utilities/load-config.js.map +0 -1
  248. package/dist/tsconfig.tsbuildinfo +0 -1
  249. package/oclif.manifest.json +0 -1
@@ -0,0 +1,1037 @@
1
+ import type {
2
+ Cart,
3
+ Shop,
4
+ Order,
5
+ CustomerAccessTokenCreatePayload,
6
+ Customer,
7
+ CustomerUpdateInput,
8
+ CustomerUpdatePayload,
9
+ CustomerAddressUpdatePayload,
10
+ MailingAddressInput,
11
+ CustomerAddressDeletePayload,
12
+ CustomerDefaultAddressUpdatePayload,
13
+ CustomerAddressCreatePayload,
14
+ CustomerCreatePayload,
15
+ CustomerRecoverPayload,
16
+ CustomerResetPayload,
17
+ CustomerActivatePayload,
18
+ } from '@shopify/hydrogen-react/storefront-api-types';
19
+ import {type EnhancedMenu, parseMenu, assertApiErrors} from '~/lib/utils';
20
+ import invariant from 'tiny-invariant';
21
+ import {logout} from '~/routes/account/__private/logout';
22
+ import type {AppLoadContext} from '@shopify/remix-oxygen';
23
+
24
+ export interface LayoutData {
25
+ headerMenu: EnhancedMenu;
26
+ footerMenu: EnhancedMenu;
27
+ shop: Shop;
28
+ cart?: Promise<Cart>;
29
+ }
30
+
31
+ export async function getLayoutData({storefront}: AppLoadContext) {
32
+ const HEADER_MENU_HANDLE = 'main-menu';
33
+ const FOOTER_MENU_HANDLE = 'footer';
34
+
35
+ const data = await storefront.query<LayoutData>(LAYOUT_QUERY, {
36
+ variables: {
37
+ headerMenuHandle: HEADER_MENU_HANDLE,
38
+ footerMenuHandle: FOOTER_MENU_HANDLE,
39
+ language: storefront.i18n?.language,
40
+ },
41
+ });
42
+
43
+ invariant(data, 'No data returned from Shopify API');
44
+
45
+ /*
46
+ Modify specific links/routes (optional)
47
+ @see: https://shopify.dev/api/storefront/unstable/enums/MenuItemType
48
+ e.g here we map:
49
+ - /blogs/news -> /news
50
+ - /blog/news/blog-post -> /news/blog-post
51
+ - /collections/all -> /products
52
+ */
53
+ const customPrefixes = {BLOG: '', CATALOG: 'products'};
54
+
55
+ const headerMenu = data?.headerMenu
56
+ ? parseMenu(data.headerMenu, customPrefixes)
57
+ : undefined;
58
+
59
+ const footerMenu = data?.footerMenu
60
+ ? parseMenu(data.footerMenu, customPrefixes)
61
+ : undefined;
62
+
63
+ return {shop: data.shop, headerMenu, footerMenu};
64
+ }
65
+
66
+ const LAYOUT_QUERY = `#graphql
67
+ query layoutMenus(
68
+ $language: LanguageCode
69
+ $headerMenuHandle: String!
70
+ $footerMenuHandle: String!
71
+ ) @inContext(language: $language) {
72
+ shop {
73
+ name
74
+ description
75
+ }
76
+ headerMenu: menu(handle: $headerMenuHandle) {
77
+ id
78
+ items {
79
+ ...MenuItem
80
+ items {
81
+ ...MenuItem
82
+ }
83
+ }
84
+ }
85
+ footerMenu: menu(handle: $footerMenuHandle) {
86
+ id
87
+ items {
88
+ ...MenuItem
89
+ items {
90
+ ...MenuItem
91
+ }
92
+ }
93
+ }
94
+ }
95
+ fragment MenuItem on MenuItem {
96
+ id
97
+ resourceId
98
+ tags
99
+ title
100
+ type
101
+ url
102
+ }
103
+ `;
104
+
105
+ export const MEDIA_FRAGMENT = `#graphql
106
+ fragment Media on Media {
107
+ __typename
108
+ mediaContentType
109
+ alt
110
+ previewImage {
111
+ url
112
+ }
113
+ ... on MediaImage {
114
+ id
115
+ image {
116
+ url
117
+ width
118
+ height
119
+ }
120
+ }
121
+ ... on Video {
122
+ id
123
+ sources {
124
+ mimeType
125
+ url
126
+ }
127
+ }
128
+ ... on Model3d {
129
+ id
130
+ sources {
131
+ mimeType
132
+ url
133
+ }
134
+ }
135
+ ... on ExternalVideo {
136
+ id
137
+ embedUrl
138
+ host
139
+ }
140
+ }
141
+ `;
142
+
143
+ export const PRODUCT_CARD_FRAGMENT = `#graphql
144
+ fragment ProductCard on Product {
145
+ id
146
+ title
147
+ publishedAt
148
+ handle
149
+ variants(first: 1) {
150
+ nodes {
151
+ id
152
+ image {
153
+ url
154
+ altText
155
+ width
156
+ height
157
+ }
158
+ price: priceV2 {
159
+ amount
160
+ currencyCode
161
+ }
162
+ compareAtPrice: compareAtPriceV2 {
163
+ amount
164
+ currencyCode
165
+ }
166
+ selectedOptions {
167
+ name
168
+ value
169
+ }
170
+ product {
171
+ handle
172
+ title
173
+ }
174
+ }
175
+ }
176
+ }
177
+ `;
178
+
179
+ export const PRODUCT_VARIANT_FRAGMENT = `#graphql
180
+ fragment ProductVariantFragment on ProductVariant {
181
+ id
182
+ availableForSale
183
+ selectedOptions {
184
+ name
185
+ value
186
+ }
187
+ image {
188
+ id
189
+ url
190
+ altText
191
+ width
192
+ height
193
+ }
194
+ price {
195
+ amount
196
+ currencyCode
197
+ }
198
+ compareAtPrice {
199
+ amount
200
+ currencyCode
201
+ }
202
+ sku
203
+ title
204
+ unitPrice {
205
+ amount
206
+ currencyCode
207
+ }
208
+ product {
209
+ title
210
+ handle
211
+ }
212
+ }
213
+ `;
214
+
215
+ const CART_FRAGMENT = `#graphql
216
+ fragment CartFragment on Cart {
217
+ id
218
+ checkoutUrl
219
+ totalQuantity
220
+ buyerIdentity {
221
+ countryCode
222
+ customer {
223
+ id
224
+ email
225
+ firstName
226
+ lastName
227
+ displayName
228
+ }
229
+ email
230
+ phone
231
+ }
232
+ lines(first: 100, reverse: true) {
233
+ edges {
234
+ node {
235
+ id
236
+ quantity
237
+ attributes {
238
+ key
239
+ value
240
+ }
241
+ cost {
242
+ totalAmount {
243
+ amount
244
+ currencyCode
245
+ }
246
+ compareAtAmountPerQuantity {
247
+ amount
248
+ currencyCode
249
+ }
250
+ }
251
+ merchandise {
252
+ ... on ProductVariant {
253
+ id
254
+ availableForSale
255
+ compareAtPriceV2 {
256
+ ...MoneyFragment
257
+ }
258
+ priceV2 {
259
+ ...MoneyFragment
260
+ }
261
+ requiresShipping
262
+ title
263
+ image {
264
+ ...ImageFragment
265
+ }
266
+ product {
267
+ handle
268
+ title
269
+ id
270
+ }
271
+ selectedOptions {
272
+ name
273
+ value
274
+ }
275
+ }
276
+ }
277
+ }
278
+ }
279
+ }
280
+ cost {
281
+ subtotalAmount {
282
+ ...MoneyFragment
283
+ }
284
+ totalAmount {
285
+ ...MoneyFragment
286
+ }
287
+ totalDutyAmount {
288
+ ...MoneyFragment
289
+ }
290
+ totalTaxAmount {
291
+ ...MoneyFragment
292
+ }
293
+ }
294
+ note
295
+ attributes {
296
+ key
297
+ value
298
+ }
299
+ discountCodes {
300
+ code
301
+ }
302
+ }
303
+
304
+ fragment MoneyFragment on MoneyV2 {
305
+ currencyCode
306
+ amount
307
+ }
308
+ fragment ImageFragment on Image {
309
+ id
310
+ url
311
+ altText
312
+ width
313
+ height
314
+ }
315
+ `;
316
+
317
+ // shop primary domain url for /admin
318
+ export async function getPrimaryShopDomain({storefront}: AppLoadContext) {
319
+ const data = await storefront.query<{shop: Shop}>(SHOP_PRIMARY_DOMAIN_QUERY);
320
+
321
+ invariant(data?.shop?.primaryDomain, 'Primary domain not found');
322
+
323
+ return data.shop;
324
+ }
325
+
326
+ const SHOP_PRIMARY_DOMAIN_QUERY = `#graphql
327
+ query {
328
+ shop {
329
+ primaryDomain {
330
+ url
331
+ }
332
+ }
333
+ }
334
+ `;
335
+
336
+ export const COLLECTION_CONTENT_FRAGMENT = `#graphql
337
+ ${MEDIA_FRAGMENT}
338
+ fragment CollectionContent on Collection {
339
+ id
340
+ handle
341
+ title
342
+ descriptionHtml
343
+ heading: metafield(namespace: "hero", key: "title") {
344
+ value
345
+ }
346
+ byline: metafield(namespace: "hero", key: "byline") {
347
+ value
348
+ }
349
+ cta: metafield(namespace: "hero", key: "cta") {
350
+ value
351
+ }
352
+ spread: metafield(namespace: "hero", key: "spread") {
353
+ reference {
354
+ ...Media
355
+ }
356
+ }
357
+ spreadSecondary: metafield(namespace: "hero", key: "spread_secondary") {
358
+ reference {
359
+ ...Media
360
+ }
361
+ }
362
+ }
363
+ `;
364
+
365
+ /*
366
+ Account ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
367
+ */
368
+
369
+ const LOGIN_MUTATION = `#graphql
370
+ mutation customerAccessTokenCreate($input: CustomerAccessTokenCreateInput!) {
371
+ customerAccessTokenCreate(input: $input) {
372
+ customerUserErrors {
373
+ code
374
+ field
375
+ message
376
+ }
377
+ customerAccessToken {
378
+ accessToken
379
+ expiresAt
380
+ }
381
+ }
382
+ }
383
+ `;
384
+
385
+ export async function login(
386
+ {storefront}: AppLoadContext,
387
+ {
388
+ email,
389
+ password,
390
+ }: {
391
+ email: string;
392
+ password: string;
393
+ },
394
+ ) {
395
+ const data = await storefront.mutate<{
396
+ customerAccessTokenCreate: CustomerAccessTokenCreatePayload;
397
+ }>(LOGIN_MUTATION, {
398
+ variables: {
399
+ input: {
400
+ email,
401
+ password,
402
+ },
403
+ },
404
+ });
405
+
406
+ if (data?.customerAccessTokenCreate?.customerAccessToken?.accessToken) {
407
+ return data.customerAccessTokenCreate.customerAccessToken.accessToken;
408
+ }
409
+
410
+ /**
411
+ * Something is wrong with the user's input.
412
+ */
413
+ throw new Error(
414
+ data?.customerAccessTokenCreate?.customerUserErrors.join(', '),
415
+ );
416
+ }
417
+
418
+ const CUSTOMER_CREATE_MUTATION = `#graphql
419
+ mutation customerCreate($input: CustomerCreateInput!) {
420
+ customerCreate(input: $input) {
421
+ customer {
422
+ id
423
+ }
424
+ customerUserErrors {
425
+ code
426
+ field
427
+ message
428
+ }
429
+ }
430
+ }
431
+ `;
432
+
433
+ export async function registerCustomer(
434
+ {storefront}: AppLoadContext,
435
+ {
436
+ email,
437
+ password,
438
+ }: {
439
+ email: string;
440
+ password: string;
441
+ },
442
+ ) {
443
+ const data = await storefront.mutate<{
444
+ customerCreate: CustomerCreatePayload;
445
+ }>(CUSTOMER_CREATE_MUTATION, {
446
+ variables: {
447
+ input: {
448
+ email,
449
+ password,
450
+ },
451
+ },
452
+ });
453
+
454
+ if (data?.customerCreate?.customer?.id) {
455
+ return data.customerCreate.customer.id;
456
+ }
457
+
458
+ /**
459
+ * Something is wrong with the user's input.
460
+ */
461
+ throw new Error(data?.customerCreate?.customerUserErrors.join(', '));
462
+ }
463
+
464
+ const CUSTOMER_RECOVER_MUTATION = `#graphql
465
+ mutation customerRecover($email: String!) {
466
+ customerRecover(email: $email) {
467
+ customerUserErrors {
468
+ code
469
+ field
470
+ message
471
+ }
472
+ }
473
+ }
474
+ `;
475
+
476
+ export async function sendPasswordResetEmail(
477
+ {storefront}: AppLoadContext,
478
+ {email}: {email: string},
479
+ ) {
480
+ await storefront.mutate<{
481
+ customerRecover: CustomerRecoverPayload;
482
+ }>(CUSTOMER_RECOVER_MUTATION, {
483
+ variables: {email},
484
+ });
485
+
486
+ // User doesn't exist but we don't need to notify that.
487
+ return null;
488
+ }
489
+
490
+ const CUSTOMER_RESET_MUTATION = `#graphql
491
+ mutation customerReset($id: ID!, $input: CustomerResetInput!) {
492
+ customerReset(id: $id, input: $input) {
493
+ customerAccessToken {
494
+ accessToken
495
+ expiresAt
496
+ }
497
+ customerUserErrors {
498
+ code
499
+ field
500
+ message
501
+ }
502
+ }
503
+ }
504
+ `;
505
+
506
+ export async function resetPassword(
507
+ {storefront}: AppLoadContext,
508
+ {
509
+ id,
510
+ resetToken,
511
+ password,
512
+ }: {
513
+ id: string;
514
+ resetToken: string;
515
+ password: string;
516
+ },
517
+ ) {
518
+ const data = await storefront.mutate<{
519
+ customerReset: CustomerResetPayload;
520
+ }>(CUSTOMER_RESET_MUTATION, {
521
+ variables: {
522
+ id: `gid://shopify/Customer/${id}`,
523
+ input: {
524
+ password,
525
+ resetToken,
526
+ },
527
+ },
528
+ });
529
+
530
+ if (data?.customerReset?.customerAccessToken) {
531
+ return data.customerReset.customerAccessToken;
532
+ }
533
+
534
+ /**
535
+ * Something is wrong with the user's input.
536
+ */
537
+ throw new Error(data?.customerReset?.customerUserErrors.join(', '));
538
+ }
539
+
540
+ const CUSTOMER_ACTIVATE_MUTATION = `#graphql
541
+ mutation customerActivate($id: ID!, $input: CustomerActivateInput!) {
542
+ customerActivate(id: $id, input: $input) {
543
+ customerAccessToken {
544
+ accessToken
545
+ expiresAt
546
+ }
547
+ customerUserErrors {
548
+ code
549
+ field
550
+ message
551
+ }
552
+ }
553
+ }
554
+ `;
555
+
556
+ export async function activateAccount(
557
+ {storefront}: AppLoadContext,
558
+ {
559
+ id,
560
+ password,
561
+ activationToken,
562
+ }: {
563
+ id: string;
564
+ password: string;
565
+ activationToken: string;
566
+ },
567
+ ) {
568
+ const data = await storefront.mutate<{
569
+ customerActivate: CustomerActivatePayload;
570
+ }>(CUSTOMER_ACTIVATE_MUTATION, {
571
+ variables: {
572
+ id: `gid://shopify/Customer/${id}`,
573
+ input: {
574
+ password,
575
+ activationToken,
576
+ },
577
+ },
578
+ });
579
+
580
+ if (data?.customerActivate?.customerAccessToken) {
581
+ return data.customerActivate.customerAccessToken;
582
+ }
583
+
584
+ /**
585
+ * Something is wrong with the user's input.
586
+ */
587
+ throw new Error(data?.customerActivate?.customerUserErrors.join(', '));
588
+ }
589
+
590
+ const CUSTOMER_QUERY = `#graphql
591
+ query CustomerDetails(
592
+ $customerAccessToken: String!
593
+ $country: CountryCode
594
+ $language: LanguageCode
595
+ ) @inContext(country: $country, language: $language) {
596
+ customer(customerAccessToken: $customerAccessToken) {
597
+ firstName
598
+ lastName
599
+ phone
600
+ email
601
+ defaultAddress {
602
+ id
603
+ formatted
604
+ firstName
605
+ lastName
606
+ company
607
+ address1
608
+ address2
609
+ country
610
+ province
611
+ city
612
+ zip
613
+ phone
614
+ }
615
+ addresses(first: 6) {
616
+ edges {
617
+ node {
618
+ id
619
+ formatted
620
+ firstName
621
+ lastName
622
+ company
623
+ address1
624
+ address2
625
+ country
626
+ province
627
+ city
628
+ zip
629
+ phone
630
+ }
631
+ }
632
+ }
633
+ orders(first: 250, sortKey: PROCESSED_AT, reverse: true) {
634
+ edges {
635
+ node {
636
+ id
637
+ orderNumber
638
+ processedAt
639
+ financialStatus
640
+ fulfillmentStatus
641
+ currentTotalPrice {
642
+ amount
643
+ currencyCode
644
+ }
645
+ lineItems(first: 2) {
646
+ edges {
647
+ node {
648
+ variant {
649
+ image {
650
+ url
651
+ altText
652
+ height
653
+ width
654
+ }
655
+ }
656
+ title
657
+ }
658
+ }
659
+ }
660
+ }
661
+ }
662
+ }
663
+ }
664
+ }
665
+ `;
666
+
667
+ const CUSTOMER_ORDER_QUERY = `#graphql
668
+ fragment Money on MoneyV2 {
669
+ amount
670
+ currencyCode
671
+ }
672
+ fragment AddressFull on MailingAddress {
673
+ address1
674
+ address2
675
+ city
676
+ company
677
+ country
678
+ countryCodeV2
679
+ firstName
680
+ formatted
681
+ id
682
+ lastName
683
+ name
684
+ phone
685
+ province
686
+ provinceCode
687
+ zip
688
+ }
689
+ fragment DiscountApplication on DiscountApplication {
690
+ value {
691
+ ... on MoneyV2 {
692
+ amount
693
+ currencyCode
694
+ }
695
+ ... on PricingPercentageValue {
696
+ percentage
697
+ }
698
+ }
699
+ }
700
+ fragment Image on Image {
701
+ altText
702
+ height
703
+ src: url(transform: {crop: CENTER, maxHeight: 96, maxWidth: 96, scale: 2})
704
+ id
705
+ width
706
+ }
707
+ fragment ProductVariant on ProductVariant {
708
+ id
709
+ image {
710
+ ...Image
711
+ }
712
+ priceV2 {
713
+ ...Money
714
+ }
715
+ product {
716
+ handle
717
+ }
718
+ sku
719
+ title
720
+ }
721
+ fragment LineItemFull on OrderLineItem {
722
+ title
723
+ quantity
724
+ discountAllocations {
725
+ allocatedAmount {
726
+ ...Money
727
+ }
728
+ discountApplication {
729
+ ...DiscountApplication
730
+ }
731
+ }
732
+ originalTotalPrice {
733
+ ...Money
734
+ }
735
+ discountedTotalPrice {
736
+ ...Money
737
+ }
738
+ variant {
739
+ ...ProductVariant
740
+ }
741
+ }
742
+
743
+ query CustomerOrder(
744
+ $country: CountryCode
745
+ $language: LanguageCode
746
+ $orderId: ID!
747
+ ) @inContext(country: $country, language: $language) {
748
+ node(id: $orderId) {
749
+ ... on Order {
750
+ id
751
+ name
752
+ orderNumber
753
+ processedAt
754
+ fulfillmentStatus
755
+ totalTaxV2 {
756
+ ...Money
757
+ }
758
+ totalPriceV2 {
759
+ ...Money
760
+ }
761
+ subtotalPriceV2 {
762
+ ...Money
763
+ }
764
+ shippingAddress {
765
+ ...AddressFull
766
+ }
767
+ discountApplications(first: 100) {
768
+ nodes {
769
+ ...DiscountApplication
770
+ }
771
+ }
772
+ lineItems(first: 100) {
773
+ nodes {
774
+ ...LineItemFull
775
+ }
776
+ }
777
+ }
778
+ }
779
+ }
780
+ `;
781
+
782
+ export async function getCustomerOrder(
783
+ {storefront}: AppLoadContext,
784
+ {
785
+ orderId,
786
+ }: {
787
+ orderId: string;
788
+ },
789
+ ): Promise<Order | undefined> {
790
+ const data = await storefront.query<{
791
+ node: Order;
792
+ }>(CUSTOMER_ORDER_QUERY, {
793
+ variables: {
794
+ orderId,
795
+ country: storefront.i18n?.country,
796
+ language: storefront.i18n?.language,
797
+ },
798
+ });
799
+
800
+ return data?.node;
801
+ }
802
+
803
+ export async function getCustomer(
804
+ context: AppLoadContext,
805
+ {
806
+ request,
807
+ customerAccessToken,
808
+ }: {
809
+ request: Request;
810
+ customerAccessToken: string;
811
+ },
812
+ ) {
813
+ const {storefront} = context;
814
+
815
+ const data = await storefront.query<{
816
+ customer: Customer;
817
+ }>(CUSTOMER_QUERY, {
818
+ variables: {
819
+ customerAccessToken,
820
+ country: context.storefront.i18n?.country,
821
+ language: context.storefront.i18n?.language,
822
+ },
823
+ });
824
+
825
+ /**
826
+ * If the customer failed to load, we assume their access token is invalid.
827
+ */
828
+ if (!data || !data.customer) {
829
+ throw await logout(request, context);
830
+ }
831
+
832
+ return data.customer;
833
+ }
834
+
835
+ const CUSTOMER_UPDATE_MUTATION = `#graphql
836
+ mutation customerUpdate($customerAccessToken: String!, $customer: CustomerUpdateInput!) {
837
+ customerUpdate(customerAccessToken: $customerAccessToken, customer: $customer) {
838
+ customerUserErrors {
839
+ code
840
+ field
841
+ message
842
+ }
843
+ }
844
+ }
845
+ `;
846
+
847
+ export async function updateCustomer(
848
+ {storefront}: AppLoadContext,
849
+ {
850
+ customerAccessToken,
851
+ customer,
852
+ }: {
853
+ customerAccessToken: string;
854
+ customer: CustomerUpdateInput;
855
+ },
856
+ ): Promise<void> {
857
+ const data = await storefront.mutate<{
858
+ customerUpdate: CustomerUpdatePayload;
859
+ }>(CUSTOMER_UPDATE_MUTATION, {
860
+ variables: {
861
+ customerAccessToken,
862
+ customer,
863
+ },
864
+ });
865
+
866
+ assertApiErrors(data.customerUpdate);
867
+ }
868
+
869
+ const UPDATE_ADDRESS_MUTATION = `#graphql
870
+ mutation customerAddressUpdate(
871
+ $address: MailingAddressInput!
872
+ $customerAccessToken: String!
873
+ $id: ID!
874
+ ) {
875
+ customerAddressUpdate(
876
+ address: $address
877
+ customerAccessToken: $customerAccessToken
878
+ id: $id
879
+ ) {
880
+ customerUserErrors {
881
+ code
882
+ field
883
+ message
884
+ }
885
+ }
886
+ }
887
+ `;
888
+
889
+ export async function updateCustomerAddress(
890
+ {storefront}: AppLoadContext,
891
+ {
892
+ customerAccessToken,
893
+ addressId,
894
+ address,
895
+ }: {
896
+ customerAccessToken: string;
897
+ addressId: string;
898
+ address: MailingAddressInput;
899
+ },
900
+ ): Promise<void> {
901
+ const data = await storefront.mutate<{
902
+ customerAddressUpdate: CustomerAddressUpdatePayload;
903
+ }>(UPDATE_ADDRESS_MUTATION, {
904
+ variables: {
905
+ customerAccessToken,
906
+ id: addressId,
907
+ address,
908
+ },
909
+ });
910
+
911
+ assertApiErrors(data.customerAddressUpdate);
912
+ }
913
+
914
+ const DELETE_ADDRESS_MUTATION = `#graphql
915
+ mutation customerAddressDelete($customerAccessToken: String!, $id: ID!) {
916
+ customerAddressDelete(customerAccessToken: $customerAccessToken, id: $id) {
917
+ customerUserErrors {
918
+ code
919
+ field
920
+ message
921
+ }
922
+ deletedCustomerAddressId
923
+ }
924
+ }
925
+ `;
926
+
927
+ export async function deleteCustomerAddress(
928
+ {storefront}: AppLoadContext,
929
+ {
930
+ customerAccessToken,
931
+ addressId,
932
+ }: {
933
+ customerAccessToken: string;
934
+ addressId: string;
935
+ },
936
+ ): Promise<void> {
937
+ const data = await storefront.mutate<{
938
+ customerAddressDelete: CustomerAddressDeletePayload;
939
+ }>(DELETE_ADDRESS_MUTATION, {
940
+ variables: {
941
+ customerAccessToken,
942
+ id: addressId,
943
+ },
944
+ });
945
+
946
+ assertApiErrors(data.customerAddressDelete);
947
+ }
948
+
949
+ const UPDATE_DEFAULT_ADDRESS_MUTATION = `#graphql
950
+ mutation customerDefaultAddressUpdate(
951
+ $addressId: ID!
952
+ $customerAccessToken: String!
953
+ ) {
954
+ customerDefaultAddressUpdate(
955
+ addressId: $addressId
956
+ customerAccessToken: $customerAccessToken
957
+ ) {
958
+ customerUserErrors {
959
+ code
960
+ field
961
+ message
962
+ }
963
+ }
964
+ }
965
+ `;
966
+
967
+ export async function updateCustomerDefaultAddress(
968
+ {storefront}: AppLoadContext,
969
+ {
970
+ customerAccessToken,
971
+ addressId,
972
+ }: {
973
+ customerAccessToken: string;
974
+ addressId: string;
975
+ },
976
+ ): Promise<void> {
977
+ const data = await storefront.mutate<{
978
+ customerDefaultAddressUpdate: CustomerDefaultAddressUpdatePayload;
979
+ }>(UPDATE_DEFAULT_ADDRESS_MUTATION, {
980
+ variables: {
981
+ customerAccessToken,
982
+ addressId,
983
+ },
984
+ });
985
+
986
+ assertApiErrors(data.customerDefaultAddressUpdate);
987
+ }
988
+
989
+ const CREATE_ADDRESS_MUTATION = `#graphql
990
+ mutation customerAddressCreate(
991
+ $address: MailingAddressInput!
992
+ $customerAccessToken: String!
993
+ ) {
994
+ customerAddressCreate(
995
+ address: $address
996
+ customerAccessToken: $customerAccessToken
997
+ ) {
998
+ customerAddress {
999
+ id
1000
+ }
1001
+ customerUserErrors {
1002
+ code
1003
+ field
1004
+ message
1005
+ }
1006
+ }
1007
+ }
1008
+ `;
1009
+
1010
+ export async function createCustomerAddress(
1011
+ {storefront}: AppLoadContext,
1012
+ {
1013
+ customerAccessToken,
1014
+ address,
1015
+ }: {
1016
+ customerAccessToken: string;
1017
+ address: MailingAddressInput;
1018
+ },
1019
+ ): Promise<string> {
1020
+ const data = await storefront.mutate<{
1021
+ customerAddressCreate: CustomerAddressCreatePayload;
1022
+ }>(CREATE_ADDRESS_MUTATION, {
1023
+ variables: {
1024
+ customerAccessToken,
1025
+ address,
1026
+ },
1027
+ });
1028
+
1029
+ assertApiErrors(data.customerAddressCreate);
1030
+
1031
+ invariant(
1032
+ data?.customerAddressCreate?.customerAddress?.id,
1033
+ 'Expected customer address to be created',
1034
+ );
1035
+
1036
+ return data.customerAddressCreate.customerAddress.id;
1037
+ }