AdonisJS Transmit is a native Server-Sent-Event (SSE) module for AdonisJS. It provides a simple API to send events to the client. It also supports Redis as a Transport Layer for broadcasting events to multiple servers or instances.
Here are a few things you should know before using this module.
π Unidirectional Communication: The data transmission occurs only from server to client, not the other way around.
π Textual Data Only: SSE only supports the transmission of textual data, binary data cannot be sent.
π HTTP Protocol: The underlying protocol used is the regular HTTP, not any special or proprietary protocol.
Install the package from the npm registry as follows:
node ace add @adonisjs/transmit
The module exposes a transmit
instance, which can be used to send events to the client.
import transmit from '@adonisjs/transmit/services/main'
// Anywhere in your code
transmit.broadcast('channelName', { username: 'lanz' })
Channels are a way to group events. For example, you can have a channel for users
and another for posts
. The client can subscribe to one or more channels to receive events.
Channels names must be a string and must not contain any special characters except /
. The following are valid channel names.
transmit.broadcast('users', { username: 'lanz' })
transmit.broadcast('users/1', { username: 'lanz' })
transmit.broadcast('users/1/posts', { username: 'lanz' })
You can mark a channel as private and then authorize the client to subscribe to it. The authorization is done using a callback function.
// start/transmit.ts
import type { HttpContext } from '@adonisjs/core/http'
transmit.authorize<{ id: string }>('users/:id', (ctx: HttpContext, { id }) => {
return ctx.auth.user?.id === +id
})
Note
Do not forget to add your start/transmit.ts
file inside the preloads
array of the adonisrc.ts
file.
When a client tries to subscribe to a private channel, the callback function is invoked with the channel params and the HTTP context. The callback function must return a boolean value to allow or disallow the subscription.
Transmit supports syncing events across multiple servers or instances using a transport layer. You can enable syncing by changing the configuration and referencing your driver (only Redis is available as of now).
// config/transmit.ts
import env from '#start/env'
import { defineConfig } from '@adonisjs/transmit'
import { redis } from '@adonisjs/transmit/transports'
export default defineConfig({
transport: {
driver: redis({
host: env.get('REDIS_HOST'),
port: env.get('REDIS_PORT'),
password: env.get('REDIS_PASSWORD'),
})
}
})
Note
Ensure to have ioredis
installed when using the redis
driver.
Transmit supports pinging the client to keep the connection alive. You can enable pinging by changing the configuration.
// config/transmit.ts
import { defineConfig } from '@adonisjs/transmit'
import { redis } from '@adonisjs/transmit/transports'
export default defineConfig({
pingInterval: '1m',
})
Transmit uses Emittery to emit any lifecycle events. You can listen for events using the on
method.
transmit.on('connect', ({ uid }) => {
console.log(`Connected: ${uid}`)
})
transmit.on('disconnect', ({ uid }) => {
console.log(`Disconnected: ${uid}`)
})
transmit.on('broadcast', ({ channel }) => {
console.log(`Broadcasted to channel ${channel}`)
})
transmit.on('subscribe', ({ uid, channel }) => {
console.log(`Subscribed ${uid} to ${channel}`)
})
transmit.on('unsubscribe', ({ uid, channel }) => {
console.log(`Unsubscribed ${uid} from ${channel}`)
})
When deploying applications that use @adonisjs/transmit
, itβs important to ensure that GZip compression does not interfere with the text/event-stream
content type used by Server-Sent Events (SSE). Compression applied to text/event-stream
can cause connection issues, leading to frequent disconnects or SSE failures.
If your deployment uses a reverse proxy (such as Traefik or Nginx) or other middleware that applies GZip, ensure that compression is disabled for the text/event-stream
content type.
traefik.http.middlewares.gzip.compress=true
traefik.http.middlewares.gzip.compress.excludedcontenttypes=text/event-stream
traefik.http.routers.my-router.middlewares=gzip