@vuu-ui/vuu-data-remote 0.13.103-alpha.1 → 0.13.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketConnection.js","sources":["../../../packages/vuu-data-remote/src/WebSocketConnection.ts"],"sourcesContent":["import { WebSocketProtocol } from \"@vuu-ui/vuu-data-types\";\nimport {\n InvalidSessionReason,\n InvalidTokenReason,\n LoginErrorMessage,\n VuuClientMessage,\n VuuServerMessage,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport {\n DeferredPromise,\n EventEmitter,\n isLoginErrorMessage,\n logger,\n} from \"@vuu-ui/vuu-utils\";\n\nexport type ConnectionPhase =\n | \"initial-connection\"\n | \"post-disconnect-reconnection\";\nexport type ConnectingStatus = \"connecting\" | \"reconnecting\";\nexport type ConnectedStatus = \"connected\" | \"reconnected\";\nexport type ConnectionStatus =\n | ConnectingStatus\n | ConnectedStatus\n | \"closed\"\n | \"websocket-open\"\n | \"disconnected\"\n | \"failed\"\n | \"inactive\";\n\nexport const isInvalidTokenReason = (\n text: string,\n): text is InvalidTokenReason =>\n text === \"Invalid token\" || text === \"Token has expired\";\n\nexport const isInvalidSessionReason = (\n text: string,\n): text is InvalidSessionReason =>\n text === \"Invalid session\" || text === \"User session limit exceeded\";\n\nconst { debug, debugEnabled, info } = logger(\"WebSocketConnection\");\n\nexport const isWebSocketConnectionStatus = (\n msg: unknown,\n): msg is ConnectionStatus =>\n typeof msg === \"string\" &&\n [\n \"connecting\",\n \"websocket-open\",\n \"connected\",\n \"reconnecting\",\n \"reconnected\",\n \"disconnected\",\n \"closed\",\n \"failed\",\n ].includes(msg);\n\nexport const isConnected = (\n status: ConnectionStatus,\n): status is ConnectedStatus =>\n status === \"connected\" || status === \"reconnected\";\n\nexport type LoginRejectedMessage = {\n type: \"LOGIN_REJECTED\";\n reason: LoginErrorMessage;\n};\n\nexport const isLoginRejectedMessage = (\n message: object,\n): message is LoginRejectedMessage =>\n message !== null && \"type\" in message && message.type === \"LOGIN_REJECTED\";\n\nexport type VuuServerMessageCallback = (\n msg: VuuServerMessage | LoginRejectedMessage,\n) => void;\n\nexport type WebSocketConnectionConfig = {\n url: string;\n protocols: WebSocketProtocol;\n callback: VuuServerMessageCallback;\n connectionTimeout?: number;\n};\n\nconst DEFAULT_CONNECTION_TIMEOUT = 10000;\n\nconst parseWebSocketMessage = (message: string): VuuServerMessage => {\n try {\n return JSON.parse(message) as VuuServerMessage;\n } catch (e) {\n throw Error(`Error parsing JSON response from server ${message}`);\n }\n};\n\nexport type WebSocketConnectionCloseReason =\n | LoginErrorMessage\n | \"failure\"\n | \"shutdown\";\n\nexport type WebSocketConnectionEvents = {\n \"connection-status\": (status: ConnectionStatus) => void;\n};\n\nexport class WebSocketConnection extends EventEmitter<WebSocketConnectionEvents> {\n #callback;\n /**\n We are not confirmedOpen until we receive the first message from the\n server. If we get an unexpected close event before that, we consider\n the reconnect attempts as still within the connection phase, not true\n reconnection. This can happen e.g. when connecting to remote host via\n a proxy.\n */\n #confirmedOpen = false;\n #connectionPhase: ConnectionPhase = \"initial-connection\";\n #connectionStatus: ConnectionStatus = \"closed\";\n\n #connectionTimeout;\n #deferredOpen?: DeferredPromise;\n #protocols;\n #url;\n #ws?: WebSocket;\n\n constructor({\n callback,\n connectionTimeout = DEFAULT_CONNECTION_TIMEOUT,\n protocols,\n url,\n }: WebSocketConnectionConfig) {\n super();\n\n this.#callback = callback;\n this.#connectionTimeout = connectionTimeout;\n this.#url = url;\n this.#protocols = protocols;\n }\n\n get websocket() {\n return this.#ws;\n }\n\n get connectionTimeout() {\n return this.#connectionTimeout;\n }\n\n get protocols() {\n return this.#protocols;\n }\n\n get isClosed() {\n return this.#connectionStatus === \"closed\";\n }\n get isDisconnected() {\n return this.#connectionStatus === \"disconnected\";\n }\n\n get connectionPhase() {\n return this.#connectionPhase;\n }\n\n get connectionStatus() {\n return this.#connectionStatus;\n }\n\n private set connectionStatus(connectionStatus: ConnectionStatus) {\n if (\n connectionStatus !== \"connecting\" &&\n connectionStatus !== \"reconnecting\"\n ) {\n this.#connectionStatus = connectionStatus;\n this.emit(\"connection-status\", this.#connectionStatus);\n }\n }\n\n get confirmedOpen() {\n return this.#confirmedOpen;\n }\n\n /**\n * We are 'confirmedOpen' when we see the first message transmitted\n * from the server. This ensures that even if we have one or more\n * proxies in our route to the endPoint, all connections have been\n * opened successfully.\n * First time in here (on our initial successful connection) we switch\n * from 'connect' phase to 'reconnect' phase. We may have different\n * retry configurations for these two phases.\n */\n private set confirmedOpen(confirmedOpen: boolean) {\n this.#confirmedOpen = confirmedOpen;\n if (confirmedOpen && this.#connectionPhase === \"initial-connection\") {\n this.#connectionPhase = \"post-disconnect-reconnection\";\n }\n }\n\n get url() {\n return this.#url;\n }\n\n async openWebSocket() {\n const initialConnect = this.#connectionPhase === \"initial-connection\";\n if (this.#deferredOpen === undefined) {\n this.#deferredOpen = new DeferredPromise();\n }\n const { connectionTimeout, protocols, url } = this;\n this.#connectionStatus = initialConnect ? \"connecting\" : \"reconnecting\";\n\n const timer = setTimeout(() => {\n throw Error(\n `Failed to open WebSocket connection to ${url}, timed out after ${connectionTimeout}ms`,\n );\n }, connectionTimeout);\n\n const ws = (this.#ws = new WebSocket(url, protocols));\n\n ws.onopen = () => {\n this.connectionStatus = \"websocket-open\";\n\n clearTimeout(timer);\n\n // Do we do this here or after login\n if (this.#deferredOpen) {\n this.#deferredOpen.resolve(undefined);\n this.#deferredOpen = undefined;\n }\n };\n\n ws.onerror = () => {\n clearTimeout(timer);\n };\n\n ws.onclose = () => {\n if (!this.isClosed) {\n this.confirmedOpen = false;\n // Do we emit disconnected even if not confirmed open ?\n // this will emit disconnected\n this.connectionStatus = \"disconnected\";\n // this will emit closed\n this.close(\"failure\");\n }\n };\n\n ws.onmessage = (evt) => {\n this.receive(evt);\n };\n\n return this.#deferredOpen?.promise;\n }\n\n private receive = (evt: MessageEvent) => {\n if (isLoginErrorMessage(evt.data)) {\n console.log(`[WebSocketConnection] closed because of login issue`);\n if (this.#deferredOpen) {\n console.log(`... and qwe have a deferred connection`);\n }\n\n this.#callback({\n type: \"LOGIN_REJECTED\",\n reason: evt.data,\n });\n this.close(evt.data);\n } else {\n const vuuMessageFromServer = parseWebSocketMessage(evt.data);\n\n if (debugEnabled) {\n if (vuuMessageFromServer.body.type !== \"HB\") {\n debug(`${vuuMessageFromServer.body.type}`);\n if (vuuMessageFromServer.body.type === \"CHANGE_VP_SUCCESS\") {\n debug(JSON.stringify(vuuMessageFromServer.body));\n }\n }\n }\n this.#callback(vuuMessageFromServer);\n\n if (!this.confirmedOpen) {\n if (vuuMessageFromServer.body.type === \"LOGIN_SUCCESS\") {\n // Now that we are confirmedOpen any subsequent close events\n // will be treated as part of a reconnection phase.\n this.connectionStatus =\n this.#connectionPhase === \"initial-connection\"\n ? \"connected\"\n : \"reconnected\";\n this.confirmedOpen = true;\n }\n }\n }\n };\n\n send = (msg: VuuClientMessage) => {\n if (msg.body.type === \"CHANGE_VP_RANGE\") {\n info?.(\n `CHANGE_VP_RANGE<#${msg.requestId}> ${msg.body.from}-${msg.body.to}`,\n );\n }\n this.#ws?.send(JSON.stringify(msg));\n };\n\n close(reason: WebSocketConnectionCloseReason = \"shutdown\") {\n this.connectionStatus = \"closed\";\n if (reason === \"failure\") {\n if (this.#deferredOpen) {\n this.#deferredOpen.reject(Error(\"connection failed\"));\n this.#deferredOpen = undefined;\n }\n } else {\n this.#ws?.close();\n }\n this.#ws = undefined;\n }\n}\n"],"names":["logger"],"mappings":";;;;AAuCsCA,gBAAO,qBAAqB;AAE3D,MAAM,2BAA8B,GAAA,CACzC,GAEA,KAAA,OAAO,QAAQ,QACf,IAAA;AAAA,EACE,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,WAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,CAAE,SAAS,GAAG;AAET,MAAM,WAAc,GAAA,CACzB,MAEA,KAAA,MAAA,KAAW,eAAe,MAAW,KAAA;;;;;"}
1
+ {"version":3,"file":"WebSocketConnection.js","sources":["../../../packages/vuu-data-remote/src/WebSocketConnection.ts"],"sourcesContent":["import { WebSocketProtocol } from \"@vuu-ui/vuu-data-types\";\nimport {\n InvalidSessionReason,\n InvalidTokenReason,\n LoginErrorMessage,\n VuuClientMessage,\n VuuServerMessage,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport {\n DeferredPromise,\n EventEmitter,\n isLoginErrorMessage,\n logger,\n} from \"@vuu-ui/vuu-utils\";\n\nexport type ConnectionPhase =\n | \"initial-connection\"\n | \"post-disconnect-reconnection\";\nexport type ConnectingStatus = \"connecting\" | \"reconnecting\";\nexport type ConnectedStatus = \"connected\" | \"reconnected\";\nexport type ConnectionStatus =\n | ConnectingStatus\n | ConnectedStatus\n | \"closed\"\n | \"websocket-open\"\n | \"disconnected\"\n | \"failed\"\n | \"inactive\";\n\nexport const isInvalidTokenReason = (\n text: string,\n): text is InvalidTokenReason =>\n text === \"Invalid token\" || text === \"Token has expired\";\n\nexport const isInvalidSessionReason = (\n text: string,\n): text is InvalidSessionReason =>\n text === \"Invalid session\" || text === \"User session limit exceeded\";\n\nconst { debug, debugEnabled, info } = logger(\"WebSocketConnection\");\n\nexport const isWebSocketConnectionStatus = (\n msg: unknown,\n): msg is ConnectionStatus =>\n typeof msg === \"string\" &&\n [\n \"connecting\",\n \"websocket-open\",\n \"connected\",\n \"reconnecting\",\n \"reconnected\",\n \"disconnected\",\n \"closed\",\n \"failed\",\n ].includes(msg);\n\nexport const isConnected = (\n status: ConnectionStatus,\n): status is ConnectedStatus =>\n status === \"connected\" || status === \"reconnected\";\n\nexport type LoginRejectedMessage = {\n type: \"LOGIN_REJECTED\";\n reason: LoginErrorMessage;\n};\n\nexport const isLoginRejectedMessage = (\n message: object,\n): message is LoginRejectedMessage =>\n message !== null && \"type\" in message && message.type === \"LOGIN_REJECTED\";\n\nexport type VuuServerMessageCallback = (\n msg: VuuServerMessage | LoginRejectedMessage,\n) => void;\n\nexport type WebSocketConnectionConfig = {\n url: string;\n protocols: WebSocketProtocol;\n callback: VuuServerMessageCallback;\n connectionTimeout?: number;\n};\n\nconst DEFAULT_CONNECTION_TIMEOUT = 10000;\n\nconst parseWebSocketMessage = (message: string): VuuServerMessage => {\n try {\n return JSON.parse(message) as VuuServerMessage;\n } catch (e) {\n throw Error(`Error parsing JSON response from server ${message}`);\n }\n};\n\nexport type WebSocketConnectionCloseReason =\n | LoginErrorMessage\n | \"failure\"\n | \"shutdown\";\n\nexport type WebSocketConnectionEvents = {\n \"connection-status\": (status: ConnectionStatus) => void;\n};\n\nexport class WebSocketConnection extends EventEmitter<WebSocketConnectionEvents> {\n #callback;\n /**\n We are not confirmedOpen until we receive the first message from the\n server. If we get an unexpected close event before that, we consider\n the reconnect attempts as still within the connection phase, not true\n reconnection. This can happen e.g. when connecting to remote host via\n a proxy.\n */\n #confirmedOpen = false;\n #connectionPhase: ConnectionPhase = \"initial-connection\";\n #connectionStatus: ConnectionStatus = \"closed\";\n\n #connectionTimeout;\n #deferredOpen?: DeferredPromise;\n #protocols;\n #url;\n #ws?: WebSocket;\n\n constructor({\n callback,\n connectionTimeout = DEFAULT_CONNECTION_TIMEOUT,\n protocols,\n url,\n }: WebSocketConnectionConfig) {\n super();\n\n this.#callback = callback;\n this.#connectionTimeout = connectionTimeout;\n this.#url = url;\n this.#protocols = protocols;\n }\n\n get connectionTimeout() {\n return this.#connectionTimeout;\n }\n\n get protocols() {\n return this.#protocols;\n }\n\n get isClosed() {\n return this.#connectionStatus === \"closed\";\n }\n get isDisconnected() {\n return this.#connectionStatus === \"disconnected\";\n }\n\n get connectionPhase() {\n return this.#connectionPhase;\n }\n\n get connectionStatus() {\n return this.#connectionStatus;\n }\n\n private set connectionStatus(connectionStatus: ConnectionStatus) {\n if (\n connectionStatus !== \"connecting\" &&\n connectionStatus !== \"reconnecting\"\n ) {\n this.#connectionStatus = connectionStatus;\n this.emit(\"connection-status\", this.#connectionStatus);\n }\n }\n\n get confirmedOpen() {\n return this.#confirmedOpen;\n }\n\n /**\n * We are 'confirmedOpen' when we see the first message transmitted\n * from the server. This ensures that even if we have one or more\n * proxies in our route to the endPoint, all connections have been\n * opened successfully.\n * First time in here (on our initial successful connection) we switch\n * from 'connect' phase to 'reconnect' phase. We may have different\n * retry configurations for these two phases.\n */\n private set confirmedOpen(confirmedOpen: boolean) {\n this.#confirmedOpen = confirmedOpen;\n if (confirmedOpen && this.#connectionPhase === \"initial-connection\") {\n this.#connectionPhase = \"post-disconnect-reconnection\";\n }\n }\n\n get url() {\n return this.#url;\n }\n\n async openWebSocket() {\n const initialConnect = this.#connectionPhase === \"initial-connection\";\n if (this.#deferredOpen === undefined) {\n this.#deferredOpen = new DeferredPromise();\n }\n const { connectionTimeout, protocols, url } = this;\n this.#connectionStatus = initialConnect ? \"connecting\" : \"reconnecting\";\n\n const timer = setTimeout(() => {\n throw Error(\n `Failed to open WebSocket connection to ${url}, timed out after ${connectionTimeout}ms`,\n );\n }, connectionTimeout);\n\n const ws = (this.#ws = new WebSocket(url, protocols));\n\n ws.onopen = () => {\n this.connectionStatus = \"websocket-open\";\n\n clearTimeout(timer);\n\n // Do we do this here or after login\n if (this.#deferredOpen) {\n this.#deferredOpen.resolve(undefined);\n this.#deferredOpen = undefined;\n }\n };\n\n ws.onerror = () => {\n clearTimeout(timer);\n };\n\n ws.onclose = () => {\n if (!this.isClosed) {\n this.confirmedOpen = false;\n // Do we emit disconnected even if not confirmed open ?\n // this will emit disconnected\n this.connectionStatus = \"disconnected\";\n // this will emit closed\n this.close(\"failure\");\n }\n };\n\n ws.onmessage = (evt) => {\n this.receive(evt);\n };\n\n return this.#deferredOpen?.promise;\n }\n\n private receive = (evt: MessageEvent) => {\n if (isLoginErrorMessage(evt.data)) {\n console.log(`[WebSocketConnection] closed because of login issue`);\n if (this.#deferredOpen) {\n console.log(`... and qwe have a deferred connection`);\n }\n\n this.#callback({\n type: \"LOGIN_REJECTED\",\n reason: evt.data,\n });\n this.close(evt.data);\n } else {\n const vuuMessageFromServer = parseWebSocketMessage(evt.data);\n\n if (debugEnabled) {\n if (vuuMessageFromServer.body.type !== \"HB\") {\n debug(`${vuuMessageFromServer.body.type}`);\n if (vuuMessageFromServer.body.type === \"CHANGE_VP_SUCCESS\") {\n debug(JSON.stringify(vuuMessageFromServer.body));\n }\n }\n }\n this.#callback(vuuMessageFromServer);\n\n if (!this.confirmedOpen) {\n if (vuuMessageFromServer.body.type === \"LOGIN_SUCCESS\") {\n // Now that we are confirmedOpen any subsequent close events\n // will be treated as part of a reconnection phase.\n this.connectionStatus =\n this.#connectionPhase === \"initial-connection\"\n ? \"connected\"\n : \"reconnected\";\n this.confirmedOpen = true;\n }\n }\n }\n };\n\n send = (msg: VuuClientMessage) => {\n if (msg.body.type === \"CHANGE_VP_RANGE\") {\n info?.(\n `CHANGE_VP_RANGE<#${msg.requestId}> ${msg.body.from}-${msg.body.to}`,\n );\n }\n this.#ws?.send(JSON.stringify(msg));\n };\n\n close(reason: WebSocketConnectionCloseReason = \"shutdown\") {\n this.connectionStatus = \"closed\";\n if (reason === \"failure\") {\n if (this.#deferredOpen) {\n this.#deferredOpen.reject(Error(\"connection failed\"));\n this.#deferredOpen = undefined;\n }\n } else {\n this.#ws?.close();\n }\n this.#ws = undefined;\n }\n}\n"],"names":["logger"],"mappings":";;;;AAuCsCA,gBAAO,qBAAqB;AAE3D,MAAM,2BAA8B,GAAA,CACzC,GAEA,KAAA,OAAO,QAAQ,QACf,IAAA;AAAA,EACE,YAAA;AAAA,EACA,gBAAA;AAAA,EACA,WAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,CAAE,SAAS,GAAG;AAET,MAAM,WAAc,GAAA,CACzB,MAEA,KAAA,MAAA,KAAW,eAAe,MAAW,KAAA;;;;;"}
@@ -1530,9 +1530,6 @@ var WebSocketConnection = class extends EventEmitter {
1530
1530
  __privateSet(this, _url, url);
1531
1531
  __privateSet(this, _protocols, protocols);
1532
1532
  }
