{"id":35101989,"url":"https://github.com/kbairak/webmq","last_synced_at":"2026-05-21T15:03:03.132Z","repository":{"id":314855640,"uuid":"1057005639","full_name":"kbairak/webmq","owner":"kbairak","description":"Real-time messaging framework that bridges web frontends with RabbitMQ using WebSockets for event-driven architecture","archived":false,"fork":false,"pushed_at":"2026-03-09T22:01:43.000Z","size":921,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-10T03:53:23.757Z","etag":null,"topics":["backend","frontend","rabbitmq","websockets"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kbairak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-15T06:40:23.000Z","updated_at":"2026-03-09T22:01:46.000Z","dependencies_parsed_at":"2025-09-15T08:37:53.501Z","dependency_job_id":"c9222e72-4f29-4b80-a0b5-f5b68ab1760f","html_url":"https://github.com/kbairak/webmq","commit_stats":null,"previous_names":["kbairak/webmq"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kbairak/webmq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbairak%2Fwebmq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbairak%2Fwebmq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbairak%2Fwebmq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbairak%2Fwebmq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kbairak","download_url":"https://codeload.github.com/kbairak/webmq/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbairak%2Fwebmq/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33305277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T12:23:38.849Z","status":"ssl_error","status_checked_at":"2026-05-21T12:22:11.673Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","frontend","rabbitmq","websockets"],"created_at":"2025-12-27T17:01:14.246Z","updated_at":"2026-05-21T15:03:03.126Z","avatar_url":"https://github.com/kbairak.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebMQ\n\nA real-time messaging framework that bridges web frontends with RabbitMQ using WebSockets for event-driven architecture.\n\n## Why WebMQ?\n\nTraditional web applications rely on request-response patterns where the client asks for data and waits for a reply. This works well for CRUD operations but falls short for real-time features like live chat, collaborative editing, or status updates. Event-driven development flips this model: applications react to events as they happen, enabling truly responsive user experiences.\n\nWhile WebSocket libraries exist, WebMQ leverages RabbitMQ's battle-tested message routing, persistence, and clustering capabilities. This means your real-time features inherit decades of messaging reliability. When you need to scale horizontally, simply spin up more backend instances—RabbitMQ handles message distribution seamlessly across your infrastructure.\n\n**You can use WebMQ as a replacement for Socket.IO, but with horizontal scaling naturally supported. But** the real power is making the frontend part of a mature distributed event-driven system. When the frontend publishes a message, any backend service out of hundreds can pick it up and process it. Similarly, the frontend can subscribe to events from any service in your infrastructure.\n\n## Quick Start\n\nHere's a complete real-time chat in under 40 lines:\n\n**Backend** (`backend.ts`):\n\n```javascript\nimport WebMQServer from 'webmq-backend';\n\nconst server = new WebMQServer({\n  rmqUrl: 'amqp://localhost',\n  exchange: 'chat_app',\n  port: 8080,\n  logLevel: 'INFO'\n});\n\nawait server.start();\nconsole.log('WebMQ server running on ws://localhost:8080');\n```\n\n**Frontend** (`App.tsx` - React):\n\n```tsx\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport WebMQClient from 'webmq-frontend';\n\nexport default function Chat() {\n  const [messages, setMessages] = useState([]);\n  const [input, setInput] = useState('');\n\n  const client = useMemo(() =\u003e new WebMQClient({\n    url: 'ws://localhost:8080',\n    sessionId: crypto.randomUUID()\n  }), []);\n\n  const appendMessage = useCallback((msg) =\u003e {\n    setMessages((prev) =\u003e [...prev, msg]);\n  }, []);\n\n  useEffect(() =\u003e {\n    client.connect();\n    client.listen('chat.messages', appendMessage);\n    return () =\u003e {\n      client.unlisten('chat.messages', appendMessage);\n      client.disconnect();\n    };\n  }, [client, appendMessage]);\n\n  const sendMessage = (e) =\u003e {\n    e.preventDefault();\n    client.publish('chat.messages', {\n      id: crypto.randomUUID(),\n      text: input,\n      user: 'Me'\n    });\n    setInput('');\n  };\n\n  return (\n    \u003cdiv\u003e\n      {messages.map(msg =\u003e \u003cp key={msg.id}\u003e\u003cb\u003e{msg.user}\u003c/b\u003e: {msg.text}\u003c/p\u003e)}\n      \u003cform onSubmit={sendMessage}\u003e\n        \u003cinput value={input} onChange={(e) =\u003e setInput(e.target.value)} /\u003e\n        \u003cbutton\u003eSend\u003c/button\u003e\n      \u003c/form\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n\u003e You can run this example with:\n\u003e\n\u003e ```sh\n\u003e cd examples/basic-chat\n\u003e npm install\n\u003e npm start\n\u003e ```\n\n*Note: WebMQ works with any frontend framework—React, Vue, vanilla JavaScript, React Native, or anything that can use WebSockets.*\n\n## Core Concepts\n\nWebMQ acts as a bridge between WebSocket connections and RabbitMQ's topic exchange. When a frontend publishes to `user.login`, it's routed through RabbitMQ to any backend services or other frontends listening for `user.*` or `user.login` specifically.\n\n**Topic Routing**: Use patterns like `chat.room.1`, `order.created`, or `user.profile.updated` to organize your events. Subscribers can listen to exact matches (`order.created`) or patterns (`order.*` for all order events, `#` for wildcard matching).\n\n**Bidirectional Flow**: Frontends can both publish events and subscribe to updates. Backend services can process events and publish results back to specific users or broadcast to all connected clients.\n\n**Guaranteed Delivery**: Messages from RabbitMQ are only acknowledged after the client confirms receipt, ensuring no messages are lost during network interruptions or reconnections.\n\n### Server-Side Hooks\n\nHooks allow you to intercept and transform messages on the backend. Each hook is an async function that receives a message header and context, and returns a (possibly modified) header.\n\n```javascript\n// Add user metadata from socket auth\nconst authHook = async (header, context, rmqMessage) =\u003e {\n  // context.socket.handshake.auth contains the sessionId\n  // You can add authentication logic here\n  return { ...header, userId: context.sessionId };\n};\n\n// Enforce authorization on binding keys\nconst authzHook = async (header, context, rmqMessage) =\u003e {\n  if (header.bindingKey \u0026\u0026 !header.bindingKey.startsWith('public.')) {\n    // Only allow listening to public topics\n    throw new Error('Unauthorized binding key');\n  }\n  return header;\n};\n\n// Add timestamps to all published messages\nconst timestampHook = async (header, context, rmqMessage) =\u003e {\n  return { ...header, timestamp: Date.now() };\n};\n\nconst server = new WebMQServer({\n  rmqUrl: 'amqp://localhost',\n  exchange: 'my_app',\n  port: 8080\n});\n\n// Register hooks using addHook method\nserver.addHook('pre', authHook);           // Runs before all actions\nserver.addHook('listen', authzHook);       // Runs only for listen actions\nserver.addHook('publish', timestampHook);  // Runs only for publish actions\n\nawait server.start();\n```\n\n**Hook Types:**\n\n- **`pre`**: Runs before all other hooks\n- **`wsMessage`**: Runs for all WebSocket→RabbitMQ messages (publish, listen, unlisten)\n- **`publish`**: Runs only for publish actions\n- **`listen`**: Runs only for listen actions\n- **`unlisten`**: Runs only for unlisten actions\n- **`rmqMessage`**: Runs for RabbitMQ→WebSocket messages\n- **`post`**: Runs after all other hooks\n\n**Hook Signature:**\n\n```typescript\ntype HookFunction = (\n  header: MessageHeader,\n  context: HookContext,\n  rmqMessage?: amqplib.ConsumeMessage\n) =\u003e Promise\u003cMessageHeader\u003e\n```\n\n**Parameters:**\n\n- **`header`**: Message header object containing:\n  - `routingKey?`: Topic for publish actions\n  - `bindingKey?`: Pattern for listen/unlisten actions\n  - `rmqOptions?`: RabbitMQ publish options\n  - Custom properties you add\n- **`context`**: Contains `socket` (Socket.IO socket), `sessionId`, and any custom properties\n- **`rmqMessage`**: Only provided for `rmqMessage` hooks, contains the raw RabbitMQ message\n\nHooks run in sequence and can modify the header. Throwing an error aborts the action.\n\n### Client-Side Hooks\n\nFrontend hooks are synchronous functions that transform message headers before they're sent.\n\n```javascript\nimport WebMQClient from 'webmq-frontend';\n\n// Add authentication token to all messages\nconst authHook = (header) =\u003e {\n  return { ...header, token: sessionStorage.getItem('authToken') };\n};\n\n// Log all published messages\nconst loggingHook = (header) =\u003e {\n  console.log('Publishing:', header.routingKey);\n  return header;\n};\n\n// Transform incoming messages\nconst transformHook = (header) =\u003e {\n  return { ...header, receivedAt: Date.now() };\n};\n\nconst client = new WebMQClient({\n  url: 'ws://localhost:8080',\n  sessionId: crypto.randomUUID()\n});\n\n// Register hooks using addHook method\nclient.addHook('pre', loggingHook);      // Runs before all actions\nclient.addHook('publish', authHook);     // Runs only for publish\nclient.addHook('message', transformHook); // Runs for incoming messages\n\nclient.connect();\n```\n\n**Hook Types:**\n\n- **`pre`**: Runs before all other hooks\n- **`publish`**: Runs only for publish actions\n- **`listen`**: Runs only for listen actions\n- **`unlisten`**: Runs only for unlisten actions\n- **`message`**: Runs for incoming messages from RabbitMQ\n- **`post`**: Runs after all other hooks\n\n**Hook Signature:**\n\n```typescript\ntype HookFunction\u003cT extends MessageHeader\u003e = (header: T) =\u003e T\n```\n\nHooks receive a header object and must return a (possibly modified) header. Throwing an error will abort the action.\n\n### Logging Configuration\n\nBoth frontend and backend support configurable logging levels:\n\n```javascript\n// Frontend\nconst client = new WebMQClient({\n  url: 'ws://localhost:8080',\n  sessionId: crypto.randomUUID(),\n  logLevel: 'DEBUG'  // 'SILENT' | 'ERROR' | 'WARNING' | 'INFO' | 'DEBUG'\n});\n\n// Backend\nconst server = new WebMQServer({\n  rmqUrl: 'amqp://localhost',\n  exchange: 'my_app',\n  port: 8080,\n  logLevel: 'INFO'  // 'SILENT' | 'ERROR' | 'WARNING' | 'INFO' | 'DEBUG'\n});\n```\n\n### Connection Events\n\nThe WebMQClient proxies Socket.IO events for connection monitoring:\n\n```javascript\nconst client = new WebMQClient({\n  url: 'ws://localhost:8080',\n  sessionId: crypto.randomUUID()\n});\n\nclient.connect();\n\n// Socket.IO connection events\nclient.on('connect', () =\u003e console.log('Connected'));\nclient.on('disconnect', () =\u003e console.log('Disconnected'));\nclient.on('connect_error', (error) =\u003e console.log('Connection error:', error));\n```\n\nAvailable events: `connect`, `disconnect`, `connect_error`, `reconnect`, `reconnect_attempt`, `reconnecting`, `reconnect_error`, `reconnect_failed`\n\n**Note:** The backend WebMQServer does not emit custom events. Use the logging system or Prometheus metrics for monitoring.\n\n### Health Check \u0026 Metrics\n\nWebMQ provides built-in HTTP endpoints for health checks and Prometheus metrics. When you specify `healthEndpoint` or `metricsEndpoint`, the backend automatically creates an HTTP server that handles these routes.\n\n```javascript\nconst server = new WebMQServer({\n  rmqUrl: 'amqp://localhost',\n  exchange: 'my_app',\n  port: 8080,\n  host: '0.0.0.0',\n  healthEndpoint: '/health',    // Creates health check at http://localhost:8080/health\n  metricsEndpoint: '/metrics'   // Creates metrics at http://localhost:8080/metrics\n});\n\nawait server.start();\n```\n\n**Health Check Response:**\n\n```json\n{\n  \"healthy\": true,\n  \"rabbitMQQueues\": 5,\n  \"websockets\": 12\n}\n```\n\nReturns HTTP 200 when healthy, 503 when unhealthy (RabbitMQ connection failures).\n\n**Metrics Endpoint:**\n\nReturns Prometheus-formatted metrics including:\n- WebSocket connections\n- RabbitMQ consumer count\n- Messages published/acked\n- Binding key counts\n- Error counts by type\n\n### Prometheus Metrics\n\nWebMQ exposes Prometheus metrics for monitoring:\n\n**Available Metrics:**\n\n| Metric | Type | Labels | Description |\n|--------|------|--------|-------------|\n| `webmq_ws_connections` | Gauge | - | Active WebSocket connections |\n| `webmq_rmq_consumers` | Gauge | - | Active RabbitMQ consumers |\n| `webmq_rmq_bindings` | Gauge | `binding_key` | Active queue bindings by pattern |\n| `webmq_rmq_consecutive_failures` | Gauge | - | Consecutive RabbitMQ connection failures |\n| `webmq_ws_messages_received` | Counter | `action` | Messages received from WebSocket clients |\n| `webmq_ws_to_rmq_publishes` | Counter | `routing_key` | Messages published to RabbitMQ |\n| `webmq_rmq_messages_acked` | Counter | `routing_key` | Messages acknowledged from RabbitMQ |\n| `webmq_errors` | Counter | `type`, `action` | Errors by type and action |\n\n**Prometheus Configuration:**\n\n```yaml\n# prometheus.yml\nscrape_configs:\n  - job_name: 'webmq'\n    scrape_interval: 15s\n    static_configs:\n      - targets: ['localhost:8080']\n```\n\n## Features\n\n- **Guaranteed message delivery**: Backend waits for client acknowledgment before acking RabbitMQ, preventing message loss\n- **Auto-reconnection**: Fast reconnection with configurable delays (default 500ms-2s)\n- **Graceful shutdowns**: Proper cleanup of connections, queues, and resources\n- **Flexible hooks**: Transform message headers on both frontend and backend\n- **Topic wildcards**: Subscribe to event patterns with `*` (single segment) and `#` (multiple segments)\n- **Connection events**: Monitor connection state via Socket.IO events\n- **Framework agnostic**: Works with React, Vue, Angular, React Native, or vanilla JS\n- **TypeScript support**: Full type definitions with JsonSerializable types\n- **Health \u0026 metrics**: Built-in health checks and Prometheus metrics\n- **Per-session queues**: Each client gets a dedicated RabbitMQ queue with configurable TTL\n\n## API Reference\n\n### Frontend API\n\n#### WebMQClient Class\n\nWebMQ uses a class-based client that you instantiate for each connection:\n\n```javascript\nimport WebMQClient from 'webmq-frontend';\n\nconst client = new WebMQClient({\n  url: 'ws://localhost:8080',\n  sessionId: crypto.randomUUID(),\n  logLevel: 'INFO'\n});\n\nclient.connect();\n```\n\nMultiple clients can be created to connect to different backends:\n\n```javascript\nconst chatClient = new WebMQClient({ \n  url: 'ws://chat.example.com', \n  sessionId: 'chat-' + crypto.randomUUID() \n});\nconst analyticsClient = new WebMQClient({ \n  url: 'ws://analytics.example.com',\n  sessionId: 'analytics-' + crypto.randomUUID()\n});\n```\n\n**Constructor:**\n\n```typescript\nnew WebMQClient(options: WebMQClientOptions)\n```\n\nOptions:\n\n- `url` (string, **required**): WebSocket server URL (e.g., 'ws://localhost:8080')\n- `sessionId` (string, **required**): Unique session identifier (used for RabbitMQ queue name)\n- `logLevel` (LogLevel, optional): 'SILENT' | 'ERROR' | 'WARNING' | 'INFO' | 'DEBUG' (default: 'INFO')\n\n**Methods:**\n\n- `connect(): void` - Establish WebSocket connection\n  - Must be called before publish/listen\n  - Auto-reconnects on disconnect with 500ms-2s delays\n\n- `disconnect(): void` - Close WebSocket connection\n  - Cleans up listeners but preserves client state\n\n- `publish(routingKey: string, payload: ArrayBuffer | JsonSerializable): void` - Publish message\n  - `routingKey`: Topic to publish to (e.g., 'chat.room.1')\n  - `payload`: Either binary data (ArrayBuffer) or JSON-serializable object\n  - JSON objects are automatically stringified and encoded\n\n- `listen(bindingKey: string, callback: (payload: JsonSerializable) =\u003e void, isJson?: true): void` - Subscribe to JSON messages (default)\n  - `bindingKey`: Topic pattern (supports `*` for single segment, `#` for multiple segments)\n  - `callback`: Handler receiving parsed JSON payload\n  - Payloads are automatically decoded and parsed\n\n- `listen(bindingKey: string, callback: (payload: ArrayBuffer) =\u003e void, isJson: false): void` - Subscribe to binary messages\n  - `callback`: Handler receiving raw ArrayBuffer payload\n\n- `listenJson(bindingKey: string, callback: (payload: JsonSerializable) =\u003e void): void` - Subscribe to JSON messages (alias)\n\n- `listenRaw(bindingKey: string, callback: (payload: ArrayBuffer) =\u003e void): void` - Subscribe to binary messages (alias)\n\n- `unlisten(bindingKey: string, callback: Function): void` - Unsubscribe from events\n  - Removes specific callback for the binding key\n  - Backend is notified when last callback is removed\n\n- `addHook(hookName: HookName, hookFunction: HookFunction): void` - Add message transformation hook\n  - See [Client-Side Hooks](#client-side-hooks) for details\n\n- `removeHook(hookName: HookName, hookFunction: HookFunction): void` - Remove hook\n\n- `on(...args): void` - Listen to Socket.IO events (proxied to internal socket)\n  - `'connect'`, `'disconnect'`, `'connect_error'`, `'reconnect'`, etc.\n\n- `off(...args): void` - Remove Socket.IO event listener\n\n**Properties:**\n\n- `url` (string, readonly): WebSocket server URL\n- `sessionId` (string, readonly): Session identifier\n- `logLevel` (LogLevel): Control logging verbosity\n\n### Backend API\n\n#### WebMQServer Class\n\n**Constructor:**\n\n```typescript\nnew WebMQServer(options: WebMQServerOptions)\n```\n\nOptions:\n\n- `rmqUrl` (string, **required**): AMQP connection URL (e.g., 'amqp://localhost' or 'amqp://user:pass@host:5672')\n- `exchange` (string, **required**): RabbitMQ exchange name (always created as durable topic exchange)\n- `port` (number, **required**): Port to listen on for HTTP and WebSocket server\n- `host` (string, optional): Host to bind to (default: all interfaces)\n- `healthEndpoint` (string, optional): HTTP path for health checks (e.g., '/health')\n- `metricsEndpoint` (string, optional): HTTP path for Prometheus metrics (e.g., '/metrics')\n- `queueTimeout` (number, optional): Queue TTL in milliseconds (default: 300000 = 5 minutes)\n  - Client queues are automatically deleted if unused for this duration\n- `logLevel` (LogLevel, optional): 'SILENT' | 'ERROR' | 'WARNING' | 'INFO' | 'DEBUG' (default: 'INFO')\n\n**Methods:**\n\n- `start(): Promise\u003cvoid\u003e` - Start server\n  - Connects to RabbitMQ and creates exchange\n  - Starts HTTP server (for WebSocket upgrade, health, and metrics)\n  - Starts Socket.IO server with ping/pong for fast disconnect detection\n  - Registers graceful shutdown handlers for SIGTERM and SIGINT\n\n- `stop(): Promise\u003cvoid\u003e` - Stop server gracefully\n  - Stops receiving new messages\n  - Waits for in-flight messages to complete\n  - Cancels all RabbitMQ consumers\n  - Closes WebSocket connections\n  - Closes RabbitMQ channels and connections\n\n- `addHook(hookName: HookName, hookFunction: HookFunction): void` - Add message transformation hook\n  - See [Server-Side Hooks](#server-side-hooks) for details\n\n- `removeHook(hookName: HookName, hookFunction: HookFunction): void` - Remove hook\n\n**Properties:**\n\n- `logLevel` (LogLevel): Control logging verbosity\n\n**Examples:**\n\nBasic setup:\n\n```javascript\nimport WebMQServer from 'webmq-backend';\n\nconst server = new WebMQServer({\n  rmqUrl: 'amqp://localhost',\n  exchange: 'my_app',\n  port: 8080,\n  healthEndpoint: '/health',\n  metricsEndpoint: '/metrics'\n});\n\nawait server.start();\n```\n\nWith hooks:\n\n```javascript\nconst server = new WebMQServer({\n  rmqUrl: 'amqp://localhost',\n  exchange: 'my_app',\n  port: 8080\n});\n\nserver.addHook('publish', async (header, context) =\u003e {\n  return { ...header, timestamp: Date.now() };\n});\n\nawait server.start();\n```\n\n## Roadmap\n\n### Recently Completed ✅\n\n- TypeScript support with full type definitions\n- Guaranteed message delivery (client acknowledgment before RabbitMQ ack)\n- Fast disconnect detection (2s ping interval, 5s timeout)\n- React Native support with Blob compatibility fixes\n- Built-in Prometheus metrics and health checks\n- Binary (ArrayBuffer) and JSON message support with type-safe overloads\n\n### Immediate Improvements\n\n1. **Developer Experience**\n   - Better error messages and error handling\n   - More example apps (collaborative editing, notifications)\n   - Better authentication examples with OAuth/JWT\n\n2. **Performance**\n   - Message batching to reduce overhead\n   - Optional compression for large payloads\n   - Connection pooling for RabbitMQ channels\n\n3. **Testing**\n   - End-to-end test suite\n   - Load testing and benchmarks\n   - Integration test helpers\n\n### Bigger Features\n\n4. **Advanced Patterns**\n   - Message persistence/replay (RabbitMQ queue durability options)\n   - Priority queues\n   - Dead letter queues for failed messages\n\n5. **Security**\n   - Rate limiting per client/session\n   - Message size limits\n   - Built-in auth middleware (JWT validation, session management)\n\n6. **Observability**\n   - Distributed tracing (OpenTelemetry)\n   - Custom metric labels/dimensions\n   - Structured logging with correlation IDs\n\n### Nice to Have\n\n7. **Framework Integrations**\n   - React hooks package (`useWebMQ`, `usePublish`, `useListen`)\n   - Vue composables\n   - Next.js API routes example\n   - SvelteKit integration\n\n8. **Alternative Backends**\n   - Redis Pub/Sub backend\n   - In-memory backend for testing (no RabbitMQ required)\n   - NATS backend\n\n## For Contributors\n\n### Prerequisites\n\n- Node.js 18+\n- Docker and Docker Compose\n- npm 7+\n\n### Development Setup\n\n1. **Start RabbitMQ**:\n\n   ```bash\n   docker-compose up -d\n   ```\n\n2. **Install dependencies**:\n\n   ```bash\n   npm install\n   ```\n\n3. **Build packages**:\n\n   ```bash\n   npm run build\n   ```\n\n4. **Run example**:\n\n   ```bash\n   npm run start:chat\n   ```\n\n### Project Structure\n\n```\npackages/\n├── backend/     # Node.js Socket.IO + RabbitMQ server library\n└── frontend/    # Framework-agnostic client library (browser \u0026 React Native)\nexamples/\n├── basic-chat/  # Simple chat application (React web)\n├── mobile-chat/ # Mobile chat application (React Native)\n├── city-search/ # City search with autocomplete\n└── todos/       # Todo list application\n```\n\n### Development Commands\n\n```bash\n# Build specific packages\nnpm run build -w webmq-backend\nnpm run build -w webmq-frontend\n\n# Run tests\nnpm run test -w webmq-backend\nnpm run test -w webmq-frontend\nnpm test  # Run e2e tests\n\n# Development mode\nnpm run dev -w webmq-backend    # TypeScript watch\nnpm run dev -w webmq-frontend   # ESBuild watch\n```\n\nThe RabbitMQ management UI is available at \u003chttp://localhost:15672\u003e (guest/guest).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbairak%2Fwebmq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkbairak%2Fwebmq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbairak%2Fwebmq/lists"}