graphql-ws
Advanced tools
Comparing version
115
package.json
{ | ||
"name": "graphql-ws", | ||
"version": "5.16.2", | ||
"version": "6.0.0-alpha-2f8a0db0dbf18c4bcf4572a2dfa5935024b27f8b", | ||
"description": "Coherent, zero-dependency, lazy, simple, GraphQL over WebSocket Protocol compliant server and client", | ||
"type": "module", | ||
"repository": { | ||
@@ -14,48 +15,41 @@ "type": "git", | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=20" | ||
}, | ||
"main": "lib/index.js", | ||
"module": "lib/index.mjs", | ||
"main": "dist/index.js", | ||
"exports": { | ||
".": { | ||
"types": "./lib/index.d.ts", | ||
"require": "./lib/index.js", | ||
"import": "./lib/index.mjs", | ||
"browser": "./umd/graphql-ws.js" | ||
"types": "./dist/index.d.ts", | ||
"require": "./dist/index.cjs", | ||
"import": "./dist/index.js", | ||
"browser": "./dist/client.js" | ||
}, | ||
"./lib/use/ws": { | ||
"types": "./lib/use/ws.d.ts", | ||
"require": "./lib/use/ws.js", | ||
"import": "./lib/use/ws.mjs" | ||
"./use/ws": { | ||
"types": "./dist/use/ws.d.ts", | ||
"require": "./dist/use/ws.cjs", | ||
"import": "./dist/use/ws.js" | ||
}, | ||
"./lib/use/uWebSockets": { | ||
"types": "./lib/use/uWebSockets.d.ts", | ||
"require": "./lib/use/uWebSockets.js", | ||
"import": "./lib/use/uWebSockets.mjs" | ||
"./use/uWebSockets": { | ||
"types": "./dist/use/uWebSockets.d.ts", | ||
"require": "./dist/use/uWebSockets.cjs", | ||
"import": "./dist/use/uWebSockets.js" | ||
}, | ||
"./lib/use/@fastify/websocket": { | ||
"types": "./lib/use/@fastify/websocket.d.ts", | ||
"require": "./lib/use/@fastify/websocket.js", | ||
"import": "./lib/use/@fastify/websocket.mjs" | ||
"./use/@fastify/websocket": { | ||
"types": "./dist/use/@fastify/websocket.d.ts", | ||
"require": "./dist/use/@fastify/websocket.cjs", | ||
"import": "./dist/use/@fastify/websocket.js" | ||
}, | ||
"./lib/use/fastify-websocket": { | ||
"types": "./lib/use/fastify-websocket.d.ts", | ||
"require": "./lib/use/fastify-websocket.js", | ||
"import": "./lib/use/fastify-websocket.mjs" | ||
"./use/bun": { | ||
"types": "./dist/use/bun.d.ts", | ||
"require": "./dist/use/bun.cjs", | ||
"import": "./dist/use/bun.js" | ||
}, | ||
"./lib/use/bun": { | ||
"bun": "./lib/use/bun.mjs", | ||
"types": "./lib/use/bun.d.ts", | ||
"require": "./lib/use/bun.js", | ||
"import": "./lib/use/bun.mjs" | ||
"./use/deno": { | ||
"types": "./dist/use/deno.d.ts", | ||
"require": "./dist/use/deno.cjs", | ||
"import": "./dist/use/deno.js" | ||
}, | ||
"./lib/use/deno": { | ||
"types": "./lib/use/deno.d.ts", | ||
"require": "./lib/use/deno.js", | ||
"import": "./lib/use/deno.mjs" | ||
}, | ||
"./package.json": "./package.json" | ||
}, | ||
"browser": "umd/graphql-ws.js", | ||
"types": "lib/index.d.ts", | ||
"browser": "./dist/client.js", | ||
"types": "./dist/index.d.ts", | ||
"sideEffects": [ | ||
@@ -67,3 +61,3 @@ "umd/*" | ||
"PROTOCOL.md", | ||
"lib", | ||
"dist", | ||
"umd", | ||
@@ -88,18 +82,13 @@ "README.md" | ||
"scripts": { | ||
"build": "yarn build:esm && yarn build:cjs && yarn build:umd && yarn postbuild", | ||
"build:cjs": "tsc -b tsconfig.cjs.json", | ||
"build:esm": "tsc -b tsconfig.esm.json && node scripts/esm-post-process.mjs", | ||
"build:umd": "rollup --bundleConfigAsCjs --config rollup.config.ts --configPlugin typescript && gzip umd/graphql-ws.min.js -c > umd/graphql-ws.min.js.gz", | ||
"changeset": "changeset", | ||
"check:format": "prettier --check .", | ||
"check:lint": "eslint 'src'", | ||
"check:type": "tsc --noEmit", | ||
"format": "yarn check:format --write", | ||
"gendocs": "typedoc --options typedoc.js src/ && node scripts/post-gendocs.mjs", | ||
"postbuild": "node scripts/fix-declaration-directives.mjs", | ||
"check:types": "tsc --noEmit", | ||
"test": "vitest", | ||
"release": "yarn build && yarn changeset publish" | ||
"build": "pkgroll --clean-dist && rollup -c rollup.config.js && gzip umd/graphql-ws.min.js -c > umd/graphql-ws.min.js.gz", | ||
"prepack": "yarn build", | ||
"gendocs": "typedoc --options typedoc.js src/ && node scripts/post-gendocs.js" | ||
}, | ||
"peerDependencies": { | ||
"graphql": ">=0.11 <=16" | ||
"graphql": "^15.9.0 || ^16.9.0" | ||
}, | ||
@@ -109,32 +98,24 @@ "devDependencies": { | ||
"@changesets/cli": "^2.27.11", | ||
"@fastify/websocket": "^9.0.0", | ||
"@fastify/websocket": "^11.0.1", | ||
"@ianvs/prettier-plugin-sort-imports": "^4.4.0", | ||
"@rollup/plugin-terser": "^0.4.4", | ||
"@rollup/plugin-typescript": "^11.1.6", | ||
"@types/eslint": "^8.56.10", | ||
"@tsconfig/strictest": "^2.0.5", | ||
"@types/glob": "^8.1.0", | ||
"@types/ws": "^8.5.10", | ||
"@typescript-eslint/eslint-plugin": "^7.7.0", | ||
"@typescript-eslint/parser": "^7.7.0", | ||
"@types/ws": "^8.5.13", | ||
"bun-types": "^1.1.4", | ||
"eslint": "^8.57.0", | ||
"fastify": "^4.26.2", | ||
"fastify-websocket": "4.2.2", | ||
"fastify": "^5.2.1", | ||
"glob": "^10.3.12", | ||
"graphql": "^16.8.1", | ||
"graphql": "^16.9.0", | ||
"jsdom": "^25.0.1", | ||
"pkgroll": "patch:pkgroll@npm%3A2.6.1#~/.yarn/patches/pkgroll-npm-2.6.1-193e78e84e.patch", | ||
"prettier": "^3.4.2", | ||
"prettier-plugin-sh": "^0.14.0", | ||
"replacestream": "^4.0.3", | ||
"rollup": "^4.14.3", | ||
"subscriptions-transport-ws": "^0.11.0", | ||
"tslib": "^2.6.2", | ||
"typedoc": "^0.25.13", | ||
"typedoc-plugin-markdown": "^3.17.1", | ||
"typescript": "^5.4.5", | ||
"uWebSockets.js": "uNetworking/uWebSockets.js#v20.43.0", | ||
"rollup": "^4.30.1", | ||
"typedoc": "^0.27.6", | ||
"typedoc-plugin-markdown": "^4.4.1", | ||
"typescript": "^5.7.3", | ||
"uWebSockets.js": "uNetworking/uWebSockets.js#v20.51.0", | ||
"vitest": "^2.1.8", | ||
"ws": "8.12.0", | ||
"ws7": "npm:ws@^7.5.9" | ||
"ws": "^8.18.0" | ||
} | ||
} |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.graphqlWs = {})); | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.graphqlWs = {})); | ||
})(this, (function (exports) { 'use strict'; | ||
/****************************************************************************** | ||
Copyright (c) Microsoft Corporation. | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */ | ||
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */ | ||
function __await(v) { | ||
return this instanceof __await ? (this.v = v, this) : new __await(v); | ||
function extendedTypeof(val) { | ||
if (val === null) { | ||
return "null"; | ||
} | ||
function __asyncGenerator(thisArg, _arguments, generator) { | ||
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); | ||
var g = generator.apply(thisArg, _arguments || []), i, q = []; | ||
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } | ||
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } | ||
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } | ||
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } | ||
function fulfill(value) { resume("next", value); } | ||
function reject(value) { resume("throw", value); } | ||
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } | ||
if (Array.isArray(val)) { | ||
return "array"; | ||
} | ||
return typeof val; | ||
} | ||
function isObject(val) { | ||
return extendedTypeof(val) === "object"; | ||
} | ||
function areGraphQLErrors(obj) { | ||
return Array.isArray(obj) && // must be at least one error | ||
obj.length > 0 && // error has at least a message | ||
obj.every((ob) => "message" in ob); | ||
} | ||
function limitCloseReason(reason, whenTooLong) { | ||
return reason.length < 124 ? reason : whenTooLong; | ||
} | ||
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { | ||
var e = new Error(message); | ||
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; | ||
}; | ||
/** @private */ | ||
function extendedTypeof(val) { | ||
if (val === null) { | ||
return 'null'; | ||
} | ||
if (Array.isArray(val)) { | ||
return 'array'; | ||
} | ||
return typeof val; | ||
const GRAPHQL_TRANSPORT_WS_PROTOCOL = "graphql-transport-ws"; | ||
const DEPRECATED_GRAPHQL_WS_PROTOCOL = "graphql-ws"; | ||
var CloseCode = /* @__PURE__ */ ((CloseCode2) => { | ||
CloseCode2[CloseCode2["InternalServerError"] = 4500] = "InternalServerError"; | ||
CloseCode2[CloseCode2["InternalClientError"] = 4005] = "InternalClientError"; | ||
CloseCode2[CloseCode2["BadRequest"] = 4400] = "BadRequest"; | ||
CloseCode2[CloseCode2["BadResponse"] = 4004] = "BadResponse"; | ||
CloseCode2[CloseCode2["Unauthorized"] = 4401] = "Unauthorized"; | ||
CloseCode2[CloseCode2["Forbidden"] = 4403] = "Forbidden"; | ||
CloseCode2[CloseCode2["SubprotocolNotAcceptable"] = 4406] = "SubprotocolNotAcceptable"; | ||
CloseCode2[CloseCode2["ConnectionInitialisationTimeout"] = 4408] = "ConnectionInitialisationTimeout"; | ||
CloseCode2[CloseCode2["ConnectionAcknowledgementTimeout"] = 4504] = "ConnectionAcknowledgementTimeout"; | ||
CloseCode2[CloseCode2["SubscriberAlreadyExists"] = 4409] = "SubscriberAlreadyExists"; | ||
CloseCode2[CloseCode2["TooManyInitialisationRequests"] = 4429] = "TooManyInitialisationRequests"; | ||
return CloseCode2; | ||
})(CloseCode || {}); | ||
var MessageType = /* @__PURE__ */ ((MessageType2) => { | ||
MessageType2["ConnectionInit"] = "connection_init"; | ||
MessageType2["ConnectionAck"] = "connection_ack"; | ||
MessageType2["Ping"] = "ping"; | ||
MessageType2["Pong"] = "pong"; | ||
MessageType2["Subscribe"] = "subscribe"; | ||
MessageType2["Next"] = "next"; | ||
MessageType2["Error"] = "error"; | ||
MessageType2["Complete"] = "complete"; | ||
return MessageType2; | ||
})(MessageType || {}); | ||
function validateMessage(val) { | ||
if (!isObject(val)) { | ||
throw new Error( | ||
`Message is expected to be an object, but got ${extendedTypeof(val)}` | ||
); | ||
} | ||
/** @private */ | ||
function isObject(val) { | ||
return extendedTypeof(val) === 'object'; | ||
if (!val.type) { | ||
throw new Error(`Message is missing the 'type' property`); | ||
} | ||
/** @private */ | ||
function areGraphQLErrors(obj) { | ||
return (Array.isArray(obj) && | ||
// must be at least one error | ||
obj.length > 0 && | ||
// error has at least a message | ||
obj.every((ob) => 'message' in ob)); | ||
if (typeof val.type !== "string") { | ||
throw new Error( | ||
`Message is expects the 'type' property to be a string, but got ${extendedTypeof( | ||
val.type | ||
)}` | ||
); | ||
} | ||
/** | ||
* Limits the WebSocket close event reason to not exceed a length of one frame. | ||
* Reference: https://datatracker.ietf.org/doc/html/rfc6455#section-5.2. | ||
* | ||
* @private | ||
*/ | ||
function limitCloseReason(reason, whenTooLong) { | ||
return reason.length < 124 ? reason : whenTooLong; | ||
} | ||
/** | ||
* | ||
* common | ||
* | ||
*/ | ||
/** | ||
* The WebSocket sub-protocol used for the [GraphQL over WebSocket Protocol](https://github.com/graphql/graphql-over-http/blob/main/rfcs/GraphQLOverWebSocket.md). | ||
* | ||
* @category Common | ||
*/ | ||
const GRAPHQL_TRANSPORT_WS_PROTOCOL = 'graphql-transport-ws'; | ||
/** | ||
* The deprecated subprotocol used by [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws). | ||
* | ||
* @private | ||
*/ | ||
const DEPRECATED_GRAPHQL_WS_PROTOCOL = 'graphql-ws'; | ||
/** | ||
* `graphql-ws` expected and standard close codes of the [GraphQL over WebSocket Protocol](https://github.com/graphql/graphql-over-http/blob/main/rfcs/GraphQLOverWebSocket.md). | ||
* | ||
* @category Common | ||
*/ | ||
exports.CloseCode = void 0; | ||
(function (CloseCode) { | ||
CloseCode[CloseCode["InternalServerError"] = 4500] = "InternalServerError"; | ||
CloseCode[CloseCode["InternalClientError"] = 4005] = "InternalClientError"; | ||
CloseCode[CloseCode["BadRequest"] = 4400] = "BadRequest"; | ||
CloseCode[CloseCode["BadResponse"] = 4004] = "BadResponse"; | ||
/** Tried subscribing before connect ack */ | ||
CloseCode[CloseCode["Unauthorized"] = 4401] = "Unauthorized"; | ||
CloseCode[CloseCode["Forbidden"] = 4403] = "Forbidden"; | ||
CloseCode[CloseCode["SubprotocolNotAcceptable"] = 4406] = "SubprotocolNotAcceptable"; | ||
CloseCode[CloseCode["ConnectionInitialisationTimeout"] = 4408] = "ConnectionInitialisationTimeout"; | ||
CloseCode[CloseCode["ConnectionAcknowledgementTimeout"] = 4504] = "ConnectionAcknowledgementTimeout"; | ||
/** Subscriber distinction is very important */ | ||
CloseCode[CloseCode["SubscriberAlreadyExists"] = 4409] = "SubscriberAlreadyExists"; | ||
CloseCode[CloseCode["TooManyInitialisationRequests"] = 4429] = "TooManyInitialisationRequests"; | ||
})(exports.CloseCode || (exports.CloseCode = {})); | ||
/** | ||
* Types of messages allowed to be sent by the client/server over the WS protocol. | ||
* | ||
* @category Common | ||
*/ | ||
exports.MessageType = void 0; | ||
(function (MessageType) { | ||
MessageType["ConnectionInit"] = "connection_init"; | ||
MessageType["ConnectionAck"] = "connection_ack"; | ||
MessageType["Ping"] = "ping"; | ||
MessageType["Pong"] = "pong"; | ||
MessageType["Subscribe"] = "subscribe"; | ||
MessageType["Next"] = "next"; | ||
MessageType["Error"] = "error"; | ||
MessageType["Complete"] = "complete"; | ||
})(exports.MessageType || (exports.MessageType = {})); | ||
/** | ||
* Validates the message against the GraphQL over WebSocket Protocol. | ||
* | ||
* Invalid messages will throw descriptive errors. | ||
* | ||
* @category Common | ||
*/ | ||
function validateMessage(val) { | ||
if (!isObject(val)) { | ||
throw new Error(`Message is expected to be an object, but got ${extendedTypeof(val)}`); | ||
switch (val.type) { | ||
case "connection_init" /* ConnectionInit */: | ||
case "connection_ack" /* ConnectionAck */: | ||
case "ping" /* Ping */: | ||
case "pong" /* Pong */: { | ||
if (val.payload != null && !isObject(val.payload)) { | ||
throw new Error( | ||
`"${val.type}" message expects the 'payload' property to be an object or nullish or missing, but got "${val.payload}"` | ||
); | ||
} | ||
if (!val.type) { | ||
throw new Error(`Message is missing the 'type' property`); | ||
break; | ||
} | ||
case "subscribe" /* Subscribe */: { | ||
if (typeof val.id !== "string") { | ||
throw new Error( | ||
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof( | ||
val.id | ||
)}` | ||
); | ||
} | ||
if (typeof val.type !== 'string') { | ||
throw new Error(`Message is expects the 'type' property to be a string, but got ${extendedTypeof(val.type)}`); | ||
if (!val.id) { | ||
throw new Error( | ||
`"${val.type}" message requires a non-empty 'id' property` | ||
); | ||
} | ||
switch (val.type) { | ||
case exports.MessageType.ConnectionInit: | ||
case exports.MessageType.ConnectionAck: | ||
case exports.MessageType.Ping: | ||
case exports.MessageType.Pong: { | ||
if (val.payload != null && !isObject(val.payload)) { | ||
throw new Error(`"${val.type}" message expects the 'payload' property to be an object or nullish or missing, but got "${val.payload}"`); | ||
} | ||
break; | ||
} | ||
case exports.MessageType.Subscribe: { | ||
if (typeof val.id !== 'string') { | ||
throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(val.id)}`); | ||
} | ||
if (!val.id) { | ||
throw new Error(`"${val.type}" message requires a non-empty 'id' property`); | ||
} | ||
if (!isObject(val.payload)) { | ||
throw new Error(`"${val.type}" message expects the 'payload' property to be an object, but got ${extendedTypeof(val.payload)}`); | ||
} | ||
if (typeof val.payload.query !== 'string') { | ||
throw new Error(`"${val.type}" message payload expects the 'query' property to be a string, but got ${extendedTypeof(val.payload.query)}`); | ||
} | ||
if (val.payload.variables != null && !isObject(val.payload.variables)) { | ||
throw new Error(`"${val.type}" message payload expects the 'variables' property to be a an object or nullish or missing, but got ${extendedTypeof(val.payload.variables)}`); | ||
} | ||
if (val.payload.operationName != null && | ||
extendedTypeof(val.payload.operationName) !== 'string') { | ||
throw new Error(`"${val.type}" message payload expects the 'operationName' property to be a string or nullish or missing, but got ${extendedTypeof(val.payload.operationName)}`); | ||
} | ||
if (val.payload.extensions != null && !isObject(val.payload.extensions)) { | ||
throw new Error(`"${val.type}" message payload expects the 'extensions' property to be a an object or nullish or missing, but got ${extendedTypeof(val.payload.extensions)}`); | ||
} | ||
break; | ||
} | ||
case exports.MessageType.Next: { | ||
if (typeof val.id !== 'string') { | ||
throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(val.id)}`); | ||
} | ||
if (!val.id) { | ||
throw new Error(`"${val.type}" message requires a non-empty 'id' property`); | ||
} | ||
if (!isObject(val.payload)) { | ||
throw new Error(`"${val.type}" message expects the 'payload' property to be an object, but got ${extendedTypeof(val.payload)}`); | ||
} | ||
break; | ||
} | ||
case exports.MessageType.Error: { | ||
if (typeof val.id !== 'string') { | ||
throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(val.id)}`); | ||
} | ||
if (!val.id) { | ||
throw new Error(`"${val.type}" message requires a non-empty 'id' property`); | ||
} | ||
if (!areGraphQLErrors(val.payload)) { | ||
throw new Error(`"${val.type}" message expects the 'payload' property to be an array of GraphQL errors, but got ${JSON.stringify(val.payload)}`); | ||
} | ||
break; | ||
} | ||
case exports.MessageType.Complete: { | ||
if (typeof val.id !== 'string') { | ||
throw new Error(`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof(val.id)}`); | ||
} | ||
if (!val.id) { | ||
throw new Error(`"${val.type}" message requires a non-empty 'id' property`); | ||
} | ||
break; | ||
} | ||
default: | ||
throw new Error(`Invalid message 'type' property "${val.type}"`); | ||
if (!isObject(val.payload)) { | ||
throw new Error( | ||
`"${val.type}" message expects the 'payload' property to be an object, but got ${extendedTypeof( | ||
val.payload | ||
)}` | ||
); | ||
} | ||
return val; | ||
} | ||
/** | ||
* Checks if the provided value is a valid GraphQL over WebSocket message. | ||
* | ||
* @deprecated Use `validateMessage` instead. | ||
* | ||
* @category Common | ||
*/ | ||
function isMessage(val) { | ||
try { | ||
validateMessage(val); | ||
return true; | ||
if (typeof val.payload.query !== "string") { | ||
throw new Error( | ||
`"${val.type}" message payload expects the 'query' property to be a string, but got ${extendedTypeof( | ||
val.payload.query | ||
)}` | ||
); | ||
} | ||
catch (_a) { | ||
return false; | ||
if (val.payload.variables != null && !isObject(val.payload.variables)) { | ||
throw new Error( | ||
`"${val.type}" message payload expects the 'variables' property to be a an object or nullish or missing, but got ${extendedTypeof( | ||
val.payload.variables | ||
)}` | ||
); | ||
} | ||
} | ||
/** | ||
* Parses the raw websocket message data to a valid message. | ||
* | ||
* @category Common | ||
*/ | ||
function parseMessage(data, reviver) { | ||
return validateMessage(typeof data === 'string' ? JSON.parse(data, reviver) : data); | ||
} | ||
/** | ||
* Stringifies a valid message ready to be sent through the socket. | ||
* | ||
* @category Common | ||
*/ | ||
function stringifyMessage(msg, replacer) { | ||
validateMessage(msg); | ||
return JSON.stringify(msg, replacer); | ||
} | ||
/** | ||
* | ||
* client | ||
* | ||
*/ | ||
/** | ||
* Creates a disposable GraphQL over WebSocket client. | ||
* | ||
* @category Client | ||
*/ | ||
function createClient(options) { | ||
const { url, connectionParams, lazy = true, onNonLazyError = console.error, lazyCloseTimeout: lazyCloseTimeoutMs = 0, keepAlive = 0, disablePong, connectionAckWaitTimeout = 0, retryAttempts = 5, retryWait = async function randomisedExponentialBackoff(retries) { | ||
let retryDelay = 1000; // start with 1s delay | ||
for (let i = 0; i < retries; i++) { | ||
retryDelay *= 2; | ||
} | ||
await new Promise((resolve) => setTimeout(resolve, retryDelay + | ||
// add random timeout from 300ms to 3s | ||
Math.floor(Math.random() * (3000 - 300) + 300))); | ||
}, shouldRetry = isLikeCloseEvent, isFatalConnectionProblem, on, webSocketImpl, | ||
/** | ||
* Generates a v4 UUID to be used as the ID using `Math` | ||
* as the random number generator. Supply your own generator | ||
* in case you need more uniqueness. | ||
* | ||
* Reference: https://gist.github.com/jed/982883 | ||
*/ | ||
generateID = function generateUUID() { | ||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { | ||
const r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8; | ||
return v.toString(16); | ||
}); | ||
}, jsonMessageReplacer: replacer, jsonMessageReviver: reviver, } = options; | ||
let ws; | ||
if (webSocketImpl) { | ||
if (!isWebSocket(webSocketImpl)) { | ||
throw new Error('Invalid WebSocket implementation provided'); | ||
} | ||
ws = webSocketImpl; | ||
if (val.payload.operationName != null && extendedTypeof(val.payload.operationName) !== "string") { | ||
throw new Error( | ||
`"${val.type}" message payload expects the 'operationName' property to be a string or nullish or missing, but got ${extendedTypeof( | ||
val.payload.operationName | ||
)}` | ||
); | ||
} | ||
else if (typeof WebSocket !== 'undefined') { | ||
ws = WebSocket; | ||
if (val.payload.extensions != null && !isObject(val.payload.extensions)) { | ||
throw new Error( | ||
`"${val.type}" message payload expects the 'extensions' property to be a an object or nullish or missing, but got ${extendedTypeof( | ||
val.payload.extensions | ||
)}` | ||
); | ||
} | ||
else if (typeof global !== 'undefined') { | ||
ws = | ||
global.WebSocket || | ||
// @ts-expect-error: Support more browsers | ||
global.MozWebSocket; | ||
break; | ||
} | ||
case "next" /* Next */: { | ||
if (typeof val.id !== "string") { | ||
throw new Error( | ||
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof( | ||
val.id | ||
)}` | ||
); | ||
} | ||
else if (typeof window !== 'undefined') { | ||
ws = | ||
window.WebSocket || | ||
// @ts-expect-error: Support more browsers | ||
window.MozWebSocket; | ||
if (!val.id) { | ||
throw new Error( | ||
`"${val.type}" message requires a non-empty 'id' property` | ||
); | ||
} | ||
if (!ws) | ||
throw new Error("WebSocket implementation missing; on Node you can `import WebSocket from 'ws';` and pass `webSocketImpl: WebSocket` to `createClient`"); | ||
const WebSocketImpl = ws; | ||
// websocket status emitter, subscriptions are handled differently | ||
const emitter = (() => { | ||
const message = (() => { | ||
const listeners = {}; | ||
return { | ||
on(id, listener) { | ||
listeners[id] = listener; | ||
return () => { | ||
delete listeners[id]; | ||
}; | ||
}, | ||
emit(message) { | ||
var _a; | ||
if ('id' in message) | ||
(_a = listeners[message.id]) === null || _a === undefined ? undefined : _a.call(listeners, message); | ||
}, | ||
}; | ||
})(); | ||
const listeners = { | ||
connecting: (on === null || on === undefined ? undefined : on.connecting) ? [on.connecting] : [], | ||
opened: (on === null || on === undefined ? undefined : on.opened) ? [on.opened] : [], | ||
connected: (on === null || on === undefined ? undefined : on.connected) ? [on.connected] : [], | ||
ping: (on === null || on === undefined ? undefined : on.ping) ? [on.ping] : [], | ||
pong: (on === null || on === undefined ? undefined : on.pong) ? [on.pong] : [], | ||
message: (on === null || on === undefined ? undefined : on.message) ? [message.emit, on.message] : [message.emit], | ||
closed: (on === null || on === undefined ? undefined : on.closed) ? [on.closed] : [], | ||
error: (on === null || on === undefined ? undefined : on.error) ? [on.error] : [], | ||
}; | ||
return { | ||
onMessage: message.on, | ||
on(event, listener) { | ||
const l = listeners[event]; | ||
l.push(listener); | ||
return () => { | ||
l.splice(l.indexOf(listener), 1); | ||
}; | ||
}, | ||
emit(event, ...args) { | ||
// we copy the listeners so that unlistens dont "pull the rug under our feet" | ||
for (const listener of [...listeners[event]]) { | ||
// @ts-expect-error: The args should fit | ||
listener(...args); | ||
} | ||
}, | ||
}; | ||
})(); | ||
// invokes the callback either when an error or closed event is emitted, | ||
// first one that gets called prevails, other emissions are ignored | ||
function errorOrClosed(cb) { | ||
const listening = [ | ||
// errors are fatal and more critical than close events, throw them first | ||
emitter.on('error', (err) => { | ||
listening.forEach((unlisten) => unlisten()); | ||
cb(err); | ||
}), | ||
// closes can be graceful and not fatal, throw them second (if error didnt throw) | ||
emitter.on('closed', (event) => { | ||
listening.forEach((unlisten) => unlisten()); | ||
cb(event); | ||
}), | ||
]; | ||
if (!isObject(val.payload)) { | ||
throw new Error( | ||
`"${val.type}" message expects the 'payload' property to be an object, but got ${extendedTypeof( | ||
val.payload | ||
)}` | ||
); | ||
} | ||
let connecting, locks = 0, lazyCloseTimeout, retrying = false, retries = 0, disposed = false; | ||
async function connect() { | ||
// clear the lazy close timeout immediatelly so that close gets debounced | ||
// see: https://github.com/enisdenjo/graphql-ws/issues/388 | ||
clearTimeout(lazyCloseTimeout); | ||
const [socket, throwOnClose] = await (connecting !== null && connecting !== undefined ? connecting : (connecting = new Promise((connected, denied) => (async () => { | ||
if (retrying) { | ||
await retryWait(retries); | ||
// subscriptions might complete while waiting for retry | ||
if (!locks) { | ||
connecting = undefined; | ||
return denied({ code: 1000, reason: 'All Subscriptions Gone' }); | ||
} | ||
retries++; | ||
} | ||
emitter.emit('connecting', retrying); | ||
const socket = new WebSocketImpl(typeof url === 'function' ? await url() : url, GRAPHQL_TRANSPORT_WS_PROTOCOL); | ||
let connectionAckTimeout, queuedPing; | ||
function enqueuePing() { | ||
if (isFinite(keepAlive) && keepAlive > 0) { | ||
clearTimeout(queuedPing); // in case where a pong was received before a ping (this is valid behaviour) | ||
queuedPing = setTimeout(() => { | ||
if (socket.readyState === WebSocketImpl.OPEN) { | ||
socket.send(stringifyMessage({ type: exports.MessageType.Ping })); | ||
emitter.emit('ping', false, undefined); | ||
} | ||
}, keepAlive); | ||
} | ||
} | ||
errorOrClosed((errOrEvent) => { | ||
connecting = undefined; | ||
clearTimeout(connectionAckTimeout); | ||
clearTimeout(queuedPing); | ||
denied(errOrEvent); | ||
if (errOrEvent instanceof TerminatedCloseEvent) { | ||
socket.close(4499, 'Terminated'); // close event is artificial and emitted manually, see `Client.terminate()` below | ||
socket.onerror = null; | ||
socket.onclose = null; | ||
} | ||
}); | ||
socket.onerror = (err) => emitter.emit('error', err); | ||
socket.onclose = (event) => emitter.emit('closed', event); | ||
socket.onopen = async () => { | ||
try { | ||
emitter.emit('opened', socket); | ||
const payload = typeof connectionParams === 'function' | ||
? await connectionParams() | ||
: connectionParams; | ||
// connectionParams might take too long causing the server to kick off the client | ||
// the necessary error/close event is already reported - simply stop execution | ||
if (socket.readyState !== WebSocketImpl.OPEN) | ||
return; | ||
socket.send(stringifyMessage(payload | ||
? { | ||
type: exports.MessageType.ConnectionInit, | ||
payload, | ||
} | ||
: { | ||
type: exports.MessageType.ConnectionInit, | ||
// payload is completely absent if not provided | ||
}, replacer)); | ||
if (isFinite(connectionAckWaitTimeout) && | ||
connectionAckWaitTimeout > 0) { | ||
connectionAckTimeout = setTimeout(() => { | ||
socket.close(exports.CloseCode.ConnectionAcknowledgementTimeout, 'Connection acknowledgement timeout'); | ||
}, connectionAckWaitTimeout); | ||
} | ||
enqueuePing(); // enqueue ping (noop if disabled) | ||
} | ||
catch (err) { | ||
emitter.emit('error', err); | ||
socket.close(exports.CloseCode.InternalClientError, limitCloseReason(err instanceof Error ? err.message : new Error(err).message, 'Internal client error')); | ||
} | ||
}; | ||
let acknowledged = false; | ||
socket.onmessage = ({ data }) => { | ||
try { | ||
const message = parseMessage(data, reviver); | ||
emitter.emit('message', message); | ||
if (message.type === 'ping' || message.type === 'pong') { | ||
emitter.emit(message.type, true, message.payload); // received | ||
if (message.type === 'pong') { | ||
enqueuePing(); // enqueue next ping (noop if disabled) | ||
} | ||
else if (!disablePong) { | ||
// respond with pong on ping | ||
socket.send(stringifyMessage(message.payload | ||
? { | ||
type: exports.MessageType.Pong, | ||
payload: message.payload, | ||
} | ||
: { | ||
type: exports.MessageType.Pong, | ||
// payload is completely absent if not provided | ||
})); | ||
emitter.emit('pong', false, message.payload); | ||
} | ||
return; // ping and pongs can be received whenever | ||
} | ||
if (acknowledged) | ||
return; // already connected and acknowledged | ||
if (message.type !== exports.MessageType.ConnectionAck) | ||
throw new Error(`First message cannot be of type ${message.type}`); | ||
clearTimeout(connectionAckTimeout); | ||
acknowledged = true; | ||
emitter.emit('connected', socket, message.payload, retrying); // connected = socket opened + acknowledged | ||
retrying = false; // future lazy connects are not retries | ||
retries = 0; // reset the retries on connect | ||
connected([ | ||
socket, | ||
new Promise((_, reject) => errorOrClosed(reject)), | ||
]); | ||
} | ||
catch (err) { | ||
socket.onmessage = null; // stop reading messages as soon as reading breaks once | ||
emitter.emit('error', err); | ||
socket.close(exports.CloseCode.BadResponse, limitCloseReason(err instanceof Error ? err.message : new Error(err).message, 'Bad response')); | ||
} | ||
}; | ||
})()))); | ||
// if the provided socket is in a closing state, wait for the throw on close | ||
if (socket.readyState === WebSocketImpl.CLOSING) | ||
await throwOnClose; | ||
let release = () => { | ||
// releases this connection | ||
}; | ||
const released = new Promise((resolve) => (release = resolve)); | ||
return [ | ||
socket, | ||
release, | ||
Promise.race([ | ||
// wait for | ||
released.then(() => { | ||
if (!locks) { | ||
// and if no more locks are present, complete the connection | ||
const complete = () => socket.close(1000, 'Normal Closure'); | ||
if (isFinite(lazyCloseTimeoutMs) && lazyCloseTimeoutMs > 0) { | ||
// if the keepalive is set, allow for the specified calmdown time and | ||
// then complete if the socket is still open. | ||
lazyCloseTimeout = setTimeout(() => { | ||
if (socket.readyState === WebSocketImpl.OPEN) | ||
complete(); | ||
}, lazyCloseTimeoutMs); | ||
} | ||
else { | ||
// otherwise complete immediately | ||
complete(); | ||
} | ||
} | ||
}), | ||
// or | ||
throwOnClose, | ||
]), | ||
]; | ||
break; | ||
} | ||
case "error" /* Error */: { | ||
if (typeof val.id !== "string") { | ||
throw new Error( | ||
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof( | ||
val.id | ||
)}` | ||
); | ||
} | ||
/** | ||
* Checks the `connect` problem and evaluates if the client should retry. | ||
*/ | ||
function shouldRetryConnectOrThrow(errOrCloseEvent) { | ||
// some close codes are worth reporting immediately | ||
if (isLikeCloseEvent(errOrCloseEvent) && | ||
(isFatalInternalCloseCode(errOrCloseEvent.code) || | ||
[ | ||
exports.CloseCode.InternalServerError, | ||
exports.CloseCode.InternalClientError, | ||
exports.CloseCode.BadRequest, | ||
exports.CloseCode.BadResponse, | ||
exports.CloseCode.Unauthorized, | ||
// CloseCode.Forbidden, might grant access out after retry | ||
exports.CloseCode.SubprotocolNotAcceptable, | ||
// CloseCode.ConnectionInitialisationTimeout, might not time out after retry | ||
// CloseCode.ConnectionAcknowledgementTimeout, might not time out after retry | ||
exports.CloseCode.SubscriberAlreadyExists, | ||
exports.CloseCode.TooManyInitialisationRequests, | ||
// 4499, // Terminated, probably because the socket froze, we want to retry | ||
].includes(errOrCloseEvent.code))) | ||
throw errOrCloseEvent; | ||
// client was disposed, no retries should proceed regardless | ||
if (disposed) | ||
return false; | ||
// normal closure (possibly all subscriptions have completed) | ||
// if no locks were acquired in the meantime, shouldnt try again | ||
if (isLikeCloseEvent(errOrCloseEvent) && errOrCloseEvent.code === 1000) | ||
return locks > 0; | ||
// retries are not allowed or we tried to many times, report error | ||
if (!retryAttempts || retries >= retryAttempts) | ||
throw errOrCloseEvent; | ||
// throw non-retryable connection problems | ||
if (!shouldRetry(errOrCloseEvent)) | ||
throw errOrCloseEvent; | ||
// @deprecated throw fatal connection problems immediately | ||
if (isFatalConnectionProblem === null || isFatalConnectionProblem === undefined ? undefined : isFatalConnectionProblem(errOrCloseEvent)) | ||
throw errOrCloseEvent; | ||
// looks good, start retrying | ||
return (retrying = true); | ||
if (!val.id) { | ||
throw new Error( | ||
`"${val.type}" message requires a non-empty 'id' property` | ||
); | ||
} | ||
// in non-lazy (hot?) mode always hold one connection lock to persist the socket | ||
if (!lazy) { | ||
(async () => { | ||
locks++; | ||
for (;;) { | ||
try { | ||
const [, , throwOnClose] = await connect(); | ||
await throwOnClose; // will always throw because releaser is not used | ||
} | ||
catch (errOrCloseEvent) { | ||
try { | ||
if (!shouldRetryConnectOrThrow(errOrCloseEvent)) | ||
return; | ||
} | ||
catch (errOrCloseEvent) { | ||
// report thrown error, no further retries | ||
return onNonLazyError === null || onNonLazyError === undefined ? undefined : onNonLazyError(errOrCloseEvent); | ||
} | ||
} | ||
} | ||
})(); | ||
if (!areGraphQLErrors(val.payload)) { | ||
throw new Error( | ||
`"${val.type}" message expects the 'payload' property to be an array of GraphQL errors, but got ${JSON.stringify( | ||
val.payload | ||
)}` | ||
); | ||
} | ||
function subscribe(payload, sink) { | ||
const id = generateID(payload); | ||
let done = false, errored = false, releaser = () => { | ||
// for handling completions before connect | ||
locks--; | ||
done = true; | ||
}; | ||
(async () => { | ||
locks++; | ||
for (;;) { | ||
try { | ||
const [socket, release, waitForReleaseOrThrowOnClose] = await connect(); | ||
// if done while waiting for connect, release the connection lock right away | ||
if (done) | ||
return release(); | ||
const unlisten = emitter.onMessage(id, (message) => { | ||
switch (message.type) { | ||
case exports.MessageType.Next: { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- payload will fit type | ||
sink.next(message.payload); | ||
return; | ||
} | ||
case exports.MessageType.Error: { | ||
(errored = true), (done = true); | ||
sink.error(message.payload); | ||
releaser(); | ||
return; | ||
} | ||
case exports.MessageType.Complete: { | ||
done = true; | ||
releaser(); // release completes the sink | ||
return; | ||
} | ||
} | ||
}); | ||
socket.send(stringifyMessage({ | ||
id, | ||
type: exports.MessageType.Subscribe, | ||
payload, | ||
}, replacer)); | ||
releaser = () => { | ||
if (!done && socket.readyState === WebSocketImpl.OPEN) | ||
// if not completed already and socket is open, send complete message to server on release | ||
socket.send(stringifyMessage({ | ||
id, | ||
type: exports.MessageType.Complete, | ||
}, replacer)); | ||
locks--; | ||
done = true; | ||
release(); | ||
}; | ||
// either the releaser will be called, connection completed and | ||
// the promise resolved or the socket closed and the promise rejected. | ||
// whatever happens though, we want to stop listening for messages | ||
await waitForReleaseOrThrowOnClose.finally(unlisten); | ||
return; // completed, shouldnt try again | ||
} | ||
catch (errOrCloseEvent) { | ||
if (!shouldRetryConnectOrThrow(errOrCloseEvent)) | ||
return; | ||
} | ||
} | ||
})() | ||
.then(() => { | ||
// delivering either an error or a complete terminates the sequence | ||
if (!errored) | ||
sink.complete(); | ||
}) // resolves on release or normal closure | ||
.catch((err) => { | ||
sink.error(err); | ||
}); // rejects on close events and errors | ||
break; | ||
} | ||
case "complete" /* Complete */: { | ||
if (typeof val.id !== "string") { | ||
throw new Error( | ||
`"${val.type}" message expects the 'id' property to be a string, but got ${extendedTypeof( | ||
val.id | ||
)}` | ||
); | ||
} | ||
if (!val.id) { | ||
throw new Error( | ||
`"${val.type}" message requires a non-empty 'id' property` | ||
); | ||
} | ||
break; | ||
} | ||
default: | ||
throw new Error(`Invalid message 'type' property "${val.type}"`); | ||
} | ||
return val; | ||
} | ||
function isMessage(val) { | ||
try { | ||
validateMessage(val); | ||
return true; | ||
} catch { | ||
return false; | ||
} | ||
} | ||
function parseMessage(data, reviver) { | ||
return validateMessage( | ||
typeof data === "string" ? JSON.parse(data, reviver) : data | ||
); | ||
} | ||
function stringifyMessage(msg, replacer) { | ||
validateMessage(msg); | ||
return JSON.stringify(msg, replacer); | ||
} | ||
function createClient(options) { | ||
const { | ||
url, | ||
connectionParams, | ||
lazy = true, | ||
onNonLazyError = console.error, | ||
lazyCloseTimeout: lazyCloseTimeoutMs = 0, | ||
keepAlive = 0, | ||
disablePong, | ||
connectionAckWaitTimeout = 0, | ||
retryAttempts = 5, | ||
retryWait = async function randomisedExponentialBackoff(retries2) { | ||
let retryDelay = 1e3; | ||
for (let i = 0; i < retries2; i++) { | ||
retryDelay *= 2; | ||
} | ||
await new Promise( | ||
(resolve) => setTimeout( | ||
resolve, | ||
retryDelay + // add random timeout from 300ms to 3s | ||
Math.floor(Math.random() * (3e3 - 300) + 300) | ||
) | ||
); | ||
}, | ||
shouldRetry = isLikeCloseEvent, | ||
isFatalConnectionProblem, | ||
on, | ||
webSocketImpl, | ||
/** | ||
* Generates a v4 UUID to be used as the ID using `Math` | ||
* as the random number generator. Supply your own generator | ||
* in case you need more uniqueness. | ||
* | ||
* Reference: https://gist.github.com/jed/982883 | ||
*/ | ||
generateID = function generateUUID() { | ||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { | ||
const r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8; | ||
return v.toString(16); | ||
}); | ||
}, | ||
jsonMessageReplacer: replacer, | ||
jsonMessageReviver: reviver | ||
} = options; | ||
let ws; | ||
if (webSocketImpl) { | ||
if (!isWebSocket(webSocketImpl)) { | ||
throw new Error("Invalid WebSocket implementation provided"); | ||
} | ||
ws = webSocketImpl; | ||
} else if (typeof WebSocket !== "undefined") { | ||
ws = WebSocket; | ||
} else if (typeof global !== "undefined") { | ||
ws = global.WebSocket || // @ts-expect-error: Support more browsers | ||
global.MozWebSocket; | ||
} else if (typeof window !== "undefined") { | ||
ws = window.WebSocket || // @ts-expect-error: Support more browsers | ||
window.MozWebSocket; | ||
} | ||
if (!ws) | ||
throw new Error( | ||
"WebSocket implementation missing; on Node you can `import WebSocket from 'ws';` and pass `webSocketImpl: WebSocket` to `createClient`" | ||
); | ||
const WebSocketImpl = ws; | ||
const emitter = (() => { | ||
const message = /* @__PURE__ */ (() => { | ||
const listeners2 = {}; | ||
return { | ||
on(id, listener) { | ||
listeners2[id] = listener; | ||
return () => { | ||
// dispose only of active subscriptions | ||
if (!done) | ||
releaser(); | ||
delete listeners2[id]; | ||
}; | ||
}, | ||
emit(message2) { | ||
if ("id" in message2) listeners2[message2.id]?.(message2); | ||
} | ||
}; | ||
})(); | ||
const listeners = { | ||
connecting: on?.connecting ? [on.connecting] : [], | ||
opened: on?.opened ? [on.opened] : [], | ||
connected: on?.connected ? [on.connected] : [], | ||
ping: on?.ping ? [on.ping] : [], | ||
pong: on?.pong ? [on.pong] : [], | ||
message: on?.message ? [message.emit, on.message] : [message.emit], | ||
closed: on?.closed ? [on.closed] : [], | ||
error: on?.error ? [on.error] : [] | ||
}; | ||
return { | ||
onMessage: message.on, | ||
on(event, listener) { | ||
const l = listeners[event]; | ||
l.push(listener); | ||
return () => { | ||
l.splice(l.indexOf(listener), 1); | ||
}; | ||
}, | ||
emit(event, ...args) { | ||
for (const listener of [...listeners[event]]) { | ||
listener(...args); | ||
} | ||
} | ||
return { | ||
on: emitter.on, | ||
subscribe, | ||
iterate(request) { | ||
const pending = []; | ||
const deferred = { | ||
done: false, | ||
error: null, | ||
resolve: () => { | ||
// noop | ||
}, | ||
}; | ||
const dispose = subscribe(request, { | ||
next(val) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- payload will fit type | ||
pending.push(val); | ||
deferred.resolve(); | ||
}, | ||
error(err) { | ||
deferred.done = true; | ||
deferred.error = err; | ||
deferred.resolve(); | ||
}, | ||
complete() { | ||
deferred.done = true; | ||
deferred.resolve(); | ||
}, | ||
}); | ||
const iterator = (function iterator() { | ||
return __asyncGenerator(this, arguments, function* iterator_1() { | ||
for (;;) { | ||
if (!pending.length) { | ||
// only wait if there are no pending messages available | ||
yield __await(new Promise((resolve) => (deferred.resolve = resolve))); | ||
} | ||
// first flush | ||
while (pending.length) { | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
yield yield __await(pending.shift()); | ||
} | ||
// then error | ||
if (deferred.error) { | ||
throw deferred.error; | ||
} | ||
// or complete | ||
if (deferred.done) { | ||
return yield __await(undefined); | ||
} | ||
} | ||
}); | ||
})(); | ||
iterator.throw = async (err) => { | ||
if (!deferred.done) { | ||
deferred.done = true; | ||
deferred.error = err; | ||
deferred.resolve(); | ||
} | ||
return { done: true, value: undefined }; | ||
}; | ||
iterator.return = async () => { | ||
dispose(); | ||
return { done: true, value: undefined }; | ||
}; | ||
return iterator; | ||
}, | ||
async dispose() { | ||
disposed = true; | ||
if (connecting) { | ||
// if there is a connection, close it | ||
const [socket] = await connecting; | ||
socket.close(1000, 'Normal Closure'); | ||
}; | ||
})(); | ||
function errorOrClosed(cb) { | ||
const listening = [ | ||
// errors are fatal and more critical than close events, throw them first | ||
emitter.on("error", (err) => { | ||
listening.forEach((unlisten) => unlisten()); | ||
cb(err); | ||
}), | ||
// closes can be graceful and not fatal, throw them second (if error didnt throw) | ||
emitter.on("closed", (event) => { | ||
listening.forEach((unlisten) => unlisten()); | ||
cb(event); | ||
}) | ||
]; | ||
} | ||
let connecting, locks = 0, lazyCloseTimeout, retrying = false, retries = 0, disposed = false; | ||
async function connect() { | ||
clearTimeout(lazyCloseTimeout); | ||
const [socket, throwOnClose] = await (connecting ?? (connecting = new Promise( | ||
(connected, denied) => (async () => { | ||
if (retrying) { | ||
await retryWait(retries); | ||
if (!locks) { | ||
connecting = undefined; | ||
return denied({ code: 1e3, reason: "All Subscriptions Gone" }); | ||
} | ||
retries++; | ||
} | ||
emitter.emit("connecting", retrying); | ||
const socket2 = new WebSocketImpl( | ||
typeof url === "function" ? await url() : url, | ||
GRAPHQL_TRANSPORT_WS_PROTOCOL | ||
); | ||
let connectionAckTimeout, queuedPing; | ||
function enqueuePing() { | ||
if (isFinite(keepAlive) && keepAlive > 0) { | ||
clearTimeout(queuedPing); | ||
queuedPing = setTimeout(() => { | ||
if (socket2.readyState === WebSocketImpl.OPEN) { | ||
socket2.send(stringifyMessage({ type: MessageType.Ping })); | ||
emitter.emit("ping", false, undefined); | ||
} | ||
}, | ||
terminate() { | ||
if (connecting) { | ||
// only if there is a connection | ||
emitter.emit('closed', new TerminatedCloseEvent()); | ||
}, keepAlive); | ||
} | ||
} | ||
errorOrClosed((errOrEvent) => { | ||
connecting = undefined; | ||
clearTimeout(connectionAckTimeout); | ||
clearTimeout(queuedPing); | ||
denied(errOrEvent); | ||
if (errOrEvent instanceof TerminatedCloseEvent) { | ||
socket2.close(4499, "Terminated"); | ||
socket2.onerror = null; | ||
socket2.onclose = null; | ||
} | ||
}); | ||
socket2.onerror = (err) => emitter.emit("error", err); | ||
socket2.onclose = (event) => emitter.emit("closed", event); | ||
socket2.onopen = async () => { | ||
try { | ||
emitter.emit("opened", socket2); | ||
const payload = typeof connectionParams === "function" ? await connectionParams() : connectionParams; | ||
if (socket2.readyState !== WebSocketImpl.OPEN) return; | ||
socket2.send( | ||
stringifyMessage( | ||
payload ? { | ||
type: MessageType.ConnectionInit, | ||
payload | ||
} : { | ||
type: MessageType.ConnectionInit | ||
// payload is completely absent if not provided | ||
}, | ||
replacer | ||
) | ||
); | ||
if (isFinite(connectionAckWaitTimeout) && connectionAckWaitTimeout > 0) { | ||
connectionAckTimeout = setTimeout(() => { | ||
socket2.close( | ||
CloseCode.ConnectionAcknowledgementTimeout, | ||
"Connection acknowledgement timeout" | ||
); | ||
}, connectionAckWaitTimeout); | ||
} | ||
enqueuePing(); | ||
} catch (err) { | ||
emitter.emit("error", err); | ||
socket2.close( | ||
CloseCode.InternalClientError, | ||
limitCloseReason( | ||
err instanceof Error ? err.message : String(err), | ||
"Internal client error" | ||
) | ||
); | ||
} | ||
}; | ||
let acknowledged = false; | ||
socket2.onmessage = ({ data }) => { | ||
try { | ||
const message = parseMessage(data, reviver); | ||
emitter.emit("message", message); | ||
if (message.type === "ping" || message.type === "pong") { | ||
emitter.emit(message.type, true, message.payload); | ||
if (message.type === "pong") { | ||
enqueuePing(); | ||
} else if (!disablePong) { | ||
socket2.send( | ||
stringifyMessage( | ||
message.payload ? { | ||
type: MessageType.Pong, | ||
payload: message.payload | ||
} : { | ||
type: MessageType.Pong | ||
// payload is completely absent if not provided | ||
} | ||
) | ||
); | ||
emitter.emit("pong", false, message.payload); | ||
} | ||
}, | ||
}; | ||
return; | ||
} | ||
if (acknowledged) return; | ||
if (message.type !== MessageType.ConnectionAck) | ||
throw new Error( | ||
`First message cannot be of type ${message.type}` | ||
); | ||
clearTimeout(connectionAckTimeout); | ||
acknowledged = true; | ||
emitter.emit("connected", socket2, message.payload, retrying); | ||
retrying = false; | ||
retries = 0; | ||
connected([ | ||
socket2, | ||
new Promise((_, reject) => errorOrClosed(reject)) | ||
]); | ||
} catch (err) { | ||
socket2.onmessage = null; | ||
emitter.emit("error", err); | ||
socket2.close( | ||
CloseCode.BadResponse, | ||
limitCloseReason( | ||
err instanceof Error ? err.message : String(err), | ||
"Bad response" | ||
) | ||
); | ||
} | ||
}; | ||
})() | ||
))); | ||
if (socket.readyState === WebSocketImpl.CLOSING) await throwOnClose; | ||
let release = () => { | ||
}; | ||
const released = new Promise((resolve) => release = resolve); | ||
return [ | ||
socket, | ||
release, | ||
Promise.race([ | ||
// wait for | ||
released.then(() => { | ||
if (!locks) { | ||
const complete = () => socket.close(1e3, "Normal Closure"); | ||
if (isFinite(lazyCloseTimeoutMs) && lazyCloseTimeoutMs > 0) { | ||
lazyCloseTimeout = setTimeout(() => { | ||
if (socket.readyState === WebSocketImpl.OPEN) complete(); | ||
}, lazyCloseTimeoutMs); | ||
} else { | ||
complete(); | ||
} | ||
} | ||
}), | ||
// or | ||
throwOnClose | ||
]) | ||
]; | ||
} | ||
/** | ||
* A synthetic close event `4499: Terminated` is issued to the current to immediately | ||
* close the connection 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. | ||
*/ | ||
class TerminatedCloseEvent extends Error { | ||
constructor() { | ||
super(...arguments); | ||
this.name = 'TerminatedCloseEvent'; | ||
this.message = '4499: Terminated'; | ||
this.code = 4499; | ||
this.reason = 'Terminated'; | ||
this.wasClean = false; | ||
function shouldRetryConnectOrThrow(errOrCloseEvent) { | ||
if (isLikeCloseEvent(errOrCloseEvent) && (isFatalInternalCloseCode(errOrCloseEvent.code) || [ | ||
CloseCode.InternalServerError, | ||
CloseCode.InternalClientError, | ||
CloseCode.BadRequest, | ||
CloseCode.BadResponse, | ||
CloseCode.Unauthorized, | ||
// CloseCode.Forbidden, might grant access out after retry | ||
CloseCode.SubprotocolNotAcceptable, | ||
// CloseCode.ConnectionInitialisationTimeout, might not time out after retry | ||
// CloseCode.ConnectionAcknowledgementTimeout, might not time out after retry | ||
CloseCode.SubscriberAlreadyExists, | ||
CloseCode.TooManyInitialisationRequests | ||
// 4499, // Terminated, probably because the socket froze, we want to retry | ||
].includes(errOrCloseEvent.code))) | ||
throw errOrCloseEvent; | ||
if (disposed) return false; | ||
if (isLikeCloseEvent(errOrCloseEvent) && errOrCloseEvent.code === 1e3) | ||
return locks > 0; | ||
if (!retryAttempts || retries >= retryAttempts) throw errOrCloseEvent; | ||
if (!shouldRetry(errOrCloseEvent)) throw errOrCloseEvent; | ||
if (isFatalConnectionProblem?.(errOrCloseEvent)) throw errOrCloseEvent; | ||
return retrying = true; | ||
} | ||
if (!lazy) { | ||
(async () => { | ||
locks++; | ||
for (; ; ) { | ||
try { | ||
const [, , throwOnClose] = await connect(); | ||
await throwOnClose; | ||
} catch (errOrCloseEvent) { | ||
try { | ||
if (!shouldRetryConnectOrThrow(errOrCloseEvent)) return; | ||
} catch (errOrCloseEvent2) { | ||
return onNonLazyError?.(errOrCloseEvent2); | ||
} | ||
} | ||
} | ||
})(); | ||
} | ||
function isLikeCloseEvent(val) { | ||
return isObject(val) && 'code' in val && 'reason' in val; | ||
function subscribe(payload, sink) { | ||
const id = generateID(payload); | ||
let done = false, errored = false, releaser = () => { | ||
locks--; | ||
done = true; | ||
}; | ||
(async () => { | ||
locks++; | ||
for (; ; ) { | ||
try { | ||
const [socket, release, waitForReleaseOrThrowOnClose] = await connect(); | ||
if (done) return release(); | ||
const unlisten = emitter.onMessage(id, (message) => { | ||
switch (message.type) { | ||
case MessageType.Next: { | ||
sink.next(message.payload); | ||
return; | ||
} | ||
case MessageType.Error: { | ||
errored = true, done = true; | ||
sink.error(message.payload); | ||
releaser(); | ||
return; | ||
} | ||
case MessageType.Complete: { | ||
done = true; | ||
releaser(); | ||
return; | ||
} | ||
} | ||
}); | ||
socket.send( | ||
stringifyMessage( | ||
{ | ||
id, | ||
type: MessageType.Subscribe, | ||
payload | ||
}, | ||
replacer | ||
) | ||
); | ||
releaser = () => { | ||
if (!done && socket.readyState === WebSocketImpl.OPEN) | ||
socket.send( | ||
stringifyMessage( | ||
{ | ||
id, | ||
type: MessageType.Complete | ||
}, | ||
replacer | ||
) | ||
); | ||
locks--; | ||
done = true; | ||
release(); | ||
}; | ||
await waitForReleaseOrThrowOnClose.finally(unlisten); | ||
return; | ||
} catch (errOrCloseEvent) { | ||
if (!shouldRetryConnectOrThrow(errOrCloseEvent)) return; | ||
} | ||
} | ||
})().then(() => { | ||
if (!errored) sink.complete(); | ||
}).catch((err) => { | ||
sink.error(err); | ||
}); | ||
return () => { | ||
if (!done) releaser(); | ||
}; | ||
} | ||
function isFatalInternalCloseCode(code) { | ||
if ([ | ||
1000, // Normal Closure is not an erroneous close code | ||
1001, // Going Away | ||
1006, // Abnormal Closure | ||
1005, // No Status Received | ||
1012, // Service Restart | ||
1013, // Try Again Later | ||
1014, // Bad Gateway | ||
].includes(code)) | ||
return false; | ||
// all other internal errors are fatal | ||
return code >= 1000 && code <= 1999; | ||
} | ||
function isWebSocket(val) { | ||
return (typeof val === 'function' && | ||
'constructor' in val && | ||
'CLOSED' in val && | ||
'CLOSING' in val && | ||
'CONNECTING' in val && | ||
'OPEN' in val); | ||
} | ||
return { | ||
on: emitter.on, | ||
subscribe, | ||
iterate(request) { | ||
const pending = []; | ||
const deferred = { | ||
done: false, | ||
error: null, | ||
resolve: () => { | ||
} | ||
}; | ||
const dispose = subscribe(request, { | ||
next(val) { | ||
pending.push(val); | ||
deferred.resolve(); | ||
}, | ||
error(err) { | ||
deferred.done = true; | ||
deferred.error = err; | ||
deferred.resolve(); | ||
}, | ||
complete() { | ||
deferred.done = true; | ||
deferred.resolve(); | ||
} | ||
}); | ||
const iterator = async function* iterator2() { | ||
for (; ; ) { | ||
if (!pending.length) { | ||
await new Promise((resolve) => deferred.resolve = resolve); | ||
} | ||
while (pending.length) { | ||
yield pending.shift(); | ||
} | ||
if (deferred.error) { | ||
throw deferred.error; | ||
} | ||
if (deferred.done) { | ||
return; | ||
} | ||
} | ||
}(); | ||
iterator.throw = async (err) => { | ||
if (!deferred.done) { | ||
deferred.done = true; | ||
deferred.error = err; | ||
deferred.resolve(); | ||
} | ||
return { done: true, value: undefined }; | ||
}; | ||
iterator.return = async () => { | ||
dispose(); | ||
return { done: true, value: undefined }; | ||
}; | ||
return iterator; | ||
}, | ||
async dispose() { | ||
disposed = true; | ||
if (connecting) { | ||
const [socket] = await connecting; | ||
socket.close(1e3, "Normal Closure"); | ||
} | ||
}, | ||
terminate() { | ||
if (connecting) { | ||
emitter.emit("closed", new TerminatedCloseEvent()); | ||
} | ||
} | ||
}; | ||
} | ||
class TerminatedCloseEvent extends Error { | ||
name = "TerminatedCloseEvent"; | ||
message = "4499: Terminated"; | ||
code = 4499; | ||
reason = "Terminated"; | ||
wasClean = false; | ||
} | ||
function isLikeCloseEvent(val) { | ||
return isObject(val) && "code" in val && "reason" in val; | ||
} | ||
function isFatalInternalCloseCode(code) { | ||
if ([ | ||
1e3, | ||
// Normal Closure is not an erroneous close code | ||
1001, | ||
// Going Away | ||
1006, | ||
// Abnormal Closure | ||
1005, | ||
// No Status Received | ||
1012, | ||
// Service Restart | ||
1013, | ||
// Try Again Later | ||
1014 | ||
// Bad Gateway | ||
].includes(code)) | ||
return false; | ||
return code >= 1e3 && code <= 1999; | ||
} | ||
function isWebSocket(val) { | ||
return typeof val === "function" && "constructor" in val && "CLOSED" in val && "CLOSING" in val && "CONNECTING" in val && "OPEN" in val; | ||
} | ||
exports.DEPRECATED_GRAPHQL_WS_PROTOCOL = DEPRECATED_GRAPHQL_WS_PROTOCOL; | ||
exports.GRAPHQL_TRANSPORT_WS_PROTOCOL = GRAPHQL_TRANSPORT_WS_PROTOCOL; | ||
exports.TerminatedCloseEvent = TerminatedCloseEvent; | ||
exports.createClient = createClient; | ||
exports.isMessage = isMessage; | ||
exports.parseMessage = parseMessage; | ||
exports.stringifyMessage = stringifyMessage; | ||
exports.validateMessage = validateMessage; | ||
exports.CloseCode = CloseCode; | ||
exports.DEPRECATED_GRAPHQL_WS_PROTOCOL = DEPRECATED_GRAPHQL_WS_PROTOCOL; | ||
exports.GRAPHQL_TRANSPORT_WS_PROTOCOL = GRAPHQL_TRANSPORT_WS_PROTOCOL; | ||
exports.MessageType = MessageType; | ||
exports.TerminatedCloseEvent = TerminatedCloseEvent; | ||
exports.createClient = createClient; | ||
exports.isMessage = isMessage; | ||
exports.parseMessage = parseMessage; | ||
exports.stringifyMessage = stringifyMessage; | ||
exports.validateMessage = validateMessage; | ||
})); |
@@ -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";function o(e){return this instanceof o?(this.v=e,this):new o(e)}function t(e,t,r){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var n,s=r.apply(e,t||[]),i=[];return n=Object.create(("function"==typeof AsyncIterator?AsyncIterator:Object).prototype),a("next"),a("throw"),a("return",(function(e){return function(o){return Promise.resolve(o).then(e,p)}})),n[Symbol.asyncIterator]=function(){return this},n;function a(e,o){s[e]&&(n[e]=function(o){return new Promise((function(t,r){i.push([e,o,t,r])>1||c(e,o)}))},o&&(n[e]=o(n[e])))}function c(e,t){try{(r=s[e](t)).value instanceof o?Promise.resolve(r.value.v).then(l,p):d(i[0][2],r)}catch(e){d(i[0][3],e)}var r}function l(e){c("next",e)}function p(e){c("throw",e)}function d(e,o){e(o),i.shift(),i.length&&c(i[0][0],i[0][1])}}function r(e){return null===e?"null":Array.isArray(e)?"array":typeof e}function n(e){return"object"===r(e)}function s(e,o){return e.length<124?e:o}"function"==typeof SuppressedError&&SuppressedError;const i="graphql-transport-ws";var a,c;function l(o){if(!n(o))throw new Error(`Message is expected to be an object, but got ${r(o)}`);if(!o.type)throw new Error("Message is missing the 'type' property");if("string"!=typeof o.type)throw new Error(`Message is expects the 'type' property to be a string, but got ${r(o.type)}`);switch(o.type){case e.MessageType.ConnectionInit:case e.MessageType.ConnectionAck:case e.MessageType.Ping:case e.MessageType.Pong:if(null!=o.payload&&!n(o.payload))throw new Error(`"${o.type}" message expects the 'payload' property to be an object or nullish or missing, but got "${o.payload}"`);break;case e.MessageType.Subscribe:if("string"!=typeof o.id)throw new Error(`"${o.type}" message expects the 'id' property to be a string, but got ${r(o.id)}`);if(!o.id)throw new Error(`"${o.type}" message requires a non-empty 'id' property`);if(!n(o.payload))throw new Error(`"${o.type}" message expects the 'payload' property to be an object, but got ${r(o.payload)}`);if("string"!=typeof o.payload.query)throw new Error(`"${o.type}" message payload expects the 'query' property to be a string, but got ${r(o.payload.query)}`);if(null!=o.payload.variables&&!n(o.payload.variables))throw new Error(`"${o.type}" message payload expects the 'variables' property to be a an object or nullish or missing, but got ${r(o.payload.variables)}`);if(null!=o.payload.operationName&&"string"!==r(o.payload.operationName))throw new Error(`"${o.type}" message payload expects the 'operationName' property to be a string or nullish or missing, but got ${r(o.payload.operationName)}`);if(null!=o.payload.extensions&&!n(o.payload.extensions))throw new Error(`"${o.type}" message payload expects the 'extensions' property to be a an object or nullish or missing, but got ${r(o.payload.extensions)}`);break;case e.MessageType.Next:if("string"!=typeof o.id)throw new Error(`"${o.type}" message expects the 'id' property to be a string, but got ${r(o.id)}`);if(!o.id)throw new Error(`"${o.type}" message requires a non-empty 'id' property`);if(!n(o.payload))throw new Error(`"${o.type}" message expects the 'payload' property to be an object, but got ${r(o.payload)}`);break;case e.MessageType.Error:if("string"!=typeof o.id)throw new Error(`"${o.type}" message expects the 'id' property to be a string, but got ${r(o.id)}`);if(!o.id)throw new Error(`"${o.type}" message requires a non-empty 'id' property`);if(t=o.payload,!(Array.isArray(t)&&t.length>0&&t.every((e=>"message"in e))))throw new Error(`"${o.type}" message expects the 'payload' property to be an array of GraphQL errors, but got ${JSON.stringify(o.payload)}`);break;case e.MessageType.Complete:if("string"!=typeof o.id)throw new Error(`"${o.type}" message expects the 'id' property to be a string, but got ${r(o.id)}`);if(!o.id)throw new Error(`"${o.type}" message requires a non-empty 'id' property`);break;default:throw new Error(`Invalid message 'type' property "${o.type}"`)}var t;return o}function p(e,o){return l("string"==typeof e?JSON.parse(e,o):e)}function d(e,o){return l(e),JSON.stringify(e,o)}e.CloseCode=void 0,(a=e.CloseCode||(e.CloseCode={}))[a.InternalServerError=4500]="InternalServerError",a[a.InternalClientError=4005]="InternalClientError",a[a.BadRequest=4400]="BadRequest",a[a.BadResponse=4004]="BadResponse",a[a.Unauthorized=4401]="Unauthorized",a[a.Forbidden=4403]="Forbidden",a[a.SubprotocolNotAcceptable=4406]="SubprotocolNotAcceptable",a[a.ConnectionInitialisationTimeout=4408]="ConnectionInitialisationTimeout",a[a.ConnectionAcknowledgementTimeout=4504]="ConnectionAcknowledgementTimeout",a[a.SubscriberAlreadyExists=4409]="SubscriberAlreadyExists",a[a.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";class y extends Error{constructor(){super(...arguments),this.name="TerminatedCloseEvent",this.message="4499: Terminated",this.code=4499,this.reason="Terminated",this.wasClean=!1}}function u(e){return n(e)&&"code"in e&&"reason"in e}e.DEPRECATED_GRAPHQL_WS_PROTOCOL="graphql-ws",e.GRAPHQL_TRANSPORT_WS_PROTOCOL=i,e.TerminatedCloseEvent=y,e.createClient=function(r){const{url:n,connectionParams:a,lazy:c=!0,onNonLazyError:l=console.error,lazyCloseTimeout:g=0,keepAlive:f=0,disablePong:m,connectionAckWaitTimeout:h=0,retryAttempts:w=5,retryWait:b=async function(e){let o=1e3;for(let t=0;t<e;t++)o*=2;await new Promise((e=>setTimeout(e,o+Math.floor(2700*Math.random()+300))))},shouldRetry:x=u,isFatalConnectionProblem:C,on:v,webSocketImpl:E,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:S,jsonMessageReviver:M}=r;let $;if(E){if(!("function"==typeof(I=E)&&"constructor"in I&&"CLOSED"in I&&"CLOSING"in I&&"CONNECTING"in I&&"OPEN"in I))throw new Error("Invalid WebSocket implementation provided");$=E}else"undefined"!=typeof WebSocket?$=WebSocket:"undefined"!=typeof global?$=global.WebSocket||global.MozWebSocket:"undefined"!=typeof window&&($=window.WebSocket||window.MozWebSocket);var I;if(!$)throw new Error("WebSocket implementation missing; on Node you can `import WebSocket from 'ws';` and pass `webSocketImpl: WebSocket` to `createClient`");const P=$,N=(()=>{const e=(()=>{const e={};return{on:(o,t)=>(e[o]=t,()=>{delete e[o]}),emit(o){var t;"id"in o&&(null===(t=e[o.id])||void 0===t||t.call(e,o))}}})(),o={connecting:(null==v?void 0:v.connecting)?[v.connecting]:[],opened:(null==v?void 0:v.opened)?[v.opened]:[],connected:(null==v?void 0:v.connected)?[v.connected]:[],ping:(null==v?void 0:v.ping)?[v.ping]:[],pong:(null==v?void 0:v.pong)?[v.pong]:[],message:(null==v?void 0:v.message)?[e.emit,v.message]:[e.emit],closed:(null==v?void 0:v.closed)?[v.closed]:[],error:(null==v?void 0:v.error)?[v.error]:[]};return{onMessage:e.on,on(e,t){const r=o[e];return r.push(t),()=>{r.splice(r.indexOf(t),1)}},emit(e,...t){for(const r of[...o[e]])r(...t)}}})();function k(e){const o=[N.on("error",(t=>{o.forEach((e=>e())),e(t)})),N.on("closed",(t=>{o.forEach((e=>e())),e(t)}))]}let A,O,R=0,q=!1,W=0,j=!1;async function L(){clearTimeout(O);const[o,t]=await(null!=A?A:A=new Promise(((o,t)=>(async()=>{if(q){if(await b(W),!R)return A=void 0,t({code:1e3,reason:"All Subscriptions Gone"});W++}N.emit("connecting",q);const r=new P("function"==typeof n?await n():n,i);let c,l;function u(){isFinite(f)&&f>0&&(clearTimeout(l),l=setTimeout((()=>{r.readyState===P.OPEN&&(r.send(d({type:e.MessageType.Ping})),N.emit("ping",!1,void 0))}),f))}k((e=>{A=void 0,clearTimeout(c),clearTimeout(l),t(e),e instanceof y&&(r.close(4499,"Terminated"),r.onerror=null,r.onclose=null)})),r.onerror=e=>N.emit("error",e),r.onclose=e=>N.emit("closed",e),r.onopen=async()=>{try{N.emit("opened",r);const o="function"==typeof a?await a():a;if(r.readyState!==P.OPEN)return;r.send(d(o?{type:e.MessageType.ConnectionInit,payload:o}:{type:e.MessageType.ConnectionInit},S)),isFinite(h)&&h>0&&(c=setTimeout((()=>{r.close(e.CloseCode.ConnectionAcknowledgementTimeout,"Connection acknowledgement timeout")}),h)),u()}catch(o){N.emit("error",o),r.close(e.CloseCode.InternalClientError,s(o instanceof Error?o.message:new Error(o).message,"Internal client error"))}};let g=!1;r.onmessage=({data:t})=>{try{const n=p(t,M);if(N.emit("message",n),"ping"===n.type||"pong"===n.type)return N.emit(n.type,!0,n.payload),void("pong"===n.type?u():m||(r.send(d(n.payload?{type:e.MessageType.Pong,payload:n.payload}:{type:e.MessageType.Pong})),N.emit("pong",!1,n.payload)));if(g)return;if(n.type!==e.MessageType.ConnectionAck)throw new Error(`First message cannot be of type ${n.type}`);clearTimeout(c),g=!0,N.emit("connected",r,n.payload,q),q=!1,W=0,o([r,new Promise(((e,o)=>k(o)))])}catch(o){r.onmessage=null,N.emit("error",o),r.close(e.CloseCode.BadResponse,s(o instanceof Error?o.message:new Error(o).message,"Bad response"))}}})())));o.readyState===P.CLOSING&&await t;let r=()=>{};const c=new Promise((e=>r=e));return[o,r,Promise.race([c.then((()=>{if(!R){const e=()=>o.close(1e3,"Normal Closure");isFinite(g)&&g>0?O=setTimeout((()=>{o.readyState===P.OPEN&&e()}),g):e()}})),t])]}function z(o){if(u(o)&&(t=o.code,![1e3,1001,1006,1005,1012,1013,1014].includes(t)&&t>=1e3&&t<=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 t;if(j)return!1;if(u(o)&&1e3===o.code)return R>0;if(!w||W>=w)throw o;if(!x(o))throw o;if(null==C?void 0:C(o))throw o;return q=!0}function B(o,t){const r=T(o);let n=!1,s=!1,i=()=>{R--,n=!0};return(async()=>{for(R++;;)try{const[a,c,l]=await L();if(n)return c();const p=N.onMessage(r,(o=>{switch(o.type){case e.MessageType.Next:return void t.next(o.payload);case e.MessageType.Error:return s=!0,n=!0,t.error(o.payload),void i();case e.MessageType.Complete:return n=!0,void i()}}));return a.send(d({id:r,type:e.MessageType.Subscribe,payload:o},S)),i=()=>{n||a.readyState!==P.OPEN||a.send(d({id:r,type:e.MessageType.Complete},S)),R--,n=!0,c()},void await l.finally(p)}catch(e){if(!z(e))return}})().then((()=>{s||t.complete()})).catch((e=>{t.error(e)})),()=>{n||i()}}return c||(async()=>{for(R++;;)try{const[,,e]=await L();await e}catch(e){try{if(!z(e))return}catch(e){return null==l?void 0:l(e)}}})(),{on:N.on,subscribe:B,iterate(e){const r=[],n={done:!1,error:null,resolve:()=>{}},s=B(e,{next(e){r.push(e),n.resolve()},error(e){n.done=!0,n.error=e,n.resolve()},complete(){n.done=!0,n.resolve()}}),i=function(){return t(this,arguments,(function*(){for(;;){for(r.length||(yield o(new Promise((e=>n.resolve=e))));r.length;)yield yield o(r.shift());if(n.error)throw n.error;if(n.done)return yield o(void 0)}}))}();return i.throw=async e=>(n.done||(n.done=!0,n.error=e,n.resolve()),{done:!0,value:void 0}),i.return=async()=>(s(),{done:!0,value:void 0}),i},async dispose(){if(j=!0,A){const[e]=await A;e.close(1e3,"Normal Closure")}},terminate(){A&&N.emit("closed",new y)}}},e.isMessage=function(e){try{return l(e),!0}catch(e){return!1}},e.parseMessage=p,e.stringifyMessage=d,e.validateMessage=l})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).graphqlWs={})}(this,(function(e){"use strict";function t(e){return null===e?"null":Array.isArray(e)?"array":typeof e}function o(e){return"object"===t(e)}function r(e,t){return e.length<124?e:t}const n="graphql-transport-ws";var i=(e=>(e[e.InternalServerError=4500]="InternalServerError",e[e.InternalClientError=4005]="InternalClientError",e[e.BadRequest=4400]="BadRequest",e[e.BadResponse=4004]="BadResponse",e[e.Unauthorized=4401]="Unauthorized",e[e.Forbidden=4403]="Forbidden",e[e.SubprotocolNotAcceptable=4406]="SubprotocolNotAcceptable",e[e.ConnectionInitialisationTimeout=4408]="ConnectionInitialisationTimeout",e[e.ConnectionAcknowledgementTimeout=4504]="ConnectionAcknowledgementTimeout",e[e.SubscriberAlreadyExists=4409]="SubscriberAlreadyExists",e[e.TooManyInitialisationRequests=4429]="TooManyInitialisationRequests",e))(i||{}),a=(e=>(e.ConnectionInit="connection_init",e.ConnectionAck="connection_ack",e.Ping="ping",e.Pong="pong",e.Subscribe="subscribe",e.Next="next",e.Error="error",e.Complete="complete",e))(a||{});function s(e){if(!o(e))throw new Error(`Message is expected to be an object, but got ${t(e)}`);if(!e.type)throw new Error("Message is missing the 'type' property");if("string"!=typeof e.type)throw new Error(`Message is expects the 'type' property to be a string, but got ${t(e.type)}`);switch(e.type){case"connection_init":case"connection_ack":case"ping":case"pong":if(null!=e.payload&&!o(e.payload))throw new Error(`"${e.type}" message expects the 'payload' property to be an object or nullish or missing, but got "${e.payload}"`);break;case"subscribe":if("string"!=typeof e.id)throw new Error(`"${e.type}" message expects the 'id' property to be a string, but got ${t(e.id)}`);if(!e.id)throw new Error(`"${e.type}" message requires a non-empty 'id' property`);if(!o(e.payload))throw new Error(`"${e.type}" message expects the 'payload' property to be an object, but got ${t(e.payload)}`);if("string"!=typeof e.payload.query)throw new Error(`"${e.type}" message payload expects the 'query' property to be a string, but got ${t(e.payload.query)}`);if(null!=e.payload.variables&&!o(e.payload.variables))throw new Error(`"${e.type}" message payload expects the 'variables' property to be a an object or nullish or missing, but got ${t(e.payload.variables)}`);if(null!=e.payload.operationName&&"string"!==t(e.payload.operationName))throw new Error(`"${e.type}" message payload expects the 'operationName' property to be a string or nullish or missing, but got ${t(e.payload.operationName)}`);if(null!=e.payload.extensions&&!o(e.payload.extensions))throw new Error(`"${e.type}" message payload expects the 'extensions' property to be a an object or nullish or missing, but got ${t(e.payload.extensions)}`);break;case"next":if("string"!=typeof e.id)throw new Error(`"${e.type}" message expects the 'id' property to be a string, but got ${t(e.id)}`);if(!e.id)throw new Error(`"${e.type}" message requires a non-empty 'id' property`);if(!o(e.payload))throw new Error(`"${e.type}" message expects the 'payload' property to be an object, but got ${t(e.payload)}`);break;case"error":if("string"!=typeof e.id)throw new Error(`"${e.type}" message expects the 'id' property to be a string, but got ${t(e.id)}`);if(!e.id)throw new Error(`"${e.type}" message requires a non-empty 'id' property`);if(r=e.payload,!(Array.isArray(r)&&r.length>0&&r.every((e=>"message"in e))))throw new Error(`"${e.type}" message expects the 'payload' property to be an array of GraphQL errors, but got ${JSON.stringify(e.payload)}`);break;case"complete":if("string"!=typeof e.id)throw new Error(`"${e.type}" message expects the 'id' property to be a string, but got ${t(e.id)}`);if(!e.id)throw new Error(`"${e.type}" message requires a non-empty 'id' property`);break;default:throw new Error(`Invalid message 'type' property "${e.type}"`)}var r;return e}function c(e,t){return s("string"==typeof e?JSON.parse(e,t):e)}function p(e,t){return s(e),JSON.stringify(e,t)}class l extends Error{name="TerminatedCloseEvent";message="4499: Terminated";code=4499;reason="Terminated";wasClean=!1}function d(e){return o(e)&&"code"in e&&"reason"in e}e.CloseCode=i,e.DEPRECATED_GRAPHQL_WS_PROTOCOL="graphql-ws",e.GRAPHQL_TRANSPORT_WS_PROTOCOL=n,e.MessageType=a,e.TerminatedCloseEvent=l,e.createClient=function(e){const{url:t,connectionParams:o,lazy:s=!0,onNonLazyError:y=console.error,lazyCloseTimeout:u=0,keepAlive:g=0,disablePong:m,connectionAckWaitTimeout:f=0,retryAttempts:b=5,retryWait:w=async function(e){let t=1e3;for(let o=0;o<e;o++)t*=2;await new Promise((e=>setTimeout(e,t+Math.floor(2700*Math.random()+300))))},shouldRetry:h=d,isFatalConnectionProblem:x,on:E,webSocketImpl:S,generateID:v=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(e=>{const t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)}))},jsonMessageReplacer:C,jsonMessageReviver:T}=e;let $;if(S){if(!("function"==typeof(k=S)&&"constructor"in k&&"CLOSED"in k&&"CLOSING"in k&&"CONNECTING"in k&&"OPEN"in k))throw new Error("Invalid WebSocket implementation provided");$=S}else"undefined"!=typeof WebSocket?$=WebSocket:"undefined"!=typeof global?$=global.WebSocket||global.MozWebSocket:"undefined"!=typeof window&&($=window.WebSocket||window.MozWebSocket);var k;if(!$)throw new Error("WebSocket implementation missing; on Node you can `import WebSocket from 'ws';` and pass `webSocketImpl: WebSocket` to `createClient`");const N=$,P=(()=>{const e=(()=>{const e={};return{on:(t,o)=>(e[t]=o,()=>{delete e[t]}),emit(t){"id"in t&&e[t.id]?.(t)}}})(),t={connecting:E?.connecting?[E.connecting]:[],opened:E?.opened?[E.opened]:[],connected:E?.connected?[E.connected]:[],ping:E?.ping?[E.ping]:[],pong:E?.pong?[E.pong]:[],message:E?.message?[e.emit,E.message]:[e.emit],closed:E?.closed?[E.closed]:[],error:E?.error?[E.error]:[]};return{onMessage:e.on,on(e,o){const r=t[e];return r.push(o),()=>{r.splice(r.indexOf(o),1)}},emit(e,...o){for(const r of[...t[e]])r(...o)}}})();function I(e){const t=[P.on("error",(o=>{t.forEach((e=>e())),e(o)})),P.on("closed",(o=>{t.forEach((e=>e())),e(o)}))]}let A,M,O=0,R=!1,q=0,W=!1;async function j(){clearTimeout(M);const[e,s]=await(A??(A=new Promise(((e,s)=>(async()=>{if(R){if(await w(q),!O)return A=void 0,s({code:1e3,reason:"All Subscriptions Gone"});q++}P.emit("connecting",R);const d=new N("function"==typeof t?await t():t,n);let y,u;function b(){isFinite(g)&&g>0&&(clearTimeout(u),u=setTimeout((()=>{d.readyState===N.OPEN&&(d.send(p({type:a.Ping})),P.emit("ping",!1,void 0))}),g))}I((e=>{A=void 0,clearTimeout(y),clearTimeout(u),s(e),e instanceof l&&(d.close(4499,"Terminated"),d.onerror=null,d.onclose=null)})),d.onerror=e=>P.emit("error",e),d.onclose=e=>P.emit("closed",e),d.onopen=async()=>{try{P.emit("opened",d);const e="function"==typeof o?await o():o;if(d.readyState!==N.OPEN)return;d.send(p(e?{type:a.ConnectionInit,payload:e}:{type:a.ConnectionInit},C)),isFinite(f)&&f>0&&(y=setTimeout((()=>{d.close(i.ConnectionAcknowledgementTimeout,"Connection acknowledgement timeout")}),f)),b()}catch(e){P.emit("error",e),d.close(i.InternalClientError,r(e instanceof Error?e.message:String(e),"Internal client error"))}};let h=!1;d.onmessage=({data:t})=>{try{const o=c(t,T);if(P.emit("message",o),"ping"===o.type||"pong"===o.type)return P.emit(o.type,!0,o.payload),void("pong"===o.type?b():m||(d.send(p(o.payload?{type:a.Pong,payload:o.payload}:{type:a.Pong})),P.emit("pong",!1,o.payload)));if(h)return;if(o.type!==a.ConnectionAck)throw new Error(`First message cannot be of type ${o.type}`);clearTimeout(y),h=!0,P.emit("connected",d,o.payload,R),R=!1,q=0,e([d,new Promise(((e,t)=>I(t)))])}catch(e){d.onmessage=null,P.emit("error",e),d.close(i.BadResponse,r(e instanceof Error?e.message:String(e),"Bad response"))}}})()))));e.readyState===N.CLOSING&&await s;let d=()=>{};const y=new Promise((e=>d=e));return[e,d,Promise.race([y.then((()=>{if(!O){const t=()=>e.close(1e3,"Normal Closure");isFinite(u)&&u>0?M=setTimeout((()=>{e.readyState===N.OPEN&&t()}),u):t()}})),s])]}function _(e){if(d(e)&&(t=e.code,![1e3,1001,1006,1005,1012,1013,1014].includes(t)&&t>=1e3&&t<=1999||[i.InternalServerError,i.InternalClientError,i.BadRequest,i.BadResponse,i.Unauthorized,i.SubprotocolNotAcceptable,i.SubscriberAlreadyExists,i.TooManyInitialisationRequests].includes(e.code)))throw e;var t;if(W)return!1;if(d(e)&&1e3===e.code)return O>0;if(!b||q>=b)throw e;if(!h(e))throw e;if(x?.(e))throw e;return R=!0}function L(e,t){const o=v(e);let r=!1,n=!1,i=()=>{O--,r=!0};return(async()=>{for(O++;;)try{const[s,c,l]=await j();if(r)return c();const d=P.onMessage(o,(e=>{switch(e.type){case a.Next:return void t.next(e.payload);case a.Error:return n=!0,r=!0,t.error(e.payload),void i();case a.Complete:return r=!0,void i()}}));return s.send(p({id:o,type:a.Subscribe,payload:e},C)),i=()=>{r||s.readyState!==N.OPEN||s.send(p({id:o,type:a.Complete},C)),O--,r=!0,c()},void await l.finally(d)}catch(e){if(!_(e))return}})().then((()=>{n||t.complete()})).catch((e=>{t.error(e)})),()=>{r||i()}}return s||(async()=>{for(O++;;)try{const[,,e]=await j();await e}catch(e){try{if(!_(e))return}catch(e){return y?.(e)}}})(),{on:P.on,subscribe:L,iterate(e){const t=[],o={done:!1,error:null,resolve:()=>{}},r=L(e,{next(e){t.push(e),o.resolve()},error(e){o.done=!0,o.error=e,o.resolve()},complete(){o.done=!0,o.resolve()}}),n=async function*(){for(;;){for(t.length||await new Promise((e=>o.resolve=e));t.length;)yield t.shift();if(o.error)throw o.error;if(o.done)return}}();return n.throw=async e=>(o.done||(o.done=!0,o.error=e,o.resolve()),{done:!0,value:void 0}),n.return=async()=>(r(),{done:!0,value:void 0}),n},async dispose(){if(W=!0,A){const[e]=await A;e.close(1e3,"Normal Closure")}},terminate(){A&&P.emit("closed",new l)}}},e.isMessage=function(e){try{return s(e),!0}catch{return!1}},e.parseMessage=c,e.stringifyMessage=p,e.validateMessage=s})); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
23
-25.81%Yes
NaN210388
-38.89%32
-37.25%4930
-11.57%1
Infinity%1
Infinity%