@shopify/cli-hydrogen 6.0.2 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/commands/hydrogen/build.js +40 -78
  2. package/dist/commands/hydrogen/codegen.js +8 -3
  3. package/dist/commands/hydrogen/deploy.js +173 -37
  4. package/dist/commands/hydrogen/deploy.test.js +192 -20
  5. package/dist/commands/hydrogen/dev.js +56 -31
  6. package/dist/commands/hydrogen/init.js +1 -1
  7. package/dist/commands/hydrogen/init.test.js +155 -53
  8. package/dist/commands/hydrogen/link.js +5 -21
  9. package/dist/commands/hydrogen/link.test.js +10 -10
  10. package/dist/commands/hydrogen/preview.js +22 -11
  11. package/dist/commands/hydrogen/setup.js +0 -4
  12. package/dist/commands/hydrogen/setup.test.js +0 -1
  13. package/dist/commands/hydrogen/shortcut.js +1 -0
  14. package/dist/commands/hydrogen/upgrade.js +720 -0
  15. package/dist/commands/hydrogen/upgrade.test.js +786 -0
  16. package/dist/generator-templates/starter/.graphqlrc.yml +12 -1
  17. package/dist/generator-templates/starter/CHANGELOG.md +126 -0
  18. package/dist/generator-templates/starter/README.md +23 -0
  19. package/dist/generator-templates/starter/app/components/Cart.tsx +1 -1
  20. package/dist/generator-templates/starter/app/components/Footer.tsx +3 -1
  21. package/dist/generator-templates/starter/app/components/Header.tsx +5 -1
  22. package/dist/generator-templates/starter/app/components/Layout.tsx +14 -11
  23. package/dist/generator-templates/starter/app/components/Search.tsx +1 -1
  24. package/dist/generator-templates/starter/app/graphql/customer-account/CustomerAddressMutations.ts +61 -0
  25. package/dist/generator-templates/starter/app/graphql/customer-account/CustomerDetailsQuery.ts +39 -0
  26. package/dist/generator-templates/starter/app/graphql/customer-account/CustomerOrderQuery.ts +87 -0
  27. package/dist/generator-templates/starter/app/graphql/customer-account/CustomerOrdersQuery.ts +58 -0
  28. package/dist/generator-templates/starter/app/graphql/customer-account/CustomerUpdateMutation.ts +24 -0
  29. package/dist/generator-templates/starter/app/lib/fragments.ts +102 -0
  30. package/dist/generator-templates/starter/app/lib/session.ts +67 -0
  31. package/dist/generator-templates/starter/app/root.tsx +11 -45
  32. package/dist/generator-templates/starter/app/routes/[robots.txt].tsx +0 -27
  33. package/dist/generator-templates/starter/app/routes/account.$.tsx +8 -4
  34. package/dist/generator-templates/starter/app/routes/account._index.tsx +5 -0
  35. package/dist/generator-templates/starter/app/routes/account.addresses.tsx +215 -206
  36. package/dist/generator-templates/starter/app/routes/account.orders.$id.tsx +56 -163
  37. package/dist/generator-templates/starter/app/routes/account.orders._index.tsx +32 -109
  38. package/dist/generator-templates/starter/app/routes/account.profile.tsx +40 -180
  39. package/dist/generator-templates/starter/app/routes/account.tsx +20 -135
  40. package/dist/generator-templates/starter/app/routes/account_.authorize.tsx +5 -0
  41. package/dist/generator-templates/starter/app/routes/account_.login.tsx +3 -140
  42. package/dist/generator-templates/starter/app/routes/account_.logout.tsx +5 -24
  43. package/dist/generator-templates/starter/app/routes/cart.tsx +7 -5
  44. package/dist/generator-templates/starter/app/routes/collections.$handle.tsx +1 -1
  45. package/dist/generator-templates/starter/app/routes/products.$handle.tsx +2 -2
  46. package/dist/generator-templates/starter/app/routes/search.tsx +1 -1
  47. package/dist/generator-templates/starter/customer-accountapi.generated.d.ts +506 -0
  48. package/dist/generator-templates/starter/package.json +11 -10
  49. package/dist/generator-templates/starter/remix.config.js +4 -0
  50. package/dist/generator-templates/starter/remix.env.d.ts +6 -11
  51. package/dist/generator-templates/starter/server.ts +24 -167
  52. package/dist/generator-templates/starter/storefrontapi.generated.d.ts +104 -881
  53. package/dist/hooks/init.js +4 -4
  54. package/dist/lib/auth.js +5 -10
  55. package/dist/lib/build.js +6 -1
  56. package/dist/lib/bundle/analyzer.js +36 -26
  57. package/dist/lib/check-lockfile.js +1 -0
  58. package/dist/lib/codegen.js +59 -18
  59. package/dist/lib/defer.js +12 -0
  60. package/dist/lib/file.js +52 -3
  61. package/dist/lib/flags.js +27 -9
  62. package/dist/lib/get-oxygen-deployment-data.test.js +4 -2
  63. package/dist/lib/graphql/admin/client.test.js +2 -2
  64. package/dist/lib/graphql/admin/get-oxygen-data.js +1 -0
  65. package/dist/lib/log.js +32 -14
  66. package/dist/lib/mini-oxygen/assets.js +118 -0
  67. package/dist/lib/mini-oxygen/common.js +2 -1
  68. package/dist/lib/mini-oxygen/index.js +7 -5
  69. package/dist/lib/mini-oxygen/mini-oxygen.test.js +214 -0
  70. package/dist/lib/mini-oxygen/node.js +19 -5
  71. package/dist/lib/mini-oxygen/workerd-inspector-logs.js +227 -0
  72. package/dist/lib/mini-oxygen/workerd-inspector-proxy.js +200 -0
  73. package/dist/lib/mini-oxygen/workerd-inspector.js +62 -235
  74. package/dist/lib/mini-oxygen/workerd.js +74 -50
  75. package/dist/lib/missing-routes.js +6 -3
  76. package/dist/lib/onboarding/common.js +40 -9
  77. package/dist/lib/onboarding/local.js +19 -11
  78. package/dist/lib/onboarding/remote.js +48 -28
  79. package/dist/lib/render-errors.js +2 -0
  80. package/dist/lib/request-events.js +65 -31
  81. package/dist/lib/setups/css/assets.js +1 -46
  82. package/dist/lib/setups/css/css-modules.js +3 -2
  83. package/dist/lib/setups/css/postcss.js +4 -2
  84. package/dist/lib/setups/css/tailwind.js +4 -2
  85. package/dist/lib/setups/css/vanilla-extract.js +3 -2
  86. package/dist/lib/setups/i18n/replacers.test.js +56 -38
  87. package/dist/lib/shell.js +1 -1
  88. package/dist/lib/template-diff.js +89 -0
  89. package/dist/lib/template-downloader.js +3 -2
  90. package/dist/lib/transpile/project.js +1 -1
  91. package/dist/virtual-routes/assets/debug-network.css +592 -0
  92. package/dist/virtual-routes/assets/favicon-dark.svg +20 -0
  93. package/dist/virtual-routes/components/FlameChartWrapper.jsx +8 -10
  94. package/dist/virtual-routes/components/IconClose.jsx +38 -0
  95. package/dist/virtual-routes/components/IconDiscard.jsx +44 -0
  96. package/dist/virtual-routes/components/RequestDetails.jsx +179 -0
  97. package/dist/virtual-routes/components/RequestTable.jsx +92 -0
  98. package/dist/virtual-routes/components/RequestWaterfall.jsx +151 -0
  99. package/dist/virtual-routes/lib/useDebugNetworkServer.jsx +176 -0
  100. package/dist/virtual-routes/routes/subrequest-profiler.jsx +243 -0
  101. package/oclif.manifest.json +134 -59
  102. package/package.json +18 -26
  103. package/dist/generator-templates/starter/app/routes/account_.activate.$id.$activationToken.tsx +0 -161
  104. package/dist/generator-templates/starter/app/routes/account_.recover.tsx +0 -129
  105. package/dist/generator-templates/starter/app/routes/account_.register.tsx +0 -207
  106. package/dist/generator-templates/starter/app/routes/account_.reset.$id.$resetToken.tsx +0 -136
  107. package/dist/virtual-routes/routes/debug-network.jsx +0 -289
  108. /package/dist/generator-templates/starter/app/{utils.ts → lib/variants.ts} +0 -0
