@awarevue/agent-sdk 2.0.73 → 2.0.75

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.
@@ -0,0 +1,16 @@
1
+ import { FromAgent, FromServer, Message } from '@awarevue/api-types';
2
+ import { Agent } from './agent';
3
+ import { AgentApp, AgentOptions } from './agent-app';
4
+ import { DuplexTransport } from './transport_types';
5
+ export type AgentAppWithDefaultsOptions = Omit<AgentOptions, 'transport'> & {
6
+ url: string;
7
+ apiKey: string;
8
+ transport?: DuplexTransport<Message<FromServer>, Message<FromAgent>>;
9
+ };
10
+ /**
11
+ * Creates an AgentApp instance with default transport settings (WS transport wrapped in a logging decorator) if no custom transport is provided.
12
+ * @param agent The agent instance to use.
13
+ * @param options Configuration options for the AgentApp.
14
+ * @returns A configured AgentApp instance.
15
+ */
16
+ export declare function createAgentApp(agent: Agent, options: AgentAppWithDefaultsOptions): AgentApp;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAgentApp = createAgentApp;
4
+ const agent_app_1 = require("./agent-app");
5
+ const logging_1 = require("./transports/logging");
6
+ const ws_1 = require("./transports/ws");
7
+ /**
8
+ * Creates an AgentApp instance with default transport settings (WS transport wrapped in a logging decorator) if no custom transport is provided.
9
+ * @param agent The agent instance to use.
10
+ * @param options Configuration options for the AgentApp.
11
+ * @returns A configured AgentApp instance.
12
+ */
13
+ function createAgentApp(agent, options) {
14
+ const { url, apiKey, transport, ...rest } = options;
15
+ const finalTransport = transport !== null && transport !== void 0 ? transport : new logging_1.LoggingDuplexTransport(new ws_1.WsDuplexTransport({
16
+ url,
17
+ headers: {
18
+ Authorization: `APIKey ${apiKey}`,
19
+ },
20
+ }));
21
+ return new agent_app_1.AgentApp(agent, { ...rest, transport: finalTransport });
22
+ }
package/dist/agent-app.js CHANGED
@@ -11,7 +11,15 @@ class AgentApp {
11
11
  this.agent = agent;
12
12
  this.options = options;
13
13
  this.sub = null;
14
- this.handleResponse$ = (requestId) => (obs) => obs.pipe((0, rxjs_1.tap)({
14
+ this.handleResponse$ = (requestId, responseBuilder) => (obs) => obs.pipe((0, rxjs_1.mergeMap)((result) => result instanceof agent_error_1.AgentProgressMessage
15
+ ? (0, rxjs_1.of)({
16
+ kind: 'progress',
17
+ requestId,
18
+ message: result.message,
19
+ })
20
+ : responseBuilder
21
+ ? (0, rxjs_1.of)(responseBuilder(result))
22
+ : rxjs_1.EMPTY), (0, rxjs_1.tap)({
15
23
  error: (error) => console.error('Error processing request', requestId, (0, utils_1.stringifyError)(error)),
16
24
  }), (0, rxjs_1.catchError)((error) => (0, rxjs_1.of)({
17
25
  kind: 'error-rs',
@@ -63,25 +71,28 @@ class AgentApp {
63
71
  case 'command':
64
72
  return this.agent.runCommand$(context, message).pipe(
65
73
  // if command observable completes without emitting, throw not supported error
66
- (0, rxjs_1.throwIfEmpty)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support command ${message.command}`, 'NOT_SUPPORTED')),
67
- // success
68
- (0, rxjs_1.map)(() => ({
74
+ (0, rxjs_1.throwIfEmpty)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support command ${message.command}`, 'NOT_SUPPORTED')), this.handleResponse$(message.id, (result) => ({
69
75
  kind: 'command-rs',
70
76
  requestId: message.id,
71
- })), this.handleResponse$(message.id));
77
+ result,
78
+ })));
72
79
  case 'query':
73
80
  if (!this.agent.getResult$) {
74
- return (0, rxjs_1.throwError)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support queries`, 'NOT_SUPPORTED')).pipe(this.handleResponse$(message.id));
81
+ return (0, rxjs_1.throwError)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support queries`, 'NOT_SUPPORTED')).pipe(this.handleResponse$(message.id, (result) => ({
82
+ kind: 'query-rs',
83
+ requestId: message.id,
84
+ result,
85
+ })));
75
86
  }
76
87
  return this.agent.getResult$(context, message).pipe(
77
88
  // if query observable completes without emitting, throw not supported error
78
89
  (0, rxjs_1.throwIfEmpty)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support query ${message.query}`, 'NOT_SUPPORTED')),
79
90
  // success
80
- (0, rxjs_1.map)((result) => ({
91
+ this.handleResponse$(message.id, (result) => ({
81
92
  kind: 'query-rs',
82
93
  requestId: message.id,
83
94
  result,
84
- })), this.handleResponse$(message.id));
95
+ })));
85
96
  case 'push-file':
86
97
  if (!this.agent.pushFile) {
87
98
  return (0, rxjs_1.throwError)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support file pushing`, 'NOT_SUPPORTED'));
