@awarevue/agent-sdk 2.0.77 → 2.0.79

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.
@@ -13,6 +13,11 @@ export type Inbound<D extends Direction> = D extends 'server' ? FromAgent : From
13
13
  export type Outbound<D extends Direction> = D extends 'server' ? FromServer : FromAgent;
14
14
  export type InMsg<D extends Direction> = Message<Inbound<D>>;
15
15
  export type OutMsg<D extends Direction> = Message<Outbound<D>>;
16
+ export interface GetReplyOptions {
17
+ /** Timeout for awaiting replies to sent messages (default 10s) */
18
+ timeoutMs?: number;
19
+ onProgress?: (progress: Message<PayloadByKind['progress']>) => void;
20
+ }
16
21
  export interface AgentProtocolOptions {
17
22
  /** Timeout for awaiting replies to sent messages (default 10s) */
18
23
  replyTimeout?: number;
@@ -27,6 +32,6 @@ export declare class AgentProtocol<D extends Direction> {
27
32
  constructor(transport: DuplexTransport<Message<Inbound<D>>, Message<Outbound<D>>>, options: AgentProtocolOptions);
28
33
  getReply$: <K extends RequestKind>(payload: Extract<Outbound<D>, {
29
34
  kind: K;
30
- }>, timeoutMs?: number) => Observable<Message<PayloadByKind[ResponseKind<K>]>>;
35
+ }>, { timeoutMs, onProgress }?: GetReplyOptions) => Observable<Message<PayloadByKind[ResponseKind<K>]>>;
31
36
  send: (payload: Outbound<D>) => void;
32
37
  }
@@ -15,7 +15,7 @@ class AgentProtocol {
15
15
  version: constants_1.AGENT_PROTOCOL_VERSION,
16
16
  on: Date.now(),
17
17
  });
