Skip to main content
Version: 2.1.0

SSE Client

The SSE Client is a simple SDK that helps to simplify writing server-sent events (SSE) code on the frontend, as well as providing additional functionalities on top of it. It integrates with the RTUS-SEH service to enable real-time updates from the backend to the frontend via server-sent events.

info

Server-sent events works in an identical way to websockets when it comes to handling incoming events, although there are some differences (e.g. it is a one-way connection). For more information, MDN has excellent documentation on server-sent events.

Installation

warning

The RTUS-SEH service must be runninng for SSE Client to connect to.

This documentation assumes that you have already have knowledge on how RTUS (Real-time Update Service) works. If not, visit the RTUS documentation page.

tip

Before proceeding, it is assumed that you have already handled all your access configuration - review the docs if you're having issues with accessing the necessary packages.

Install via command line

npm install @mssfoobar/sse-client

Install via package.json

Add the dependency below into the dependencies object in your package.json, and save the file. Afterwards, run npm i or npm install to install the sse-client.

"@mssfoobar/sse-client": "*"

Configuration Object

SSESubscribeClient

interface BaseSSEClientConfig<T> {
readonly tenantId: string;
readonly mapName: string;
readonly domainURL: string;
readonly init?: boolean;
readonly maxReconnectAttempts?: number;
readonly baseReconnectDelay?: number;
readonly eventHandlers?: { [K in EventName]?: (data: T) => void };
readonly refreshUrl?: string;
readonly onAnyEvent?: (eventName: string, data: T) => void;
readonly onConnected?: (event: Event) => void;
readonly onDisconnected?: (error?: Error) => void;
readonly OnReconnecting?: (attempt: number) => void;
readonly onError?: (error: Error) => void;
}
info

Only tenantId, mapName, and domainURL are mandatory properties when initializing the SSESubScribeClient class, as they are required to form the URL to call the RTUS SEH.

Initialization Example

For User-based mapping
const baseSehUrl = env.PUBLIC_RTUS_SEH_URL;

onMount(() => {
const domainURL = `${baseSehUrl}`;
const tenantId = data.user.active_tenant.tenant_id;
const mapName = "ian";
const userId = data.user.sub;

sseClient = new SSESubscribeClient({
domainURL,
tenantId,
mapName,
userId,
init: false,
maxReconnectAttempts: 10,
baseReconnectDelay: 1000,
eventHandlers: {
Added: (data) => {
const { unread_count, message } = data;
logger.debug("Added.");
},
Updated: (data) => {
const { unread_count, message } = data;
logger.debug("Updated.");
},
Removed: (data) => {
const { unread_count, message } = data;
logger.debug("Removed.");
},
Timeout: (data) => {
const { unread_count, message } = data;
logger.debug("Timeout.");
},
},
onAnyEvent: (eventName, data) => {
logger.debug(`Received event ${eventName}`, data);
// Additional custom handling of the event
},
onConnected: () => {
logger.debug("Connected to SSE");
},
onDisconnected: () => {
logger.debug("Disconnected to SSE");
},
OnReconnecting: () => {
logger.debug("Attempting to reconnect to SSE");
},
OnError: (error) => {
logger.debug("Error handling message here.", error);
},
});
});
info

For map-based mapping for the GIS service, userId is not required to form the URL for RTUS-SEH.

API

maxReconnectAttempts

The maxReconnectAttempts property will determine the maximium amount of time the sse-client will attempt to reconnect to RTUS SEH. If this property is not included in the initialization of the SSESubscribeClient class, it will have a default value of 10.

initialization example of SSESubscribeClient
sseClient = new SSESubscribeClient({
domainURL,
tenantId,
mapName,
userId,
init: false,
maxReconnectAttempts: 10,
baseReconnectDelay: 1000,
.
.
.
});

baseReconnectDelay

The baseReconnectDelay property will determine the delay between reconnection attempts when the SSE client tries to reestablish a connection with the RTUS SEH after being disconnected.

