Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
753fd5e
install pkgroll
enisdenjo Jan 10, 2025
0a1ee83
bump node 20
enisdenjo Jan 10, 2025
a179963
changeset
enisdenjo Jan 10, 2025
6407524
graphql latest
enisdenjo Jan 10, 2025
85dd6d1
a lot
enisdenjo Jan 10, 2025
7f3426b
fixes and stuff
enisdenjo Jan 10, 2025
e132cef
drop eslint and check typeS
enisdenjo Jan 10, 2025
65929fd
rollup uses dist and no plugins lol
enisdenjo Jan 10, 2025
0307335
reorder scripts and blah
enisdenjo Jan 10, 2025
d3ea2ca
cleanup deps
enisdenjo Jan 10, 2025
0d708e9
bump ws
enisdenjo Jan 10, 2025
4d56941
always website
enisdenjo Jan 10, 2025
60a071b
bump typedocs
enisdenjo Jan 10, 2025
cefd42e
remove /index from links too
enisdenjo Jan 10, 2025
ee4be7c
hide page header
enisdenjo Jan 10, 2025
4f8d698
chcek types
enisdenjo Jan 10, 2025
49a1f9f
check types 2
enisdenjo Jan 10, 2025
a16f2fd
changeset
enisdenjo Jan 13, 2025
fb0e3b3
remove isFatalConnectionProblem
enisdenjo Jan 13, 2025
c3224ad
remove isMessage
enisdenjo Jan 13, 2025
47fb627
bump graphql
enisdenjo Jan 13, 2025
f8d13bb
describe concurrent and ping must have key
enisdenjo Jan 13, 2025
51bb411
graphql ^15.10.1 peer dependencies
enisdenjo Jan 14, 2025
604e659
no tsconfig for builds
enisdenjo Jan 14, 2025
a838798
catch subscribe thrown errors
enisdenjo Jan 14, 2025
e2cd432
no close but throw
enisdenjo Jan 14, 2025
afa2699
buble test fails when waiting
enisdenjo Jan 14, 2025
f96af3d
make sure server doesnt close
enisdenjo Jan 14, 2025
d000e6c
chagneset
enisdenjo Jan 14, 2025
f2e60eb
fix(server): onError should return GraphQLFormattedError (#599)
benjie Jan 14, 2025
139d039
bump deps
enisdenjo Jan 14, 2025
c1b7859
dot
enisdenjo Jan 14, 2025
2002d68
formatted execution resul
enisdenjo Jan 14, 2025
f2d7b7a
common and utils use only types from graphql
enisdenjo Jan 14, 2025
68721ae
no full messages in hooks
enisdenjo Jan 14, 2025
dd8d588
check and test node and graphql matrix
enisdenjo Jan 14, 2025
8d563aa
with graphql
enisdenjo Jan 14, 2025
8ffe9b5
add --dev
enisdenjo Jan 14, 2025
e7ed3a8
check name
enisdenjo Jan 14, 2025
a784a01
tsignore
enisdenjo Jan 14, 2025
762205f
shorter name in test
enisdenjo Jan 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/clean-seas-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'graphql-ws': major
---

Drop support for `ws` v7

`ws` v7 has been deprecated. Please upgrade and use v8.
7 changes: 7 additions & 0 deletions .changeset/friendly-cats-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'graphql-ws': major
---

Drop support for deprecated `fastify-websocket`

[`fastify-websocket` has been deprecated since v4.3.0.](https://www.npmjs.com/package/fastify-websocket). Please upgrade and use [`@fastify/websocket`](https://github.com/fastify/fastify-websocket).
44 changes: 44 additions & 0 deletions .changeset/lemon-dolls-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
'graphql-ws': major
---

The `/lib/` part from imports has been removed, for example `graphql-ws/lib/use/ws` becomes `graphql-ws/use/ws`

### Migrating from v5 to v6

Simply remove the `/lib/` part from your graphql-ws imports that use a handler.

#### ws

```diff
- import { useServer } from 'graphql-ws/lib/use/ws';
+ import { useServer } from 'graphql-ws/use/ws';
```

#### uWebSockets.js

```diff
- import { makeBehavior } from 'graphql-ws/lib/use/uWebSockets';
+ import { makeBehavior } from 'graphql-ws/use/uWebSockets';
```

#### @fastify/websocket

```diff
- import { makeHandler } from 'graphql-ws/lib/use/@fastify/websocket';
+ import { makeHandler } from 'graphql-ws/use/@fastify/websocket';
```

#### Bun

```diff
- import { handleProtocols, makeHandler } from 'graphql-ws/lib/use/bun';
+ import { handleProtocols, makeHandler } from 'graphql-ws/use/bun';
```

#### Deno

```diff
- import { makeHandler } from 'https://esm.sh/graphql-ws/lib/use/deno';
+ import { makeHandler } from 'https://esm.sh/graphql-ws/use/deno';
```
5 changes: 5 additions & 0 deletions .changeset/long-glasses-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'graphql-ws': major
---

`ErrorMessage` uses and `onError` returns `GraphQLFormattedError` (instead of `GraphQLError`)
17 changes: 17 additions & 0 deletions .changeset/nervous-peaches-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'graphql-ws': minor
---

Client is truly zero-dependency, not even a peer dependency on `graphql`

In non-browser environments, you can use only the client and not even depend on `graphql` by importing from `graphql-ws/client`.

```ts
import { createClient } from 'graphql-ws/client';

const client = createClient({
url: 'ws://localhost:4000/graphql'
});
```

Note that, in browser envirments (and of course having your bundler use the [`browser` package.json field](https://docs.npmjs.com/cli/v11/configuring-npm/package-json#browser)), you don't have to import from `graphql-ws/client` - simply importing from `graphql-ws` will only have the `createClient` available.
7 changes: 7 additions & 0 deletions .changeset/proud-emus-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'graphql-ws': major
---

Least supported Node version is v20

Node v10 has been deprecated for years now. There is no reason to support it. Bumping the engine to the current LTS (v20) also allows the code to be leaner and use less polyfills.
7 changes: 7 additions & 0 deletions .changeset/shaggy-geese-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'graphql-ws': major
---

Least supported `graphql` peer dependency is ^15.10.0 and ^16.10.0

Users are advised to use the latest of `graphql` because of various improvements in performance and security.
5 changes: 5 additions & 0 deletions .changeset/stale-tomatoes-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'graphql-ws': major
---

`NextMessage` uses and `onNext` returns `FormattedExecutionResult` (instead of `ExecutionResult`)
107 changes: 107 additions & 0 deletions .changeset/strange-ties-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
'graphql-ws': major
---

`onSubscribe`, `onOperation`, `onError`, `onNext` and `onComplete` hooks don't have the full accompanying message anymore, only the ID and the relevant part from the message

There is really no need to pass the full `SubscribeMessage` to the `onSubscribe` hook. The only relevant parts from the message are the `id` and the `payload`, the `type` is useless since the hook inherently has it (`onNext` is `next` type, `onError` is `error` type, etc).

The actual techincal reason for not having the full message is to avoid serialising results and errors twice. Both `onNext` and `onError` allow the user to augment the result and return it to be used instead. `onNext` originally had the `NextMessage` argument which already has the `FormattedExecutionResult`, and `onError` originally had the `ErrorMessage` argument which already has the `GraphQLFormattedError`, and they both also returned `FormattedExecutionResult` and `GraphQLFormattedError` respectivelly - meaning, if the user serialised the results - the serialisation would happen **twice**.

### Migrating from v5 to v6

#### `onSubscribe`

```diff
import { ServerOptions, SubscribePayload } from 'graphql-ws';

const opts: ServerOptions = {
- onSubscribe(ctx, message) {
- const messageId = message.id;
- const messagePayload: SubscribePayload = message.payload;
- },
+ onSubscribe(ctx, id, payload) {
+ const messageId = id;
+ const messagePayload: SubscribePayload = payload;
+ },
};
```

#### `onOperation`

The `SubscribeMessage.payload` is not useful here at all, the `payload` has been parsed to ready-to-use graphql execution args and should be used instead.

```diff
import { ExecutionArgs } from 'graphql';
import { ServerOptions, SubscribePayload } from 'graphql-ws';

const opts: ServerOptions = {
- onOperation(ctx, message) {
- const messageId = message.id;
- const messagePayload: SubscribePayload = message.payload;
- },
+ onOperation(ctx, id, args) {
+ const messageId = id;
+ const executionArgs: ExecutionArgs = args;
+ },
};
```

#### `onError`

The `ErrorMessage.payload` (`GraphQLFormattedError[]`) is not useful here at all, the user has access to `GraphQLError[]` that are true instances of the error containing object references to `originalError`s and other properties. The user can always convert and return `GraphQLFormattedError[]` by using the `.toJSON()` method.

```diff
import { GraphQLError, GraphQLFormattedError } from 'graphql';
import { ServerOptions } from 'graphql-ws';

const opts: ServerOptions = {
- onError(ctx, message, errors) {
- const messageId = message.id;
- const graphqlErrors: readonly GraphQLError[] = errors;
- const messagePayload: readonly GraphQLFormattedError[] = message.payload;
- },
+ onError(ctx, id, errors) {
+ const messageId = id;
+ const graphqlErrors: readonly GraphQLError[] = errors;
+ const messagePayload: readonly GraphQLFormattedError[] = errors.map((e) => e.toJSON());
+ },
};
```

#### `onNext`

The `NextMessage.payload` (`FormattedExecutionResult`) is not useful here at all, the user has access to `ExecutionResult` that contains actual object references to error instances. The user can always convert and return `FormattedExecutionResult` by serialising the errors with `GraphQLError.toJSON()` method.

```diff
import { ExecutionResult, FormattedExecutionResult } from 'graphql';
import { ServerOptions } from 'graphql-ws';

const opts: ServerOptions = {
- onNext(ctx, message, result) {
- const messageId = message.id;
- const graphqlResult: ExecutionResult = result;
- const messagePayload: FormattedExecutionResult = message.payload;
- },
+ onNext(ctx, id, result) {
+ const messageId = id;
+ const graphqlResult: ExecutionResult = result;
+ const messagePayload: FormattedExecutionResult = { ...result, errors: result.errors?.map((e) => e.toJSON()) };
+ },
};
```

#### `onComplete`

```diff
import { ServerOptions } from 'graphql-ws';

const opts: ServerOptions = {
- onComplete(ctx, message) {
- const messageId = message.id;
- },
+ onComplete(ctx, id) {
+ const messageId = id;
+ },
};
```
49 changes: 49 additions & 0 deletions .changeset/tiny-worms-fry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
'graphql-ws': major
---

Errors thrown from subscription iterables will be caught and reported through the `ErrorMessage`

Compared to the behaviour before, which terminated the whole WebSocket connection - those errors are now gracefully reported and terminate only the specific subscription that threw the error.

There's been [an editorial change in the GraphQL Spec suggesting this being the correct approach](https://github.com/graphql/graphql-spec/pull/1099).

Also, if you'd like to get involved and ideally drop your opinion about whether iterable errors should be reported as errors or `ExecutionResult`s with `errors` field set, [please read more here](https://github.com/graphql/graphql-spec/pull/1127).

### Migrating from v5 to v6

If you had used the suggested "ws server usage with custom subscribe method that gracefully handles thrown errors" recipe, you can simply remove it since this behaviour is now baked in.

```diff
import { subscribe } from 'graphql';
import { useServer } from 'graphql-ws/use/ws';
import { WebSocketServer } from 'ws'; // yarn add ws

const wsServer = new WebSocketServer({
port: 4000,
path: '/graphql',
});

useServer(
{
schema,
- async subscribe(...args) {
- const result = await subscribe(...args);
- if ('next' in result) {
- // is an async iterable, augment the next method to handle thrown errors
- const originalNext = result.next;
- result.next = async () => {
- try {
- return await originalNext();
- } catch (err) {
- // gracefully handle the error thrown from the next method
- return { value: { errors: [err] } };
- }
- };
- }
- return result;
- },
},
wsServer,
);
```
24 changes: 24 additions & 0 deletions .changeset/twelve-rabbits-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
'graphql-ws': major
---

Remove deprecated `isMessage`, use `validateMessage` instead

### Migrating from v5 to v6

Replace all ocurrances of `isMessage` with `validateMessage`. Note that `validateMessage` throws if the message is not valid, compared with `isMessage` that simply returned true/false.

```diff
- import { isMessage } from 'graphql-ws';
+ import { validateMessage } from 'graphql-ws';

function isGraphQLWSMessage(val) {
- return isMessage(val);
+ try {
+ validateMessage(val);
+ return true;
+ } catch {
+ return false;
+ }
}
```
19 changes: 19 additions & 0 deletions .changeset/wet-teachers-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'graphql-ws': major
---

Removed deprecated `isFatalConnectionProblem`, use `shouldRetry` instead

### Migrating from v5 to v6

Replace all ocurrances of `isFatalConnectionProblem` with `shouldRetry`. Note that the result is inverted, where you returned `false` in `isFatalConnectionProblem` you should return `true` in `shouldRetry`.

```diff
import { createClient } from 'graphql-ws';

const client = createClient({
url: 'ws://localhost:4000/graphql',
- isFatalConnectionProblem: () => false,
+ shouldRetry: () => true,
});
```
23 changes: 0 additions & 23 deletions .eslintrc.js

This file was deleted.

31 changes: 16 additions & 15 deletions .github/workflows/ci.yml → .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI
name: Check

on:
push:
Expand All @@ -7,15 +7,8 @@ on:
pull_request:

jobs:
check:
strategy:
fail-fast: false
matrix:
check:
- format
- lint
- type
name: Check ${{ matrix.check }}
format:
name: Format
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -25,17 +18,25 @@ jobs:
with:
node-version-file: .node-version
- name: Check
run: yarn check:${{ matrix.check }}
run: yarn check:format

test:
name: Test
types:
name: Types with graphql@${{matrix.graphql}}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
graphql: [15, 16]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup
uses: the-guild-org/shared-config/setup@v1
with:
node-version-file: .node-version
- name: Test
run: yarn test
- name: Install
run: yarn add --dev graphql@${{matrix.graphql}}
- name: Info
run: yarn info graphql
- name: Check
run: yarn check:types
Loading