
Research
Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.
Extend your events across processes, threads, and machines. Demitter brings the familiar Node.js event API (via emittery) API to distributed systems, enabling real-time event communication between multiple Node.js processes with near-zero configuration.
Live auction system with multiple bidders across separate terminal processes - all synchronized in real-time
npm install demitter
# or
pnpm install demitter
# or
yarn add demitter
Get distributed events running in 3 steps:
import { createForwarder } from "demitter";
const forwarder = await createForwarder();
console.log("Forwarder ready - events can now flow between processes!");
import { createDistributedEmitter } from "demitter";
// In Process A
const emitterA = await createDistributedEmitter();
// In Process B
const emitterB = await createDistributedEmitter();
// Process A: Listen for events
emitterA.on("user:login", (data) => {
console.log("User logged in:", data);
});
// Process B: Emit events that Process A will receive
emitterB.emit("user:login", { userId: 123, timestamp: Date.now() });
That's it! Events emitted in one process are automatically received by all other connected processes.
Demitter extends the powerful emittery API with distributed capabilities. All emittery methods work exactly the same:
// All the familiar emittery methods work across processes:
await emitter.emit(eventName, data);
emitter.on(eventName, listener);
emitter.off(eventName, listener);
await emitter.once(eventName);
emitter.onAny(listener);
emitter.clearListeners();
// ... and many more
📖 Full API Documentation: See the complete emittery API docs for all available methods, TypeScript usage, and advanced features.
createDistributedEmitter(options?)Creates a new distributed emitter instance.
const emitter = await createDistributedEmitter({
xsubAddress: "tcp://localhost:5555", // Connect to forwarder
xpubAddress: "tcp://localhost:5556", // Connect to forwarder
});
createForwarder(options?)Creates and starts a message forwarder to enable event distribution.
const forwarder = await createForwarder({
xsubPort: 5555, // Default port for subscribers
xpubPort: 5556, // Default port for publishers
});
emitter.close()Closes the distributed emitter and cleans up connections.
await emitter.close();
distributed:error: Emitted when distributed operations fail (network issues, serialization errors, etc.)emitter.on("distributed:error", (error) => {
console.error("Distributed operation failed:", error);
});
Explore practical examples in the examples/ directory:
basic-usage.ts - Simple distributed events setuperror-handling.ts - Robust error handling patternslive_auction/ - Complete live auction system demo
# Basic usage
pnpm run example:basic
# Error handling
pnpm run example:errors
# Live auction demo (see examples/live_auction/auction-demo/README.md)
cd examples/live_auction/auction-demo
pnpm install
pnpm run demo
Start the forwarder within your application:
import { createForwarder, createDistributedEmitter } from "demitter";
const forwarder = await createForwarder();
const emitter = await createDistributedEmitter();
Run the forwarder as a separate service:
# Using the CLI
npx demitter-forwarder
# Or start with custom ports
XSUB_PORT=7777 XPUB_PORT=8888 npx demitter-forwarder
FROM node:22-alpine
RUN npm install -g demitter
EXPOSE 5555 5556
CMD ["demitter-forwarder"]
The system consists of two main components:
Emittery class in the emittery library for distributed event emissionThe forwarder acts as a central message broker using ZeroMQ's XSUB-XPUB proxy pattern.
After installing the package globally:
npm install -g demitter
# or
pnpm install -g demitter
You can run the forwarder from anywhere:
# Start with default ports (XSUB: 5555, XPUB: 5556)
demitter-forwarder
# With custom ports
XSUB_PORT=6000 XPUB_PORT=6001 demitter-forwarder
# With debug logging
LOG_LEVEL=debug demitter-forwarder
# Show help
demitter-forwarder --help
For projects with demitter as a dependency:
npx demitter-forwarder
# Start with default ports (XSUB: 5555, XPUB: 5556)
node src/forwarder.js
# Or using the CLI script
node src/cli.js
# With custom ports
XSUB_PORT=6000 XPUB_PORT=6001 node src/forwarder.js
# With debug logging
LOG_LEVEL=debug node src/forwarder.js
import { createForwarder } from "./src/forwarder.js";
// Start forwarder with default configuration
const forwarder = await createForwarder();
// Custom configuration
const forwarder = await createForwarder({
xsubPort: 6000,
xpubPort: 6001,
loggerOptions: { level: "debug" },
});
// Graceful shutdown
await forwarder.close();
The forwarder can be configured using environment variables:
| Variable | Default | Description |
|---|---|---|
XSUB_PORT | 5555 | Port for XSUB socket (receives from publishers) |
XPUB_PORT | 5556 | Port for XPUB socket (sends to subscribers) |
XSUB_ADDRESS | tcp://*:${XSUB_PORT} | Full address for XSUB socket |
XPUB_ADDRESS | tcp://*:${XPUB_PORT} | Full address for XPUB socket |
LOG_LEVEL | info | Logging level (debug, info, warn, error) |
demitter-forwarder --help
# or when running locally
node src/cli.js --help
See LICENSE file.
I'm open to contributions but the details for contributions are not yet finalized. If you have ideas or improvements, feel free to open an issue or start a discussion before you raise a pull request.
FAQs
Distributed Node.js Event Emitter
We found that demitter demonstrated a healthy version release cadence and project activity because the last version was released less than 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
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.