initialization example of SSESubscribeClient
sseClient = new SSESubscribeClient({
domainURL,
tenantId,
mapName,
userId,
init: false,
maxReconnectAttempts: 10,
baseReconnectDelay: 1000,
.
.
.
});

However, as its name suggests, it is only the base reconnection delay time. Exponential backoff and "jitter," or randomness, is also integrated within the calculation of the reconnection delay time to mitigate the potential of a thunder herding problem.

info

The exponential backoff algorithm implemented takes reference from AWS's "exponential backoff with full jitter" algorithm, which can be found here.

eventHandlers

The RTUS-SEH service currently supports 4 custom events: Added, Removed, Updated and Timeout. With the eventHandlers property, the application will be able to respond to the different custom events respectively.

sseClient = new SSESubscribeClient({
domainURL,
tenantId,
mapName,
userId,
init: false,
maxReconnectAttempts: 10,
baseReconnectDelay: 1000,
// this example shows 2 eventHandlers for the "Added" and "Updated" events
eventHandlers: {
Added: (data) => {
const { unread_count, message } = data;
updateNotificationStore([message], unread_count, false, "sse");
},
Updated: (data) => {
const { unread_count, message } = data;
updateNotificationStore([message], unread_count, false, "sse");
},
},
});

refreshUrl

The refreshUrl property allows the application to set the specific URL endpoint responsible for token refresh. If left empty, the default url will be the default Web Base token refresh URL.

sseClient = new SSESubscribeClient({
domainURL,
tenantId,
mapName,
userId,
init: false,
maxReconnectAttempts: 10,
baseReconnectDelay: 1000,
refreshUrl: '/api/to/refresh/token'
.
.
.
});

onAnyEvent

The onAnyEvent property is a catch-all handler intended for common logic that applies to all events, regardless of the specific event type.

const domainURL = `${baseSehUrl}`;
const tenantId = data.user.active_tenant.tenant_id;
const mapName = "ian";
const userId = data.user.sub;

sseClient = new SSESubscribeClient({
domainURL,
tenantId,
.
.
.
onAnyEvent: (eventName, data) => {
logger.debug(`Received event ${eventName}`, data);
// Additional custom handling of the event
},
.
.
});

onConnected

The onConnected property allows the application to handle the EventSource open event when the event source is opened.

const domainURL = `${baseSehUrl}`;
const tenantId = data.user.active_tenant.tenant_id;
const mapName = "ian";
const userId = data.user.sub;

sseClient = new SSESubscribeClient({
domainURL,
tenantId,
.
.
.
onConnected: () => {
logger.debug("Connected to SSE");
},
.
.
.
});

onDisconnected

The onDisconnected property allows the the application to to handle and execute custom logic when the connection to the SSE server is lost or closed.

sseClient = new SSESubscribeClient({
domainURL,
tenantId,
.
.
.
onConnected: () => {
logger.debug("Connected to SSE");
},
onDisconnected: () => {
logger.debug("Disconnected to SSE");
}
.
.
.
});

onReconnecting

The onReconnecting property allows the application to handle and execute custom logic when the sse-client is attempting to reconnect to the RTUS-SEH service.

sseClient = new SSESubscribeClient({
domainURL,
tenantId,
.
.
.
onConnected: () => {
logger.debug("Connected to SSE");
},
onDisconnected: () => {
logger.debug("Disconnected to SSE");
},
onReconnecting: () => {
logger.debug("Attempting to reconnect to SSE");
},
.
.
.
});

onError

The onError property allows the application to handle and execute custom logic when an error is encountered, (e.g. logging the error or displaying a user-friendly message).

const sseClient = new SSESubscribeClient({
domainURL,
tenantId,
.
.
.
onConnected: () => {
logger.debug("Connected to SSE");
},
onDisconnected: () => {
logger.debug("Disconnected to SSE");
},
onReconnecting: () => {
logger.debug("Attempting to reconnect to SSE");
},
onError: (error) => {
logger.debug("There is an error.");
}
.
.
.
});