@godman-protocols/signal 0.2.0 → 0.3.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/dist/bus.d.ts DELETED
@@ -1,53 +0,0 @@
1
- /**
2
- * SIGNAL — Event Bus and Pub/Sub for Agent Swarms
3
- * In-memory EventBus implementation
4
- * @version 0.2.0
5
- */
6
- import type { AgentId, DeliveryReceipt, Event, Subscription, SubscriptionId, Timestamp } from './types.js';
7
- /**
8
- * Match a topic against a glob-style filter.
9
- * - `*` matches exactly one segment
10
- * - `**` matches zero or more segments
11
- * - Exact strings match literally
12
- */
13
- export declare function topicMatches(filter: string, topic: string): boolean;
14
- /**
15
- * Create a signed event.
16
- */
17
- export declare function createEvent(publisher: AgentId, topic: string, payload: unknown, secret: string, options?: {
18
- id?: string;
19
- idempotencyKey?: string;
20
- publishedAt?: Timestamp;
21
- }): Event;
22
- type EventHandler = (event: Event) => void | Promise<void>;
23
- export declare class EventBus {
24
- private subs;
25
- private seenIdempotencyKeys;
26
- private receipts;
27
- /**
28
- * Subscribe to events matching a topic filter.
29
- */
30
- subscribe(subscriberAgent: AgentId, topicFilter: string, handler: EventHandler, deliveryMode?: 'at-least-once' | 'at-most-once'): Subscription;
31
- /**
32
- * Unsubscribe. Marks the subscription as cancelled.
33
- */
34
- unsubscribe(subscriptionId: SubscriptionId): void;
35
- /**
36
- * Publish an event to all matching subscribers.
37
- * Deduplicates by idempotencyKey.
38
- * Returns delivery receipts.
39
- */
40
- publish(event: Event): Promise<DeliveryReceipt[]>;
41
- /**
42
- * Get all delivery receipts.
43
- */
44
- getReceipts(): ReadonlyArray<DeliveryReceipt>;
45
- /**
46
- * Get active subscription count.
47
- */
48
- get subscriptionCount(): number;
49
- }
50
- /** Default singleton bus for single-process use */
51
- export declare const defaultBus: EventBus;
52
- export {};
53
- //# sourceMappingURL=bus.d.ts.map
package/dist/bus.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../src/bus.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,KAAK,EACL,YAAY,EACZ,cAAc,EACd,SAAS,EACV,MAAM,YAAY,CAAC;AAMpB;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAInE;AAuBD;;GAEG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,OAAO,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,SAAS,CAAA;CAAO,GAC9E,KAAK,CAOP;AAMD,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAO3D,qBAAa,QAAQ;IACnB,OAAO,CAAC,IAAI,CAA0C;IACtD,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAyB;IAEzC;;OAEG;IACH,SAAS,CACP,eAAe,EAAE,OAAO,EACxB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,EACrB,YAAY,GAAE,eAAe,GAAG,cAAgC,GAC/D,YAAY;IAaf;;OAEG;IACH,WAAW,CAAC,cAAc,EAAE,cAAc,GAAG,IAAI;IAOjD;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAwCvD;;OAEG;IACH,WAAW,IAAI,aAAa,CAAC,eAAe,CAAC;IAI7C;;OAEG;IACH,IAAI,iBAAiB,IAAI,MAAM,CAE9B;CACF;AAED,mDAAmD;AACnD,eAAO,MAAM,UAAU,UAAiB,CAAC"}
package/dist/bus.js DELETED
@@ -1,141 +0,0 @@
1
- /**
2
- * SIGNAL — Event Bus and Pub/Sub for Agent Swarms
3
- * In-memory EventBus implementation
4
- * @version 0.2.0
5
- */
6
- import { createHmac, randomUUID } from 'node:crypto';
7
- // ---------------------------------------------------------------------------
8
- // Topic matching
9
- // ---------------------------------------------------------------------------
10
- /**
11
- * Match a topic against a glob-style filter.
12
- * - `*` matches exactly one segment
13
- * - `**` matches zero or more segments
14
- * - Exact strings match literally
15
- */
16
- export function topicMatches(filter, topic) {
17
- const filterParts = filter.split('.');
18
- const topicParts = topic.split('.');
19
- return matchParts(filterParts, 0, topicParts, 0);
20
- }
21
- function matchParts(f, fi, t, ti) {
22
- if (fi === f.length && ti === t.length)
23
- return true;
24
- if (fi === f.length)
25
- return false;
26
- if (f[fi] === '**') {
27
- // ** can match zero or more segments
28
- for (let i = ti; i <= t.length; i++) {
29
- if (matchParts(f, fi + 1, t, i))
30
- return true;
31
- }
32
- return false;
33
- }
34
- if (ti === t.length)
35
- return false;
36
- if (f[fi] === '*' || f[fi] === t[ti]) {
37
- return matchParts(f, fi + 1, t, ti + 1);
38
- }
39
- return false;
40
- }
41
- // ---------------------------------------------------------------------------
42
- // Event creation
43
- // ---------------------------------------------------------------------------
44
- /**
45
- * Create a signed event.
46
- */
47
- export function createEvent(publisher, topic, payload, secret, options = {}) {
48
- const id = options.id ?? randomUUID();
49
- const publishedAt = options.publishedAt ?? new Date().toISOString();
50
- const idempotencyKey = options.idempotencyKey ?? id;
51
- const sigPayload = `${id}:${topic}:${publisher}:${publishedAt}`;
52
- const signature = createHmac('sha256', secret).update(sigPayload, 'utf8').digest('hex');
53
- return { id, topic, publisher, publishedAt, idempotencyKey, payload, signature };
54
- }
55
- export class EventBus {
56
- subs = new Map();
57
- seenIdempotencyKeys = new Set();
58
- receipts = [];
59
- /**
60
- * Subscribe to events matching a topic filter.
61
- */
62
- subscribe(subscriberAgent, topicFilter, handler, deliveryMode = 'at-least-once') {
63
- const sub = {
64
- id: randomUUID(),
65
- subscriberAgent,
66
- topicFilter,
67
- deliveryMode,
68
- createdAt: new Date().toISOString(),
69
- cancelledAt: null,
70
- };
71
- this.subs.set(sub.id, { subscription: sub, handler });
72
- return sub;
73
- }
74
- /**
75
- * Unsubscribe. Marks the subscription as cancelled.
76
- */
77
- unsubscribe(subscriptionId) {
78
- const entry = this.subs.get(subscriptionId);
79
- if (!entry)
80
- throw new Error(`Subscription ${subscriptionId} not found`);
81
- entry.subscription.cancelledAt = new Date().toISOString();
82
- this.subs.delete(subscriptionId);
83
- }
84
- /**
85
- * Publish an event to all matching subscribers.
86
- * Deduplicates by idempotencyKey.
87
- * Returns delivery receipts.
88
- */
89
- async publish(event) {
90
- // Idempotency check
91
- if (this.seenIdempotencyKeys.has(event.idempotencyKey)) {
92
- const receipt = {
93
- eventId: event.id,
94
- subscriptionId: 'none',
95
- receivedAt: new Date().toISOString(),
96
- status: 'duplicate-skipped',
97
- };
98
- this.receipts.push(receipt);
99
- return [receipt];
100
- }
101
- this.seenIdempotencyKeys.add(event.idempotencyKey);
102
- const newReceipts = [];
103
- for (const [, entry] of this.subs) {
104
- if (entry.subscription.cancelledAt)
105
- continue;
106
- if (!topicMatches(entry.subscription.topicFilter, event.topic))
107
- continue;
108
- let status = 'processed';
109
- try {
110
- await entry.handler(event);
111
- }
112
- catch {
113
- status = 'failed';
114
- }
115
- const receipt = {
116
- eventId: event.id,
117
- subscriptionId: entry.subscription.id,
118
- receivedAt: new Date().toISOString(),
119
- status,
120
- };
121
- newReceipts.push(receipt);
122
- }
123
- this.receipts.push(...newReceipts);
124
- return newReceipts;
125
- }
126
- /**
127
- * Get all delivery receipts.
128
- */
129
- getReceipts() {
130
- return [...this.receipts];
131
- }
132
- /**
133
- * Get active subscription count.
134
- */
135
- get subscriptionCount() {
136
- return this.subs.size;
137
- }
138
- }
139
- /** Default singleton bus for single-process use */
140
- export const defaultBus = new EventBus();
141
- //# sourceMappingURL=bus.js.map
package/dist/bus.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"bus.js","sourceRoot":"","sources":["../src/bus.ts"],"names":[],"mappings":"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"}
package/src/bus.ts DELETED
@@ -1,180 +0,0 @@
1
- /**
2
- * SIGNAL — Event Bus and Pub/Sub for Agent Swarms
3
- * In-memory EventBus implementation
4
- * @version 0.2.0
5
- */
6
-
7
- import { createHmac, randomUUID } from 'node:crypto';
8
- import type {
9
- AgentId,
10
- DeliveryReceipt,
11
- Event,
12
- Subscription,
13
- SubscriptionId,
14
- Timestamp,
15
- } from './types.js';
16
-
17
- // ---------------------------------------------------------------------------
18
- // Topic matching
19
- // ---------------------------------------------------------------------------
20
-
21
- /**
22
- * Match a topic against a glob-style filter.
23
- * - `*` matches exactly one segment
24
- * - `**` matches zero or more segments
25
- * - Exact strings match literally
26
- */
27
- export function topicMatches(filter: string, topic: string): boolean {
28
- const filterParts = filter.split('.');
29
- const topicParts = topic.split('.');
30
- return matchParts(filterParts, 0, topicParts, 0);
31
- }
32
-
33
- function matchParts(f: string[], fi: number, t: string[], ti: number): boolean {
34
- if (fi === f.length && ti === t.length) return true;
35
- if (fi === f.length) return false;
36
- if (f[fi] === '**') {
37
- // ** can match zero or more segments
38
- for (let i = ti; i <= t.length; i++) {
39
- if (matchParts(f, fi + 1, t, i)) return true;
40
- }
41
- return false;
42
- }
43
- if (ti === t.length) return false;
44
- if (f[fi] === '*' || f[fi] === t[ti]) {
45
- return matchParts(f, fi + 1, t, ti + 1);
46
- }
47
- return false;
48
- }
49
-
50
- // ---------------------------------------------------------------------------
51
- // Event creation
52
- // ---------------------------------------------------------------------------
53
-
54
- /**
55
- * Create a signed event.
56
- */
57
- export function createEvent(
58
- publisher: AgentId,
59
- topic: string,
60
- payload: unknown,
61
- secret: string,
62
- options: { id?: string; idempotencyKey?: string; publishedAt?: Timestamp } = {}
63
- ): Event {
64
- const id = options.id ?? randomUUID();
65
- const publishedAt = options.publishedAt ?? new Date().toISOString();
66
- const idempotencyKey = options.idempotencyKey ?? id;
67
- const sigPayload = `${id}:${topic}:${publisher}:${publishedAt}`;
68
- const signature = createHmac('sha256', secret).update(sigPayload, 'utf8').digest('hex');
69
- return { id, topic, publisher, publishedAt, idempotencyKey, payload, signature };
70
- }
71
-
72
- // ---------------------------------------------------------------------------
73
- // EventBus
74
- // ---------------------------------------------------------------------------
75
-
76
- type EventHandler = (event: Event) => void | Promise<void>;
77
-
78
- interface InternalSub {
79
- subscription: Subscription;
80
- handler: EventHandler;
81
- }
82
-
83
- export class EventBus {
84
- private subs = new Map<SubscriptionId, InternalSub>();
85
- private seenIdempotencyKeys = new Set<string>();
86
- private receipts: DeliveryReceipt[] = [];
87
-
88
- /**
89
- * Subscribe to events matching a topic filter.
90
- */
91
- subscribe(
92
- subscriberAgent: AgentId,
93
- topicFilter: string,
94
- handler: EventHandler,
95
- deliveryMode: 'at-least-once' | 'at-most-once' = 'at-least-once'
96
- ): Subscription {
97
- const sub: Subscription = {
98
- id: randomUUID(),
99
- subscriberAgent,
100
- topicFilter,
101
- deliveryMode,
102
- createdAt: new Date().toISOString(),
103
- cancelledAt: null,
104
- };
105
- this.subs.set(sub.id, { subscription: sub, handler });
106
- return sub;
107
- }
108
-
109
- /**
110
- * Unsubscribe. Marks the subscription as cancelled.
111
- */
112
- unsubscribe(subscriptionId: SubscriptionId): void {
113
- const entry = this.subs.get(subscriptionId);
114
- if (!entry) throw new Error(`Subscription ${subscriptionId} not found`);
115
- entry.subscription.cancelledAt = new Date().toISOString();
116
- this.subs.delete(subscriptionId);
117
- }
118
-
119
- /**
120
- * Publish an event to all matching subscribers.
121
- * Deduplicates by idempotencyKey.
122
- * Returns delivery receipts.
123
- */
124
- async publish(event: Event): Promise<DeliveryReceipt[]> {
125
- // Idempotency check
126
- if (this.seenIdempotencyKeys.has(event.idempotencyKey)) {
127
- const receipt: DeliveryReceipt = {
128
- eventId: event.id,
129
- subscriptionId: 'none',
130
- receivedAt: new Date().toISOString(),
131
- status: 'duplicate-skipped',
132
- };
133
- this.receipts.push(receipt);
134
- return [receipt];
135
- }
136
- this.seenIdempotencyKeys.add(event.idempotencyKey);
137
-
138
- const newReceipts: DeliveryReceipt[] = [];
139
-
140
- for (const [, entry] of this.subs) {
141
- if (entry.subscription.cancelledAt) continue;
142
- if (!topicMatches(entry.subscription.topicFilter, event.topic)) continue;
143
-
144
- let status: DeliveryReceipt['status'] = 'processed';
145
- try {
146
- await entry.handler(event);
147
- } catch {
148
- status = 'failed';
149
- }
150
-
151
- const receipt: DeliveryReceipt = {
152
- eventId: event.id,
153
- subscriptionId: entry.subscription.id,
154
- receivedAt: new Date().toISOString(),
155
- status,
156
- };
157
- newReceipts.push(receipt);
158
- }
159
-
160
- this.receipts.push(...newReceipts);
161
- return newReceipts;
162
- }
163
-
164
- /**
165
- * Get all delivery receipts.
166
- */
167
- getReceipts(): ReadonlyArray<DeliveryReceipt> {
168
- return [...this.receipts];
169
- }
170
-
171
- /**
172
- * Get active subscription count.
173
- */
174
- get subscriptionCount(): number {
175
- return this.subs.size;
176
- }
177
- }
178
-
179
- /** Default singleton bus for single-process use */
180
- export const defaultBus = new EventBus();