omniwire 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.omniwire-state/update-state.json +7 -0
- package/LICENSE +674 -21
- package/README.md +71 -13
- package/assets/banner-dark.svg +14 -10
- package/assets/banner-light.svg +14 -10
- package/dist/mcp/events.d.ts +53 -0
- package/dist/mcp/events.js +317 -0
- package/dist/mcp/events.js.map +1 -0
- package/dist/mcp/index.js +20 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.js +763 -20
- package/dist/mcp/server.js.map +1 -1
- package/dist/mesh/omnimesh.d.ts +85 -0
- package/dist/mesh/omnimesh.js +307 -0
- package/dist/mesh/omnimesh.js.map +1 -0
- package/dist/update.d.ts +25 -4
- package/dist/update.js +227 -52
- package/dist/update.js.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -8,13 +8,21 @@
|
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/omniwire"><img src="https://img.shields.io/npm/v/omniwire?style=for-the-badge&logo=npm&color=CB3837&labelColor=0D1117" alt="npm" /></a>
|
|
11
|
-
<img src="https://img.shields.io/badge/MCP_Tools-
|
|
11
|
+
<img src="https://img.shields.io/badge/MCP_Tools-81-59C2FF?style=for-the-badge&labelColor=0D1117" alt="tools" />
|
|
12
12
|
<img src="https://img.shields.io/badge/A2A-Protocol-00C853?style=for-the-badge&labelColor=0D1117" alt="A2A" />
|
|
13
|
-
<img src="https://img.shields.io/badge/Latency-~
|
|
14
|
-
<img src="https://img.shields.io/badge/
|
|
13
|
+
<img src="https://img.shields.io/badge/Latency-~81ms-FF6D00?style=for-the-badge&labelColor=0D1117" alt="latency" />
|
|
14
|
+
<img src="https://img.shields.io/badge/CyberBase-Sync-CC93E6?style=for-the-badge&labelColor=0D1117" alt="cyberbase" />
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/GPL--3.0-license-8B949E?style=for-the-badge&labelColor=0D1117" alt="license" /></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
+
<div align="center">
|
|
19
|
+
|
|
20
|
+
**The infrastructure layer for AI agent swarms.**
|
|
21
|
+
|
|
22
|
+
81 MCP tools · A2A protocol · OmniMesh VPN · nftables firewall · CDP browser · cookie sync · CyberBase persistence
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
18
26
|
---
|
|
19
27
|
|
|
20
28
|
## Quick Start
|
|
@@ -206,7 +214,7 @@ graph TB
|
|
|
206
214
|
direction TB
|
|
207
215
|
MCP["MCP Protocol Layer<br/>stdio | SSE | REST"]
|
|
208
216
|
|
|
209
|
-
subgraph tools["
|
|
217
|
+
subgraph tools["81 Tools"]
|
|
210
218
|
direction LR
|
|
211
219
|
EXEC["Execution<br/>exec run batch<br/>broadcast pipeline bg"]
|
|
212
220
|
AGENT["Agentic<br/>store watch task<br/>a2a events locks"]
|
|
@@ -287,7 +295,7 @@ omniwire_workflow reusable named DAGs
|
|
|
287
295
|
|
|
288
296
|
### Adaptive File Transfer
|
|
289
297
|
```
|
|
290
|
-
< 10 MB SFTP native,
|
|
298
|
+
< 10 MB SFTP native, 81ms
|
|
291
299
|
10M-1GB netcat+LZ4 compressed, 100ms
|
|
292
300
|
> 1 GB aria2c 16-parallel, max speed
|
|
293
301
|
```
|
|
@@ -340,7 +348,7 @@ watch(assert="ready") poll until
|
|
|
340
348
|
|
|
341
349
|
---
|
|
342
350
|
|
|
343
|
-
## All
|
|
351
|
+
## All 81 Tools
|
|
344
352
|
|
|
345
353
|
> **Every tool** supports `background: true` -- returns a task ID immediately. Poll with `omniwire_bg`.
|
|
346
354
|
|
|
@@ -408,18 +416,51 @@ watch(assert="ready") poll until
|
|
|
408
416
|
| `omniwire_git` | Git commands on repos on any node |
|
|
409
417
|
| `omniwire_syslog` | Query journalctl with filters |
|
|
410
418
|
|
|
411
|
-
### Network, VPN &
|
|
419
|
+
### Network, VPN & Security (9)
|
|
412
420
|
|
|
413
421
|
| Tool | Description |
|
|
414
422
|
|------|-------------|
|
|
415
423
|
| `omniwire_firewall` | nftables firewall engine. Presets (server/paranoid/pentest), rate-limit, geo-block, port-knock, ban/unban, audit. Mesh always whitelisted. |
|
|
416
|
-
| `omniwire_vpn` |
|
|
424
|
+
| `omniwire_vpn` | VPN (Mullvad/OpenVPN/WireGuard/Tailscale). Multi-hop, DAITA, quantum, obfuscation, killswitch. Mesh-safe. |
|
|
425
|
+
| `omniwire_cookies` | Cookie management. JSON/Header/Netscape formats. Browser extract, CyberBase + 1Password sync. |
|
|
426
|
+
| `omniwire_cdp` | Chrome DevTools Protocol. Launch headless Chrome, screenshot, PDF, DOM dump, cookie extract. |
|
|
427
|
+
| `omniwire_proxy` | HTTP/SOCKS proxy management. Start/stop proxies on any node. |
|
|
428
|
+
| `omniwire_dns` | DNS management. Resolve, set server, flush cache, block domains. |
|
|
417
429
|
| `omniwire_port_forward` | Create/list/close SSH tunnels |
|
|
418
|
-
| `omniwire_open_browser` | Open URL in browser on a node |
|
|
419
430
|
| `omniwire_shell` | Persistent PTY session (preserves cwd/env) |
|
|
420
|
-
| `omniwire_stream` | Capture streaming output (tail -f, watch) |
|
|
421
431
|
| `omniwire_clipboard` | Shared clipboard buffer across mesh |
|
|
422
432
|
|
|
433
|
+
### Infrastructure (9)
|
|
434
|
+
|
|
435
|
+
| Tool | Description |
|
|
436
|
+
|------|-------------|
|
|
437
|
+
| `omniwire_backup` | Snapshot/restore paths on any node. Diff, cleanup, retention policies. |
|
|
438
|
+
| `omniwire_container` | Full Docker lifecycle. Compose up/down, build, push, logs, prune, stats. |
|
|
439
|
+
| `omniwire_cert` | TLS certificates. Let's Encrypt issue/renew, check expiry, self-signed generation. |
|
|
440
|
+
| `omniwire_user` | User & SSH key management. Add/remove users, deploy keys, sudo config. |
|
|
441
|
+
| `omniwire_schedule` | Distributed cron with failover. Add/remove/list/run-now scheduled tasks. |
|
|
442
|
+
| `omniwire_alert` | Threshold alerting. Disk/mem/load/offline checks with webhook notifications. |
|
|
443
|
+
| `omniwire_log_aggregate` | Cross-node log search. Grep journalctl/syslog across all nodes in parallel. |
|
|
444
|
+
| `omniwire_benchmark` | Node performance testing. CPU/memory/disk/network benchmarks. |
|
|
445
|
+
| `omniwire_stream` | Capture streaming output (tail -f, watch) |
|
|
446
|
+
|
|
447
|
+
### Agent Toolkit (7)
|
|
448
|
+
|
|
449
|
+
| Tool | Description |
|
|
450
|
+
|------|-------------|
|
|
451
|
+
| `omniwire_snippet` | Save/run reusable command templates with `{{var}}` substitution. |
|
|
452
|
+
| `omniwire_alias` | In-session command shortcuts. Set/run aliases. |
|
|
453
|
+
| `omniwire_trace` | Distributed tracing. Start/stop/view span waterfalls across nodes. |
|
|
454
|
+
| `omniwire_doctor` | Health diagnostics. Checks SSH, disk, mem, docker, WireGuard, tools, CyberBase. |
|
|
455
|
+
| `omniwire_metrics` | Prometheus-compatible metrics. Scrape/export node stats. |
|
|
456
|
+
| `omniwire_audit` | Command audit log. View/search/stats on all executed commands. |
|
|
457
|
+
| `omniwire_plugin` | Plugin system. List/load plugins from `~/.omniwire/plugins/`. |
|
|
458
|
+
| `omniwire_omnimesh` | OmniMesh — built-in WireGuard mesh manager. Init/up/down/add-peer/sync-peers/health/rotate-keys/topology across all OS. |
|
|
459
|
+
| `omniwire_mesh_expose` | Expose localhost-bound services to the entire mesh. Discover/expose/unexpose/expose-remote. |
|
|
460
|
+
| `omniwire_mesh_gateway` | Auto-expose all localhost services mesh-wide. Sync/teardown/add-rule/remove-rule. |
|
|
461
|
+
| `omniwire_events` | Event bus with Webhook + WebSocket + SSE. Publish events, manage webhooks, query log. |
|
|
462
|
+
| `omniwire_knowledge` | CyberBase knowledge CRUD + text/semantic search + health + vacuum + bulk-set + export. |
|
|
463
|
+
|
|
423
464
|
### CyberSync (9)
|
|
424
465
|
|
|
425
466
|
| Tool | Description |
|
|
@@ -441,7 +482,7 @@ watch(assert="ready") poll until
|
|
|
441
482
|
|
|
442
483
|
| Operation | Latency | Optimization |
|
|
443
484
|
|-----------|---------|-------------|
|
|
444
|
-
| **Command exec** | **~
|
|
485
|
+
| **Command exec** | **~81ms** | AES-128-GCM cipher, persistent SSH2, zero-fork `:` ping |
|
|
445
486
|
| **Mesh status** | **~100ms** | Parallel probes, 5s cache, single `/proc` read |
|
|
446
487
|
| **File read (<1MB)** | **~60ms** | SFTP-first (skips `cat` fork) |
|
|
447
488
|
| **Transfer (10MB)** | **~120ms** | LZ4 compression (10x faster than gzip) |
|
|
@@ -516,6 +557,23 @@ Create `~/.omniwire/mesh.json`:
|
|
|
516
557
|
|
|
517
558
|
## Changelog
|
|
518
559
|
|
|
560
|
+
<details>
|
|
561
|
+
<summary><b>v3.0.0 -- 81 Tools, CyberBase Persistence, Full Platform</b></summary>
|
|
562
|
+
|
|
563
|
+
**19 new tools**: proxy, dns, backup, container, cert, user, schedule, alert, log_aggregate, benchmark, snippet, alias, trace, doctor, metrics, audit, plugin, cookies, cdp.
|
|
564
|
+
|
|
565
|
+
**CyberBase auto-persistence**: Store, audit, blackboard, cookies all sync to PostgreSQL. pgvector semantic search. 5s statement_timeout on all DB calls.
|
|
566
|
+
|
|
567
|
+
**Architecture**: Priority command queues, smart output truncation, predictive node selection, latency history, connection pool stats.
|
|
568
|
+
|
|
569
|
+
**Security**: Command denylist (blocks rm -rf /, fork bombs, disk wipes). Audit log with CyberBase persistence.
|
|
570
|
+
|
|
571
|
+
**A2A**: Typed message schemas (JSON validation), dead letter queue for failed tasks, pub/sub event filters.
|
|
572
|
+
|
|
573
|
+
**DX**: GitHub Actions CI, bash/zsh/fish shell completions, --json flag, cookie sync to 1Password.
|
|
574
|
+
|
|
575
|
+
</details>
|
|
576
|
+
|
|
519
577
|
<details>
|
|
520
578
|
<summary><b>v2.7.0 -- Firewall Engine</b></summary>
|
|
521
579
|
|
|
@@ -539,7 +597,7 @@ Create `~/.omniwire/mesh.json`:
|
|
|
539
597
|
<details>
|
|
540
598
|
<summary><b>v2.5.1 -- Universal Background Dispatch</b></summary>
|
|
541
599
|
|
|
542
|
-
**`background: true`** auto-injected into all
|
|
600
|
+
**`background: true`** auto-injected into all 81 tools via server-level wrapper. Returns task ID, poll with `omniwire_bg`. New `omniwire_bg` tool for list/poll/result.
|
|
543
601
|
|
|
544
602
|
</details>
|
|
545
603
|
|
|
@@ -578,7 +636,7 @@ Security fixes, multi-path SSH failover, CyberBase integration, VaultBridge Obsi
|
|
|
578
636
|
```
|
|
579
637
|
omniwire/
|
|
580
638
|
src/
|
|
581
|
-
mcp/ MCP server (
|
|
639
|
+
mcp/ MCP server (81 tools, 3 transports)
|
|
582
640
|
nodes/ SSH2 pool, transfer engine, PTY, tunnels
|
|
583
641
|
sync/ CyberSync + CyberBase (PostgreSQL, Obsidian, encryption)
|
|
584
642
|
protocol/ Mesh config, types, path parsing
|
package/assets/banner-dark.svg
CHANGED
|
@@ -60,20 +60,24 @@
|
|
|
60
60
|
<text x="450" y="130" font-family="'Segoe UI', system-ui, -apple-system, sans-serif" font-size="20" font-weight="400" fill="#8B949E" text-anchor="middle">The infrastructure layer for AI agent swarms</text>
|
|
61
61
|
|
|
62
62
|
<!-- Stats bar -->
|
|
63
|
-
<g font-family="'Segoe UI Mono', 'SF Mono', monospace" font-size="
|
|
64
|
-
<text x="
|
|
65
|
-
<text x="
|
|
66
|
-
<text x="
|
|
67
|
-
<text x="
|
|
68
|
-
<text x="
|
|
63
|
+
<g font-family="'Segoe UI Mono', 'SF Mono', monospace" font-size="12" fill="#59C2FF" opacity="0.7">
|
|
64
|
+
<text x="112" y="175" text-anchor="middle">81 MCP Tools</text>
|
|
65
|
+
<text x="250" y="175" text-anchor="middle">A2A Protocol</text>
|
|
66
|
+
<text x="375" y="175" text-anchor="middle">OmniMesh</text>
|
|
67
|
+
<text x="490" y="175" text-anchor="middle">nftables FW</text>
|
|
68
|
+
<text x="612" y="175" text-anchor="middle">CyberBase</text>
|
|
69
|
+
<text x="728" y="175" text-anchor="middle">~80ms</text>
|
|
70
|
+
<text x="815" y="175" text-anchor="middle">v3.1</text>
|
|
69
71
|
</g>
|
|
70
72
|
|
|
71
73
|
<!-- Separator dots between stats -->
|
|
72
74
|
<g fill="#59C2FF" opacity="0.3">
|
|
73
|
-
<circle cx="
|
|
74
|
-
<circle cx="
|
|
75
|
-
<circle cx="
|
|
76
|
-
<circle cx="
|
|
75
|
+
<circle cx="182" cy="172" r="1.5"/>
|
|
76
|
+
<circle cx="313" cy="172" r="1.5"/>
|
|
77
|
+
<circle cx="432" cy="172" r="1.5"/>
|
|
78
|
+
<circle cx="550" cy="172" r="1.5"/>
|
|
79
|
+
<circle cx="670" cy="172" r="1.5"/>
|
|
80
|
+
<circle cx="770" cy="172" r="1.5"/>
|
|
77
81
|
</g>
|
|
78
82
|
|
|
79
83
|
<!-- Bottom wave -->
|
package/assets/banner-light.svg
CHANGED
|
@@ -53,20 +53,24 @@
|
|
|
53
53
|
<text x="450" y="130" font-family="'Segoe UI', system-ui, -apple-system, sans-serif" font-size="20" font-weight="400" fill="#586069" text-anchor="middle">The infrastructure layer for AI agent swarms</text>
|
|
54
54
|
|
|
55
55
|
<!-- Stats bar -->
|
|
56
|
-
<g font-family="'Segoe UI Mono', 'SF Mono', monospace" font-size="
|
|
57
|
-
<text x="
|
|
58
|
-
<text x="
|
|
59
|
-
<text x="
|
|
60
|
-
<text x="
|
|
61
|
-
<text x="
|
|
56
|
+
<g font-family="'Segoe UI Mono', 'SF Mono', monospace" font-size="12" fill="#1A3A5C" opacity="0.6">
|
|
57
|
+
<text x="112" y="175" text-anchor="middle">81 MCP Tools</text>
|
|
58
|
+
<text x="250" y="175" text-anchor="middle">A2A Protocol</text>
|
|
59
|
+
<text x="375" y="175" text-anchor="middle">OmniMesh</text>
|
|
60
|
+
<text x="490" y="175" text-anchor="middle">nftables FW</text>
|
|
61
|
+
<text x="612" y="175" text-anchor="middle">CyberBase</text>
|
|
62
|
+
<text x="728" y="175" text-anchor="middle">~80ms</text>
|
|
63
|
+
<text x="815" y="175" text-anchor="middle">v3.1</text>
|
|
62
64
|
</g>
|
|
63
65
|
|
|
64
66
|
<!-- Separator dots between stats -->
|
|
65
67
|
<g fill="#1A3A5C" opacity="0.25">
|
|
66
|
-
<circle cx="
|
|
67
|
-
<circle cx="
|
|
68
|
-
<circle cx="
|
|
69
|
-
<circle cx="
|
|
68
|
+
<circle cx="182" cy="172" r="1.5"/>
|
|
69
|
+
<circle cx="313" cy="172" r="1.5"/>
|
|
70
|
+
<circle cx="432" cy="172" r="1.5"/>
|
|
71
|
+
<circle cx="550" cy="172" r="1.5"/>
|
|
72
|
+
<circle cx="670" cy="172" r="1.5"/>
|
|
73
|
+
<circle cx="770" cy="172" r="1.5"/>
|
|
70
74
|
</g>
|
|
71
75
|
|
|
72
76
|
<!-- Bottom wave -->
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type ServerResponse } from 'node:http';
|
|
2
|
+
import { WebSocket } from 'ws';
|
|
3
|
+
import { EventEmitter } from 'node:events';
|
|
4
|
+
export interface OmniWireEvent {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly type: OmniWireEventType;
|
|
7
|
+
readonly timestamp: number;
|
|
8
|
+
readonly source: string;
|
|
9
|
+
readonly data: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export type OmniWireEventType = 'exec.start' | 'exec.complete' | 'exec.error' | 'node.online' | 'node.offline' | 'node.health' | 'transfer.start' | 'transfer.complete' | 'transfer.error' | 'update.available' | 'update.applied' | 'mesh.peer-added' | 'mesh.peer-removed' | 'mesh.health' | 'sync.start' | 'sync.complete' | 'sync.conflict' | 'alert.fired' | 'alert.resolved' | 'firewall.blocked' | 'firewall.rule-changed' | 'vpn.connected' | 'vpn.disconnected' | 'store.set' | 'store.delete' | 'a2a.message' | 'a2a.task' | 'custom';
|
|
12
|
+
export interface WebhookConfig {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly url: string;
|
|
15
|
+
readonly events: readonly OmniWireEventType[] | '*';
|
|
16
|
+
readonly secret?: string;
|
|
17
|
+
readonly headers?: Record<string, string>;
|
|
18
|
+
readonly retries: number;
|
|
19
|
+
readonly timeoutMs: number;
|
|
20
|
+
readonly active: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare class OmniWireEventBus extends EventEmitter {
|
|
23
|
+
private sseClients;
|
|
24
|
+
private wsClients;
|
|
25
|
+
private webhooks;
|
|
26
|
+
private eventLog;
|
|
27
|
+
private maxLogSize;
|
|
28
|
+
private eventCounter;
|
|
29
|
+
/** Emit an event to all transports */
|
|
30
|
+
emit(type: string, ...args: unknown[]): boolean;
|
|
31
|
+
/** Publish an event to all connected clients (SSE, WS, webhooks) */
|
|
32
|
+
publish(type: OmniWireEventType, source: string, data?: Record<string, unknown>): OmniWireEvent;
|
|
33
|
+
addSSEClient(res: ServerResponse, filter?: readonly OmniWireEventType[]): void;
|
|
34
|
+
private broadcastSSE;
|
|
35
|
+
addWSClient(ws: WebSocket): void;
|
|
36
|
+
private broadcastWS;
|
|
37
|
+
addWebhook(config: WebhookConfig): void;
|
|
38
|
+
removeWebhook(id: string): boolean;
|
|
39
|
+
listWebhooks(): WebhookConfig[];
|
|
40
|
+
private broadcastWebhooks;
|
|
41
|
+
private sendWebhook;
|
|
42
|
+
getRecentEvents(count?: number, filter?: OmniWireEventType): readonly OmniWireEvent[];
|
|
43
|
+
getStats(): {
|
|
44
|
+
sseClients: number;
|
|
45
|
+
wsClients: number;
|
|
46
|
+
webhooks: number;
|
|
47
|
+
totalEvents: number;
|
|
48
|
+
logSize: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export declare const eventBus: OmniWireEventBus;
|
|
52
|
+
export declare function startEventServer(port: number): void;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// OmniWire Events — Webhook + WebSocket + SSE event bus
|
|
2
|
+
// Unified event system for real-time notifications across all transports
|
|
3
|
+
import { createServer as createHttpServer } from 'node:http';
|
|
4
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
5
|
+
import { EventEmitter } from 'node:events';
|
|
6
|
+
// --- Event Bus ---
|
|
7
|
+
class OmniWireEventBus extends EventEmitter {
|
|
8
|
+
sseClients = new Set();
|
|
9
|
+
wsClients = new Set();
|
|
10
|
+
webhooks = new Map();
|
|
11
|
+
eventLog = [];
|
|
12
|
+
maxLogSize = 1000;
|
|
13
|
+
eventCounter = 0;
|
|
14
|
+
/** Emit an event to all transports */
|
|
15
|
+
emit(type, ...args) {
|
|
16
|
+
return super.emit(type, ...args);
|
|
17
|
+
}
|
|
18
|
+
/** Publish an event to all connected clients (SSE, WS, webhooks) */
|
|
19
|
+
publish(type, source, data = {}) {
|
|
20
|
+
const event = {
|
|
21
|
+
id: `evt-${Date.now()}-${++this.eventCounter}`,
|
|
22
|
+
type,
|
|
23
|
+
timestamp: Date.now(),
|
|
24
|
+
source,
|
|
25
|
+
data,
|
|
26
|
+
};
|
|
27
|
+
// Store in log (ring buffer)
|
|
28
|
+
this.eventLog.push(event);
|
|
29
|
+
if (this.eventLog.length > this.maxLogSize) {
|
|
30
|
+
this.eventLog = this.eventLog.slice(-this.maxLogSize);
|
|
31
|
+
}
|
|
32
|
+
// Emit locally
|
|
33
|
+
super.emit(type, event);
|
|
34
|
+
super.emit('*', event);
|
|
35
|
+
// Send to SSE clients
|
|
36
|
+
this.broadcastSSE(event);
|
|
37
|
+
// Send to WebSocket clients
|
|
38
|
+
this.broadcastWS(event);
|
|
39
|
+
// Send to webhooks (fire-and-forget)
|
|
40
|
+
this.broadcastWebhooks(event);
|
|
41
|
+
return event;
|
|
42
|
+
}
|
|
43
|
+
// --- SSE ---
|
|
44
|
+
addSSEClient(res, filter) {
|
|
45
|
+
res.writeHead(200, {
|
|
46
|
+
'Content-Type': 'text/event-stream',
|
|
47
|
+
'Cache-Control': 'no-cache',
|
|
48
|
+
'Connection': 'keep-alive',
|
|
49
|
+
'Access-Control-Allow-Origin': '*',
|
|
50
|
+
});
|
|
51
|
+
// Send initial connection event
|
|
52
|
+
const init = {
|
|
53
|
+
id: `evt-${Date.now()}-init`,
|
|
54
|
+
type: 'custom',
|
|
55
|
+
timestamp: Date.now(),
|
|
56
|
+
source: 'system',
|
|
57
|
+
data: { message: 'connected', filter: filter ?? '*' },
|
|
58
|
+
};
|
|
59
|
+
res.write(`data: ${JSON.stringify(init)}\n\n`);
|
|
60
|
+
// Tag the response with filter for selective broadcasting
|
|
61
|
+
res.__omniwireFilter = filter;
|
|
62
|
+
this.sseClients.add(res);
|
|
63
|
+
res.on('close', () => this.sseClients.delete(res));
|
|
64
|
+
}
|
|
65
|
+
broadcastSSE(event) {
|
|
66
|
+
const payload = `id: ${event.id}\nevent: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`;
|
|
67
|
+
for (const client of this.sseClients) {
|
|
68
|
+
const filter = client.__omniwireFilter;
|
|
69
|
+
if (!filter || filter.includes(event.type)) {
|
|
70
|
+
try {
|
|
71
|
+
client.write(payload);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
this.sseClients.delete(client);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// --- WebSocket ---
|
|
80
|
+
addWSClient(ws) {
|
|
81
|
+
this.wsClients.add(ws);
|
|
82
|
+
ws.on('close', () => this.wsClients.delete(ws));
|
|
83
|
+
ws.on('error', () => this.wsClients.delete(ws));
|
|
84
|
+
// Handle incoming messages (subscriptions, commands)
|
|
85
|
+
ws.on('message', (data) => {
|
|
86
|
+
try {
|
|
87
|
+
const msg = JSON.parse(data.toString());
|
|
88
|
+
if (msg.type === 'subscribe') {
|
|
89
|
+
ws.__omniwireFilter = msg.events;
|
|
90
|
+
ws.send(JSON.stringify({ type: 'subscribed', events: msg.events }));
|
|
91
|
+
}
|
|
92
|
+
else if (msg.type === 'ping') {
|
|
93
|
+
ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
|
|
94
|
+
}
|
|
95
|
+
else if (msg.type === 'replay') {
|
|
96
|
+
// Replay recent events
|
|
97
|
+
const count = Math.min(msg.count ?? 50, this.eventLog.length);
|
|
98
|
+
const events = this.eventLog.slice(-count);
|
|
99
|
+
ws.send(JSON.stringify({ type: 'replay', events }));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch { /* ignore malformed messages */ }
|
|
103
|
+
});
|
|
104
|
+
// Send connected event
|
|
105
|
+
ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now(), logSize: this.eventLog.length }));
|
|
106
|
+
}
|
|
107
|
+
broadcastWS(event) {
|
|
108
|
+
const payload = JSON.stringify(event);
|
|
109
|
+
for (const ws of this.wsClients) {
|
|
110
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
111
|
+
this.wsClients.delete(ws);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const filter = ws.__omniwireFilter;
|
|
115
|
+
if (!filter || filter.includes(event.type)) {
|
|
116
|
+
try {
|
|
117
|
+
ws.send(payload);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
this.wsClients.delete(ws);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// --- Webhooks ---
|
|
126
|
+
addWebhook(config) {
|
|
127
|
+
this.webhooks.set(config.id, config);
|
|
128
|
+
}
|
|
129
|
+
removeWebhook(id) {
|
|
130
|
+
return this.webhooks.delete(id);
|
|
131
|
+
}
|
|
132
|
+
listWebhooks() {
|
|
133
|
+
return [...this.webhooks.values()];
|
|
134
|
+
}
|
|
135
|
+
async broadcastWebhooks(event) {
|
|
136
|
+
for (const webhook of this.webhooks.values()) {
|
|
137
|
+
if (!webhook.active)
|
|
138
|
+
continue;
|
|
139
|
+
if (webhook.events !== '*' && !webhook.events.includes(event.type))
|
|
140
|
+
continue;
|
|
141
|
+
// Fire-and-forget with retries
|
|
142
|
+
void this.sendWebhook(webhook, event);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async sendWebhook(webhook, event, attempt = 0) {
|
|
146
|
+
try {
|
|
147
|
+
const body = JSON.stringify(event);
|
|
148
|
+
const headers = {
|
|
149
|
+
'Content-Type': 'application/json',
|
|
150
|
+
'X-OmniWire-Event': event.type,
|
|
151
|
+
'X-OmniWire-Event-ID': event.id,
|
|
152
|
+
'X-OmniWire-Timestamp': String(event.timestamp),
|
|
153
|
+
...webhook.headers,
|
|
154
|
+
};
|
|
155
|
+
// HMAC signature if secret is configured
|
|
156
|
+
if (webhook.secret) {
|
|
157
|
+
const { createHmac } = await import('node:crypto');
|
|
158
|
+
const sig = createHmac('sha256', webhook.secret).update(body).digest('hex');
|
|
159
|
+
headers['X-OmniWire-Signature'] = `sha256=${sig}`;
|
|
160
|
+
}
|
|
161
|
+
const controller = new AbortController();
|
|
162
|
+
const timeout = setTimeout(() => controller.abort(), webhook.timeoutMs);
|
|
163
|
+
const response = await fetch(webhook.url, {
|
|
164
|
+
method: 'POST',
|
|
165
|
+
headers,
|
|
166
|
+
body,
|
|
167
|
+
signal: controller.signal,
|
|
168
|
+
});
|
|
169
|
+
clearTimeout(timeout);
|
|
170
|
+
if (!response.ok && attempt < webhook.retries) {
|
|
171
|
+
// Exponential backoff: 1s, 2s, 4s
|
|
172
|
+
await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, attempt)));
|
|
173
|
+
return this.sendWebhook(webhook, event, attempt + 1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
if (attempt < webhook.retries) {
|
|
178
|
+
await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, attempt)));
|
|
179
|
+
return this.sendWebhook(webhook, event, attempt + 1);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// --- Query ---
|
|
184
|
+
getRecentEvents(count = 50, filter) {
|
|
185
|
+
const events = filter ? this.eventLog.filter((e) => e.type === filter) : this.eventLog;
|
|
186
|
+
return events.slice(-count);
|
|
187
|
+
}
|
|
188
|
+
getStats() {
|
|
189
|
+
return {
|
|
190
|
+
sseClients: this.sseClients.size,
|
|
191
|
+
wsClients: this.wsClients.size,
|
|
192
|
+
webhooks: this.webhooks.size,
|
|
193
|
+
totalEvents: this.eventCounter,
|
|
194
|
+
logSize: this.eventLog.length,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Singleton event bus
|
|
199
|
+
export const eventBus = new OmniWireEventBus();
|
|
200
|
+
// --- HTTP + WebSocket Server ---
|
|
201
|
+
export function startEventServer(port) {
|
|
202
|
+
const httpServer = createHttpServer((req, res) => {
|
|
203
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
204
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
205
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
206
|
+
if (req.method === 'OPTIONS') {
|
|
207
|
+
res.writeHead(204);
|
|
208
|
+
res.end();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const url = new URL(req.url ?? '/', `http://localhost:${port}`);
|
|
212
|
+
// GET /events/stream — SSE stream
|
|
213
|
+
if (req.method === 'GET' && url.pathname === '/events/stream') {
|
|
214
|
+
const filterParam = url.searchParams.get('filter');
|
|
215
|
+
const filter = filterParam ? filterParam.split(',') : undefined;
|
|
216
|
+
eventBus.addSSEClient(res, filter);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// GET /events/recent — recent events
|
|
220
|
+
if (req.method === 'GET' && url.pathname === '/events/recent') {
|
|
221
|
+
const count = parseInt(url.searchParams.get('count') ?? '50');
|
|
222
|
+
const filter = url.searchParams.get('type');
|
|
223
|
+
const events = eventBus.getRecentEvents(count, filter || undefined);
|
|
224
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
225
|
+
res.end(JSON.stringify({ events }));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
// GET /events/stats — event bus stats
|
|
229
|
+
if (req.method === 'GET' && url.pathname === '/events/stats') {
|
|
230
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
231
|
+
res.end(JSON.stringify(eventBus.getStats()));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// POST /events/publish — publish custom event
|
|
235
|
+
if (req.method === 'POST' && url.pathname === '/events/publish') {
|
|
236
|
+
let body = '';
|
|
237
|
+
req.on('data', (chunk) => { body += chunk; });
|
|
238
|
+
req.on('end', () => {
|
|
239
|
+
try {
|
|
240
|
+
const { type, source, data } = JSON.parse(body);
|
|
241
|
+
const event = eventBus.publish(type ?? 'custom', source ?? 'api', data ?? {});
|
|
242
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
243
|
+
res.end(JSON.stringify(event));
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
247
|
+
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// GET /webhooks — list webhooks
|
|
253
|
+
if (req.method === 'GET' && url.pathname === '/webhooks') {
|
|
254
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
255
|
+
res.end(JSON.stringify({ webhooks: eventBus.listWebhooks() }));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// POST /webhooks — register webhook
|
|
259
|
+
if (req.method === 'POST' && url.pathname === '/webhooks') {
|
|
260
|
+
let body = '';
|
|
261
|
+
req.on('data', (chunk) => { body += chunk; });
|
|
262
|
+
req.on('end', () => {
|
|
263
|
+
try {
|
|
264
|
+
const config = JSON.parse(body);
|
|
265
|
+
if (!config.url) {
|
|
266
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
267
|
+
res.end(JSON.stringify({ error: 'url required' }));
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const webhook = {
|
|
271
|
+
id: config.id ?? `wh-${Date.now()}`,
|
|
272
|
+
url: config.url,
|
|
273
|
+
events: config.events ?? '*',
|
|
274
|
+
secret: config.secret,
|
|
275
|
+
headers: config.headers,
|
|
276
|
+
retries: config.retries ?? 3,
|
|
277
|
+
timeoutMs: config.timeoutMs ?? 5000,
|
|
278
|
+
active: config.active ?? true,
|
|
279
|
+
};
|
|
280
|
+
eventBus.addWebhook(webhook);
|
|
281
|
+
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
282
|
+
res.end(JSON.stringify(webhook));
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
286
|
+
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// DELETE /webhooks/:id — remove webhook
|
|
292
|
+
const whMatch = url.pathname.match(/^\/webhooks\/(.+)$/);
|
|
293
|
+
if (req.method === 'DELETE' && whMatch) {
|
|
294
|
+
const removed = eventBus.removeWebhook(whMatch[1]);
|
|
295
|
+
res.writeHead(removed ? 200 : 404, { 'Content-Type': 'application/json' });
|
|
296
|
+
res.end(JSON.stringify({ removed }));
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
300
|
+
res.end(JSON.stringify({ error: 'Not found. Endpoints: /events/stream, /events/recent, /events/stats, /events/publish, /webhooks' }));
|
|
301
|
+
});
|
|
302
|
+
// WebSocket upgrade
|
|
303
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
304
|
+
httpServer.on('upgrade', (req, socket, head) => {
|
|
305
|
+
const url = new URL(req.url ?? '/', `http://localhost:${port}`);
|
|
306
|
+
if (url.pathname === '/ws' || url.pathname === '/events/ws') {
|
|
307
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
308
|
+
eventBus.addWSClient(ws);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
socket.destroy();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
httpServer.listen(port, '0.0.0.0');
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/mcp/events.ts"],"names":[],"mappings":"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"}
|