npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@weiwangfds/wasm-ripple

v0.1.0

Published

A high-performance, memory-safe message queue library compiled to WebAssembly

Readme

Wasm-Ripple

Rust WebAssembly

A high-performance, memory-safe message queue library compiled to WebAssembly, designed for modern web applications.

✨ Features

  • 🚀 High Performance - Built with Rust and compiled to WebAssembly for near-native speed
  • 🧵 Memory Safe - Rust's ownership model ensures memory safety without garbage collection pauses
  • 📡 Topic-based Pub/Sub - Flexible publish/subscribe pattern with topic-based messaging
  • 🔄 Cross-tab Communication - Seamless message passing between browser tabs via BroadcastChannel API
  • ⚡ Synchronous & Async - Choose between immediate delivery or microtask-based async publishing
  • 💾 Ring Buffer Support - Optional message buffering with O(1) operations and overflow handling
  • 📦 Zero-copy Messaging - Direct JavaScript value passing without serialization overhead
  • 🎯 Lightweight - ~40KB gzipped WebAssembly module

📦 Installation

npm install wasm-ripple

Or use directly from the pkg directory:

<script type="module">
  import init, { MessageQueue } from './pkg/wasm_ripple.js';

  await init();
  const mq = new MessageQueue('my-channel');
</script>

🚀 Quick Start

import init, { MessageQueue } from 'wasm-ripple';

// Initialize the WASM module
await init();

// Create a message queue with optional channel name for cross-tab communication
const mq = new MessageQueue('my-app');

// Register a topic and get its ID (REQUIRED for all operations)
const topicId = mq.register_topic('events');

// Subscribe to a topic using ID
// Callback receives: payload, topic_id, timestamp, message_id
const subId = mq.subscribe(topicId, (payload, tid, ts, msgId) => {
  console.log('Received:', payload);
});

// Publish a message synchronously using topic ID
mq.publish(topicId, { text: 'Hello, World!', count: 42 });

// Or publish asynchronously (non-blocking)
await mq.publish_async(topicId, { text: 'Async message', data: [1, 2, 3] });

// Batch publish for high throughput
const messages = new Array(100).fill({ data: 'batch' });
mq.publish_batch_by_id(topicId, messages);

// Unsubscribe when done
mq.unsubscribe(topicId, subId);

// Clean up resources
mq.close();

📊 Performance

Benchmark results on Chrome (Apple M3 Pro):

| Metric | Result | Notes | | :--- | :--- | :--- | | Sync Throughput | ~5.3M ops/sec | Zero-allocation hot path | | Batch Throughput | ~7.9M ops/sec | Optimized batch processing | | Latency | ~0.3 µs | Ultra-low overhead dispatch | | 100k Messages | ~20 ms | Full processing time |

Note: These results are achieved using the optimized ID-based API and zero-allocation dispatch mechanism.

📚 API Reference

Constructor

const mq = new MessageQueue(channelName?: string)
  • channelName (optional): Channel name for cross-tab communication via BroadcastChannel

Topic Management

// Register a topic and get its ID (O(1) lookups)
const topicId = mq.register_topic('my-topic'); // returns number (u32)

// Check if topic exists by ID
const exists = mq.has_topic(topicId); // returns boolean

// Destroy a topic by ID
const destroyed = mq.destroy_topic(topicId); // returns boolean

// Get topic count
const count = mq.topic_count(); // returns number

Subscription

// Subscribe to a topic by ID
// Callback signature: (payload, topic_id, timestamp, message_id)
const subId = mq.subscribe(topicId, callback); // returns subscriber ID

// Unsubscribe
const success = mq.unsubscribe(topicId, subId); // returns boolean

// Unsubscribe all
const count = mq.unsubscribe_all(topicId); // returns number of unsubscribed

// Get subscriber count
const count = mq.subscriber_count(topicId); // returns number

Publishing

// Synchronous publish (immediate delivery)
mq.publish(topicId, payload);

// Asynchronous publish (delivered in microtask)
await mq.publish_async(topicId, payload);

// Batch publish (highest throughput)
mq.publish_batch_by_id(topicId, [payload1, payload2, ...]);

Ring Buffer Management

// Enable message buffering for a topic
mq.enable_topic_buffer(topicId, 100); // capacity (default: 100)

// Check if buffering is enabled
const hasBuffer = mq.has_buffer(topicId); // boolean

// Get buffer size
const size = mq.get_buffer_size(topicId); // current message count

// Get buffer capacity
const capacity = mq.get_buffer_capacity(topicId); // maximum capacity

// Get buffered messages
const messages = mq.get_buffered_messages(topicId); // Array of messages

