Skip to content

Commit

Permalink
feat(client): Inspect incoming messages through `ClientOptions.onMess…
Browse files Browse the repository at this point in the history
…age`

Closes #20
  • Loading branch information
enisdenjo committed Apr 14, 2022
1 parent 70d6cca commit 496e74b
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 6 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,20 @@ const client = createClient({

</details>

<details id="client-debug-messages">
<summary><a href="#client-debug-messages">🔗</a> Client usage with logging of incoming messages (<a href="https://github.com/enisdenjo/graphql-sse/issues/20">browsers don't show them in the DevTools</a>)</summary>

```typescript
import { createClient } from 'graphql-sse';

const client = createClient({
url: 'http://let-me-see.messages:4000/graphql/stream',
onMessage: console.log,
});
```

</details>

<details id="browser">
<summary><a href="#browser">🔗</a> Client usage in browser</summary>

Expand Down
6 changes: 3 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ ___

#### Type parameters

| Name | Type |
| :------ | :------ |
| `T` | `unknown` |
| Name |
| :------ |
| `T` |

#### Parameters

Expand Down
22 changes: 22 additions & 0 deletions docs/interfaces/ClientOptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
### Methods

- [generateID](ClientOptions.md#generateid)
- [onMessage](ClientOptions.md#onmessage)
- [retry](ClientOptions.md#retry)

## Properties
Expand Down Expand Up @@ -198,6 +199,27 @@ Reference: https://gist.github.com/jed/982883

___

### onMessage

`Optional` **onMessage**(`message`): `void`

Browsers show stream messages in the DevTools **only** if they're received through the [native EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource),
and because `graphql-sse` implements a custom SSE parser - received messages will **not** appear in browser's DevTools.

Use this function if you want to inspect valid messages received through the active SSE connection.

#### Parameters

| Name | Type |
| :------ | :------ |
| `message` | [`StreamMessage`](StreamMessage.md)<`SingleConnection`, [`StreamEvent`](../README.md#streamevent)\> |

#### Returns

`void`

___

### retry

`Optional` **retry**(`retries`): `Promise`<`void`\>
Expand Down
73 changes: 73 additions & 0 deletions src/__tests__/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,79 @@ it('should use the provided headers', async (done) => {
);
});

it('should supply all valid messages received to onMessage', async () => {
expect.assertions(4);

const { url } = await startTServer();

// single connection mode
let i = 0;
let client = createClient({
singleConnection: true,
url,
fetchFn: fetch,
retryAttempts: 0,
generateID: () => 'veryunique',
onMessage: (msg) => {
switch (++i) {
case 1:
expect(msg).toEqual({
event: 'next',
data: {
id: 'veryunique',
payload: { data: { getValue: 'value' } },
},
});
return;
case 2:
expect(msg).toEqual({
event: 'complete',
data: { id: 'veryunique' },
});
return;
default:
fail('Unexpected message receieved');
}
},
});
let sub = tsubscribe(client, {
query: '{ getValue }',
});
await sub.waitForComplete();

// distinct connection mode
i = 0;
client = createClient({
singleConnection: false,
url,
fetchFn: fetch,
retryAttempts: 0,
generateID: () => 'veryunique',
onMessage: (msg) => {
switch (++i) {
case 1:
expect(msg).toEqual({
event: 'next',
data: { data: { getValue: 'value' } },
});
return;
case 2:
expect(msg).toEqual({
event: 'complete',
data: null,
});
return;
default:
fail('Unexpected message receieved');
}
},
});
sub = tsubscribe(client, {
query: '{ getValue }',
});
await sub.waitForComplete();
});

describe('single connection mode', () => {
it('should not call complete after subscription error', async () => {
const { url } = await startTServer();
Expand Down
23 changes: 20 additions & 3 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
ExecutionResult,
ExecutionPatchResult,
TOKEN_HEADER_KEY,
StreamEvent,
} from './common';

/** This file is the entry point for browsers, re-export common elements. */
Expand Down Expand Up @@ -154,6 +155,13 @@ export interface ClientOptions<SingleConnection extends boolean = false> {
* @default 'Randomised exponential backoff, 5 times'
*/
retry?: (retries: number) => Promise<void>;
/**
* Browsers show stream messages in the DevTools **only** if they're received through the [native EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource),
* and because `graphql-sse` implements a custom SSE parser - received messages will **not** appear in browser's DevTools.
*
* Use this function if you want to inspect valid messages received through the active SSE connection.
*/
onMessage?: (message: StreamMessage<SingleConnection, StreamEvent>) => void;
}

/** @category Client */
Expand Down Expand Up @@ -226,6 +234,7 @@ export function createClient<SingleConnection extends boolean = false>(
);
},
credentials = 'same-origin',
onMessage,
} = options;
const fetchFn = (options.fetchFn || fetch) as typeof fetch;
const AbortControllerImpl = (options.abortControllerImpl ||
Expand Down Expand Up @@ -329,6 +338,7 @@ export function createClient<SingleConnection extends boolean = false>(
credentials,
url,
fetchFn,
onMessage,
});
retryingErr = null; // future connects are not retries
retries = 0; // reset the retries on connect
Expand Down Expand Up @@ -417,6 +427,7 @@ export function createClient<SingleConnection extends boolean = false>(
url,
body: JSON.stringify(request),
fetchFn,
onMessage,
});
retryingErr = null; // future connects are not retries
retries = 0; // reset the retries on connect
Expand Down Expand Up @@ -623,19 +634,23 @@ interface Connection {
}) => AsyncIterable<ExecutionResult | ExecutionPatchResult>;
}

interface ConnectOptions {
interface ConnectOptions<SingleConnection extends boolean> {
signal: AbortSignal;
url: string;
credentials: 'omit' | 'same-origin' | 'include';
headers?: Record<string, string> | undefined;
body?: string;
fetchFn: typeof fetch;
onMessage:
| ((message: StreamMessage<SingleConnection, StreamEvent>) => void)
| undefined;
}

async function connect<SingleConnection extends boolean>(
options: ConnectOptions,
options: ConnectOptions<SingleConnection>,
): Promise<Connection> {
const { signal, url, credentials, headers, body, fetchFn } = options;
const { signal, url, credentials, headers, body, fetchFn, onMessage } =
options;

const waiting: {
[id: string]: { proceed: () => void };
Expand Down Expand Up @@ -678,6 +693,8 @@ async function connect<SingleConnection extends boolean>(
if (!msgs) continue;

for (const msg of msgs) {
onMessage?.(msg);

const operationId =
msg.data && 'id' in msg.data
? msg.data.id // StreamDataForID
Expand Down

0 comments on commit 496e74b

Please sign in to comment.