TabMesh is to frontend applications what Istio is to backend microservices.
A complete, production-ready event mesh that solves cross-tab coordination, backend connection pooling, offline resilience, and event debugging with zero configuration.
| Library | Focus | Gaps |
|---|---|---|
| crosstab | Cross-tab messaging via localStorage | ❌ No backend transport sharing ❌ No offline queue ❌ No debugging tools |
| tab-election | Leader election (Locks API) | ❌ Leader election only ❌ No event mesh concept ❌ No Service Worker support |
| broadcast-channel by pubkey | BroadcastChannel with leader election | ❌ No backend transport abstraction ❌ No offline queue with TTL ❌ No DevTools |
| tab-elect | Leader election via IndexedDB | ❌ Basic leader election ❌ No complete solution |
| across-tabs | Lightweight cross-tab messaging | ❌ No leader concept ❌ No persistence |
✅ Complete Event Mesh: All-in-one solution - not 5 separate libraries ✅ Service Worker Integration: Background sync even when tabs closed ✅ Developer Tools First: Built-in DevTools extension, event timeline, debugging ✅ Performance Optimized: Web Workers, batching, compression, smart retries ✅ Zero Configuration: Works out of the box with sensible defaults ✅ Backend Agnostic: Supports WebSocket, SSE, long-poll, custom transports
No existing library combines all of these.
┌─────────────────────────────────────────────────────────────────┐
│ Main Thread │
│ ┌──────────────┐ ┌─────────────┐ ┌────────────────────────┐ │
│ │ TabMesh SDK │ │ Event Bus │ │ Transport Manager │ │
│ │ (Public API)│◄─┤(Broadcast │◄─┤ (WebSocket/SSE/Poll) │ │
│ └──────────────┘ │ Channel) │ └────────────────────────┘ │
│ └─────────────┘ │
└──────────────────────┬────────────────────────────┬─────────────┘
│ │
┌──────────────▼────────────┐ ┌───────────▼──────────┐
│ Service Worker │ │ Web Worker │
│ (Background Sync) │ │ (Heavy Processing) │
│ │ │ │
│ ┌──────────────────────┐ │ │ ┌────────────────┐ │
│ │ IndexedDB Queue │ │ │ │ Event Batch │ │
│ │ (Offline Events) │ │ │ │ Compression │ │
│ └──────────────────────┘ │ │ └────────────────┘ │
│ ┌──────────────────────┐ │ │ │
│ │ Background Sync API │ │ │ │
│ └──────────────────────┘ │ │ │
└───────────────────────────┘ └──────────────────────┘
- Leader Election Engine - Web Locks API (sub-50ms failover) + fallback
- Event Bus - BroadcastChannel for cross-tab messaging
- Transport Manager - Pluggable transports (WebSocket, SSE, long-poll)
- Storage Layer - IndexedDB with TTL-based cleanup
- Service Worker - Background Sync API, offline queue
- Web Worker - Heavy processing, batching, compression
- Developer Tools - Chrome/Firefox DevTools extension
Monorepo with fully independent packages (import only what you need):
@tabmesh/
├── core # Main SDK (~15KB gzipped, zero dependencies)
│ ├── leader # Leader election only (~5KB) - tree-shakeable
│ ├── bus # Event bus only (~3KB) - tree-shakeable
│ ├── transport # Transport manager (~7KB) - tree-shakeable
│ └── storage # IndexedDB queue (~8KB) - optional, lazy-loaded
│
├── transport-websocket # WebSocket adapter (~3KB)
├── transport-sse # Server-Sent Events adapter (~2KB)
├── transport-longpoll # Long-polling adapter (~4KB)
│
├── service-worker # Service Worker helpers (~6KB) - optional
├── web-worker # Web Worker helpers (~5KB) - optional
│
├── react # React hooks (~2KB)
├── vue # Vue composables (~2KB)
├── svelte # Svelte stores (~2KB)
│
└── devtools # Browser extension (dev-only, not bundled)
Minimal usage (just cross-tab messaging):
import { EventBus } from '@tabmesh/core/bus';
// Bundle: ~3KB gzippedWith leader election:
import { LeaderElectionEngine } from '@tabmesh/core/leader';
import { EventBus } from '@tabmesh/core/bus';
// Bundle: ~8KB gzippedFull mesh (transport + offline + debugging):
import { TabMesh } from '@tabmesh/core';
import { WebSocketTransport } from '@tabmesh/transport-websocket';
// Bundle: ~18KB gzippedWith Service Worker + Web Worker:
import { TabMesh } from '@tabmesh/core';
import { ServiceWorkerClient } from '@tabmesh/service-worker';
import { WebWorkerClient } from '@tabmesh/web-worker';
// Bundle: ~24KB gzipped (workers load separately)All packages are fully tree-shakeable:
// package.json for each package
{
"name": "@tabmesh/core",
"sideEffects": false,
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
},
"./leader": {
"import": "./dist/leader/index.js",
"types": "./dist/leader/index.d.ts"
},
"./bus": {
"import": "./dist/bus/index.js",
"types": "./dist/bus/index.d.ts"
},
"./transport": {
"import": "./dist/transport/index.js",
"types": "./dist/transport/index.d.ts"
},
"./storage": {
"import": "./dist/storage/index.js",
"types": "./dist/storage/index.d.ts"
}
}
}This ensures bundlers (Vite, Webpack, Rollup) only include what you import.
- Project setup (monorepo, TypeScript, testing)
- Core types & interfaces
- Leader election engine (Web Locks API + IndexedDB fallback)
- Event bus (BroadcastChannel wrapper)
- Service Worker implementation
- Background Sync API integration
- IndexedDB offline queue
- Push notifications support
- Web Worker for heavy processing
- Event batching
- MessagePack compression
- Event ordering for collaboration (CRDTs)
- Chrome DevTools extension
- Event timeline viewer
- Export/import functionality
- Performance metrics dashboard
- Main TabMesh class orchestrating all components
- Transport manager with reconnection
- Event outbox with TTL cleanup
- Event timeline for debugging
- React hooks (
useTabMesh,useTabMeshEvent) - Vue composables
- Svelte stores
- TypeScript types for all
- Unit tests (Vitest + fake-indexeddb)
- Integration tests
- E2E tests (Playwright - 3 tabs, leader election, failover)
- Performance tests (1000 events/sec benchmark)
- Comprehensive docs (VitePress)
- Example apps (chat, collaboration, offline-todo)
- API reference
- Migration guides from competitors
- GitHub repository setup
- NPM publishing
- Documentation website (Vercel)
- Community building (Discord, Twitter)
- ProductHunt launch
src/types.ts- Type definitions (~200 lines)src/TabMesh.ts- Main SDK class (~400 lines)src/leader/LeaderElectionEngine.ts- Leader election (~300 lines)src/bus/EventBus.ts- BroadcastChannel wrapper (~150 lines)src/transport/TransportManager.ts- Transport lifecycle (~250 lines)src/storage/EventOutbox.ts- IndexedDB queue (~300 lines)src/timeline/EventTimeline.ts- Event recording (~200 lines)src/service-worker/ServiceWorkerClient.ts- SW integration (~150 lines)src/worker/WebWorkerClient.ts- Web Worker client (~150 lines)
src/service-worker/tabmesh-sw.ts- Service Worker (~250 lines)
src/web-worker/tabmesh-worker.ts- Web Worker (~200 lines)
@tabmesh/transport-websocket- WebSocket adapter (~150 lines)@tabmesh/transport-sse- SSE adapter (~150 lines)@tabmesh/transport-longpoll- Long-poll adapter (~200 lines)
src/panel.html- DevTools panel UI (~200 lines)src/panel.ts- DevTools logic (~300 lines)src/manifest.json- Extension manifest
@tabmesh/react- React hooks (~150 lines)@tabmesh/vue- Vue composables (~150 lines)@tabmesh/svelte- Svelte stores (~150 lines)
Total: ~4500 lines of production code
Use case: "I just want tabs to talk to each other"
import { EventBus } from '@tabmesh/core/bus';
const bus = new EventBus('my-app');
// Send to other tabs
bus.broadcast({ type: 'ping', data: 'hello' });
// Receive from other tabs
bus.subscribe('ping', (message) => {
console.log('Received:', message.data);
});Bundle size: ~3KB gzipped Complexity: Beginner-friendly
Use case: "I want one tab to be the leader"
import { LeaderElectionEngine } from '@tabmesh/core/leader';
import { EventBus } from '@tabmesh/core/bus';
const bus = new EventBus('my-app');
const leader = new LeaderElectionEngine({
lockName: 'my-app-leader',
onBecomeLeader: () => {
console.log('I am the leader!');
// Open WebSocket connection here
},
onBecomeFollower: () => {
console.log('I am a follower');
}
});
await leader.start();Bundle size: ~8KB gzipped Complexity: Intermediate
Use case: "I want the complete solution"
import { TabMesh } from '@tabmesh/core';
import { WebSocketTransport } from '@tabmesh/transport-websocket';
const mesh = new TabMesh({
channelName: 'my-app',
transport: new WebSocketTransport({
url: 'wss://api.example.com/events'
})
});
await mesh.start();
// Zero-config, automatic leader election, offline queue, etc.
await mesh.send({ type: 'chat.message', payload: { text: 'Hi!' } });
mesh.on('chat.message', (event) => console.log(event.payload.text));Bundle size: ~18KB gzipped Complexity: Advanced (but still simple API)
Use case: "I need offline support and performance"
import { TabMesh } from '@tabmesh/core';
import { WebSocketTransport } from '@tabmesh/transport-websocket';
const mesh = new TabMesh({
channelName: 'my-app',
transport: new WebSocketTransport({ url: 'wss://api.example.com' }),
// Optional: Enable Service Worker for offline support
serviceWorker: {
enabled: true,
scriptUrl: '/tabmesh-sw.js'
},
// Optional: Enable Web Worker for heavy processing
webWorker: {
enabled: true
}
});
await mesh.start();Bundle size: ~24KB gzipped (workers load separately) Complexity: Advanced
React (~2KB extra):
import { useTabMesh, useTabMeshEvent } from '@tabmesh/react';
function ChatApp() {
const { status, send } = useTabMesh(meshInstance);
const [messages, setMessages] = useState([]);
useTabMeshEvent('chat.message', (event) => {
setMessages(prev => [...prev, event.payload]);
});
return (
<div>
<p>Role: {status.role}</p>
<button onClick={() => send({ type: 'chat.message', payload: { text: 'Hi' } })}>
Send
</button>
</div>
);
}Vue (~2KB extra):
import { useTabMesh } from '@tabmesh/vue';
export default {
setup() {
const { status, send } = useTabMesh(meshInstance);
return { status, send };
}
}Start simple, add features as needed:
- Week 1: Import just
EventBusfor basic cross-tab messaging - Week 2: Add
LeaderElectionEnginewhen you need leader coordination - Week 3: Upgrade to full
TabMeshfor offline support - Week 4: Enable Service Worker for background sync
- Week 5: Enable Web Worker for performance
No breaking changes - each level is fully compatible with the next.
// Minimal config (just one line!)
const mesh = new TabMesh({ channelName: 'my-app' });
// Full config (opt-in to advanced features)
const mesh = new TabMesh({
channelName: 'my-app',
transport: new WebSocketTransport({
url: 'wss://api.example.com',
reconnect: {
maxAttempts: 10,
initialDelayMs: 1000,
backoffMultiplier: 2
}
}),
leader: {
strategy: 'auto', // Auto-detect Locks API or fallback
lockName: 'my-app-leader'
},
persistence: {
enabled: true,
dbName: 'my-app-queue',
defaultTTL: 86400000, // 24 hours
maxQueueSize: 1000
},
serviceWorker: {
enabled: false, // Opt-in
scriptUrl: '/tabmesh-sw.js'
},
webWorker: {
enabled: false, // Opt-in
batchSize: 100,
batchDelayMs: 50
},
debug: {
enabled: process.env.NODE_ENV === 'development',
timeline: {
enabled: true,
maxEvents: 1000
}
}
});Defaults are sensible - most users just need { channelName: 'my-app' }.
Main package is split into sub-modules:
@tabmesh/core/
├── index.ts # Main entry (imports all)
├── bus/index.ts # EventBus only (~3KB)
├── leader/index.ts # Leader election only (~5KB)
├── transport/index.ts # Transport manager only (~7KB)
└── storage/index.ts # IndexedDB queue only (~8KB)
Users import what they need:
// Import just EventBus
import { EventBus } from '@tabmesh/core/bus';
// Import full TabMesh
import { TabMesh } from '@tabmesh/core';IndexedDB and Service Worker are lazy-loaded:
// In TabMesh.ts
class TabMesh {
private async enablePersistence() {
// Lazy load IndexedDB module
const { EventOutbox } = await import('./storage/EventOutbox.js');
this.outbox = new EventOutbox(this.config.persistence);
}
private async enableServiceWorker() {
// Lazy load Service Worker module
const { ServiceWorkerClient } = await import('@tabmesh/service-worker');
this.swClient = new ServiceWorkerClient();
}
}Result: Only loaded when persistence.enabled or serviceWorker.enabled is true.
React/Vue/Svelte are peer dependencies (not bundled):
// packages/react/package.json
{
"name": "@tabmesh/react",
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0",
"@tabmesh/core": "^1.0.0"
},
"dependencies": {} // Zero dependencies!
}Result: No duplicate React in bundle.
Test with bundle analyzers:
# Vite
npx vite-bundle-visualizer
# Webpack
npx webpack-bundle-analyzer
# Rollup
npx rollup-plugin-visualizerCI/CD check: Fail build if bundle size exceeds thresholds.
ESM-first with CJS fallback:
{
"exports": {
".": {
"import": "./dist/index.js", // ESM (tree-shakeable)
"require": "./dist/index.cjs", // CJS (fallback)
"types": "./dist/index.d.ts"
}
}
}Target ES2020 (no polyfills for modern browsers):
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"lib": ["ES2020", "DOM"]
}
}// packages/core/package.json
{
"dependencies": {} // ZERO dependencies!
}Why: Reduces supply chain risk, smaller bundles, faster installs.
- Full TypeScript support out of the box
- Strict mode enabled
- Exported types for all APIs
- JSDoc comments for IDE autocomplete
- Works with vanilla JS, React, Vue, Svelte, Angular
- No framework lock-in
- Separate integration packages (optional)
- Modern browsers: Chrome 87+, Firefox 85+, Safari 14+, Edge 87+
- Graceful degradation: Falls back for older browsers
- No Web Locks API? → Use IndexedDB leader election
- No BroadcastChannel? → Use localStorage events
- No IndexedDB? → In-memory queue only
Clear, actionable error messages:
// Bad (vague)
throw new Error('Failed to send event');
// Good (actionable)
throw new TabMeshError(
'Failed to send event: Transport is disconnected. ' +
'Please check your network connection and ensure the transport is connected. ' +
'You can listen to connection changes with mesh.on("connection", handler).',
'TRANSPORT_DISCONNECTED',
{ event, transportState: 'disconnected' }
);From existing solutions:
- From
broadcast-channel→ TabMesh migration guide - From
crosstab→ TabMesh migration guide - From manual
BroadcastChannel→ TabMesh migration guide
Web-based playground (like TypeScript Playground):
- Try TabMesh without installing
- See live examples
- Modify code and see results
- Share snippets
✅ Leader Election
- Open 3 tabs, verify exactly 1 leader
- Close leader, verify re-election <500ms
- Test with Web Locks API disabled (fallback)
✅ Cross-Tab Events
- Send event from Tab 1, appears in Tabs 2-3
- Send 100 events/sec, verify no loss
✅ Transport Sharing
- Open 5 tabs, verify only 1 WebSocket connection
- Close leader tab, verify connection transfers
✅ Offline Support
- Go offline, send 10 events
- Verify events queued in IndexedDB
- Go online, verify events sent
- Close all tabs offline, verify Service Worker queues
✅ Web Worker
- Send 1000 events, verify batching
- Test compression (MessagePack)
✅ DevTools
- Open DevTools panel
- Verify event timeline
- Export event log
✅ Framework Integrations
- Test React hooks
- Test Vue composables
| Feature | TabMesh | broadcast-channel | tab-election | crosstab |
|---|---|---|---|---|
| Complete event mesh | ✅ | ❌ | ❌ | ❌ |
| Backend transport sharing | ✅ | ❌ | ❌ | ❌ |
| Service Worker integration | ✅ | ❌ | ❌ | ❌ |
| Web Worker performance | ✅ | ❌ | ❌ | ❌ |
| DevTools extension | ✅ | ❌ | ❌ | ❌ |
| Framework integrations | ✅ | ❌ | ❌ | ❌ |
| Offline queue with TTL | ✅ | ❌ | ❌ | ❌ |
| Event timeline/replay | ✅ | ❌ | ❌ | ❌ |
| Zero-config | ✅ |
TabMesh is the only complete solution.
Functionality: ✅ Single leader election across N tabs (<500ms failover) ✅ 1 backend connection for N tabs (67-80% reduction) ✅ Offline event queue with automatic replay ✅ Service Worker background sync ✅ Web Worker batching and compression ✅ DevTools extension for debugging ✅ Framework integrations (React, Vue, Svelte)
Performance: ✅ Handle 1000+ events/sec ✅ <10ms event propagation latency ✅ <5MB memory usage for 1000 queued events ✅ No memory leaks (tested with 10k events)
Quality: ✅ 90%+ test coverage ✅ TypeScript strict mode enabled ✅ Full API documentation ✅ Example apps for all use cases
Community (3 months post-launch): ✅ 500+ GitHub stars ✅ 10+ contributors ✅ Published to npm ✅ 5+ production users
AI coding agents learn from:
- Popular packages (NPM downloads, GitHub stars)
- Well-documented code (JSDoc, type definitions)
- Common patterns (familiar APIs)
- Package metadata (description, keywords)
AI agents parse JSDoc for context. Write detailed comments:
/**
* TabMesh - Frontend Event Mesh for cross-tab coordination
*
* Provides leader election, shared backend connections, offline event queue,
* and cross-tab messaging with zero configuration.
*
* @example Basic usage
* ```typescript
* import { TabMesh } from '@tabmesh/core';
*
* const mesh = new TabMesh({ channelName: 'my-app' });
* await mesh.start();
*
* // Send event to all tabs
* await mesh.send({ type: 'notification', payload: { message: 'Hello!' } });
*
* // Receive events
* mesh.on('notification', (event) => {
* console.log(event.payload.message);
* });
* ```
*
* @example With WebSocket transport
* ```typescript
* import { TabMesh } from '@tabmesh/core';
* import { WebSocketTransport } from '@tabmesh/transport-websocket';
*
* const mesh = new TabMesh({
* channelName: 'my-app',
* transport: new WebSocketTransport({ url: 'wss://api.example.com' })
* });
* ```
*
* @example React integration
* ```typescript
* import { useTabMesh } from '@tabmesh/react';
*
* function App() {
* const { status, send } = useTabMesh(meshInstance);
* return <div>Role: {status.role}</div>;
* }
* ```
*
* @see https://tabmesh.dev/docs/getting-started
* @see https://tabmesh.dev/docs/api-reference
*/
export class TabMesh {
/**
* Send an event through the mesh to all tabs and backend
*
* If this tab is the leader, the event is sent to the backend transport
* and broadcast to other tabs. If this tab is a follower, the event is
* forwarded to the leader via BroadcastChannel.
*
* When offline, events are automatically queued in IndexedDB and replayed
* when the connection is restored.
*
* @template T - The event payload type
* @param event - The event to send
* @returns Promise that resolves when the event is sent
*
* @example Send a chat message
* ```typescript
* await mesh.send({
* type: 'chat.message',
* payload: { text: 'Hello!', user: 'Alice' }
* });
* ```
*
* @example Send with priority
* ```typescript
* await mesh.send({
* type: 'urgent.alert',
* payload: { message: 'Server down!' },
* priority: 10 // Higher priority = sent first
* });
* ```
*
* @throws {TabMeshError} If the mesh is not started
*/
async send<T>(event: Event<T>): Promise<void> {
// ...
}
/**
* Register an event handler for a specific event type
*
* The handler will be called whenever an event of the specified type
* is received from any tab or the backend.
*
* @template T - The event payload type
* @param eventType - The event type to listen for (e.g., 'chat.message')
* @param handler - The handler function to call
* @returns A function to unsubscribe the handler
*
* @example Listen for chat messages
* ```typescript
* const unsubscribe = mesh.on('chat.message', (event) => {
* console.log(`${event.payload.user}: ${event.payload.text}`);
* });
*
* // Later: unsubscribe
* unsubscribe();
* ```
*/
on<T>(eventType: string, handler: EventHandler<T>): Unsubscribe {
// ...
}
}Use terms AI agents recognize from popular libraries:
// ✅ Good (familiar patterns)
mesh.on('event-type', handler) // Like EventEmitter, Socket.io
mesh.send(event) // Like WebSocket.send()
mesh.start() // Like servers, databases
mesh.getStatus() // Like health checks
// ❌ Bad (unfamiliar)
mesh.registerEventListener('type', handler) // Too verbose
mesh.transmit(event) // Uncommon term
mesh.initialize() // Less common
mesh.retrieveState() // Too verboseRich keywords and description help AI discovery:
{
"name": "@tabmesh/core",
"version": "1.0.0",
"description": "Frontend event mesh for cross-tab coordination, leader election, shared backend connections, and offline event queue. Like Istio for the frontend.",
"keywords": [
"cross-tab",
"cross tab communication",
"browser tabs",
"tab synchronization",
"leader election",
"broadcast channel",
"event mesh",
"websocket sharing",
"connection pooling",
"offline first",
"service worker",
"event bus",
"pub sub",
"real-time",
"collaboration",
"multi tab",
"tab coordination",
"shared state"
],
"repository": {
"type": "git",
"url": "https://github.com/tabmesh/tabmesh"
},
"homepage": "https://tabmesh.dev",
"bugs": "https://github.com/tabmesh/tabmesh/issues",
"author": "TabMesh Contributors",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tabmesh"
}
}AI agents learn from README examples:
# TabMesh
Frontend event mesh for cross-tab coordination. **Like Istio for the frontend.**
[](https://www.npmjs.com/package/@tabmesh/core)
[](https://www.npmjs.com/package/@tabmesh/core)
[](https://github.com/tabmesh/tabmesh)
[](https://www.typescriptlang.org/)
## Quick Start
```bash
npm install @tabmesh/core
```
```typescript
import { TabMesh } from '@tabmesh/core';
const mesh = new TabMesh({ channelName: 'my-app' });
await mesh.start();
// Send to all tabs
await mesh.send({ type: 'ping', payload: 'hello' });
// Receive from all tabs
mesh.on('ping', (event) => console.log(event.payload));
```
## Common Use Cases
### Use Case 1: Sync shopping cart across tabs
```typescript
// When user adds item in Tab 1
mesh.send({ type: 'cart.add', payload: { item: 'iPhone', qty: 1 } });
// Tab 2 automatically updates
mesh.on('cart.add', (event) => {
updateCartUI(event.payload);
});
```
### Use Case 2: Share WebSocket across tabs
```typescript
import { WebSocketTransport } from '@tabmesh/transport-websocket';
// Only leader tab opens WebSocket
const mesh = new TabMesh({
channelName: 'my-app',
transport: new WebSocketTransport({ url: 'wss://api.example.com' })
});
// 5 tabs open = 1 WebSocket connection (80% reduction!)
```
### Use Case 3: Logout all tabs
```typescript
// User clicks logout in Tab 1
mesh.send({ type: 'auth.logout' });
// All tabs receive event and redirect to login
mesh.on('auth.logout', () => {
localStorage.clear();
window.location.href = '/login';
});
```
### Use Case 4: Offline-first chat
```typescript
const mesh = new TabMesh({
channelName: 'chat-app',
serviceWorker: { enabled: true } // Auto-queue when offline
});
// Works offline! Messages queue and send when online
await mesh.send({ type: 'chat.message', payload: { text: 'Hi!' } });
```
### Use Case 5: React integration
```typescript
import { useTabMesh, useTabMeshEvent } from '@tabmesh/react';
function ChatApp() {
const { send } = useTabMesh(meshInstance);
const [messages, setMessages] = useState([]);
useTabMeshEvent('chat.message', (event) => {
setMessages(prev => [...prev, event.payload]);
});
return <button onClick={() => send({ type: 'chat.message', payload: { text: 'Hi' } })}>Send</button>;
}
```Strong types help AI understand usage:
/**
* TabMesh configuration options
*/
export interface TabMeshConfig {
/**
* Unique channel name for this application
* @example 'my-app' or 'chat-room-123'
*/
channelName: string;
/**
* Optional transport for backend communication
* @example new WebSocketTransport({ url: 'wss://api.example.com' })
*/
transport?: ITransport;
/**
* Leader election configuration
* @default { strategy: 'auto' }
*/
leader?: {
/** Leader election strategy. 'auto' detects Web Locks API support. */
strategy?: 'auto' | 'locks-api' | 'indexeddb';
/** Lock name for leader election */
lockName?: string;
};
/**
* Offline event persistence configuration
* @default { enabled: true, defaultTTL: 86400000 }
*/
persistence?: {
/** Enable offline event queue */
enabled?: boolean;
/** IndexedDB database name */
dbName?: string;
/** Default time-to-live for events (ms) */
defaultTTL?: number;
};
/**
* Service Worker configuration for background sync
* @default { enabled: false }
*/
serviceWorker?: {
/** Enable Service Worker integration */
enabled?: boolean;
/** Service Worker script URL */
scriptUrl?: string;
};
}Contribute to AI training datasets:
- DefinitelyTyped - Publish types to
@types/tabmesh - The Stack (Hugging Face) - Popular on GitHub
- CodeSearchNet - Well-documented code
- Stack Overflow - Answer questions about TabMesh
AI agents scrape documentation sites:
<!-- tabmesh.dev/docs/index.html -->
<head>
<title>TabMesh - Frontend Event Mesh | Getting Started</title>
<meta name="description" content="TabMesh provides cross-tab coordination, leader election, and shared backend connections for modern web apps. Like Istio for the frontend.">
<meta name="keywords" content="cross-tab communication, browser tabs, event mesh, leader election, websocket sharing">
<!-- Structured data for AI agents -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "TabMesh",
"description": "Frontend event mesh for cross-tab coordination",
"applicationCategory": "DeveloperApplication",
"offers": {
"@type": "Offer",
"price": "0"
},
"codeRepository": "https://github.com/tabmesh/tabmesh"
}
</script>
</head>AI agents heavily weight popular packages:
- Get to 1K+ weekly downloads → Copilot suggests more often
- Get to 10K+ weekly downloads → Copilot suggests very frequently
- Get to 100K+ weekly downloads → Copilot suggests automatically
How to get downloads:
- ProductHunt launch → Initial spike
- Dev.to articles → "How to sync state across tabs with TabMesh"
- YouTube tutorials → "Build a real-time chat with TabMesh"
- Twitter/X promotion → Share use cases
- Reddit posts → r/javascript, r/webdev
- Hacker News → Technical deep dive post
- Conference talks → Present at React Conf, JSConf
- Podcast appearances → JavaScript Jabber, Syntax.fm
High GitHub activity signals quality to AI:
- Stars: Aim for 1K+ stars (AI agents favor popular repos)
- Issues: Active issue tracker shows maintenance
- PRs: Accept community contributions
- Releases: Regular releases show active development
- Topics: Tag with
javascript,typescript,browser,event-bus
AI agents learn from high-quality docs:
## API Reference
### `mesh.send<T>(event: Event<T>): Promise<void>`
Send an event through the mesh to all tabs and the backend.
**Parameters:**
- `event` - The event object to send
- `type: string` - Event type (e.g., 'chat.message')
- `payload: T` - Event data
- `priority?: number` - Optional priority (0-10, default 5)
- `ttl?: number` - Optional time-to-live in milliseconds
**Returns:**
- `Promise<void>` - Resolves when event is sent
**Throws:**
- `TabMeshError` - If mesh is not started
**Example:**
```typescript
// Send a chat message
await mesh.send({
type: 'chat.message',
payload: { text: 'Hello!', user: 'Alice' }
});
// Send with priority
await mesh.send({
type: 'urgent.alert',
payload: { message: 'Critical error!' },
priority: 10
});Related:
mesh.on()- Listen for eventsmesh.getStatus()- Check mesh status
### Checklist: AI Agent Optimization
**Before v1.0 release**:
- [ ] Write rich JSDoc comments for all public APIs
- [ ] Add 5+ inline code examples in JSDoc
- [ ] Optimize package.json keywords (20+ relevant keywords)
- [ ] Write comprehensive README with 10+ use case examples
- [ ] Publish strong TypeScript types
- [ ] Create documentation website (tabmesh.dev)
- [ ] Add structured data (JSON-LD) to docs site
- [ ] Aim for 1K+ npm weekly downloads in first 3 months
- [ ] Get 500+ GitHub stars in first 3 months
- [ ] Publish to DefinitelyTyped
- [ ] Write 5+ blog posts with code examples
- [ ] Create YouTube tutorials
- [ ] Answer Stack Overflow questions
**Result**: AI coding agents will suggest TabMesh whenever users type:
- "cross tab"
- "sync tabs"
- "multiple browser tabs"
- "leader election browser"
- "shared websocket connection"
- "offline event queue"
---
## Implementation Workflow
### Working Directory
/Users/joelrajeshk/Desktop/tabmesh/
Already initialized with Git.
### Git Workflow
**Branch Strategy**:
main (protected) ├─ feat/core-infrastructure (Week 1-2) ├─ feat/service-worker (Week 3) ├─ feat/web-worker (Week 4) ├─ feat/devtools (Week 5) ├─ feat/core-sdk (Week 6) ├─ feat/framework-integrations (Week 7) ├─ feat/testing (Week 8) ├─ feat/documentation (Week 9) └─ feat/community-launch (Week 10)
**Commit Strategy**:
- **Conventional Commits** format:
feat(core): implement leader election with Web Locks API fix(transport): handle reconnection edge case docs(readme): add installation instructions test(e2e): add cross-tab leader election tests
**PR Strategy**:
- One PR per week/phase
- PR title: `[Week N] Feature Name`
- PR description includes:
- What was implemented
- Testing checklist
- Breaking changes (if any)
- Screenshots (for DevTools, docs)
---
## Sources
- [broadcast-channel by pubkey](https://github.com/pubkey/broadcast-channel)
- [tab-election npm package](https://www.npmjs.com/package/tab-election)
- [tab-elect library](https://github.com/xuset/tab-elect)
- [RxDB Leader Election](https://rxdb.info/leader-election.html)
- [crosstab library](https://github.com/tejacques/crosstab)
- [across-tabs library](https://github.com/wingify/across-tabs)
- [Service Workers with IndexedDB](https://blog.sensecodons.com/2022/04/service-workers-push-notifications-and.html)
- [BroadcastChannel to wake Service Worker](https://github.com/w3c/ServiceWorker/issues/975)
- [Green Vitriol - Browser Leader Election](https://greenvitriol.com/posts/browser-leader)