@@ -1,36 +1,35 @@
1
1
  import {json, redirect, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
2
2
  import {Link, useLoaderData, type MetaFunction} from '@remix-run/react';
3
3
  import {Money, Image, flattenConnection} from '@shopify/hydrogen';
4
- import type {OrderLineItemFullFragment} from 'storefrontapi.generated';
4
+ import type {OrderLineItemFullFragment} from 'customer-accountapi.generated';
5
+ import {CUSTOMER_ORDER_QUERY} from '~/graphql/customer-account/CustomerOrderQuery';
5
6
 
6
7
  export const meta: MetaFunction<typeof loader> = ({data}) => {
7
8
  return [{title: `Order ${data?.order?.name}`}];
8
9
  };
9
10
 
10
- export async function loader({params, context}: LoaderFunctionArgs) {
11
- const {session, storefront} = context;
12
-
11
+ export async function loader({params, context, request}: LoaderFunctionArgs) {
13
12
  if (!params.id) {
14
13
  return redirect('/account/orders');
15
14
  }
16
15
 
17
16
  const orderId = atob(params.id);
18
- const customerAccessToken = await session.get('customerAccessToken');
17
+ const {data, errors} = await context.customerAccount.query(
18
+ CUSTOMER_ORDER_QUERY,
19
+ {
20
+ variables: {orderId},
21
+ },
22
+ );
19
23
 
20
- if (!customerAccessToken) {
21
- return redirect('/account/login');
24
+ if (errors?.length || !data?.order) {
25
+ throw new Error('Order not found');
22
26
  }
23
27
 
24
- const {order} = await storefront.query(CUSTOMER_ORDER_QUERY, {
25
- variables: {orderId},
26
- });
27
-
28
- if (!order || !('lineItems' in order)) {
29
- throw new Response('Order not found', {status: 404});
30
- }
28
+ const {order} = data;
31
29
 
32
30
  const lineItems = flattenConnection(order.lineItems);
33
31
  const discountApplications = flattenConnection(order.discountApplications);
32
+ const fulfillmentStatus = flattenConnection(order.fulfillments)[0].status;
34
33
 
35
34
  const firstDiscount = discountApplications[0]?.value;
36
35
 
@@ -41,17 +40,30 @@ export async function loader({params, context}: LoaderFunctionArgs) {
41
40
  firstDiscount?.__typename === 'PricingPercentageValue' &&
42
41
  firstDiscount?.percentage;
43
42
 
44
- return json({
43
+ return json(
44
+ {
45
+ order,
46
+ lineItems,
47
+ discountValue,
48
+ discountPercentage,
49
+ fulfillmentStatus,
50
+ },
51
+ {
52
+ headers: {
53
+ 'Set-Cookie': await context.session.commit(),
54
+ },
55
+ },
56
+ );
57
+ }
58
+
59
+ export default function OrderRoute() {
60
+ const {
45
61
  order,
46
62
  lineItems,
47
63
  discountValue,
48
64
  discountPercentage,
49
- });
50
- }
51
-
52
- export default function OrderRoute() {
53
- const {order, lineItems, discountValue, discountPercentage} =
54
- useLoaderData<typeof loader>();
65
+ fulfillmentStatus,
66
+ } = useLoaderData<typeof loader>();
55
67
  return (
56
68
  <div className="account-order">
57
69
  <h2>Order {order.name}</h2>
@@ -100,7 +112,7 @@ export default function OrderRoute() {
100
112
  <p>Subtotal</p>
101
113
  </th>
102
114
  <td>
103
- <Money data={order.subtotalPriceV2!} />
115
+ <Money data={order.subtotal!} />
104
116
  </td>
105
117
  </tr>
106
118
  <tr>
@@ -111,7 +123,7 @@ export default function OrderRoute() {
111
123
  <p>Tax</p>
112
124
  </th>
113
125
  <td>
114
- <Money data={order.totalTaxV2!} />
126
+ <Money data={order.totalTax!} />
115
127
  </td>
116
128
  </tr>
117
129
  <tr>
@@ -122,7 +134,7 @@ export default function OrderRoute() {
122
134
  <p>Total</p>
123
135
  </th>
124
136
  <td>
125
- <Money data={order.totalPriceV2!} />
137
+ <Money data={order.totalPrice!} />
126
138
  </td>
127
139
  </tr>
128
140
  </tfoot>
@@ -131,17 +143,16 @@ export default function OrderRoute() {
131
143
  <h3>Shipping Address</h3>
132
144
  {order?.shippingAddress ? (
133
145
  <address>
134
- <p>
135
- {order.shippingAddress.firstName &&
136
- order.shippingAddress.firstName + ' '}
137
- {order.shippingAddress.lastName}
138
- </p>
139
- {order?.shippingAddress?.formatted ? (
140
- order.shippingAddress.formatted.map((line: string) => (
141
- <p key={line}>{line}</p>
142
- ))
146
+ <p>{order.shippingAddress.name}</p>
147
+ {order.shippingAddress.formatted ? (
148
+ <p>{order.shippingAddress.formatted}</p>
143
149
  ) : (
144
- <></>
150
+ ''
151
+ )}
152
+ {order.shippingAddress.formattedArea ? (
153
+ <p>{order.shippingAddress.formattedArea}</p>
154
+ ) : (
155
+ ''
145
156
  )}
146
157
  </address>
147
158
  ) : (
@@ -149,13 +160,13 @@ export default function OrderRoute() {
149
160
  )}
150
161
  <h3>Status</h3>
151
162
  <div>
152
- <p>{order.fulfillmentStatus}</p>
163
+ <p>{fulfillmentStatus}</p>
153
164
  </div>
154
165
  </div>
155
166
  </div>
156
167
  <br />
157
168
  <p>
158
- <a target="_blank" href={order.statusUrl} rel="noreferrer">
169
+ <a target="_blank" href={order.statusPageUrl} rel="noreferrer">
159
170
  View Order Status →
160
171
  </a>
161
172
  </p>
@@ -165,145 +176,27 @@ export default function OrderRoute() {
165
176
 
166
177
  function OrderLineRow({lineItem}: {lineItem: OrderLineItemFullFragment}) {
167
178
  return (
168
- <tr key={lineItem.variant!.id}>
179
+ <tr key={lineItem.id}>
169
180
  <td>
170
181
  <div>
171
- <Link to={`/products/${lineItem.variant!.product!.handle}`}>
172
- {lineItem?.variant?.image && (
173
- <div>
174
- <Image data={lineItem.variant.image} width={96} height={96} />
175
- </div>
176
- )}
177
- </Link>
182
+ {lineItem?.image && (
183
+ <div>
184
+ <Image data={lineItem.image} width={96} height={96} />
185
+ </div>
186
+ )}
178
187
  <div>
179
188
  <p>{lineItem.title}</p>
180
- <small>{lineItem.variant!.title}</small>
189
+ <small>{lineItem.variantTitle}</small>
181
190
  </div>
182
191
  </div>
183
192
  </td>
184
193
  <td>
185
- <Money data={lineItem.variant!.price!} />
194
+ <Money data={lineItem.price!} />
186
195
  </td>
187
196
  <td>{lineItem.quantity}</td>
188
197
  <td>
189
- <Money data={lineItem.discountedTotalPrice!} />
198
+ <Money data={lineItem.totalDiscount!} />
190
199
  </td>
191
200
  </tr>
192
201
  );
193
202
  }
194
-
195
- // NOTE: https://shopify.dev/docs/api/storefront/latest/objects/Order
196
- const CUSTOMER_ORDER_QUERY = `#graphql
197
- fragment OrderMoney on MoneyV2 {
198
- amount
199
- currencyCode
200
- }
201
- fragment AddressFull on MailingAddress {
202
- address1
203
- address2
204
- city
205
- company
206
- country
207
- countryCodeV2
208
- firstName
209
- formatted
210
- id
211
- lastName
212
- name
213
- phone
214
- province
215
- provinceCode
216
- zip
217
- }
218
- fragment DiscountApplication on DiscountApplication {
219
- value {
220
- __typename
221
- ... on MoneyV2 {
222
- ...OrderMoney
223
- }
224
- ... on PricingPercentageValue {
225
- percentage
226
- }
227
- }
228
- }
229
- fragment OrderLineProductVariant on ProductVariant {
230
- id
231
- image {
232
- altText
233
- height
234
- url
235
- id
236
- width
237
- }
238
- price {
239
- ...OrderMoney
240
- }
241
- product {
242
- handle
243
- }
244
- sku
245
- title
246
- }
247
- fragment OrderLineItemFull on OrderLineItem {
248
- title
249
- quantity
250
- discountAllocations {
251
- allocatedAmount {
252
- ...OrderMoney
253
- }
254
- discountApplication {
255
- ...DiscountApplication
256
- }
257
- }
258
- originalTotalPrice {
259
- ...OrderMoney
260
- }
261
- discountedTotalPrice {
262
- ...OrderMoney
263
- }
264
- variant {
265
- ...OrderLineProductVariant
266
- }
267
- }
268
- fragment Order on Order {
269
- id
270
- name
271
- orderNumber
272
- statusUrl
273
- processedAt
274
- fulfillmentStatus
275
- totalTaxV2 {
276
- ...OrderMoney
277
- }
278
- totalPriceV2 {
279
- ...OrderMoney
280
- }
281
- subtotalPriceV2 {
282
- ...OrderMoney
283
- }
284
- shippingAddress {
285
- ...AddressFull
286
- }
287
- discountApplications(first: 100) {
288
- nodes {
289
- ...DiscountApplication
290
- }
291
- }
292
- lineItems(first: 100) {
293
- nodes {
294
- ...OrderLineItemFull
295
- }
296
- }
297
- }
298
- query Order(
299
- $country: CountryCode
300
- $language: LanguageCode
301
- $orderId: ID!
302
- ) @inContext(country: $country, language: $language) {
303
- order: node(id: $orderId) {
304
- ... on Order {
305
- ...Order
306
- }
307
- }
308
- }
309
- ` as const;
@@ -1,60 +1,54 @@
1
1
  import {Link, useLoaderData, type MetaFunction} from '@remix-run/react';
2
- import {Money, Pagination, getPaginationVariables} from '@shopify/hydrogen';
2
+ import {
3
+ Money,
4
+ Pagination,
5
+ getPaginationVariables,
6
+ flattenConnection,
7
+ } from '@shopify/hydrogen';
3
8
  import {json, redirect, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
9
+ import {CUSTOMER_ORDERS_QUERY} from '~/graphql/customer-account/CustomerOrdersQuery';
4
10
  import type {
5
11
  CustomerOrdersFragment,
6
12
  OrderItemFragment,
7
- } from 'storefrontapi.generated';
13
+ } from 'customer-accountapi.generated';
8
14
 
9
15
  export const meta: MetaFunction = () => {
10
16
  return [{title: 'Orders'}];
11
17
  };
12
18
 
13
19
  export async function loader({request, context}: LoaderFunctionArgs) {
14
- const {session, storefront} = context;
20
+ const paginationVariables = getPaginationVariables(request, {
21
+ pageBy: 20,
22
+ });
15
23
 
16
- const customerAccessToken = await session.get('customerAccessToken');
17
- if (!customerAccessToken?.accessToken) {
18
- return redirect('/account/login');
19
- }
20
-
21
- try {
22
- const paginationVariables = getPaginationVariables(request, {
23
- pageBy: 20,
24
- });
25
-
26
- const {customer} = await storefront.query(CUSTOMER_ORDERS_QUERY, {
24
+ const {data, errors} = await context.customerAccount.query(
25
+ CUSTOMER_ORDERS_QUERY,
26
+ {
27
27
  variables: {
28
- customerAccessToken: customerAccessToken.accessToken,
29
- country: storefront.i18n.country,
30
- language: storefront.i18n.language,
31
28
  ...paginationVariables,
32
29
  },
33
- cache: storefront.CacheNone(),
34
- });
35
-
36
- if (!customer) {
37
- throw new Error('Customer not found');
38
- }
30
+ },
31
+ );
39
32
 
40
- return json({customer});
41
- } catch (error: unknown) {
42
- if (error instanceof Error) {
43
- return json({error: error.message}, {status: 400});
44
- }
45
- return json({error}, {status: 400});
33
+ if (errors?.length || !data?.customer) {
34
+ throw Error('Customer orders not found');
46
35
  }
36
+
37
+ return json(
38
+ {customer: data.customer},
39
+ {
40
+ headers: {
41
+ 'Set-Cookie': await context.session.commit(),
42
+ },
43
+ },
44
+ );
47
45
  }
48
46
 
49
47
  export default function Orders() {
50
48
  const {customer} = useLoaderData<{customer: CustomerOrdersFragment}>();
51
- const {orders, numberOfOrders} = customer;
49
+ const {orders} = customer;
52
50
  return (
53
51
  <div className="orders">
54
- <h2>
55
- Orders <small>({numberOfOrders})</small>
56
- </h2>
57
- <br />
58
52
  {orders.nodes.length ? <OrdersTable orders={orders} /> : <EmptyOrders />}
59
53
  </div>
60
54
  );
@@ -101,91 +95,20 @@ function EmptyOrders() {
101
95
  }
102
96
 
103
97
  function OrderItem({order}: {order: OrderItemFragment}) {
98
+ const fulfillmentStatus = flattenConnection(order.fulfillments)[0].status;
104
99
  return (
105
100
  <>
106
101
  <fieldset>
107
102
  <Link to={`/account/orders/${order.id}`}>
108
- <strong>#{order.orderNumber}</strong>
103
+ <strong>#{order.number}</strong>
109
104
  </Link>
110
105
  <p>{new Date(order.processedAt).toDateString()}</p>
111
106
  <p>{order.financialStatus}</p>
112
- <p>{order.fulfillmentStatus}</p>
113
- <Money data={order.currentTotalPrice} />
107
+ <p>{fulfillmentStatus}</p>
108
+ <Money data={order.totalPrice} />
114
109
  <Link to={`/account/orders/${btoa(order.id)}`}>View Order →</Link>
115
110
  </fieldset>
116
111
  <br />
117
112
  </>
118
113
  );
119
114
  }
120
-
121
- const ORDER_ITEM_FRAGMENT = `#graphql
122
- fragment OrderItem on Order {
123
- currentTotalPrice {
124
- amount
125
- currencyCode
126
- }
127
- financialStatus
128
- fulfillmentStatus
129
- id
130
- lineItems(first: 10) {
131
- nodes {
132
- title
133
- variant {
134
- image {
135
- url
136
- altText
137
- height
138
- width
139
- }
140
- }
141
- }
142
- }
143
- orderNumber
144
- customerUrl
145
- statusUrl
146
- processedAt
147
- }
148
- ` as const;
149
-
150
- export const CUSTOMER_FRAGMENT = `#graphql
151
- fragment CustomerOrders on Customer {
152
- numberOfOrders
153
- orders(
154
- sortKey: PROCESSED_AT,
155
- reverse: true,
156
- first: $first,
157
- last: $last,
158
- before: $startCursor,
159
- after: $endCursor
160
- ) {
161
- nodes {
162
- ...OrderItem
163
- }
164
- pageInfo {
165
- hasPreviousPage
166
- hasNextPage
167
- endCursor
168
- startCursor
169
- }
170
- }
171
- }
172
- ${ORDER_ITEM_FRAGMENT}
173
- ` as const;
174
-
175
- // NOTE: https://shopify.dev/docs/api/storefront/latest/queries/customer
176
- const CUSTOMER_ORDERS_QUERY = `#graphql
177
- ${CUSTOMER_FRAGMENT}
178
- query CustomerOrders(
179
- $country: CountryCode
180
- $customerAccessToken: String!
181
- $endCursor: String
182
- $first: Int
183
- $language: LanguageCode
184
- $last: Int
185
- $startCursor: String
186
- ) @inContext(country: $country, language: $language) {
187
- customer(customerAccessToken: $customerAccessToken) {
188
- ...CustomerOrders
189
- }
190
- }
191
- ` as const;