Repository: FormidableLabs/urql
Pull request #1828 (2021-07-30 04:59:05)

(auth) - expose AuthConfig type
## Summary

Exposes the `AuthConfig<T>` type in the auth exchange package. This would be useful for doing something like:

```ts
const baseAuthConfig: AuthConfig<MyAuthContext> = { ... }
```

Currently `AuthConfig` cannot properly be derived at all because it is generic.

```ts
type AuthConfig = Parameters<typeof authExchange>[0] // => AuthConfig<unknown>
```

## Set of changes

 - re-export `AuthConfig<T>` from `authExchange.ts`


changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 89a92bc76457af25bf3be72a674d16654f2f29ff

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/arempe93/urql/new/fix-auth-types?filename=.changeset/purple-monkeys-dream.md&value=---%0A%22%40urql%2Fexchange-auth%22%3A%20patch%0A---%0A%0A(auth)%20-%20expose%20AuthConfig%20type%0A)



Patch:
diff --git a/.changeset/spicy-suits-tease.md b/.changeset/spicy-suits-tease.md
new file mode 100644
index 00000000..84a300d0
--- /dev/null
+++ b/.changeset/spicy-suits-tease.md
@@ -0,0 +1,5 @@
+---
+'@urql/exchange-auth': patch
+---
+
+Expose `AuthContext` type
diff --git a/.changeset/weak-doors-cheer.md b/.changeset/weak-doors-cheer.md
new file mode 100644
index 00000000..60fb2aee
--- /dev/null
+++ b/.changeset/weak-doors-cheer.md
@@ -0,0 +1,5 @@
+---
+'@urql/core': patch
+---
+
+Warn for invalid operation passed to query/subscription/mutation
diff --git a/exchanges/auth/src/index.ts b/exchanges/auth/src/index.ts
index e2b0c49b..10de620a 100644
--- a/exchanges/auth/src/index.ts
+++ b/exchanges/auth/src/index.ts
@@ -1,1 +1,1 @@
-export { authExchange } from './authExchange';
+export { authExchange, AuthConfig } from './authExchange';
diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts
index 754035f2..e954b0ab 100755
--- a/packages/core/src/client.ts
+++ b/packages/core/src/client.ts
@@ -46,6 +46,7 @@ import {
   maskTypename,
   noop,
   makeOperation,
+  getOperationType,
 } from './utils';
 
 /** Options for configuring the URQL [client]{@link Client}. */
@@ -289,6 +290,16 @@ export const Client: new (opts: ClientOptions) => Client = function Client(
     },
 
     createRequestOperation(kind, request, opts) {
+      const requestOperationType = getOperationType(request.query);
+      if (
+        process.env.NODE_ENV !== 'production' &&
+        kind !== 'teardown' &&
+        requestOperationType !== kind
+      ) {
+        throw new Error(
+          `Expected operation of type "${kind}" but found "${requestOperationType}"`
+        );
+      }
       return makeOperation(kind, request, client.createOperationContext(opts));
     },
 
diff --git a/packages/core/src/utils/request.ts b/packages/core/src/utils/request.ts
index 7b85daf7..7fdb8c65 100644
--- a/packages/core/src/utils/request.ts
+++ b/packages/core/src/utils/request.ts
@@ -98,3 +98,15 @@ export const getOperationName = (query: DocumentNode): string | undefined => {
     }
   }
 };
+
+/**
+ * Finds the operation-type
+ */
+export const getOperationType = (query: DocumentNode): string | undefined => {
+  for (let i = 0, l = query.definitions.length; i < l; i++) {
+    const node = query.definitions[i];
+    if (node.kind === Kind.OPERATION_DEFINITION) {
+      return node.operation;
+    }
+  }
+};


Test patch:
diff --git a/packages/core/src/client.test.ts b/packages/core/src/client.test.ts
index 98df50bd..57f40fe5 100755
--- a/packages/core/src/client.test.ts
+++ b/packages/core/src/client.test.ts
@@ -52,6 +52,30 @@ const query = {
   variables: { example: 1234 },
 };
 
