BSER Binary Serialization
BSER (Binary Serialization) is a compact, framed binary serialization scheme designed as an alternative to JSON, primarily for local Inter-Process Communication (IPC). It is part of the larger Watchman project by Facebook (Meta Platforms, Inc.), which implies its development is active and closely tied to Watchman's needs. While the npm package version is 2.1.1, the upstream Watchman project sees rapid, often weekly, releases in a `vYYYY.MM.DD.00` format, indicating continuous development and updates. BSER differentiates itself with framed encoding for streaming sequences of values, treating strings as binary without specific character encoding (matching OS filename conventions), making it efficient for specific low-level IPC scenarios. It offers both synchronous (`loadFromBuffer`, `dumpToBuffer`) and asynchronous (`BunserBuf` for event-driven decoding) APIs.
Common errors
-
TypeError: bser.loadFromBuffer is not a function
cause Attempting to call `loadFromBuffer` on an `undefined` or improperly imported `bser` object, often due to incorrect CommonJS `require` or failed ESM `import` in a dual-module setup.fixEnsure the module is correctly imported in CommonJS: `const bser = require('bser');`. If in ESM, confirm your build system or Node.js environment correctly handles CommonJS module interop, or use `import bser from 'bser'` if it's a default export (less likely for this package). -
Error: Invalid BSER buffer
cause The input `Buffer` provided to `bser.loadFromBuffer` or `bunser.append` does not conform to the BSER binary serialization format, indicating corrupted data or an incorrect protocol.fixVerify the source of the buffer data. Ensure the sending side is correctly encoding data using `bser.dumpToBuffer` and that no data corruption or truncation occurs during transmission. Implement `try...catch` around `loadFromBuffer` and `bunser.on('error', ...)` for `BunserBuf`. -
Data is not being processed from BunserBuf after `append` call
cause The asynchronous `BunserBuf` is being used, but no listener has been attached to its `'value'` event, so decoded objects are emitted but not captured or processed.fixAlways attach a listener to the `'value'` event of your `BunserBuf` instance: `bunser.on('value', function(obj) { console.log('Decoded object:', obj); });`. Also consider handling the `'error'` event for robustness.
Warnings
- gotcha The `bser.loadFromBuffer` and `bser.dumpToBuffer` APIs are synchronous. While suitable for small IPC payloads, using them with very large buffers can block the Node.js event loop, leading to performance bottlenecks and unresponsiveness in high-throughput applications.
- gotcha The `bser.loadFromBuffer` function throws an error directly if the input buffer is not a valid BSER stream. This requires explicit `try...catch` blocks for robust error handling to prevent application crashes.
- gotcha The `BunserBuf` API is entirely event-driven for asynchronous decoding. Data is not returned directly but emitted via the `'value'` event. Developers new to event emitters might overlook attaching this listener, resulting in data appearing to be 'lost' or not processed.
- gotcha The `bser` package is primarily distributed and documented as a CommonJS module using `require()`. While Node.js can sometimes interop with CommonJS modules from ESM, directly using `import { Name } from 'bser'` syntax in an ESM context might lead to unexpected `undefined` imports or runtime errors without specific `package.json` `exports` configurations (which are not explicitly provided by `bser`).
- gotcha BSER is explicitly 'intended to be used for local-IPC only' and its strings are 'represented as binary with no specific encoding'. This means it's not suitable for cross-platform or network communication where explicit character encoding (e.g., UTF-8) and network framing protocols are critical for interoperability and security.
Install
-
npm install bser -
yarn add bser -
pnpm add bser
Imports
- bser
import * as bser from 'bser';
const bser = require('bser'); - loadFromBuffer
import { loadFromBuffer } from 'bser';const { loadFromBuffer } = require('bser'); - BunserBuf
import { BunserBuf } from 'bser';const BunserBuf = require('bser').BunserBuf;
Quickstart
const net = require('net');
const bser = require('bser');
// Simulate a socket server
const server = net.createServer(socket => {
console.log('Client connected.');
const bunser = new bser.BunserBuf();
bunser.on('value', obj => {
console.log('Server received (decoded):', obj);
// Echo back a response
const response = bser.dumpToBuffer(['pong', obj[1]]);
socket.write(response);
});
socket.on('data', buf => {
bunser.append(buf);
});
socket.on('end', () => {
console.log('Client disconnected.');
});
socket.on('error', err => {
console.error('Server socket error:', err);
});
});
const SOCKET_PATH = '/tmp/bser-socket';
server.listen(SOCKET_PATH, () => {
console.log(`Server listening on ${SOCKET_PATH}`);
// Simulate a client
const client = net.connect(SOCKET_PATH, () => {
console.log('Client connected to server.');
const payload = ['hello', 'world', 123];
const encoded = bser.dumpToBuffer(payload);
console.log('Client sending (encoded):', encoded);
client.write(encoded);
const clientBunser = new bser.BunserBuf();
clientBunser.on('value', obj => {
console.log('Client received (decoded):', obj);
client.end(); // End client after receiving response
});
client.on('data', buf => {
clientBunser.append(buf);
});
client.on('error', err => {
console.error('Client socket error:', err);
});
});
client.on('end', () => {
console.log('Client disconnected. Server closing.');
server.close();
});
});