18
- this.getReply$ = (payload, timeoutMs) => {
18
+ this.getReply$ = (payload, { timeoutMs, onProgress } = {}) => {
19
19
  const responseKind = api_types_1.ReplyKindByRequestKind[payload.kind];
20
20
  const reply$ = (id) => this.transport.messages$.pipe(
21
21
  // pass through only messages with matching requestId (it could be response, error or progress update)
@@ -29,6 +29,12 @@ class AgentProtocol {
29
29
  }),
30
30
  // enforce timeout (progress updates will reset the timer, but if no messages arrive for `timeoutMs` duration, the request is considered failed)
31
31
  (0, rxjs_1.timeout)(timeoutMs || this.options.replyTimeout || 10000),
32
+ // if an onProgress callback was provided, tap into the stream to route progress updates to the callback
33
+ (0, rxjs_1.tap)((message) => {
34
+ if (message.kind === 'progress' && onProgress) {
35
+ onProgress(message);
36
+ }
37
+ }),
32
38
  // pass through only the final response message (filter out progress updates)
33
39
  (0, rxjs_1.filter)((message) => message.kind === responseKind),
34
40
  // we only expect one response message, so complete the stream after the response arrives
@@ -38,10 +38,14 @@ export declare class AgentServer<TPeer extends PeerId = string> {
38
38
  agentId: string;
39
39
  }>;
40
40
  private sub;
41
+ private readonly _peerSubs;
41
42
  private readonly _agentToPeer;
42
43
  private readonly _peerToAgent;
43
44
  constructor(hub: HubTransport<Message<FromAgent>, Message<FromServer>, TPeer>, options?: AgentServerOptions);
44
45
  init(): void;
46
+ private onPeerJoin;
47
+ private onPeerLeave;
48
+ private processMessage;
45
49
  startAgent({ agentId, ...rest }: StartAgentArgs): void;
46
50
  stopAgent(agentId: string, provider: string): void;
47
51
  finalize(): void;
@@ -12,6 +12,7 @@ class AgentServer {
12
12
  this.notifications$ = new rxjs_1.Subject();
13
13
  this.messages$ = new rxjs_1.Subject();
14
14
  this.sub = null;
15
+ this._peerSubs = new Map();
15
16
  this._agentToPeer = new Map();
16
17
  this._peerToAgent = new Map();
17
18
  }
@@ -19,91 +20,100 @@ class AgentServer {
19
20
  if (this.sub) {
20
21
  return;
21
22
  }
22
- const processMessages$ = this.hub.messages$.pipe(
23
- // validate
24
- (0, rxjs_1.map)(({ msg, peer }) => ({ msg, peer, isValid: (0, api_types_1.isMessageFromAgent)(msg) })), (0, rxjs_1.tap)(({ msg, peer, isValid }) => {
25
- var _a;
26
- const id = (_a = msg.id) !== null && _a !== void 0 ? _a : 'unknown';
27
- if (msg.version !== constants_1.AGENT_PROTOCOL_VERSION) {
28
- this.notifications$.next(`Agent ${msg.from} has incompatible protocol version: ${msg.version}`);
29
- const protocol = this.getPeerSender(peer);
30
- protocol === null || protocol === void 0 ? void 0 : protocol.send({
31
- kind: 'error-rs',
32
- requestId: id,
33
- error: `Incompatible protocol version. Expected ${constants_1.AGENT_PROTOCOL_VERSION} but got ${msg.version}`,
34
- });
35
- }
36
- else if (!isValid) {
37
- // log
38
- const issues = (0, api_types_1.getAgentMessageIssues)(msg).join(', ');
39
- this.notifications$.next(`Received invalid message from agent ${peer}: ${issues}`);
40
- const sender = this.getPeerSender(peer);
41
- sender === null || sender === void 0 ? void 0 : sender.send({
42
- kind: 'error-rs',
43
- requestId: id,
44
- error: issues,
45
- });
46
- return;
47
- }
48
- }),
49
- // dismiss invalid protocol messages
50
- (0, rxjs_1.filter)(({ msg, isValid }) => msg.version === constants_1.AGENT_PROTOCOL_VERSION && isValid),
51
- // forward valid messages to the messages$ stream
52
- (0, rxjs_1.tap)((m) => {
53
- var _a, _b, _c, _d, _e, _f;
54
- const agentId = m.msg.from;
55
- // if this is a registration message, establish the agentId ↔ peer mapping
56
- if (m.msg.kind === 'register') {
57
- this._agentToPeer.set(agentId, m.peer);
58
- this._peerToAgent.set(m.peer, agentId);
59
- this.messages$.next({ ...m, agentId });
60
- (_b = (_a = this.options).onRegister) === null || _b === void 0 ? void 0 : _b.call(_a, {
61
- ...m.msg,
62
- agentId,
63
- reject: (reason) => {
64
- const protocol = this.getPeerSender(m.peer);
65
- protocol === null || protocol === void 0 ? void 0 : protocol.send({
66
- kind: 'error-rs',
67
- requestId: m.msg.id,
68
- error: reason,
69
- });
70
- this._agentToPeer.delete(agentId);
71
- this._peerToAgent.delete(m.peer);
72
- },
73
- accept: () => {
74
- const protocol = this.getPeerSender(m.peer);
75
- protocol === null || protocol === void 0 ? void 0 : protocol.send({
76
- kind: 'register-rs',
77
- requestId: m.msg.id,
78
- });
79
- },
80
- });
23
+ this.sub = this.hub.peerEvents$.subscribe((event) => {
24
+ if (event.type === 'join') {
25
+ this.onPeerJoin(event.peer);
81
26
  }
82
27
  else {
83
- this.messages$.next({ ...m, agentId });
84
- if (m.msg.kind === 'start-rs') {
85
- (_d = (_c = this.options).onStarted) === null || _d === void 0 ? void 0 : _d.call(_c, { agentId });
86
- }
87
- else if (m.msg.kind === 'stop-rs') {
88
- (_f = (_e = this.options).onStopped) === null || _f === void 0 ? void 0 : _f.call(_e, { agentId });
89
- }
28
+ this.onPeerLeave(event.peer, event.reason);
90
29
  }
91
- }));
92
- const processConnections$ = this.hub.peerEvents$.pipe((0, rxjs_1.filter)((event) => event.type === 'leave'), (0, rxjs_1.tap)(({ peer, reason }) => {
93
- var _a, _b;
94
- const agentId = this._peerToAgent.get(peer);
95
- this.notifications$.next(`Peer ${peer}${agentId ? ` (agent: ${agentId})` : ''} left: ${reason !== null && reason !== void 0 ? reason : 'unknown reason'}`);
96
- // clean up maps
97
- if (agentId) {
98
- this._peerToAgent.delete(peer);
99
- this._agentToPeer.delete(agentId);
100
- (_b = (_a = this.options).onUnregistered) === null || _b === void 0 ? void 0 : _b.call(_a, {
101
- agentId,
102
- reason: reason,
103
- });
30
+ });
31
+ }
32
+ onPeerJoin(peer) {
33
+ const conn = this.hub.connection(peer);
34
+ if (!conn)
35
+ return;
36
+ const sub = conn.messages$.subscribe((msg) => {
37
+ this.processMessage(msg, peer);
38
+ });
39
+ this._peerSubs.set(peer, sub);
40
+ }
41
+ onPeerLeave(peer, reason) {
42
+ var _a, _b, _c;
43
+ // tear down message subscription
44
+ (_a = this._peerSubs.get(peer)) === null || _a === void 0 ? void 0 : _a.unsubscribe();
45
+ this._peerSubs.delete(peer);
46
+ const agentId = this._peerToAgent.get(peer);
47
+ this.notifications$.next(`Peer ${peer}${agentId ? ` (agent: ${agentId})` : ''} left: ${reason !== null && reason !== void 0 ? reason : 'unknown reason'}`);
48
+ if (agentId) {
49
+ this._peerToAgent.delete(peer);
50
+ this._agentToPeer.delete(agentId);
51
+ (_c = (_b = this.options).onUnregistered) === null || _c === void 0 ? void 0 : _c.call(_b, {
52
+ agentId,
53
+ reason: reason,
54
+ });
55
+ }
56
+ }
57
+ processMessage(msg, peer) {
58
+ var _a, _b, _c, _d, _e, _f, _g;
59
+ const id = (_a = msg.id) !== null && _a !== void 0 ? _a : 'unknown';
60
+ if (msg.version !== constants_1.AGENT_PROTOCOL_VERSION) {
61
+ this.notifications$.next(`Agent ${msg.from} has incompatible protocol version: ${msg.version}`);
62
+ const protocol = this.getPeerSender(peer);
63
+ protocol === null || protocol === void 0 ? void 0 : protocol.send({
64
+ kind: 'error-rs',
65
+ requestId: id,
66
+ error: `Incompatible protocol version. Expected ${constants_1.AGENT_PROTOCOL_VERSION} but got ${msg.version}`,
67
+ });
68
+ return;
69
+ }
70
+ if (!(0, api_types_1.isMessageFromAgent)(msg)) {
71
+ const issues = (0, api_types_1.getAgentMessageIssues)(msg).join(', ');
72
+ this.notifications$.next(`Received invalid message from agent ${peer}: ${issues}`);
73
+ const sender = this.getPeerSender(peer);
74
+ sender === null || sender === void 0 ? void 0 : sender.send({
75
+ kind: 'error-rs',
76
+ requestId: id,
77
+ error: issues,
78
+ });
79
+ return;
80
+ }
81
+ const agentId = msg.from;
82
+ if (msg.kind === 'register') {
83
+ this._agentToPeer.set(agentId, peer);
84
+ this._peerToAgent.set(peer, agentId);
85
+ this.messages$.next({ msg, peer, agentId });
86
+ (_c = (_b = this.options).onRegister) === null || _c === void 0 ? void 0 : _c.call(_b, {
87
+ ...msg,
88
+ agentId,
89
+ reject: (reason) => {
90
+ const protocol = this.getPeerSender(peer);
91
+ protocol === null || protocol === void 0 ? void 0 : protocol.send({
92
+ kind: 'error-rs',
93
+ requestId: msg.id,
94
+ error: reason,
95
+ });
96
+ this._agentToPeer.delete(agentId);
97
+ this._peerToAgent.delete(peer);
98
+ },
99
+ accept: () => {
100
+ const protocol = this.getPeerSender(peer);
101
+ protocol === null || protocol === void 0 ? void 0 : protocol.send({
102
+ kind: 'register-rs',
103
+ requestId: msg.id,
104
+ });
105
+ },
106
+ });
107
+ }
108
+ else {
109
+ this.messages$.next({ msg, peer, agentId });
110
+ if (msg.kind === 'start-rs') {
111
+ (_e = (_d = this.options).onStarted) === null || _e === void 0 ? void 0 : _e.call(_d, { agentId });
112
+ }
113
+ else if (msg.kind === 'stop-rs') {
114
+ (_g = (_f = this.options).onStopped) === null || _g === void 0 ? void 0 : _g.call(_f, { agentId });
104
115
  }
105
- }));
106
- this.sub = (0, rxjs_1.merge)(processMessages$, processConnections$).subscribe();
116
+ }
107
117
  }
108
118
  startAgent({ agentId, ...rest }) {
109
119
  const protocol = this.getAgentSender(agentId);
@@ -117,6 +127,10 @@ class AgentServer {
117
127
  var _a;
118
128
  (_a = this.sub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
119
129
  this.sub = null;
130
+ for (const sub of this._peerSubs.values()) {
131
+ sub.unsubscribe();
132
+ }
133
+ this._peerSubs.clear();
120
134
  this._agentToPeer.clear();
121
135
  this._peerToAgent.clear();
122
136
  }
package/dist/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/Linc-Security-Systems/aware-essentials.git"
6
6
  },
7
- "version": "2.0.77",
7
+ "version": "2.0.79",
8
8
  "description": "SDK for building Agent implementations that speak the agent protocol.",
9
9
  "author": "Yaser Awajan",
10
10
  "license": "MIT",
@@ -31,12 +31,12 @@
31
31
  "lint:fix": "yarn lint --fix"
32
32
  },
33
33
  "peerDependencies": {
34
- "@awarevue/api-types": "2.0.77",
34
+ "@awarevue/api-types": "2.0.79",
35
35
  "rxjs": "^7.8.2",
36
36
  "ws": "^8"
37
37
  },
38
38
  "devDependencies": {
39
- "@awarevue/api-types": "2.0.77",
39
+ "@awarevue/api-types": "2.0.79",
40
40
  "@types/node": "^20.12.7",
41
41
  "@types/ws": "^8.18.1",
42
42
  "@typescript-eslint/eslint-plugin": "^8.31.1",
@@ -29,11 +29,6 @@ export type PeerEvent<TPeer> = {
29
29
  export interface HubTransport<TIn, TOut, TPeer> {
30
30
  /** Peer join/leave stream */
31
31
  readonly peerEvents$: Observable<PeerEvent<TPeer>>;
32
- /** Incoming messages with peer attribution */
33
- readonly messages$: Observable<{
34
- msg: TIn;
35
- peer: TPeer;
36
- }>;
37
32
  /** Disconnect one peer */
38
33
  closePeer(peer: TPeer): void;
39
34
  /** Close hub transport */
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "git+https://github.com/Linc-Security-Systems/aware-essentials.git"
6
6
  },
7
- "version": "2.0.77",
7
+ "version": "2.0.79",
8
8
  "description": "SDK for building Agent implementations that speak the agent protocol.",
9
9
  "author": "Yaser Awajan",
10
10
  "license": "MIT",
@@ -31,12 +31,12 @@
31
31
  "lint:fix": "yarn lint --fix"
32
32
  },
33
33
  "peerDependencies": {
34
- "@awarevue/api-types": "2.0.77",
34
+ "@awarevue/api-types": "2.0.79",
35
35
  "rxjs": "^7.8.2",
36
36
  "ws": "^8"
37
37
  },
38
38
  "devDependencies": {
39
- "@awarevue/api-types": "2.0.77",
39
+ "@awarevue/api-types": "2.0.79",
40
40
  "@types/node": "^20.12.7",
41
41
  "@types/ws": "^8.18.1",
42
42
  "@typescript-eslint/eslint-plugin": "^8.31.1",