import { print } from 'graphql/language/printer' import { useContext, useEffect, useState } from 'react' export function createWebsocket({ name, uri, token, query, onMessage }) { if (!uri) { let subscriptionProtocol = process.env.REACT_APP_API_URL.includes( 'https', ) ? 'wss' : 'ws' uri = `${subscriptionProtocol}://${ process.env.REACT_APP_API_URL.split('://')[1]}` } const socket = new WebSocket(uri, ['graphql-ws']) socket.onopen = (event) => { console.info(`Opening ${name} WebSocket`, event) socket.send( JSON.stringify({ payload: { authorization: `Bearer ${token}`, headers: { Authorization: `Bearer ${token}`, }, }, type: 'connection_init', }), ) socket.send( JSON.stringify({ id: '1', type: 'start', payload: { variables: {}, extensions: {}, operationName: query.definitions[0].name.value, query: print(query), }, }), ) } socket.onmessage = (messageEvent) => { let data = JSON.parse(messageEvent.data)?.payload?.data?.[ query.definitions[0].selectionSet.selections[0].name.value ] if (data && onMessage) { onMessage(data) } } socket.onclose = (closeEvent) => { if (process.env.NODE_ENV !== 'test') { console.info(`Closing ${name} WebSocket`, closeEvent) } } socket.onerror = (event) => { if (process.env.NODE_ENV !== 'test') { console.error(`Error ${name} WebSocket`, event) throw new Error(event) } } return socket } export default function useSubscription(options) { const { authToken } = useContext(AuthContext) let [socket, setSocket] = useState() if (!options?.token) { options.token = authToken } useEffect( () => { if (process.env.REACT_APP_BUILD_ENV !== 'integration') { setSocket(createWebsocket(options)) } return () => { if (process.env.NODE_ENV !== 'test') { console.info(`Unmount Closing ${options?.name} WebSocket`) } try { if (socket) { socket.close() } } catch (exception) { console.error('Socket already closed.', exception) } } }, // eslint-disable-next-line react-hooks/exhaustive-deps [], ) return socket }