+const mutation = {
+  key: 1,
+  query: gql`
+    mutation {
+      todos {
+        id
+      }
+    }
+  `,
+  variables: { example: 1234 },
+};
+
+const subscription = {
+  key: 1,
+  query: gql`
+    subscription {
+      todos {
+        id
+      }
+    }
+  `,
+  variables: { example: 1234 },
+};
+
 let receivedOps: Operation[] = [];
 let client = createClient({ url: '1234' });
 const receiveMock = jest.fn((s: Source<Operation>) =>
@@ -119,21 +143,17 @@ describe('promisified methods', () => {
   });
 
   it('mutation', () => {
-    const mutationResult = client
-      .mutation(
-        gql`
-          {
-            todos {
-              id
-            }
-          }
-        `,
-        { example: 1234 }
-      )
-      .toPromise();
+    const mut = gql`
+      mutation {
+        todos {
+          id
+        }
+      }
+    `;
+    const mutationResult = client.mutation(mut, { example: 1234 }).toPromise();
 
     const received = receivedOps[0];
-    expect(print(received.query)).toEqual(print(query.query));
+    expect(print(received.query)).toEqual(print(mut));
     expect(received.key).toBeDefined();
     expect(received.variables).toEqual({ example: 1234 });
     expect(received.kind).toEqual('mutation');
@@ -187,6 +207,17 @@ describe('executeQuery', () => {
     expect(print(receivedQuery)).toBe(print(query.query));
   });
 
+  it('should throw when passing in a mutation', () => {
+    try {
+      client.executeQuery(mutation);
+      expect(true).toBeFalsy();
+    } catch (e) {
+      expect(e.message).toMatchInlineSnapshot(
+        `"Expected operation of type \\"query\\" but found \\"mutation\\""`
+      );
+    }
+  });
+
   it('passes variables type to exchange', () => {
     pipe(
       client.executeQuery(query),
@@ -242,17 +273,17 @@ describe('executeQuery', () => {
 describe('executeMutation', () => {
   it('passes query string exchange', async () => {
     pipe(
-      client.executeMutation(query),
+      client.executeMutation(mutation),
       subscribe(x => x)
     );
 
     const receivedQuery = receivedOps[0].query;
-    expect(print(receivedQuery)).toBe(print(query.query));
+    expect(print(receivedQuery)).toBe(print(mutation.query));
   });
 
   it('passes variables type to exchange', () => {
     pipe(
-      client.executeMutation(query),
+      client.executeMutation(mutation),
       subscribe(x => x)
     );
 
@@ -261,7 +292,7 @@ describe('executeMutation', () => {
 
   it('passes kind type to exchange', () => {
     pipe(
-      client.executeMutation(query),
+      client.executeMutation(mutation),
       subscribe(x => x)
     );
 
@@ -270,7 +301,7 @@ describe('executeMutation', () => {
 
   it('passes url (from context) to exchange', () => {
     pipe(
-      client.executeMutation(query),
+      client.executeMutation(mutation),
       subscribe(x => x)
     );
 
@@ -281,26 +312,26 @@ describe('executeMutation', () => {
 describe('executeSubscription', () => {
   it('passes query string exchange', async () => {
     pipe(
-      client.executeSubscription(query),
+      client.executeSubscription(subscription),
       subscribe(x => x)
     );
 
     const receivedQuery = receivedOps[0].query;
-    expect(print(receivedQuery)).toBe(print(query.query));
+    expect(print(receivedQuery)).toBe(print(subscription.query));
   });
 
   it('passes variables type to exchange', () => {
     pipe(
-      client.executeSubscription(query),
+      client.executeSubscription(subscription),
       subscribe(x => x)
     );
 
-    expect(receivedOps[0]).toHaveProperty('variables', query.variables);
+    expect(receivedOps[0]).toHaveProperty('variables', subscription.variables);
   });
 
   it('passes kind type to exchange', () => {
     pipe(
-      client.executeSubscription(query),
+      client.executeSubscription(subscription),
       subscribe(x => x)
     );