graphql-ws
Advanced tools
Comparing version
@@ -346,2 +346,15 @@ /** | ||
subscribe<Data = Record<string, unknown>, Extensions = unknown>(payload: SubscribePayload, sink: Sink<ExecutionResult<Data, Extensions>>): () => void; | ||
/** | ||
* Terminates the WebSocket abruptly and immediately. | ||
* | ||
* A close event `4499: Terminated` is issued to the current WebSocket and an | ||
* artificial `{ code: 4499, reason: 'Terminated', wasClean: false }` close-event-like | ||
* object is immediately emitted without waiting for the one coming from `WebSocket.onclose`. | ||
* | ||
* Terminating is not considered fatal and a connection retry will occur as expected. | ||
* | ||
* Useful in cases where the WebSocket is stuck and not emitting any events; | ||
* can happen on iOS Safari, see: https://github.com/enisdenjo/graphql-ws/discussions/290. | ||
*/ | ||
terminate(): void; | ||
} | ||
@@ -348,0 +361,0 @@ /** |
@@ -175,2 +175,7 @@ "use strict"; | ||
denied(errOrEvent); | ||
if (isLikeCloseEvent(errOrEvent) && errOrEvent.code === 4499) { | ||
socket.close(4499, 'Terminated'); // close event is artificial and emitted manually, see `Client.terminate()` below | ||
socket.onerror = null; | ||
socket.onclose = null; | ||
} | ||
}); | ||
@@ -312,2 +317,3 @@ socket.onerror = (err) => emitter.emit('error', err); | ||
common_1.CloseCode.TooManyInitialisationRequests, | ||
// 4499, // Terminated, probably because the socket froze, we want to retry | ||
].includes(errOrCloseEvent.code))) | ||
@@ -439,2 +445,12 @@ throw errOrCloseEvent; | ||
}, | ||
terminate() { | ||
if (connecting) { | ||
// only if there is a connection | ||
emitter.emit('closed', { | ||
code: 4499, | ||
reason: 'Terminated', | ||
wasClean: false, | ||
}); | ||
} | ||
}, | ||
}; | ||
@@ -441,0 +457,0 @@ } |
{ | ||
"name": "graphql-ws", | ||
"version": "5.6.4", | ||
"version": "5.7.0", | ||
"description": "Coherent, zero-dependency, lazy, simple, GraphQL over WebSocket Protocol compliant server and client", | ||
@@ -85,3 +85,3 @@ "keywords": [ | ||
"devDependencies": { | ||
"@babel/core": "^7.17.8", | ||
"@babel/core": "^7.17.9", | ||
"@babel/plugin-proposal-class-properties": "^7.16.7", | ||
@@ -98,9 +98,9 @@ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", | ||
"@types/ws": "^8.5.3", | ||
"@typescript-eslint/eslint-plugin": "^5.16.0", | ||
"@typescript-eslint/parser": "^5.16.0", | ||
"@typescript-eslint/eslint-plugin": "^5.18.0", | ||
"@typescript-eslint/parser": "^5.18.0", | ||
"babel-jest": "^27.5.1", | ||
"eslint": "^8.11.0", | ||
"eslint": "^8.12.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"fastify": "^3.27.4", | ||
"fastify": "^3.28.0", | ||
"fastify-websocket": "^4.2.1", | ||
@@ -110,3 +110,3 @@ "glob": "^7.2.0", | ||
"jest": "^27.5.1", | ||
"prettier": "^2.6.0", | ||
"prettier": "^2.6.2", | ||
"replacestream": "^4.0.3", | ||
@@ -118,5 +118,5 @@ "rollup": "^2.70.1", | ||
"tslib": "^2.3.1", | ||
"typedoc": "^0.22.13", | ||
"typedoc": "^0.22.14", | ||
"typedoc-plugin-markdown": "^3.11.14", | ||
"typescript": "^4.6.2", | ||
"typescript": "^4.6.3", | ||
"uWebSockets.js": "uNetworking/uWebSockets.js#v20.6.0", | ||
@@ -123,0 +123,0 @@ "ws": "^8.5.0", |
@@ -19,2 +19,4 @@ # GraphQL over WebSocket Protocol | ||
Multiple operations identified with separate IDs can be active at any time and their messages can be interleaved on the connection. | ||
The server can close the socket (kick the client off) at any time. The close event dispatched by the server is used to describe the fatal error to the client. | ||
@@ -102,4 +104,6 @@ | ||
If there is already an active subscriber for an operation matching the provided ID, regardless of the operation type, the server must close the socket immediately with the event `4409: Subscriber for <unique-operation-id> already exists`. | ||
If there is already an active subscriber for an operation matching the provided ID, regardless of the operation type, the server **must** close the socket immediately with the event `4409: Subscriber for <unique-operation-id> already exists`. | ||
The server needs only keep track of IDs for as long as the subscription is active. Once a client completes an operation, it is free to re-use that ID. | ||
```typescript | ||
@@ -140,3 +144,3 @@ interface SubscribeMessage { | ||
Operation execution error(s) triggered by the `Next` message happening before the actual execution, usually due to validation errors. | ||
Operation execution error(s) in response to the `Subscribe` message. This can occur _before_ execution starts, usually due to validation errors, or _during_ the execution of the request. This message terminates the operation and no further messages will be sent. | ||
@@ -159,4 +163,6 @@ ```typescript | ||
- **Client -> Server** indicates that the client has stopped listening and wants to complete the subscription. No further events, relevant to the original subscription, should be sent through. Even if the client completed a single result operation before it resolved, the result should not be sent through once it does. | ||
- **Client -> Server** indicates that the client has stopped listening and wants to complete the subscription. No further events, relevant to the original subscription, should be sent through. Even if the client sent a `Complete` message for a _single-result-operation_ before it resolved, the result should not be sent through once it does. | ||
Note: The asynchronous nature of the full-duplex connection means that a client can send a `Complete` message to the server even when messages are in-flight to the client, or when the server has itself completed the operation (via a `Error` or `Complete` message). Both client and server must therefore be prepared to receive (and ignore) messages for operations that they consider already completed. | ||
```typescript | ||
@@ -175,2 +181,4 @@ interface CompleteMessage { | ||
Receiving a message (other than `Subscribe`) with an ID that belongs to an operation that has been previously completed does not constitute an error. It is permissable to simply ignore all _unknown_ IDs without closing the connection. | ||
## Examples | ||
@@ -197,15 +205,2 @@ | ||
### Single result operation | ||
#### `query` and `mutation` operations without streaming directives | ||
_The client and the server has already gone through [successful connection initialisation](#successful-connection-initialisation)._ | ||
1. _Client_ generates a unique ID for the following operation | ||
1. _Client_ dispatches the `Subscribe` message with the generated ID through the `id` field and the requested operation passed through the `payload` field | ||
<br>_All future communication is linked through this unique ID_ | ||
1. _Server_ executes the single result GraphQL operation | ||
1. _Server_ dispatches the result with the `Next` message | ||
1. _Server_ dispatches the `Complete` message indicating that the execution has completed | ||
### Streaming operation | ||
@@ -226,7 +221,37 @@ | ||
1. _Server_ _optionally_ checks if the operation is valid before starting executing it, e.g. checking permissions | ||
- If **not** valid, the _server_ sends an `Error` message and deems the operation complete. | ||
- If valid, continue... | ||
1. _Server_ dispatches results over time with the `Next` message | ||
1. - _Client_ stops the subscription by dispatching a `Complete` message | ||
- _Server_ completes the source stream | ||
<br>_or_ | ||
1. - _Server_ dispatches the `Complete` message indicating that the source stream has completed | ||
- _Client_ completes the stream observer | ||
<br>**or** | ||
- _Client_ stops the subscription by dispatching a `Complete` message | ||
- _Server_ receives `Complete` message and completes the source stream | ||
- _Client_ ignores all further messages that it recives with this ID | ||
<br>**or** | ||
- _Server_ dispatches the `Complete` message indicating that the source stream has completed | ||
- _Client_ completes the stream observer | ||
- **Simultaneously** _client_ stops the subscription by dispatching a `Complete` message | ||
- _Client_ ignores all further messages that it recives with this ID | ||
- _Server_ ignores the `Complete` message from the client | ||
### Single result operation | ||
#### `query` and `mutation` operations without streaming directives | ||
A single result operation is identical to a streaming operation except that _at most one_ `Next` message is sent. | ||
It shares the same name-space for IDs as streaming operations and can be multiplexed with other operations on the connection. | ||
_The client and the server has already gone through [successful connection initialisation](#successful-connection-initialisation)._ | ||
1. _Client_ generates a unique ID for the following operation | ||
1. _Client_ dispatches the `Subscribe` message with the generated ID through the `id` field and the requested operation passed through the `payload` field | ||
<br>_All future communication is linked through this unique ID_ | ||
1. _Server_ executes the single result GraphQL operation | ||
1. _Server_ dispatches the result with the `Next` message | ||
1. _Server_ dispatches the `Complete` message indicating that the execution has completed | ||
The _client_ may dispatch a `Complete` message at any time, just as shown in the streaming operations examples above, and the same interactions ensue. |
@@ -423,16 +423,18 @@ <div align="center"> | ||
// to define your own GraphQLWsLink. | ||
import { GraphQLWsLink } from "@apollo/client/link/subscriptions"; | ||
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; | ||
const link = new GraphQLWsLink(createClient({ | ||
url: 'ws://where.is:4000/graphql', | ||
connectionParams: () => { | ||
const session = getSession(); | ||
if (!session) { | ||
return {}; | ||
} | ||
return { | ||
Authorization: `Bearer ${session.token}`, | ||
}; | ||
}, | ||
}); | ||
const link = new GraphQLWsLink( | ||
createClient({ | ||
url: 'ws://where.is:4000/graphql', | ||
connectionParams: () => { | ||
const session = getSession(); | ||
if (!session) { | ||
return {}; | ||
} | ||
return { | ||
Authorization: `Bearer ${session.token}`, | ||
}; | ||
}, | ||
}), | ||
); | ||
``` | ||
@@ -475,3 +477,3 @@ | ||
</details> | ||
<details id="kotlin"> | ||
@@ -693,2 +695,38 @@ <summary><a href="#kotlin">🔗</a> Client usage with <a href="https://github.com/apollographql/apollo-kotlin">Apollo Kotlin</a></summary> | ||
<details id="client-terminate"> | ||
<summary><a href="#client-terminate">🔗</a> Client usage with abrupt termination on pong timeout</summary> | ||
```typescript | ||
import { createClient } from 'graphql-ws'; | ||
let timedOut; | ||
const client = createClient({ | ||
url: 'ws://terminate.me:4000/on-pong-timeout', | ||
keepAlive: 10_000, // ping server every 10 seconds | ||
on: { | ||
ping: (received) => { | ||
if (!received /* sent */) { | ||
timedOut = setTimeout(() => { | ||
// a close event `4499: Terminated` is issued to the current WebSocket and an | ||
// artificial `{ code: 4499, reason: 'Terminated', wasClean: false }` close-event-like | ||
// object is immediately emitted without waiting for the one coming from `WebSocket.onclose` | ||
// | ||
// calling terminate is not considered fatal and a connection retry will occur as expected | ||
// | ||
// see: https://github.com/enisdenjo/graphql-ws/discussions/290 | ||
client.terminate(); | ||
}, 5_000); | ||
} | ||
}, | ||
pong: (received) => { | ||
if (received) { | ||
clearTimeout(timedOut); | ||
} | ||
}, | ||
}, | ||
}); | ||
``` | ||
</details> | ||
<details id="custom-client-pinger"> | ||
@@ -1173,3 +1211,3 @@ <summary><a href="#custom-client-pinger">🔗</a> Client usage with manual pings and pongs</summary> | ||
// create apollo server | ||
const server = new ApolloServer({ | ||
const apolloServer = new ApolloServer({ | ||
schema, | ||
@@ -1757,4 +1795,4 @@ plugins: [ | ||
This library and the [GraphQL over WebSocket Protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) are **not** cross-compatible with the legacy [`subscriptions-transport-ws`](https://github.com/apollographql/subscriptions-transport-ws) and its [accompanying Protocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md). | ||
This library and the [GraphQL over WebSocket Protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) are **not** cross-compatible with the [deprecated `subscriptions-transport-ws`](https://github.com/apollographql/subscriptions-transport-ws) and its [accompanying Protocol](https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md). | ||
You must use `graphql-ws` coherently and implement the [GraphQL over WebSocket Protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) on both sides, server and the client. |
@@ -334,2 +334,7 @@ (function (global, factory) { | ||
denied(errOrEvent); | ||
if (isLikeCloseEvent(errOrEvent) && errOrEvent.code === 4499) { | ||
socket.close(4499, 'Terminated'); // close event is artificial and emitted manually, see `Client.terminate()` below | ||
socket.onerror = null; | ||
socket.onclose = null; | ||
} | ||
}); | ||
@@ -471,2 +476,3 @@ socket.onerror = (err) => emitter.emit('error', err); | ||
exports.CloseCode.TooManyInitialisationRequests, | ||
// 4499, // Terminated, probably because the socket froze, we want to retry | ||
].includes(errOrCloseEvent.code))) | ||
@@ -598,2 +604,12 @@ throw errOrCloseEvent; | ||
}, | ||
terminate() { | ||
if (connecting) { | ||
// only if there is a connection | ||
emitter.emit('closed', { | ||
code: 4499, | ||
reason: 'Terminated', | ||
wasClean: false, | ||
}); | ||
} | ||
}, | ||
}; | ||
@@ -600,0 +616,0 @@ } |
@@ -1,1 +0,1 @@ | ||
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports):"function"==typeof define&&define.amd?define(["exports"],o):o((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlWs={})}(this,(function(e){"use strict";const o=Object.prototype.hasOwnProperty;function n(e){return"object"==typeof e&&null!==e}function t(e,n){return o.call(e,n)}function r(e,t){return o.call(e,t)&&n(e[t])}function i(e,n){return o.call(e,n)&&"string"==typeof e[n]}function a(e,o){return e.length<124?e:o}const s="graphql-transport-ws";var c,l;function d(o){if(n(o)){if(!i(o,"type"))return!1;switch(o.type){case e.MessageType.ConnectionInit:case e.MessageType.ConnectionAck:case e.MessageType.Ping:case e.MessageType.Pong:return!t(o,"payload")||void 0===o.payload||n(o.payload);case e.MessageType.Subscribe:return i(o,"id")&&r(o,"payload")&&(!t(o.payload,"operationName")||void 0===o.payload.operationName||null===o.payload.operationName||"string"==typeof o.payload.operationName)&&i(o.payload,"query")&&(!t(o.payload,"variables")||void 0===o.payload.variables||null===o.payload.variables||r(o.payload,"variables"))&&(!t(o.payload,"extensions")||void 0===o.payload.extensions||null===o.payload.extensions||r(o.payload,"extensions"));case e.MessageType.Next:return i(o,"id")&&r(o,"payload");case e.MessageType.Error:return i(o,"id")&&(a=o.payload,Array.isArray(a)&&a.length>0&&a.every((e=>"message"in e)));case e.MessageType.Complete:return i(o,"id");default:return!1}}var a;return!1}function p(e,o){if(d(e))return e;if("string"!=typeof e)throw new Error("Message not parsable");const n=JSON.parse(e,o);if(!d(n))throw new Error("Invalid message");return n}function u(e,o){if(!d(e))throw new Error("Cannot stringify invalid message");return JSON.stringify(e,o)}function y(e){return n(e)&&"code"in e&&"reason"in e}e.CloseCode=void 0,(c=e.CloseCode||(e.CloseCode={}))[c.InternalServerError=4500]="InternalServerError",c[c.InternalClientError=4005]="InternalClientError",c[c.BadRequest=4400]="BadRequest",c[c.BadResponse=4004]="BadResponse",c[c.Unauthorized=4401]="Unauthorized",c[c.Forbidden=4403]="Forbidden",c[c.SubprotocolNotAcceptable=4406]="SubprotocolNotAcceptable",c[c.ConnectionInitialisationTimeout=4408]="ConnectionInitialisationTimeout",c[c.ConnectionAcknowledgementTimeout=4504]="ConnectionAcknowledgementTimeout",c[c.SubscriberAlreadyExists=4409]="SubscriberAlreadyExists",c[c.TooManyInitialisationRequests=4429]="TooManyInitialisationRequests",e.MessageType=void 0,(l=e.MessageType||(e.MessageType={})).ConnectionInit="connection_init",l.ConnectionAck="connection_ack",l.Ping="ping",l.Pong="pong",l.Subscribe="subscribe",l.Next="next",l.Error="error",l.Complete="complete",e.DEPRECATED_GRAPHQL_WS_PROTOCOL="graphql-ws",e.GRAPHQL_TRANSPORT_WS_PROTOCOL=s,e.createClient=function(o){const{url:n,connectionParams:t,lazy:r=!0,onNonLazyError:i=console.error,lazyCloseTimeout:c=0,keepAlive:l=0,disablePong:d,connectionAckWaitTimeout:g=0,retryAttempts:f=5,retryWait:m=async function(e){let o=1e3;for(let n=0;n<e;n++)o*=2;await new Promise((e=>setTimeout(e,o+Math.floor(2700*Math.random()+300))))},isFatalConnectionProblem:C=(e=>!y(e)),on:b,webSocketImpl:w,generateID:x=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(e=>{const o=16*Math.random()|0;return("x"==e?o:3&o|8).toString(16)}))},jsonMessageReplacer:T,jsonMessageReviver:v}=o;let M;if(w){if(!("function"==typeof(S=w)&&"constructor"in S&&"CLOSED"in S&&"CLOSING"in S&&"CONNECTING"in S&&"OPEN"in S))throw new Error("Invalid WebSocket implementation provided");M=w}else"undefined"!=typeof WebSocket?M=WebSocket:"undefined"!=typeof global?M=global.WebSocket||global.MozWebSocket:"undefined"!=typeof window&&(M=window.WebSocket||window.MozWebSocket);var S;if(!M)throw new Error("WebSocket implementation missing; on Node you can `import WebSocket from 'ws';` and pass `webSocketImpl: WebSocket` to `createClient`");const h=M,E=(()=>{const e=(()=>{const e={};return{on:(o,n)=>(e[o]=n,()=>{delete e[o]}),emit(o){var n;"id"in o&&(null===(n=e[o.id])||void 0===n||n.call(e,o))}}})(),o={connecting:(null==b?void 0:b.connecting)?[b.connecting]:[],opened:(null==b?void 0:b.opened)?[b.opened]:[],connected:(null==b?void 0:b.connected)?[b.connected]:[],ping:(null==b?void 0:b.ping)?[b.ping]:[],pong:(null==b?void 0:b.pong)?[b.pong]:[],message:(null==b?void 0:b.message)?[e.emit,b.message]:[e.emit],closed:(null==b?void 0:b.closed)?[b.closed]:[],error:(null==b?void 0:b.error)?[b.error]:[]};return{onMessage:e.on,on(e,n){const t=o[e];return t.push(n),()=>{t.splice(t.indexOf(n),1)}},emit(e,...n){for(const t of[...o[e]])t(...n)}}})();function P(e){const o=[E.on("error",(n=>{o.forEach((e=>e())),e(n)})),E.on("closed",(n=>{o.forEach((e=>e())),e(n)}))]}let N,I=0,k=!1,A=0,O=!1;async function R(){const[o,r]=await(null!=N?N:N=new Promise(((o,r)=>(async()=>{if(k){if(await m(A),!I)return N=void 0,r({code:1e3,reason:"All Subscriptions Gone"});A++}E.emit("connecting");const i=new h("function"==typeof n?await n():n,s);let c,y;function f(){isFinite(l)&&l>0&&(clearTimeout(y),y=setTimeout((()=>{i.readyState===h.OPEN&&(i.send(u({type:e.MessageType.Ping})),E.emit("ping",!1,void 0))}),l))}P((e=>{N=void 0,clearTimeout(c),clearTimeout(y),r(e)})),i.onerror=e=>E.emit("error",e),i.onclose=e=>E.emit("closed",e),i.onopen=async()=>{try{E.emit("opened",i);const o="function"==typeof t?await t():t;if(i.readyState!==h.OPEN)return;i.send(u(o?{type:e.MessageType.ConnectionInit,payload:o}:{type:e.MessageType.ConnectionInit},T)),isFinite(g)&&g>0&&(c=setTimeout((()=>{i.close(e.CloseCode.ConnectionAcknowledgementTimeout,"Connection acknowledgement timeout")}),g)),f()}catch(o){E.emit("error",o),i.close(e.CloseCode.InternalClientError,a(o instanceof Error?o.message:new Error(o).message,"Internal client error"))}};let C=!1;i.onmessage=({data:n})=>{try{const t=p(n,v);if(E.emit("message",t),"ping"===t.type||"pong"===t.type)return E.emit(t.type,!0,t.payload),void("pong"===t.type?f():d||(i.send(u(t.payload?{type:e.MessageType.Pong,payload:t.payload}:{type:e.MessageType.Pong})),E.emit("pong",!1,t.payload)));if(C)return;if(t.type!==e.MessageType.ConnectionAck)throw new Error(`First message cannot be of type ${t.type}`);clearTimeout(c),C=!0,E.emit("connected",i,t.payload),k=!1,A=0,o([i,new Promise(((e,o)=>P(o)))])}catch(o){i.onmessage=null,E.emit("error",o),i.close(e.CloseCode.BadResponse,a(o instanceof Error?o.message:new Error(o).message,"Bad response"))}}})())));o.readyState===h.CLOSING&&await r;let i=()=>{};const y=new Promise((e=>i=e));return[o,i,Promise.race([y.then((()=>{if(!I){const e=()=>o.close(1e3,"Normal Closure");isFinite(c)&&c>0?setTimeout((()=>{I||o.readyState!==h.OPEN||e()}),c):e()}})),r])]}function W(o){if(y(o)&&(n=o.code,![1e3,1001,1006,1005,1012,1013,1013].includes(n)&&n>=1e3&&n<=1999||[e.CloseCode.InternalServerError,e.CloseCode.InternalClientError,e.CloseCode.BadRequest,e.CloseCode.BadResponse,e.CloseCode.Unauthorized,e.CloseCode.SubprotocolNotAcceptable,e.CloseCode.SubscriberAlreadyExists,e.CloseCode.TooManyInitialisationRequests].includes(o.code)))throw o;var n;if(O)return!1;if(y(o)&&1e3===o.code)return I>0;if(!f||A>=f)throw o;if(C(o))throw o;return k=!0}return r||(async()=>{for(I++;;)try{const[,,e]=await R();await e}catch(e){try{if(!W(e))return}catch(e){return null==i?void 0:i(e)}}})(),{on:E.on,subscribe(o,n){const t=x();let r=!1,i=!1,a=()=>{I--,r=!0};return(async()=>{for(I++;;)try{const[s,c,l]=await R();if(r)return c();const d=E.onMessage(t,(o=>{switch(o.type){case e.MessageType.Next:return void n.next(o.payload);case e.MessageType.Error:return i=!0,r=!0,n.error(o.payload),void a();case e.MessageType.Complete:return r=!0,void a()}}));return s.send(u({id:t,type:e.MessageType.Subscribe,payload:o},T)),a=()=>{r||s.readyState!==h.OPEN||s.send(u({id:t,type:e.MessageType.Complete},T)),I--,r=!0,c()},void await l.finally(d)}catch(e){if(!W(e))return}})().then((()=>{i||n.complete()})).catch((e=>{n.error(e)})),()=>{r||a()}},async dispose(){if(O=!0,N){const[e]=await N;e.close(1e3,"Normal Closure")}}}},e.isMessage=d,e.parseMessage=p,e.stringifyMessage=u,Object.defineProperty(e,"__esModule",{value:!0})})); | ||
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports):"function"==typeof define&&define.amd?define(["exports"],o):o((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlWs={})}(this,(function(e){"use strict";const o=Object.prototype.hasOwnProperty;function n(e){return"object"==typeof e&&null!==e}function t(e,n){return o.call(e,n)}function r(e,t){return o.call(e,t)&&n(e[t])}function i(e,n){return o.call(e,n)&&"string"==typeof e[n]}function a(e,o){return e.length<124?e:o}const s="graphql-transport-ws";var l,c;function d(o){if(n(o)){if(!i(o,"type"))return!1;switch(o.type){case e.MessageType.ConnectionInit:case e.MessageType.ConnectionAck:case e.MessageType.Ping:case e.MessageType.Pong:return!t(o,"payload")||void 0===o.payload||n(o.payload);case e.MessageType.Subscribe:return i(o,"id")&&r(o,"payload")&&(!t(o.payload,"operationName")||void 0===o.payload.operationName||null===o.payload.operationName||"string"==typeof o.payload.operationName)&&i(o.payload,"query")&&(!t(o.payload,"variables")||void 0===o.payload.variables||null===o.payload.variables||r(o.payload,"variables"))&&(!t(o.payload,"extensions")||void 0===o.payload.extensions||null===o.payload.extensions||r(o.payload,"extensions"));case e.MessageType.Next:return i(o,"id")&&r(o,"payload");case e.MessageType.Error:return i(o,"id")&&(a=o.payload,Array.isArray(a)&&a.length>0&&a.every((e=>"message"in e)));case e.MessageType.Complete:return i(o,"id");default:return!1}}var a;return!1}function p(e,o){if(d(e))return e;if("string"!=typeof e)throw new Error("Message not parsable");const n=JSON.parse(e,o);if(!d(n))throw new Error("Invalid message");return n}function u(e,o){if(!d(e))throw new Error("Cannot stringify invalid message");return JSON.stringify(e,o)}function y(e){return n(e)&&"code"in e&&"reason"in e}e.CloseCode=void 0,(l=e.CloseCode||(e.CloseCode={}))[l.InternalServerError=4500]="InternalServerError",l[l.InternalClientError=4005]="InternalClientError",l[l.BadRequest=4400]="BadRequest",l[l.BadResponse=4004]="BadResponse",l[l.Unauthorized=4401]="Unauthorized",l[l.Forbidden=4403]="Forbidden",l[l.SubprotocolNotAcceptable=4406]="SubprotocolNotAcceptable",l[l.ConnectionInitialisationTimeout=4408]="ConnectionInitialisationTimeout",l[l.ConnectionAcknowledgementTimeout=4504]="ConnectionAcknowledgementTimeout",l[l.SubscriberAlreadyExists=4409]="SubscriberAlreadyExists",l[l.TooManyInitialisationRequests=4429]="TooManyInitialisationRequests",e.MessageType=void 0,(c=e.MessageType||(e.MessageType={})).ConnectionInit="connection_init",c.ConnectionAck="connection_ack",c.Ping="ping",c.Pong="pong",c.Subscribe="subscribe",c.Next="next",c.Error="error",c.Complete="complete",e.DEPRECATED_GRAPHQL_WS_PROTOCOL="graphql-ws",e.GRAPHQL_TRANSPORT_WS_PROTOCOL=s,e.createClient=function(o){const{url:n,connectionParams:t,lazy:r=!0,onNonLazyError:i=console.error,lazyCloseTimeout:l=0,keepAlive:c=0,disablePong:d,connectionAckWaitTimeout:g=0,retryAttempts:f=5,retryWait:m=async function(e){let o=1e3;for(let n=0;n<e;n++)o*=2;await new Promise((e=>setTimeout(e,o+Math.floor(2700*Math.random()+300))))},isFatalConnectionProblem:C=(e=>!y(e)),on:b,webSocketImpl:w,generateID:T=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(e=>{const o=16*Math.random()|0;return("x"==e?o:3&o|8).toString(16)}))},jsonMessageReplacer:x,jsonMessageReviver:v}=o;let M;if(w){if(!("function"==typeof(S=w)&&"constructor"in S&&"CLOSED"in S&&"CLOSING"in S&&"CONNECTING"in S&&"OPEN"in S))throw new Error("Invalid WebSocket implementation provided");M=w}else"undefined"!=typeof WebSocket?M=WebSocket:"undefined"!=typeof global?M=global.WebSocket||global.MozWebSocket:"undefined"!=typeof window&&(M=window.WebSocket||window.MozWebSocket);var S;if(!M)throw new Error("WebSocket implementation missing; on Node you can `import WebSocket from 'ws';` and pass `webSocketImpl: WebSocket` to `createClient`");const h=M,E=(()=>{const e=(()=>{const e={};return{on:(o,n)=>(e[o]=n,()=>{delete e[o]}),emit(o){var n;"id"in o&&(null===(n=e[o.id])||void 0===n||n.call(e,o))}}})(),o={connecting:(null==b?void 0:b.connecting)?[b.connecting]:[],opened:(null==b?void 0:b.opened)?[b.opened]:[],connected:(null==b?void 0:b.connected)?[b.connected]:[],ping:(null==b?void 0:b.ping)?[b.ping]:[],pong:(null==b?void 0:b.pong)?[b.pong]:[],message:(null==b?void 0:b.message)?[e.emit,b.message]:[e.emit],closed:(null==b?void 0:b.closed)?[b.closed]:[],error:(null==b?void 0:b.error)?[b.error]:[]};return{onMessage:e.on,on(e,n){const t=o[e];return t.push(n),()=>{t.splice(t.indexOf(n),1)}},emit(e,...n){for(const t of[...o[e]])t(...n)}}})();function P(e){const o=[E.on("error",(n=>{o.forEach((e=>e())),e(n)})),E.on("closed",(n=>{o.forEach((e=>e())),e(n)}))]}let N,I=0,k=!1,A=0,O=!1;async function R(){const[o,r]=await(null!=N?N:N=new Promise(((o,r)=>(async()=>{if(k){if(await m(A),!I)return N=void 0,r({code:1e3,reason:"All Subscriptions Gone"});A++}E.emit("connecting");const i=new h("function"==typeof n?await n():n,s);let l,f;function C(){isFinite(c)&&c>0&&(clearTimeout(f),f=setTimeout((()=>{i.readyState===h.OPEN&&(i.send(u({type:e.MessageType.Ping})),E.emit("ping",!1,void 0))}),c))}P((e=>{N=void 0,clearTimeout(l),clearTimeout(f),r(e),y(e)&&4499===e.code&&(i.close(4499,"Terminated"),i.onerror=null,i.onclose=null)})),i.onerror=e=>E.emit("error",e),i.onclose=e=>E.emit("closed",e),i.onopen=async()=>{try{E.emit("opened",i);const o="function"==typeof t?await t():t;if(i.readyState!==h.OPEN)return;i.send(u(o?{type:e.MessageType.ConnectionInit,payload:o}:{type:e.MessageType.ConnectionInit},x)),isFinite(g)&&g>0&&(l=setTimeout((()=>{i.close(e.CloseCode.ConnectionAcknowledgementTimeout,"Connection acknowledgement timeout")}),g)),C()}catch(o){E.emit("error",o),i.close(e.CloseCode.InternalClientError,a(o instanceof Error?o.message:new Error(o).message,"Internal client error"))}};let b=!1;i.onmessage=({data:n})=>{try{const t=p(n,v);if(E.emit("message",t),"ping"===t.type||"pong"===t.type)return E.emit(t.type,!0,t.payload),void("pong"===t.type?C():d||(i.send(u(t.payload?{type:e.MessageType.Pong,payload:t.payload}:{type:e.MessageType.Pong})),E.emit("pong",!1,t.payload)));if(b)return;if(t.type!==e.MessageType.ConnectionAck)throw new Error(`First message cannot be of type ${t.type}`);clearTimeout(l),b=!0,E.emit("connected",i,t.payload),k=!1,A=0,o([i,new Promise(((e,o)=>P(o)))])}catch(o){i.onmessage=null,E.emit("error",o),i.close(e.CloseCode.BadResponse,a(o instanceof Error?o.message:new Error(o).message,"Bad response"))}}})())));o.readyState===h.CLOSING&&await r;let i=()=>{};const f=new Promise((e=>i=e));return[o,i,Promise.race([f.then((()=>{if(!I){const e=()=>o.close(1e3,"Normal Closure");isFinite(l)&&l>0?setTimeout((()=>{I||o.readyState!==h.OPEN||e()}),l):e()}})),r])]}function W(o){if(y(o)&&(n=o.code,![1e3,1001,1006,1005,1012,1013,1013].includes(n)&&n>=1e3&&n<=1999||[e.CloseCode.InternalServerError,e.CloseCode.InternalClientError,e.CloseCode.BadRequest,e.CloseCode.BadResponse,e.CloseCode.Unauthorized,e.CloseCode.SubprotocolNotAcceptable,e.CloseCode.SubscriberAlreadyExists,e.CloseCode.TooManyInitialisationRequests].includes(o.code)))throw o;var n;if(O)return!1;if(y(o)&&1e3===o.code)return I>0;if(!f||A>=f)throw o;if(C(o))throw o;return k=!0}return r||(async()=>{for(I++;;)try{const[,,e]=await R();await e}catch(e){try{if(!W(e))return}catch(e){return null==i?void 0:i(e)}}})(),{on:E.on,subscribe(o,n){const t=T();let r=!1,i=!1,a=()=>{I--,r=!0};return(async()=>{for(I++;;)try{const[s,l,c]=await R();if(r)return l();const d=E.onMessage(t,(o=>{switch(o.type){case e.MessageType.Next:return void n.next(o.payload);case e.MessageType.Error:return i=!0,r=!0,n.error(o.payload),void a();case e.MessageType.Complete:return r=!0,void a()}}));return s.send(u({id:t,type:e.MessageType.Subscribe,payload:o},x)),a=()=>{r||s.readyState!==h.OPEN||s.send(u({id:t,type:e.MessageType.Complete},x)),I--,r=!0,l()},void await c.finally(d)}catch(e){if(!W(e))return}})().then((()=>{i||n.complete()})).catch((e=>{n.error(e)})),()=>{r||a()}},async dispose(){if(O=!0,N){const[e]=await N;e.close(1e3,"Normal Closure")}},terminate(){N&&E.emit("closed",{code:4499,reason:"Terminated",wasClean:!1})}}},e.isMessage=d,e.parseMessage=p,e.stringifyMessage=u,Object.defineProperty(e,"__esModule",{value:!0})})); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
285142
2.3%4526
1.39%1794
2.16%