Skip to content

Commit

Permalink
Fix async error stack in Storefront and Customer Account clients (#1656)
Browse files Browse the repository at this point in the history
* Fix async error stack in storefront and customer clients

* Changesets

* Keep error prototype

* Avoid duplicating stacks for non-async calls

* Simplify signature
  • Loading branch information
frandiox authored Jan 22, 2024
1 parent 0591c2d commit 952fedf
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/tidy-starfishes-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/hydrogen': patch
---

Fix error stack traces thrown from Storefront API and Customer Account API clients when promises are not awaited.
10 changes: 7 additions & 3 deletions packages/hydrogen/src/customer/customer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
import {parseJSON} from '../utils/parse-json';
import {hashKey} from '../utils/hash';
import {CrossRuntimeRequest, getDebugHeaders} from '../utils/request';
import {getCallerStackLine} from '../utils/callsites';
import {getCallerStackLine, withSyncStack} from '../utils/callsites';

type CustomerAPIResponse<ReturnType> = {
data: ReturnType;
Expand Down Expand Up @@ -353,13 +353,17 @@ export function createCustomerClient({
mutation = minifyQuery(mutation);
assertMutation(mutation, 'customer.mutate');

return fetchCustomerAPI({query: mutation, type: 'mutation', ...options});
return withSyncStack(
fetchCustomerAPI({query: mutation, type: 'mutation', ...options}),
);
},
query(query, options?) {
query = minifyQuery(query);
assertQuery(query, 'customer.query');

return fetchCustomerAPI({query, type: 'query', ...options});
return withSyncStack(
fetchCustomerAPI({query, type: 'query', ...options}),
);
},
authorize: async () => {
const code = url.searchParams.get('code');
Expand Down
24 changes: 3 additions & 21 deletions packages/hydrogen/src/storefront.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import {
type GraphQLErrorOptions,
GraphQLFormattedError,
} from './utils/graphql';
import {getCallerStackLine} from './utils/callsites';
import {getCallerStackLine, withSyncStack} from './utils/callsites';

export type I18nBase = {
language: LanguageCode;
Expand Down Expand Up @@ -396,16 +396,7 @@ export function createStorefrontClient<TI18n extends I18nBase>(
query = minifyQuery(query);
assertQuery(query, 'storefront.query');

const result = fetchStorefrontApi({
...options,
query,
});

// This is a no-op, but we need to catch the promise to avoid unhandled rejections
// we cannot return the catch no-op, or it would swallow the error
result.catch(() => {});

return result;
return withSyncStack(fetchStorefrontApi({...options, query}));
},
/**
* Sends a GraphQL mutation to the Storefront API.
Expand All @@ -424,16 +415,7 @@ export function createStorefrontClient<TI18n extends I18nBase>(
mutation = minifyQuery(mutation);
assertMutation(mutation, 'storefront.mutate');

const result = fetchStorefrontApi({
...options,
mutation,
});

// This is a no-op, but we need to catch the promise to avoid unhandled rejections
// we cannot return the catch no-op, or it would swallow the error
result.catch(() => {});

return result;
return withSyncStack(fetchStorefrontApi({...options, mutation}));
},
cache,
CacheNone,
Expand Down
17 changes: 17 additions & 0 deletions packages/hydrogen/src/utils/callsites.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/**
* Ensures that the error of an async rejected promise
* contains the entire synchronous stack trace.
*/
export function withSyncStack<T>(promise: Promise<T>): Promise<T> {
const syncError = new Error();

return promise.catch((error: Error) => {
// Remove error message, caller function and current function from the stack.
const syncStack = (syncError.stack ?? '').split('\n').slice(3).join('\n');

error.stack = `Error: ${error.message}\n` + syncStack;

throw error;
});
}

export type StackInfo = {
file?: string;
func?: string;
Expand Down

0 comments on commit 952fedf

Please sign in to comment.