@opentap/runner-client 2.7.1-alpha.1.2 → 2.7.1-alpha.1.3

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.
@@ -29,6 +29,7 @@ export declare class BaseClient {
29
29
  set timeout(value: number);
30
30
  constructor(baseSubject: string, options: ConnectionOptions);
31
31
  private withTimeout;
32
+ private flattenArrays;
32
33
  /**
33
34
  * Send a request to the nats server.
34
35
  * @param subject The subject to request
@@ -50,12 +51,15 @@ export declare class BaseClient {
50
51
  */
51
52
  private buildHeaders;
52
53
  /**
53
- * Subscribes to given subject.
54
+ * Subscribes to given subject with support for chunks. If a message is not chunked,
55
+ * it will be treated as a normal message and passed to the callback immediately.
54
56
  * @param subject The subject to subscribe
55
57
  * @param options Subscription options
58
+ * @param fromJS A method to convert the json payload to an object of type T
59
+ * @param callback Callback which receives the final payload
56
60
  * @returns Subscription object
57
61
  */
58
- protected subscribe(subject: string, options: SubscriptionOptions): Subscription;
62
+ protected subscribeChunked<T>(subject: string, options: SubscriptionOptions, fromJS: (obj: T) => T, callback: (result: T | undefined, error: Error | null) => void): Subscription;
59
63
  protected encode(payload: any): Uint8Array;
60
64
  /**
61
65
  * Check if the the response is an error from the server.
package/lib/BaseClient.js CHANGED
@@ -54,6 +54,33 @@ var Events;
54
54
  (function (Events) {
55
55
  Events["ERROR"] = "error_event";
56
56
  })(Events || (Events = {}));
57
+ var RequestInfo = /** @class */ (function () {
58
+ function RequestInfo(msg) {
59
+ this.chunked = false;
60
+ this.chunkSize = 0;
61
+ this.chunkNumber = 0;
62
+ this.requestId = '';
63
+ // We assume the message is chunked if it contains the following three headers:
64
+ var chunkSize = this.getHeader(msg, 'ChunkSize');
65
+ var chunkNumber = this.getHeader(msg, 'ChunkNumber');
66
+ var requestId = this.getHeader(msg, 'RequestId');
67
+ if (chunkSize && chunkNumber && requestId) {
68
+ this.chunked = true;
69
+ this.chunkSize = parseInt(chunkSize, 10);
70
+ this.chunkNumber = parseInt(chunkNumber, 10);
71
+ this.requestId = requestId;
72
+ }
73
+ }
74
+ RequestInfo.prototype.getHeader = function (msg, name) {
75
+ var _a, _b;
76
+ var values = (_b = (_a = msg.headers) === null || _a === void 0 ? void 0 : _a.values(name)) !== null && _b !== void 0 ? _b : [];
77
+ if (values.length > 0) {
78
+ return values[0];
79
+ }
80
+ return null;
81
+ };
82
+ return RequestInfo;
83
+ }());
57
84
  var BaseClient = /** @class */ (function () {
58
85
  function BaseClient(baseSubject, options) {
59
86
  this.domainAccess = new Map();
@@ -102,6 +129,17 @@ var BaseClient = /** @class */ (function () {
102
129
  BaseClient.prototype.withTimeout = function (promise, timeout) {
103
130
  return Promise.race([promise, new Promise(function (_, reject) { return setTimeout(function () { return reject(new Error(ErrorCode.Timeout)); }, timeout); })]);
104
131
  };
132
+ BaseClient.prototype.flattenArrays = function (dataArrays) {
133
+ var flattenedSize = dataArrays.reduce(function (sum, array) { return sum + array.length; }, 0);
134
+ var flattenedArray = new Uint8Array(flattenedSize);
135
+ var k = 0;
136
+ dataArrays.map(function (m) {
137
+ for (var i = 0; i < m.length; i++) {
138
+ flattenedArray[k++] = m[i];
139
+ }
140
+ });
141
+ return flattenedArray;
142
+ };
105
143
  /**
106
144
  * Send a request to the nats server.
107
145
  * @param subject The subject to request
@@ -170,22 +208,10 @@ var BaseClient = /** @class */ (function () {
170
208
  return reject(Error('Response is not a valid chunk.'));
171
209
  }
172
210
  if (parseInt(finalMessageNumber) !== messages.length) {
173
- return reject(Error("Expected {finalMessageNumber} chunks, but received ".concat(messages.length, ". ") +
211
+ return reject(Error("Expected ".concat(finalMessageNumber, " chunks, but received ").concat(messages.length, ". ") +
174
212
  "The connection may have been interrupted."));
175
213
  }
176
- // Concatenate the payloads
177
- // When there are many chunks, doing a single allocation
178
- // is significantly faster than concatenating arrays in sequence
179
- var dataArrays = messages.map(function (m) { return m.data; });
180
- var flattenedSize = dataArrays.reduce(function (sum, array) { return sum + array.length; }, 0);
181
- var flattenedArray = new Uint8Array(flattenedSize);
182
- var k = 0;
183
- dataArrays.map(function (m) {
184
- for (var i = 0; i < m.length; i++) {
185
- flattenedArray[k++] = m[i];
186
- }
187
- });
188
- return resolve(flattenedArray);
214
+ return resolve(_this.flattenArrays(messages.map(function (m) { return m.data; })));
189
215
  };
190
216
  })
191
217
  .then(function (byteArray) {
@@ -256,12 +282,15 @@ var BaseClient = /** @class */ (function () {
256
282
  return _headers;
257
283
  };
258
284
  /**
259
- * Subscribes to given subject.
285
+ * Subscribes to given subject with support for chunks. If a message is not chunked,
286
+ * it will be treated as a normal message and passed to the callback immediately.
260
287
  * @param subject The subject to subscribe
261
288
  * @param options Subscription options
289
+ * @param fromJS A method to convert the json payload to an object of type T
290
+ * @param callback Callback which receives the final payload
262
291
  * @returns Subscription object
263
292
  */
264
- BaseClient.prototype.subscribe = function (subject, options) {
293
+ BaseClient.prototype.subscribeChunked = function (subject, options, fromJS, callback) {
265
294
  if (!subject)
266
295
  throw Error('Subject is not defined!');
267
296
  if (!this.connection)
@@ -269,7 +298,97 @@ var BaseClient = /** @class */ (function () {
269
298
  if (this.connection.isClosed())
270
299
  throw Error('Connection has been closed! Please reconnect!');
271
300
  var natsSubject = "".concat(this.baseSubject, ".").concat(subject);
272
- return this.connection.subscribe(natsSubject, options);
301
+ function respond(bytes, err) {
302
+ if (err) {
303
+ callback(undefined, err);
304
+ return;
305
+ }
306
+ try {
307
+ var jsonCodec = JSONCodec();
308
+ var jsObject = jsonCodec.decode(bytes);
309
+ var result = fromJS(jsObject);
310
+ callback(result, null);
311
+ }
312
+ catch (error) {
313
+ callback(undefined, error);
314
+ }
315
+ }
316
+ // Make a reference to this method to use inside RequestHandler
317
+ var flattenArrays = this.flattenArrays;
318
+ // This class represents a single request, which may be comprised of several chunks.
319
+ // We declare it inside this closure because it needs to access a few closure
320
+ var RequestHandler = /** @class */ (function () {
321
+ function RequestHandler() {
322
+ this.messages = [];
323
+ this.lastUpdate = Date.now();
324
+ }
325
+ // We consider a message expired if there has been no activity for 60 seconds.
326
+ // Since chunked messages can potentially be quite large, we need to ensure
327
+ // that they can be garbage collected.
328
+ // Note that a message is explicitly cleaned up if it is completed. This only applies
329
+ // if the message was interrupted.
330
+ RequestHandler.prototype.expired = function () {
331
+ var now = Date.now();
332
+ if (now - this.lastUpdate > 60000) {
333
+ return true;
334
+ }
335
+ return false;
336
+ };
337
+ // Handle a message. Return true if the message was terminated, otherwise return false.
338
+ RequestHandler.prototype.handleMessage = function (msg, requestInfo, error) {
339
+ // If there was a nats error, terminate immediately.
340
+ if (error) {
341
+ respond(new Uint8Array(), error);
342
+ return true;
343
+ }
344
+ // If the message is not chunked, it is finished after a single message.
345
+ if (requestInfo.chunked === false) {
346
+ respond(msg.data, null);
347
+ return true;
348
+ }
349
+ // Otherwise, the message is finished if we have determined this to be the last chunk.
350
+ // This is the case if the chunk is smaller than the max chunk size.
351
+ this.lastUpdate = Date.now();
352
+ this.messages.push(msg);
353
+ if (msg.data.length === 0 || msg.data.length < requestInfo.chunkSize) {
354
+ if (requestInfo.chunkNumber != this.messages.length) {
355
+ respond(new Uint8Array(), Error("Expected ".concat(requestInfo.chunkNumber, " chunks, but received ").concat(this.messages.length, ". ") +
356
+ "The connection may have been interrupted."));
357
+ }
358
+ respond(flattenArrays(this.messages.map(function (m) { return m.data; })), null);
359
+ return true;
360
+ }
361
+ return false;
362
+ };
363
+ return RequestHandler;
364
+ }());
365
+ var requestHandlers = new Map();
366
+ options = __assign(__assign({}, options), { callback: function (error, msg) {
367
+ var requestInfo = new RequestInfo(msg);
368
+ var requestHandler = new RequestHandler();
369
+ if (requestHandlers.has(requestInfo.requestId)) {
370
+ requestHandler = requestHandlers.get(requestInfo.requestId);
371
+ }
372
+ else {
373
+ requestHandlers.set(requestInfo.requestId, requestHandler);
374
+ }
375
+ var done = requestHandler.handleMessage(msg, requestInfo, error);
376
+ // The message was terminated, so we can remove the handler from the lut
377
+ if (done)
378
+ requestHandlers.delete(requestInfo.requestId);
379
+ // If a client doesn't send the terminating chunk,
380
+ // this object can't be garbage collected.
381
+ // This is especially an issue because this object
382
+ // holds onto chunks, and can therefore become quite leaky.
383
+ // We should check if a request handler can be collected periodically.
384
+ requestHandlers.forEach(function (value, key) {
385
+ if (value.expired()) {
386
+ requestHandlers.delete(key);
387
+ }
388
+ });
389
+ } });
390
+ var subscription = this.connection.subscribe(natsSubject, options);
391
+ return subscription;
273
392
  };
274
393
  BaseClient.prototype.encode = function (payload) {
275
394
  if (!payload) {
@@ -13,19 +13,7 @@ var __extends = (this && this.__extends) || (function () {
13
13
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
14
14
  };
15
15
  })();
16
- var __assign = (this && this.__assign) || function () {
17
- __assign = Object.assign || function(t) {
18
- for (var s, i = 1, n = arguments.length; i < n; i++) {
19
- s = arguments[i];
20
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
21
- t[p] = s[p];
22
- }
23
- return t;
24
- };
25
- return __assign.apply(this, arguments);
26
- };
27
16
  import { BreakPoints, CommonContext, CommonSettings, DataGridControl, Image, Interaction, ListItemType, LogList, Result, RunStatus, SessionEvent, Setting, TestPlan, TestRun, TestStepType, TestStepValidationError, WatchDog, } from './DTOs';
28
- import { JSONCodec } from 'nats.ws';
29
17
  import { BaseClient } from './BaseClient';
30
18
  var SessionClient = /** @class */ (function (_super) {
31
19
  __extends(SessionClient, _super);
@@ -40,21 +28,7 @@ var SessionClient = /** @class */ (function (_super) {
40
28
  * @returns Subscription object
41
29
  */
42
30
  SessionClient.prototype.connectSessionLogs = function (sessionLogsHandler, options) {
43
- return this.subscribe('SessionLogs', __assign(__assign({}, options), { callback: function (error, encodedMessage) {
44
- if (error) {
45
- sessionLogsHandler(undefined, error);
46
- return;
47
- }
48
- try {
49
- var jsonCodec = JSONCodec();
50
- var logListJson = jsonCodec.decode(encodedMessage === null || encodedMessage === void 0 ? void 0 : encodedMessage.data);
51
- var logList = LogList.fromJS(logListJson);
52
- sessionLogsHandler(logList, error);
53
- }
54
- catch (error) {
55
- sessionLogsHandler(undefined, error);
56
- }
57
- } }));
31
+ return this.subscribeChunked('SessionLogs', options || {}, LogList.fromJS, sessionLogsHandler);
58
32
  };
59
33
  /**
60
34
  * @param eventHandler Function to be called when session event or error is received
@@ -62,23 +36,8 @@ var SessionClient = /** @class */ (function (_super) {
62
36
  * @returns Subscription object
63
37
  */
64
38
  SessionClient.prototype.connectSessionEvents = function (eventHandler, options) {
65
- var callback = function (error, encodedMessage) {
66
- if (error) {
67
- eventHandler(undefined, error);
68
- return;
69
- }
70
- try {
71
- var jsonCodec = JSONCodec();
72
- var sessionEventJs = jsonCodec.decode(encodedMessage === null || encodedMessage === void 0 ? void 0 : encodedMessage.data);
73
- var sessionEvent = SessionEvent.fromJS(sessionEventJs);
74
- eventHandler(sessionEvent, error);
75
- }
76
- catch (error) {
77
- eventHandler(undefined, error);
78
- }
79
- };
80
- this.subscriptions.push(this.subscribe('Events', __assign(__assign({}, options), { callback: callback })));
81
- this.subscriptions.push(this.subscribe('Events.*', __assign(__assign({}, options), { callback: callback })));
39
+ this.subscriptions.push(this.subscribeChunked('Events', options || {}, SessionEvent.fromJS, eventHandler));
40
+ this.subscriptions.push(this.subscribeChunked('Events.*', options || {}, SessionEvent.fromJS, eventHandler));
82
41
  };
83
42
  /**
84
43
  * @param resultHandler Function to be called when result or error is received
@@ -88,36 +47,8 @@ var SessionClient = /** @class */ (function (_super) {
88
47
  */
89
48
  SessionClient.prototype.connectSessionResults = function (resultHandler, testRunHandler, options) {
90
49
  return [
91
- this.subscribe('OnResult', __assign(__assign({}, options), { callback: function (error, encodedMessage) {
92
- if (error) {
93
- resultHandler(undefined, error);
94
- return;
95
- }
96
- try {
97
- var jsonCodec = JSONCodec();
98
- var resultJs = jsonCodec.decode(encodedMessage === null || encodedMessage === void 0 ? void 0 : encodedMessage.data);
99
- var result = Result.fromJS(resultJs);
100
- resultHandler(result, error);
101
- }
102
- catch (error) {
103
- resultHandler(undefined, error);
104
- }
105
- } })),
106
- this.subscribe('OnTestRun', __assign(__assign({}, options), { callback: function (error, encodedMessage) {
107
- if (error) {
108
- testRunHandler(undefined, error);
109
- return;
110
- }
111
- try {
112
- var jsonCodec = JSONCodec();
113
- var testRunJs = jsonCodec.decode(encodedMessage === null || encodedMessage === void 0 ? void 0 : encodedMessage.data);
114
- var testRun = TestRun.fromJS(testRunJs);
115
- testRunHandler(testRun, error);
116
- }
117
- catch (error) {
118
- testRunHandler(undefined, error);
119
- }
120
- } })),
50
+ this.subscribeChunked('OnResult', options || {}, Result.fromJS, resultHandler),
51
+ this.subscribeChunked('OnTestRun', options || {}, TestRun.fromJS, testRunHandler),
121
52
  ];
122
53
  };
123
54
  /**
@@ -8,6 +8,7 @@ export interface RunnerLifetimeEvent {
8
8
  }
9
9
  export declare class SystemClient extends BaseClient {
10
10
  constructor(baseSubject: string, options: ConnectionOptions);
11
+ private callbackConverter;
11
12
  /**
12
13
  * Subscribe to the lifetime event.
13
14
  * @param listener
@@ -13,25 +13,29 @@ var __extends = (this && this.__extends) || (function () {
13
13
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
14
14
  };
15
15
  })();
16
- var __assign = (this && this.__assign) || function () {
17
- __assign = Object.assign || function(t) {
18
- for (var s, i = 1, n = arguments.length; i < n; i++) {
19
- s = arguments[i];
20
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
21
- t[p] = s[p];
22
- }
23
- return t;
24
- };
25
- return __assign.apply(this, arguments);
26
- };
27
16
  import { BaseClient } from './BaseClient';
28
- import { JSONCodec } from 'nats.ws';
17
+ import { NatsError } from 'nats.ws';
29
18
  import { TestPlanRunCompletedEventArgs, TestPlanRunStartEventArgs, TestStepRunCompletedEventArgs, TestStepRunStartEventArgs, } from './DTOs';
30
19
  var SystemClient = /** @class */ (function (_super) {
31
20
  __extends(SystemClient, _super);
32
21
  function SystemClient(baseSubject, options) {
33
22
  return _super.call(this, baseSubject, options) || this;
34
23
  }
24
+ // The callbacks in this file are structured differently from the callbacks in BaseClient.
25
+ // This converter performs the appropriate error conversions and arguments flips
26
+ // so we can use these callbacks as input to subscribeChunked.
27
+ SystemClient.prototype.callbackConverter = function (subject, cb) {
28
+ var _this = this;
29
+ return function (result, error) {
30
+ if (error instanceof NatsError) {
31
+ var err = _this.natsErrorHandler(error, subject);
32
+ cb(err, null);
33
+ }
34
+ else {
35
+ cb(null, result || null);
36
+ }
37
+ };
38
+ };
35
39
  /**
36
40
  * Subscribe to the lifetime event.
37
41
  * @param listener
@@ -39,22 +43,9 @@ var SystemClient = /** @class */ (function (_super) {
39
43
  * @returns {Subscription}
40
44
  */
41
45
  SystemClient.prototype.subscribeLifetimeEventListener = function (listener, options) {
42
- var _this = this;
43
46
  var subject = '*.Events.Lifetime';
44
- return this.subscribe(subject, __assign(__assign({}, options), { callback: function (error, message) {
45
- if (error) {
46
- listener(_this.natsErrorHandler(error, subject), null);
47
- return;
48
- }
49
- try {
50
- var jsonCodec = JSONCodec();
51
- var data = jsonCodec.decode(message === null || message === void 0 ? void 0 : message.data);
52
- listener(null, data);
53
- }
54
- catch (error) {
55
- listener(_this.natsErrorHandler(error, subject), null);
56
- }
57
- } }));
47
+ var callback = this.callbackConverter(subject, listener);
48
+ return this.subscribeChunked(subject, options || {}, function (t) { return t; }, callback);
58
49
  };
59
50
  /**
60
51
  * Subscribe to the test step run start events for the given Runner and Run ID.
@@ -65,23 +56,9 @@ var SystemClient = /** @class */ (function (_super) {
65
56
  * @param {SubscriptionOptions} options?
66
57
  */
67
58
  SystemClient.prototype.subscribeTestStepRunStartEventListener = function (runnerId, runId, listener, options) {
68
- var _this = this;
69
59
  var subject = "".concat(runnerId, ".Runs.").concat(runId, ".Events.TestStepRunStart");
70
- return this.subscribe(subject, __assign(__assign({}, options), { callback: function (error, message) {
71
- if (error) {
72
- listener(_this.natsErrorHandler(error, subject), null);
73
- return;
74
- }
75
- try {
76
- var jsonCodec = JSONCodec();
77
- var testStepRunStartEventArgsJs = jsonCodec.decode(message === null || message === void 0 ? void 0 : message.data);
78
- var testStepRunStartEventArgs = TestStepRunStartEventArgs.fromJS(testStepRunStartEventArgsJs);
79
- listener(null, testStepRunStartEventArgs);
80
- }
81
- catch (error) {
82
- listener(_this.natsErrorHandler(error, subject), null);
83
- }
84
- } }));
60
+ var callback = this.callbackConverter(subject, listener);
61
+ return this.subscribeChunked(subject, options || {}, TestStepRunStartEventArgs.fromJS, callback);
85
62
  };
86
63
  /**
87
64
  * Subscribe to the test step run completed events for the given Runner and Run ID.
@@ -92,23 +69,9 @@ var SystemClient = /** @class */ (function (_super) {
92
69
  * @param {SubscriptionOptions} options?
93
70
  */
94
71
  SystemClient.prototype.subscribeTestStepRunCompletedEventListener = function (runnerId, runId, listener, options) {
95
- var _this = this;
96
72
  var subject = "".concat(runnerId, ".Runs.").concat(runId, ".Events.TestStepRunCompleted");
97
- return this.subscribe(subject, __assign(__assign({}, options), { callback: function (error, message) {
98
- if (error) {
99
- listener(_this.natsErrorHandler(error, subject), null);
100
- return;
101
- }
102
- try {
103
- var jsonCodec = JSONCodec();
104
- var testStepRunCompletedEventArgsJs = jsonCodec.decode(message === null || message === void 0 ? void 0 : message.data);
105
- var testStepRunCompletedEventArgs = TestStepRunCompletedEventArgs.fromJS(testStepRunCompletedEventArgsJs);
106
- listener(null, testStepRunCompletedEventArgs);
107
- }
108
- catch (error) {
109
- listener(_this.natsErrorHandler(error, subject), null);
110
- }
111
- } }));
73
+ var callback = this.callbackConverter(subject, listener);
74
+ return this.subscribeChunked(subject, options || {}, TestStepRunCompletedEventArgs.fromJS, callback);
112
75
  };
113
76
  /**
114
77
  * Subscribe to the test plan run start events for the given Runner and Run ID.
@@ -119,23 +82,9 @@ var SystemClient = /** @class */ (function (_super) {
119
82
  * @param {SubscriptionOptions} options?
120
83
  */
121
84
  SystemClient.prototype.subscribeTestPlanRunStartEventListener = function (runnerId, runId, listener, options) {
122
- var _this = this;
123
85
  var subject = "".concat(runnerId, ".Runs.").concat(runId, ".Events.TestPlanRunStart");
124
- return this.subscribe(subject, __assign(__assign({}, options), { callback: function (error, message) {
125
- if (error) {
126
- listener(_this.natsErrorHandler(error, subject), null);
127
- return;
128
- }
129
- try {
130
- var jsonCodec = JSONCodec();
131
- var testPlanRunStartEventArgsJs = jsonCodec.decode(message === null || message === void 0 ? void 0 : message.data);
132
- var testPlanRunStartEventArgs = TestPlanRunStartEventArgs.fromJS(testPlanRunStartEventArgsJs);
133
- listener(null, testPlanRunStartEventArgs);
134
- }
135
- catch (error) {
136
- listener(_this.natsErrorHandler(error, subject), null);
137
- }
138
- } }));
86
+ var callback = this.callbackConverter(subject, listener);
87
+ return this.subscribeChunked(subject, options || {}, TestPlanRunStartEventArgs.fromJS, callback);
139
88
  };
140
89
  /**
141
90
  * Subscribe to the test plan run completed events for the given Runner and Run ID.
@@ -146,23 +95,9 @@ var SystemClient = /** @class */ (function (_super) {
146
95
  * @param {SubscriptionOptions} options?
147
96
  */
148
97
  SystemClient.prototype.subscribeTestPlanRunCompletedEventListener = function (runnerId, runId, listener, options) {
149
- var _this = this;
150
98
  var subject = "".concat(runnerId, ".Runs.").concat(runId, ".Events.TestPlanRunCompleted");
151
- return this.subscribe(subject, __assign(__assign({}, options), { callback: function (error, message) {
152
- if (error) {
153
- listener(_this.natsErrorHandler(error, subject), null);
154
- return;
155
- }
156
- try {
157
- var jsonCodec = JSONCodec();
158
- var testPlanRunCompletedEventArgsJs = jsonCodec.decode(message === null || message === void 0 ? void 0 : message.data);
159
- var testPlanRunCompletedEventArgs = TestPlanRunCompletedEventArgs.fromJS(testPlanRunCompletedEventArgsJs);
160
- listener(null, testPlanRunCompletedEventArgs);
161
- }
162
- catch (error) {
163
- listener(_this.natsErrorHandler(error, subject), null);
164
- }
165
- } }));
99
+ var callback = this.callbackConverter(subject, listener);
100
+ return this.subscribeChunked(subject, options || {}, TestPlanRunCompletedEventArgs.fromJS, callback);
166
101
  };
167
102
  return SystemClient;
168
103
  }(BaseClient));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentap/runner-client",
3
- "version": "2.7.1-alpha.1.2",
3
+ "version": "2.7.1-alpha.1.3",
4
4
  "description": "This is the web client for the OpenTAP Runner.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",