Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
utilities for Server Sent Events that adopts the HTML Spec Standard for the EventSource Web API.
utilities for Server Sent Events that adopts the HTML Spec Standard for the EventSource Web API.
This is a TypeScript implementation of the Server-Sent Events specification. This is to make sending Event Source streams easier to implement on the server side.
It's a lightweight wrapper around the Web API specification. It's not a polyfill. It's not a replacement. It's just a simple wrapper around Streams according to the HTML Spec Standard.
❗ This is not to be confused with Node's Stream API. This is a wrapper around the Web Streams API which is also newly available in Node 20 and above.
For example, this utility accepts a
WritableStreamDefaultWriter
and not astream.Writable
.
This lib is actually small enough to be a gist or directly copy pasta. You can go to writer.ts
and copy the code directly if you'd like.
This borrows from node-ssestream
and also Nestjs's sse
implementation.
npm install ts-sse
This wrapper is compatible with any server/runtime that can return a responseStream.readable
. Here's an example with Nextjs that implements a "syncing" streaming route.
import { EventNotifier, getSSEWriter } from 'ts-sse'
Before you can send events, you need to define the data
structure of the messages you'll be sending. This example uses zod, but you can just use pure TS too.
import { z } from 'zod';
const syncSchema = z.object({
sync_status: z.enum(['begin_stream', 'error', 'sync_update', 'sync_complete']),
sync_message: z.string(),
sync_date: z.string(),
});
type SyncEvents = EventNotifier<{
update: {
data: z.infer<typeof syncSchema>
comment: string
}
complete: {
data: z.infer<typeof syncSchema>
event: 'some_event' | 'some_other_event'
}
close: {
data: never
}
error: {
data: never
}
}>;
The EventNotifier
is a generic type that takes in an object of event types: update
, complete
, close
, and error
.
These event types take the following properties:
data
: The main content of the message. It can be a string or an object.comment
(optional)event
(optional)id
(optional)retry
(optional)these properties follow properties outlined in the HTML Spec Standard for Server-Sent Events. Search "process the field".
Now, let's dive into some Next! Create a function that will handle the SSE logic:
// api/stream/route.ts
export async function GET() {
// ... (authentication and other logic)
const responseStream = new TransformStream();
const writer = responseStream.writable.getWriter();
const encoder = new TextEncoder();
const syncStatusStream = async (notifier: SyncEvents) => {
// Begin the stream
notifier.update({
data: {
sync_status: 'begin_stream',
},
});
// ... (your logic for fetching data and sending updates)
// Example: Sending a sync update
notifier.update({
data: {
sync_status: 'sync_update',
sync_date: 'your-date-here',
sync_message: 'Syncing...',
},
});
// ... (more logic, handling errors, completion, etc.)
};
// Use the getSSEWriter to initialize the utility with the writer
syncStatusStream(getSSEWriter(writer, encoder));
// Return the response stream
return new NextResponse(responseStream.readable, {
headers: {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
'Cache-Control': 'no-cache, no-transform',
},
});
}
If you need to close the connection, you can call either close
, complete
, or error
on the notifier
object.
// api/stream/route.ts
// ... (your logic for fetching data and sending updates)
notifier.complete({
data: {
sync_status: 'sync_complete',
sync_date: 'your-date-here',
sync_message: `I'm done!`,
},
});
If you want to run some custom behavior before or after the event is sent, you can pass in a callback to the update
method for example.
// api/stream/route.ts
// ... (your logic for fetching data and sending updates)
notifier.update(
{
data: {
eventType: 'begin_stream',
},
},
{
beforeFn: (message) => {
syncSchema.parse(message.data)
},
},
)
You can use the EventSource Web API to consume the stream.
'use client'
// some-component.tsx
const SomeComponent = () => {
const [syncStatus, setSyncStatus] = useState<SyncEvents['update']['data']>('begin_stream');
useEffect(() => {
const eventSource = new EventSource('/api/stream/route');
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data) as SyncEvents['update']['data'];
setSyncStatus(data.sync_status);
};
return () => {
eventSource.close();
};
}, []);
return (
<div>
<p>Sync Status: {syncStatus}</p>
</div>
);
};
See here for the full API: API.md
FAQs
Utilities for Server-Sent Events that adopts the HTML Spec Standard for the EventSource Web API.
The npm package ts-sse receives a total of 571 weekly downloads. As such, ts-sse popularity was classified as not popular.
We found that ts-sse demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.