@@ -91,13 +102,11 @@ class AgentApp {
91
102
  (0, rxjs_1.mergeMap)(() => rxjs_1.EMPTY), this.handleResponse$(message.id));
92
103
  case 'get-available-devices':
93
104
  // get available devices
94
- return this.agent.getDevicesAndRelations$(context).pipe(
95
- // success
96
- (0, rxjs_1.map)((rs) => ({
105
+ return this.agent.getDevicesAndRelations$(context).pipe(this.handleResponse$(message.id, (result) => ({
106
+ ...result,
97
107
  kind: 'get-available-devices-rs',
98
- ...rs,
99
108
  requestId: message.id,
100
- })), this.handleResponse$(message.id));
109
+ })));
101
110
  case 'validate-change':
102
111
  let validateOb$ = (0, rxjs_1.throwError)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support access change validation`, 'NOT_SUPPORTED'));
103
112
  if (this.agent.validateAccessChange$) {
@@ -111,22 +120,22 @@ class AgentApp {
111
120
  : v$(validationContext, message);
112
121
  }));
113
122
  }
114
- return validateOb$.pipe((0, rxjs_1.map)((issues) => ({
123
+ return validateOb$.pipe(this.handleResponse$(message.id, (result) => ({
115
124
  kind: 'validate-change-rs',
116
125
  requestId: message.id,
117
- issues,
118
- })), this.handleResponse$(message.id));
126
+ issues: result,
127
+ })));
119
128
  case 'apply-change':
120
129
  // apply access change
121
130
  const applyContext = this.createAccessChangeContext(context, message.refMap, objectCache);
122
131
  const applyOb$ = !this.agent.applyAccessChange$
123
132
  ? (0, rxjs_1.throwError)(() => new agent_error_1.AgentError(`Agent ${context.provider} does not support access change apply`, 'NOT_SUPPORTED'))
124
133
  : this.agent.applyAccessChange$(applyContext, message);
125
- return applyOb$.pipe((0, rxjs_1.map)((result) => ({
134
+ return applyOb$.pipe(this.handleResponse$(message.id, (result) => ({
126
135
  kind: 'apply-change-rs',
127
136
  requestId: message.id,
128
137
  refs: result,
129
- })), this.handleResponse$(message.id));
138
+ })));
130
139
  default:
131
140
  return rxjs_1.EMPTY;
132
141
  }
@@ -170,13 +179,11 @@ class AgentApp {
170
179
  provider,
171
180
  config,
172
181
  })
173
- .pipe(
174
- // success
175
- (0, rxjs_1.map)((issues) => ({
182
+ .pipe(this.handleResponse$(message.id, (result) => ({
176
183
  kind: 'validate-config-rs',
177
184
  requestId: message.id,
178
- issues,
179
- })), this.handleResponse$(message.id));
185
+ issues: result,
186
+ })));
180
187
  }));
181
188
  return (0, rxjs_1.merge)(registration$, startStop$, validateConfig$);
182
189
  };
@@ -3,3 +3,7 @@ export declare class AgentError extends Error {
3
3
  readonly code: AgentErrorCode;
4
4
  constructor(message: string, code: AgentErrorCode);
5
5
  }
6
+ export declare class AgentProgressMessage {
7
+ readonly message: string;
8
+ constructor(message: string);
9
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AgentError = void 0;
3
+ exports.AgentProgressMessage = exports.AgentError = void 0;
4
4
  class AgentError extends Error {
5
5
  constructor(message, code) {
6
6
  super(message);
@@ -9,3 +9,9 @@ class AgentError extends Error {
9
9
  }
10
10
  }
11
11
  exports.AgentError = AgentError;
12
+ class AgentProgressMessage {
13
+ constructor(message) {
14
+ this.message = message;
15
+ }
16
+ }
17
+ exports.AgentProgressMessage = AgentProgressMessage;
@@ -27,6 +27,6 @@ export declare class AgentProtocol<D extends Direction> {
27
27
  constructor(transport: DuplexTransport<Message<Inbound<D>>, Message<Outbound<D>>>, options: AgentProtocolOptions);
28
28
  getReply$: <K extends RequestKind>(payload: Extract<Outbound<D>, {
29
29
  kind: K;
30
- }>) => Observable<Message<PayloadByKind[ResponseKind<K>]>>;
30
+ }>, timeoutMs?: number) => Observable<Message<PayloadByKind[ResponseKind<K>]>>;
31
31
  send: (payload: Outbound<D>) => void;
32
32
  }
@@ -15,17 +15,24 @@ class AgentProtocol {
15
15
  version: constants_1.AGENT_PROTOCOL_VERSION,
16
16
  on: Date.now(),
17
17
  });
18
- this.getReply$ = (payload) => {
18
+ this.getReply$ = (payload, timeoutMs) => {
19
19
  const responseKind = api_types_1.ReplyKindByRequestKind[payload.kind];
20
- const reply$ = (id) => this.transport.messages$.pipe((0, rxjs_1.mergeMap)((message) => {
21
- if (message.kind === 'error-rs' && message.requestId === id) {
20
+ const reply$ = (id) => this.transport.messages$.pipe(
21
+ // pass through only messages with matching requestId (it could be response, error or progress update)
22
+ (0, rxjs_1.filter)((message) => 'requestId' in message && message.requestId === id), (0, rxjs_1.mergeMap)((message) => {
23
+ // if the agent responded with an error message related to our request, throw an error to fail the stream
24
+ if (message.kind === 'error-rs') {
22
25
  const error = message.error;
23
26
  return (0, rxjs_1.throwError)(() => new Error(`Server failed to process message ${payload.kind}: ${error}`));
24
27
  }
25
28
  return (0, rxjs_1.of)(message);
26
- }), (0, rxjs_1.filter)((message) => message.kind === responseKind &&
27
- 'requestId' in message &&
28
- message.requestId === id), (0, rxjs_1.take)(1), (0, rxjs_1.timeout)(this.options.replyTimeout || 10000));
29
+ }),
30
+ // enforce timeout (progress updates will reset the timer, but if no messages arrive for `timeoutMs` duration, the request is considered failed)
31
+ (0, rxjs_1.timeout)(timeoutMs || this.options.replyTimeout || 10000),
32
+ // pass through only the final response message (filter out progress updates)
33
+ (0, rxjs_1.filter)((message) => message.kind === responseKind),
34
+ // we only expect one response message, so complete the stream after the response arrives
35
+ (0, rxjs_1.take)(1));
29
36
  return (0, rxjs_1.of)(this.addEnvelope({ ...payload, id: AgentProtocol.nextId() })).pipe(
30
37
  // send the message to the agent
31
38
  (0, rxjs_1.tap)((p) => this.transport.send(p)),
@@ -7,4 +7,4 @@ export declare const createValidator: <T extends Agent>(agent: T) => (context: C
7
7
  objectKind?: "person" | "zone" | "schedule" | "device" | "accessRule" | undefined;
8
8
  objectId?: string | undefined;
9
9
  index?: number | undefined;
10
- }[], Record<"accessRule" | "schedule" | "person" | "device" | "zone", Record<string, Record<string, unknown>>>]>;
10
+ }[], Record<"accessRule" | "schedule" | "person" | "zone" | "device", Record<string, Record<string, unknown>>>]>;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './agent-app';
2
+ export * from './agent-app-with-defaults';
2
3
  export * from './agent';
3
4
  export * from './constants';
4
5
  export * from './agent-protocol';
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./agent-app"), exports);
18
+ __exportStar(require("./agent-app-with-defaults"), exports);
18
19
  __exportStar(require("./agent"), exports);
19
20
  __exportStar(require("./constants"), exports);
20
21
  __exportStar(require("./agent-protocol"), exports);
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.73",
7
+ "version": "2.0.75",
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.73",
34
+ "@awarevue/api-types": "2.0.75",
35
35
  "rxjs": "^7.8.2",
36
36
  "ws": "^8"
37
37
  },
38
38
  "devDependencies": {
39
- "@awarevue/api-types": "2.0.73",
39
+ "@awarevue/api-types": "2.0.75",
40
40
  "@types/node": "^20.12.7",
41
41
  "@types/ws": "^8.18.1",
42
42
  "@typescript-eslint/eslint-plugin": "^8.31.1",
@@ -16,7 +16,7 @@ class LoggingDuplexTransport {
16
16
  this.inner = inner;
17
17
  this.label = (_a = opts.label) !== null && _a !== void 0 ? _a : 'transport';
18
18
  this.sink =
19
- (_b = opts.logger) !== null && _b !== void 0 ? _b : ((direction, label, msg) => console.log(`[${label}] ${direction}`, JSON.stringify(msg, null, 2)));
19
+ (_b = opts.logger) !== null && _b !== void 0 ? _b : ((direction, label, msg) => console.log(`[${label}] ${direction}`, JSON.stringify(msg)));
20
20
  this.connected$ = inner.connected$;
21
21
  // Tap into the incoming stream before exposing it to consumers.
22
22
  this.messages$ = inner.messages$.pipe((0, operators_1.tap)((msg) => this.sink('IN', this.label, msg)));
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.73",
7
+ "version": "2.0.75",
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.73",
34
+ "@awarevue/api-types": "2.0.75",
35
35
  "rxjs": "^7.8.2",
36
36
  "ws": "^8"
37
37
  },
38
38
  "devDependencies": {
39
- "@awarevue/api-types": "2.0.73",
39
+ "@awarevue/api-types": "2.0.75",
40
40
  "@types/node": "^20.12.7",
41
41
  "@types/ws": "^8.18.1",
42
42
  "@typescript-eslint/eslint-plugin": "^8.31.1",