Skip to content

Drivers and Config ​

Experimental

Realtime and Broadcast are Experimental in 0.4.0. Production reliability work is still pending; review the production limits before relying on live updates.

Broadcasting settings live in config/broadcast.ts. You list named connections, each with a driver, and pick one as the default. The worker section configures the WebSocket server started by npx holo broadcast:work.

Default config ​

npx holo install broadcast writes this file:

ts
import { defineBroadcastConfig } from '@holo-js/broadcast'
import { env } from '@holo-js/config'

const broadcastScheme = env('BROADCAST_SCHEME') === 'https' ? 'https' : 'http'

export default defineBroadcastConfig({
  default: env('BROADCAST_CONNECTION', 'holo'),
  worker: {
    allowedOrigins: [env('APP_URL', 'http://localhost:3000')],
  },
  connections: {
    holo: {
      driver: 'holo',
      appId: env('BROADCAST_APP_ID'),
      key: env('BROADCAST_APP_KEY'),
      secret: env('BROADCAST_APP_SECRET'),
      options: {
        host: env('BROADCAST_HOST', '127.0.0.1'),
        port: env('BROADCAST_PORT', 8080),
        scheme: broadcastScheme,
        useTLS: broadcastScheme === 'https',
      },
      clientOptions: {
        authEndpoint: `${env('APP_URL', 'http://localhost:3000')}/broadcasting/auth`,
      },
    },
    log: {
      driver: 'log',
    },
    null: {
      driver: 'null',
    },
  },
})

The clientOptions.authEndpoint block is only added when auth is installed.

holo new writes a generated app ID, key, and secret into .env. Existing apps get them from holo install broadcast. Holo has no built-in defaults for these values. Your config still loads without them, but the worker, publishing, and channel authorization fail with an error that names the variables until they're set.

DANGER

BROADCAST_APP_SECRET signs channel authorizations and publish requests. Never expose it to the browser, and don't share it between environments.

Environment variables ​

VariableDefaultUsed for
BROADCAST_CONNECTIONholoWhich connection broadcast(...) uses by default.
BROADCAST_APP_IDnoneIdentifies your app on the worker. Generated by holo new.
BROADCAST_APP_KEYnonePublic key. Browsers connect with it. Generated by holo new.
BROADCAST_APP_SECRETnonePrivate secret for signing. Generated by holo new.
BROADCAST_HOST127.0.0.1Host where your app server reaches the worker. Browsers use it too unless you set worker.publicHost.
BROADCAST_PORT8080Worker port.
BROADCAST_SCHEMEhttphttps turns on TLS for the connection.
APP_URLhttp://localhost:3000Allowed browser origin and auth endpoint base.

Drivers ​

DriverWhat it does
holoSends events to the Holo WebSocket worker you run with npx holo broadcast:work. This is the only driver the built-in Flux client connects to.
pusherSends events to Pusher's HTTP API.
logLogs the event name and channels with console.warn. Nothing is delivered. Useful while building.
nullDrops every event. Useful in tests or when you want broadcasting off.

Switch drivers without editing code by changing BROADCAST_CONNECTION:

bash
BROADCAST_CONNECTION=log

When there is no config/broadcast.ts, the default connection is null and nothing is sent.

holo ​

The self-hosted driver. Your app server signs each event and posts it to the worker at options.host and options.port. The worker then delivers it to connected browsers.

OptionDescription
appId, key, secretRequired.
options.hostWorker host. Defaults to 127.0.0.1.
options.portWorker port, from 1 to 65535. The worker listens on this port too, unless worker.port is set.
options.schemehttp or https.
options.useTLSDefaults to true when the scheme is https.
clientOptions.authEndpointURL Flux uses to authorize private and presence channels. Only the path is sent to the browser.

The browser reads the default connection's settings from /broadcasting/config. That endpoint needs the default connection to use the holo driver.

pusher ​

ts
import { defineBroadcastConfig } from '@holo-js/broadcast'
import { env } from '@holo-js/config'

export default defineBroadcastConfig({
  default: env('BROADCAST_CONNECTION', 'pusher'),
  connections: {
    pusher: {
      driver: 'pusher',
      appId: env('PUSHER_APP_ID'),
      key: env('PUSHER_APP_KEY'),
      secret: env('PUSHER_APP_SECRET'),
      options: {
        cluster: env('PUSHER_APP_CLUSTER', 'mt1'),
      },
    },
  },
})

With a cluster, Holo posts to api-<cluster>.pusher.com. Without one, it uses api-mt1.pusher.com. Set options.host, options.port, and options.scheme to target a different Pusher-compatible API.

WARNING

The pusher driver only covers sending from your server. Flux connects to the Holo worker, and /broadcasting/config only serves holo connections, so the useFlux helpers won't receive Pusher events out of the box.

Use several connections ​

Define as many connections as you need and pick one per broadcast with .using(...):

ts
import { defineBroadcastConfig } from '@holo-js/broadcast'
import { env } from '@holo-js/config'

export default defineBroadcastConfig({
  default: 'holo',
  connections: {
    holo: {
      driver: 'holo',
      appId: env('BROADCAST_APP_ID'),
      key: env('BROADCAST_APP_KEY'),
      secret: env('BROADCAST_APP_SECRET'),
      options: { host: '127.0.0.1', port: 8080, scheme: 'http' },
    },
    audit: {
      driver: 'log',
    },
  },
})
ts
import { broadcast } from '@holo-js/broadcast'

await broadcast(shipmentUpdated(order.id, 'shipped')).using('audit')

Holo throws when it loads the config if default names a connection that doesn't exist.

Worker settings ​

The worker section configures npx holo broadcast:work. You only need it to change ports, allowed origins, or limits.

OptionDefaultDescription
host0.0.0.0Interface the worker listens on.
portThe default holo connection's port, else 8080Port the worker listens on, from 0 to 65535. 0 picks a free port and prints it when the worker starts. Your app still publishes to options.port, and browsers connect to publicPort or options.port. Neither learns the port the worker picked, so 0 is only for tests and tools that read it from the broadcast:work output. In production, set worker.port and options.port to the same fixed port.
path/appWebSocket path prefix. Browsers connect to <path>/<key>.
publicHostnoneHost browsers connect to, when it differs from options.host.
publicPortnonePort browsers connect to, from 1 to 65535, used with publicHost.
publicSchemeThe connection's schemehttp or https for browser connections.
allowedOriginsThe public originBrowser origins allowed to open a WebSocket. Use exact origins such as https://example.com. ['*'] allows any origin.
maxRequestBytes1048576 (1 MB)Largest publish request the worker accepts. Larger requests get 413.
maxMessageBytes65536 (64 KB)Largest WebSocket message. Larger messages close the socket with code 1009.
healthPath/healthHealth check URL. Always on.
statsPath/statsStatistics URL.
statsEnabledfalseServe statistics at statsPath. Returns 404 when off.
scalingfalse{ driver: 'redis', connection: 'default' } to share state across several workers.

See Scaling in production for publicHost, origins, and Redis scaling.

Custom drivers ​

A plugin can contribute broadcast drivers. Give the connection that driver name in config/broadcast.ts. Holo throws if a connection uses a driver that isn't registered. You can register one yourself with registerBroadcastDriver.

Next steps ​

Released under the MIT License.