A library to easily intercept, modify, and simulate EventSource server-sent events.
Table of Contents
- Intercept new connections
- Change connection URL
- Intercept incoming events
- Modify events (data, origin, id, etc.)
- Block events
- Simulate incoming events
Install with npm:
npm install --save event-source-hook
Install in a browser:
- download file
browser/eshook.js
orbrowser/eshook.min.js
- import it on your web page
Note: these scripts are polyfilled, so it should run on every browser supporting EventSource
API.
EventSource
before other libraries or code instantiate it.
This applies the patch to the native EventSource
constructor.
View code
In Node:
import ESHook from "event-source-hook";
ESHook.enable();
In a browser:
// In a browser, the library object is exposed globally.
ESHook.enable();
Attach a hook function to listen each new opening connection. You can save EventSource
instances for later use if you wish.
View code
const connections = [];
ESHook.createHook = (eventSource) => {
console.log("New connection:", eventSource);
connections.push(eventSource);
};
Attach a hook function to change a connection URL just before a new connection is established.
View code
ESHook.urlHook = (url) => {
if (url === "http://a-url") {
url = "http://new-url";
}
return url;
};
You can simulate an incoming MessageEvent
. It will be handled as if it were an genuine event received from the server.
It is required to specify on which connection you want to simulate the event.
View code
// Connection where the event should be received.
const eventSource = connections[0];
// Event type: can be anything.
const type = "message";
// Event options.
// See: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/MessageEvent#options
const options = {
data: { foo: "bar" },
lastEventId: "id",
};
ESHook.simulate(eventSource, type, options);
Note: the simulated
property is set to true
on the MessageEvent
object. Thus, it is possible to detect the simulated event like in section 4 just below.
Attach a hook function to listen for incoming MessageEvent
just before the native EventSource
receives them.
Note: the hook function can be synchronous or asynchronous (see, below examples).
You can modify all event object's properties (such as data
, lastEventId
) as it is mutable.
View code (synchronous)
Return the (modified) event or null
to block the event.
EventSourceHook.eventHook = (type, event, eventSource) => {
// Block incoming events with type `message`.
if (type === "message") {
return null;
}
// Modify incoming events data from URL `https://test`.
if (eventSource.url === "https://test") {
const data = JSON.parse(event.data);
data.foo = "new value";
event.data = JSON.stringify(data);
return event;
}
// Detect simulated events.
if (event.simulated) {
console.log("This event was simulated by the library.");
}
// Leave the other events as they are.
return event;
};
View code (asynchronous)
To make the hook function asynchronous, include the optional result
callback parameter, and call it to return the (modified) event or null
to block the event.
Example with a promise:
EventSourceHook.eventHook = (type, event, eventSource, result) => {
// Block incoming events with type `message`.
if (type === "message") {
result(null);
return;
}
// Modify incoming events data from URL `http://test`.
if (eventSource.url === "https://test") {
fetchData().then((data) => {
event.data = JSON.stringify(data);
result(event);
});
return;
}
// Leave the other events as they are.
result(event);
};
Example with async/await:
EventSourceHook.eventHook = async (type, event, eventSource, result) => {
const thing = await something();
if (thing) {
event.data = thing;
result(event);
} else {
result(null);
}
};
You can disable hooks by setting null
.
View code
ESHook.urlHook = null;
ESHook.createHook = null;
ESHook.eventHook = null;
...
View API docs.