Repository: urql-graphql/urql
Pull request #3113 (2023-03-31 14:03:48)

fix(svelte): misplaced second argument in TSDoc


Patch:
diff --git a/.changeset/rotten-planes-heal.md b/.changeset/rotten-planes-heal.md
new file mode 100644
index 00000000..33067e36
--- /dev/null
+++ b/.changeset/rotten-planes-heal.md
@@ -0,0 +1,5 @@
+---
+'@urql/exchange-auth': patch
+---
+
+Avoid infinite loop when `didAuthError` keeps returning true
diff --git a/exchanges/auth/src/authExchange.ts b/exchanges/auth/src/authExchange.ts
index 3fdfa520..d5a878de 100644
--- a/exchanges/auth/src/authExchange.ts
+++ b/exchanges/auth/src/authExchange.ts
@@ -270,6 +270,7 @@ export function authExchange(
           operation.key,
           addAuthAttemptToOperation(operation, true)
         );
+
         // check that another operation isn't already doing refresh
         if (config && !authPromise) {
           authPromise = config.refreshAuth().finally(flushQueue);
@@ -310,7 +311,9 @@ export function authExchange(
       const opsWithAuth$ = pipe(
         merge([retries.source, pendingOps$]),
         map(operation => {
-          if (bypassQueue.has(operation)) {
+          if (operation.context.authAttempt) {
+            return addAuthToOperation(operation);
+          } else if (bypassQueue.has(operation)) {
             return operation;
           } else if (authPromise) {
             if (!retryQueue.has(operation.key)) {
diff --git a/packages/svelte-urql/src/subscriptionStore.ts b/packages/svelte-urql/src/subscriptionStore.ts
index 8bb15d72..dd80c70a 100644
--- a/packages/svelte-urql/src/subscriptionStore.ts
+++ b/packages/svelte-urql/src/subscriptionStore.ts
@@ -127,10 +127,11 @@ export type SubscriptionArgs<
  *       newNotification { id, text }
  *     }
  *   `,
+ *   },
  *   function combineNotifications(notifications = [], data) {
  *     return [...notifications, data.newNotification];
  *   },
- * });
+ * );
  * ```
  */
 export function subscriptionStore<


Test patch:
diff --git a/exchanges/auth/src/authExchange.test.ts b/exchanges/auth/src/authExchange.test.ts
index 7795e342..b9045a87 100644
--- a/exchanges/auth/src/authExchange.test.ts
+++ b/exchanges/auth/src/authExchange.test.ts
@@ -158,7 +158,7 @@ it('supports calls to the mutate() method in refreshAuth()', async () => {
     },
   });
 
-  expect(res.operation.context.authAttempt).toBe(false);
+  expect(res.operation.context.authAttempt).toBe(true);
   expect(res.operation.context.fetchOptions).toEqual({
     method: 'POST',
     headers: {
@@ -385,3 +385,60 @@ it('calls willAuthError on queued operations', async () => {
     'final-token'
   );
 });
+
+it('does not infinitely retry authentication when an operation did error', async () => {
+  const { exchangeArgs, result, operations } = makeExchangeArgs();
+  const { source, next } = makeSubject<any>();
+
+  const didAuthError = vi.fn().mockReturnValue(true);
+
+  pipe(
+    source,
+    authExchange(async utils => {
+      let token = 'initial-token';
+      return {
+        addAuthToOperation(operation) {
+          return utils.appendHeaders(operation, {
+            Authorization: token,
+          });
+        },
+        didAuthError,
+        async refreshAuth() {
+          token = 'final-token';
+        },
+      };
+    })(exchangeArgs),
+    publish
+  );
+
+  await new Promise(resolve => setTimeout(resolve));
+
+  result.mockImplementation(x => ({
+    ...queryResponse,
+    operation: {
+      ...queryResponse.operation,
+      ...x,
+    },
+    data: undefined,
+    error: new CombinedError({
+      graphQLErrors: [{ message: 'Oops' }],
+    }),
+  }));
+
+  next(queryOperation);
+  expect(result).toHaveBeenCalledTimes(1);
+  expect(didAuthError).toHaveBeenCalledTimes(1);
+
+  await new Promise(resolve => setTimeout(resolve));
+
+  expect(result).toHaveBeenCalledTimes(2);
+  expect(operations.length).toBe(2);
+  expect(operations[0]).toHaveProperty(
+    'context.fetchOptions.headers.Authorization',
+    'initial-token'
+  );
+  expect(operations[1]).toHaveProperty(
+    'context.fetchOptions.headers.Authorization',
+    'final-token'
+  );
+});