1533
- get websocket() {
1534
- return __privateGet(this, _ws);
1535
- }
1536
1533
  get connectionTimeout() {
1537
1534
  return __privateGet(this, _connectionTimeout);
1538
1535
  }
@@ -1663,28 +1660,6 @@ function addLabelsToLinks(links, viewports) {
1663
1660
  }
1664
1661
  });
1665
1662
  }
1666
- var ConnectionDisruptor = class {
1667
- constructor(server) {
1668
- this.server = server;
1669
- globalThis.websocketDisruptor = this;
1670
- }
1671
- killWebSocket() {
1672
- var _a;
1673
- console.log("close the websocket");
1674
- const ws = this.server["connection"].websocket;
1675
- if (ws) {
1676
- ws.close();
1677
- (_a = ws.onclose) == null ? void 0 : _a.call(
1678
- ws,
1679
- new CloseEvent("close", {
1680
- code: 9e3,
1681
- reason: "Programamtic closure for test",
1682
- wasClean: true
1683
- })
1684
- );
1685
- }
1686
- }
1687
- };
1688
1663
  var ServerProxy = class {
1689
1664
  constructor(connection, callback) {
1690
1665
  __publicField(this, "connection");
@@ -1745,7 +1720,6 @@ var ServerProxy = class {
1745
1720
  this.viewports = /* @__PURE__ */ new Map();
1746
1721
  this.mapClientToServerViewport = /* @__PURE__ */ new Map();
1747
1722
  connection.on("connection-status", this.connectionStatusChanged);
1748
- new ConnectionDisruptor(this);
1749
1723
  }
1750
1724
  async login(authToken) {
1751
1725
  if (authToken) {