// Clear buffer
const cleared = mq.clear_buffer(topicId); // number of cleared messages

// Disable buffering
mq.disable_topic_buffer(topicId);

Utilities

// Get unique client ID
const clientId = mq.get_client_id(); // string

// Close the queue and release resources
mq.close();

🔄 Ring Buffer

The ring buffer provides efficient message caching with O(1) operations:

const logTopic = mq.register_topic('logs');

// Enable buffer with capacity of 5 messages
mq.enable_topic_buffer(logTopic, 5);

// Publish 10 messages
for (let i = 0; i < 10; i++) {
  mq.publish(logTopic, { id: i, message: `Log ${i}` });
}

// Buffer only keeps the last 5 messages (IDs 5-9)
console.log(mq.get_buffer_size(logTopic)); // 5
console.log(mq.get_buffer_capacity(logTopic)); // 5

// Retrieve buffered messages
const messages = mq.get_buffered_messages(logTopic);
console.log(messages[0].payload.id); // 5 (oldest)
console.log(messages[4].payload.id); // 9 (newest)

Key Features:

  • Fixed size: Prevents unbounded memory growth
  • Automatic overflow: Oldest messages are automatically displaced when full
  • O(1) operations: Constant time push and retrieval
  • Per-topic: Each topic can have different buffer settings

🌐 Cross-tab Communication

Open the same page in multiple tabs to test cross-tab messaging:

// In tab 1
const mq = new MessageQueue('cross-tab-channel');
const topicId = mq.register_topic('updates');
mq.subscribe(topicId, (msg) => console.log('Tab 1 received:', msg));

// In tab 2
const mq = new MessageQueue('cross-tab-channel');
const topicId = mq.register_topic('updates');
mq.publish(topicId, { text: 'Hello from tab 2!' });
// Tab 1 will receive the message!

🆚 Comparison

| Feature | wasm-mq | Mitt / Tiny-emitter | PubSubJS | RxJS | | :--- | :--- | :--- | :--- | :--- | | Sync Throughput | ~5.3M ops/sec | ~26M ops/sec | ~18M ops/sec | ~41M ops/sec | | Batch Throughput | ~7.0M ops/sec | ~44M ops/sec | ~19M ops/sec | ~47M ops/sec | | Memory Jitter | Low (±0.5 MB) | Medium (±0.7 MB) | High (±1.0 MB) | High (±0.9 MB) | | Cross-tab | ✅ Built-in | ❌ (Manual) | ❌ | ❌ | | Buffering | ✅ Ring Buffer | ❌ | ❌ | ✅ (ReplaySubject) | | Size (Gzipped) | ~40KB (WASM) | < 200B | ~3KB | > 20KB |

When to use which?

  1. Use wasm-mq if:

    • You need Cross-tab Communication out of the box.
    • You require stable memory usage (low jitter) for long-running apps (dashboards, games).
    • You need Message History (Ring Buffer) for late subscribers.
    • You are already using Rust/WASM and want zero-overhead communication within WASM.
  2. Use mitt if:

    • You just need simple, ultra-fast component communication within a single page.
    • Bundle size (<200B) is your top priority.
  3. Use RxJS if:

    • You need complex functional reactive programming (FRP) operators (map, filter, throttle, debounce).

🔬 Running Benchmarks

You can verify these results yourself by running the included benchmark suite:

# Start local server
npm run serve

# Open in browser
# http://localhost:8000/benchmark/comparison/index.html

🏗️ Building from Source

# Install Rust and wasm-pack
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install wasm-pack

# Clone and build
git clone <repo-url>
cd mq-
wasm-pack build --dev --target web

# The compiled files will be in the `pkg/` directory

📖 Examples

Please refer to the code snippets in the "Quick Start" section above for usage examples.

🎯 Use Cases

  • Real-time dashboards - Broadcast updates across multiple tabs
  • State synchronization - Keep application state in sync
  • Event logging - Buffer and replay events with ring buffer
  • Multi-tab coordination - Coordinate actions between browser tabs
  • Message caching - Temporarily cache messages for new subscribers

🔧 Configuration

Release Build Optimization

The library is optimized for size in release mode:

[profile.release]
lto = true           # Link-time optimization
opt-level = "s"      # Optimize for size
strip = true         # Remove debug symbols
codegen-units = 1    # Better optimization at cost of compile time

Result: ~40KB gzipped WebAssembly module

🧪 Testing

# Run Rust tests
cargo test

📝 License

MIT OR Apache-2.0

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📮 Support

For issues and questions, please use the GitHub issue tracker.