@opentap/runner-client 4.2.0 → 4.4.0-beta.1.34231471562

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.
@@ -1,4 +1,4 @@
1
- import { ConnectionOptions, Consumer, ConsumerConfig, JetStreamOptions, NatsError, PublishOptions, Subscription, SubscriptionOptions } from 'nats.ws';
1
+ import { ConnectionOptions, Consumer, ConsumerConfig, JetStreamOptions, NatsConnection, NatsError, PublishOptions, Subscription, SubscriptionOptions } from 'nats.ws';
2
2
  import { DownloadTapSettingsRequest } from './requestDTOs';
3
3
  import { ComponentSettingsBase, ComponentSettingsIdentifier, ComponentSettingsListItem, DataGridControl, ErrorResponse, FileParameter, ListItemType, ProfileGroup, RepositoryPackageReference, RepositorySettingsPackageDefinition } from './DTOs';
4
4
  interface BaseClientRequestOptions {
@@ -12,28 +12,23 @@ interface BaseClientRequestOptions {
12
12
  }
13
13
  export declare class BaseClient {
14
14
  readonly baseSubject: string;
15
- private connection;
15
+ private natsConnection;
16
16
  private connectionOptions;
17
17
  private domainAccess;
18
18
  private eventEmitter;
19
19
  private _accessToken;
20
20
  private _headers;
21
21
  private _timeout;
22
- /** Get request access token */
22
+ get connection(): NatsConnection | null;
23
23
  get accessToken(): string;
24
- /** Set request access token */
25
24
  set accessToken(value: string);
26
- /** Get request headers */
27
25
  get headers(): {
28
26
  [key: string]: string;
29
27
  };
30
- /** Set request headers */
31
28
  set headers(value: {
32
29
  [key: string]: string;
33
30
  });
34
- /** Get timeout */
35
31
  get timeout(): number;
36
- /** Set timeout in milliseconds. Default is 40000 milliseconds */
37
32
  set timeout(value: number);
38
33
  constructor(baseSubject: string, options: ConnectionOptions);
39
34
  private withTimeout;
@@ -44,7 +39,7 @@ export declare class BaseClient {
44
39
  * @param options (optional)
45
40
  * @returns Promise of an object
46
41
  */
47
- protected request<T>(subject: string, payload?: any, options?: BaseClientRequestOptions): Promise<T>;
42
+ request<T>(subject: string, payload?: any, options?: BaseClientRequestOptions): Promise<T>;
48
43
  /**
49
44
  * Handle the error
50
45
  * @param error
@@ -78,7 +73,7 @@ export declare class BaseClient {
78
73
  * Create a connection to the nats server.
79
74
  * @param {ConnectionOptions} options
80
75
  */
81
- connect(): Promise<void>;
76
+ connect(connection?: NatsConnection): Promise<void>;
82
77
  /**
83
78
  * Close the connection.
84
79
  */
@@ -258,6 +253,7 @@ export declare class BaseClient {
258
253
  * Dispatches a request with the given subject and returns a Promise of type T
259
254
  * @param subject The subject to send the request to
260
255
  * @returns Promise<T> The response from the request
256
+ * @deprecated Use {@link request} instead.
261
257
  */
262
258
  dispatchRequest<T>(subject: string, payload?: any, options?: BaseClientRequestOptions): Promise<T>;
263
259
  }
@@ -52,6 +52,28 @@ var nats_ws_1 = require("nats.ws");
52
52
  var DTOs_1 = require("./DTOs");
53
53
  var events_1 = require("events");
54
54
  var uuid_1 = require("uuid");
55
+ // A browser extension like CrowdStrike may have already replaced globalThis.WebSocket before this module loads,
56
+ // so reading the global is unreliable. A freshly created same-origin iframe exposes the browser's
57
+ // pristine, un-patched WebSocket; NATS traffic is pinned to it to bypass any extension shim.
58
+ // The iframe is kept attached because a detached iframe's realm becomes unusable in some browsers.
59
+ function getNativeWebSocket() {
60
+ var _a, _b, _c;
61
+ var globalWebSocket = typeof globalThis !== 'undefined' ? globalThis.WebSocket : undefined;
62
+ var doc = globalThis.document;
63
+ if (!doc || typeof doc.createElement !== 'function') {
64
+ return globalWebSocket;
65
+ }
66
+ try {
67
+ var iframe = doc.createElement('iframe');
68
+ iframe.style.display = 'none';
69
+ ((_a = doc.body) !== null && _a !== void 0 ? _a : doc.documentElement).appendChild(iframe);
70
+ return (_c = (_b = iframe.contentWindow) === null || _b === void 0 ? void 0 : _b.WebSocket) !== null && _c !== void 0 ? _c : globalWebSocket;
71
+ }
72
+ catch (_d) {
73
+ return globalWebSocket;
74
+ }
75
+ }
76
+ var OriginalWebSocket = getNativeWebSocket();
55
77
  var DEFAULT_TIMEOUT = 40000; // default timeout of 40 seconds
56
78
  var Events;
57
79
  (function (Events) {
@@ -64,14 +86,28 @@ var BaseClient = /** @class */ (function () {
64
86
  this.baseSubject = baseSubject;
65
87
  this.connectionOptions = __assign({}, options);
66
88
  this.connectionOptions.timeout = (options === null || options === void 0 ? void 0 : options.timeout) || DEFAULT_TIMEOUT;
89
+ // Force NATS to use the WebSocket captured at load time so an extension that later
90
+ // overrides globalThis.WebSocket cannot intercept NATS traffic. Respect a caller-provided factory.
91
+ // wsFactory is read by nats.ws's WsTransport at runtime but lives on WsConnectionOptions, which
92
+ // isn't re-exported, so it's absent from the public ConnectionOptions type and requires this cast.
93
+ if (OriginalWebSocket && !this.connectionOptions.wsFactory) {
94
+ this.connectionOptions.wsFactory = function (url) {
95
+ return Promise.resolve({ socket: new OriginalWebSocket(url), encrypted: url.indexOf('wss://') === 0 });
96
+ };
97
+ }
67
98
  this.eventEmitter = new events_1.EventEmitter();
68
99
  }
100
+ Object.defineProperty(BaseClient.prototype, "connection", {
101
+ get: function () {
102
+ return this.natsConnection;
103
+ },
104
+ enumerable: false,
105
+ configurable: true
106
+ });
69
107
  Object.defineProperty(BaseClient.prototype, "accessToken", {
70
- /** Get request access token */
71
108
  get: function () {
72
109
  return this._accessToken;
73
110
  },
74
- /** Set request access token */
75
111
  set: function (value) {
76
112
  this._accessToken = value;
77
113
  },
@@ -79,11 +115,9 @@ var BaseClient = /** @class */ (function () {
79
115
  configurable: true
80
116
  });
81
117
  Object.defineProperty(BaseClient.prototype, "headers", {
82
- /** Get request headers */
83
118
  get: function () {
84
119
  return this._headers;
85
120
  },
86
- /** Set request headers */
87
121
  set: function (value) {
88
122
  this._headers = value;
89
123
  },
@@ -91,11 +125,9 @@ var BaseClient = /** @class */ (function () {
91
125
  configurable: true
92
126
  });
93
127
  Object.defineProperty(BaseClient.prototype, "timeout", {
94
- /** Get timeout */
95
128
  get: function () {
96
129
  return this._timeout || DEFAULT_TIMEOUT;
97
130
  },
98
- /** Set timeout in milliseconds. Default is 40000 milliseconds */
99
131
  set: function (value) {
100
132
  this._timeout = value;
101
133
  },
@@ -127,9 +159,9 @@ var BaseClient = /** @class */ (function () {
127
159
  if (!(options === null || options === void 0 ? void 0 : options.fullSubject)) {
128
160
  subject = "".concat(this.baseSubject, ".Request.").concat(subject);
129
161
  }
130
- if (!this.connection)
162
+ if (!this.natsConnection)
131
163
  return [2 /*return*/, Promise.reject("".concat(subject, ": Connection is down! Please try again!"))];
132
- if (this.connection.isClosed())
164
+ if (this.natsConnection.isClosed())
133
165
  return [2 /*return*/, Promise.reject("".concat(subject, ": Connection has been closed! Please reconnect!"))];
134
166
  data = this.encode(payload);
135
167
  headers = this.buildHeaders();
@@ -141,7 +173,7 @@ var BaseClient = /** @class */ (function () {
141
173
  }
142
174
  timeout = (options === null || options === void 0 ? void 0 : options.timeout) || this.timeout;
143
175
  replySubject = (_b = (_a = options === null || options === void 0 ? void 0 : options.publishOptions) === null || _a === void 0 ? void 0 : _a.reply) !== null && _b !== void 0 ? _b : "".concat(subject, ".Reply.").concat((0, uuid_1.v4)());
144
- serverMaxPayload = (_d = (_c = this.connection) === null || _c === void 0 ? void 0 : _c.info) === null || _d === void 0 ? void 0 : _d.max_payload;
176
+ serverMaxPayload = (_d = (_c = this.natsConnection) === null || _c === void 0 ? void 0 : _c.info) === null || _d === void 0 ? void 0 : _d.max_payload;
145
177
  chunkSize = serverMaxPayload ? serverMaxPayload - 50000 : 512000;
146
178
  // The Session and the Client need to agree on the chunk size. Put it in a header.
147
179
  headers.append('ChunkSize', chunkSize.toString());
@@ -155,9 +187,16 @@ var BaseClient = /** @class */ (function () {
155
187
  var offset = chunk * fileDescriptor.chunkSize;
156
188
  return data.slice(offset, offset + fileDescriptor.chunkSize);
157
189
  };
158
- subscription = this.connection.subscribe(replySubject);
190
+ subscription = this.natsConnection.subscribe(replySubject);
159
191
  responsePromise = new Promise(function (resolve, reject) {
192
+ // Chunk payloads stored at their sequence index so order is preserved
193
+ // regardless of the order in which messages arrive.
160
194
  var messages = [];
195
+ var receivedCount = 0;
196
+ // Total number of chunks and the size of the final chunk, both known
197
+ // once the final (smaller) chunk arrives.
198
+ var expectedCount;
199
+ var finalChunkLength = 0;
161
200
  subscription.callback = function (error, message) {
162
201
  var _a, _b, _c, _d;
163
202
  if (error) {
@@ -173,59 +212,65 @@ var BaseClient = /** @class */ (function () {
173
212
  subscription.unsubscribe();
174
213
  return resolve({ byteArray: message.data, isErrorResponse: ((_c = message.headers) === null || _c === void 0 ? void 0 : _c.get('OpenTapNatsError')) === 'true' });
175
214
  }
176
- // Put all the response chunks in an array in the order they are received
177
- messages.push(message);
178
- // If the chunk has a size equal to the chunkSize, we should expect another message
179
- if (message.data.length === chunkSize) {
215
+ // Place each chunk at its sequence position (ChunkNumber is 1-based).
216
+ messages[parseInt(chunkNumber) - 1] = message.data;
217
+ receivedCount += 1;
218
+ // The final chunk is the only one smaller than chunkSize; its sequence
219
+ // number tells us how many chunks to expect and its length fixes the total size.
220
+ if (message.data.length < chunkSize) {
221
+ expectedCount = parseInt(chunkNumber);
222
+ finalChunkLength = message.data.length;
223
+ }
224
+ // Keep waiting until every expected chunk has been received.
225
+ if (expectedCount === undefined || receivedCount < expectedCount) {
180
226
  return;
181
227
  }
182
- // If the chunk has a length smaller than the chunkSize, the message is complete
183
- // If the final message was received, we can safely unsubscribe
228
+ // All expected chunks received; we can safely unsubscribe.
184
229
  subscription.unsubscribe();
185
- // Check if the number of the final message is equal to the number of
186
- // messages we received. If this is not the case, we dropped a chunk,
187
- // likely due to a network error. In this case, the entire message is invalid.
188
- if (parseInt(chunkNumber) !== messages.length) {
189
- return reject(Error("Expected {finalMessageNumber} chunks, but received ".concat(messages.length, ". ") +
190
- "The connection may have been interrupted."));
191
- }
192
- // Concatenate the payloads
193
- // When there are many chunks, doing a single allocation
194
- // is significantly faster than concatenating arrays in sequence
195
- var flattenedSize = messages.reduce(function (sum, array) { return sum + array.data.length; }, 0);
230
+ // Every chunk before the last is exactly chunkSize, so the total size is
231
+ // deterministic and each chunk's offset is simply its index * chunkSize.
232
+ var flattenedSize = (expectedCount - 1) * chunkSize + finalChunkLength;
196
233
  var flattenedArray = new Uint8Array(flattenedSize);
197
- var k = 0;
198
- messages.forEach(function (m) {
199
- for (var i = 0; i < m.data.length; i++) {
200
- flattenedArray[k++] = m.data[i];
234
+ for (var i = 0; i < expectedCount; i++) {
235
+ var chunk_1 = messages[i];
236
+ // A missing chunk means we dropped one, likely due to a network error,
237
+ // so the entire message is invalid.
238
+ if (!chunk_1) {
239
+ return reject(Error("Expected ".concat(expectedCount, " chunks, but chunk ").concat(i + 1, " is missing. ") +
240
+ "The connection may have been interrupted."));
201
241
  }
202
- });
242
+ flattenedArray.set(chunk_1, i * chunkSize);
243
+ }
203
244
  return resolve({ byteArray: flattenedArray, isErrorResponse: ((_d = message.headers) === null || _d === void 0 ? void 0 : _d.get('OpenTapNatsError')) === 'true' });
204
245
  };
205
246
  }).then(function (_a) {
206
247
  var byteArray = _a.byteArray, isErrorResponse = _a.isErrorResponse;
248
+ var jsonCodec = (0, nats_ws_1.JSONCodec)();
249
+ if (isErrorResponse) {
250
+ return Promise.reject(DTOs_1.ErrorResponse.fromJS(jsonCodec.decode(byteArray)));
251
+ }
207
252
  if (byteArray.length === 0) {
208
253
  return Promise.resolve(undefined);
209
254
  }
210
- var jsonCodec = (0, nats_ws_1.JSONCodec)();
211
- // If a raw response is requested, we should avoid decoding the bytes.
212
- var response = (options === null || options === void 0 ? void 0 : options.rawResponse) ? byteArray : jsonCodec.decode(byteArray);
213
- return isErrorResponse ? Promise.reject(DTOs_1.ErrorResponse.fromJS(response)) : Promise.resolve(response);
255
+ if (options === null || options === void 0 ? void 0 : options.rawResponse) {
256
+ return Promise.resolve(byteArray);
257
+ }
258
+ return Promise.resolve(jsonCodec.decode(byteArray));
214
259
  });
215
260
  chunk = getChunk(0);
216
- this.connection.publish(subject, chunk, opts);
261
+ this.natsConnection.publish(subject, chunk, opts);
217
262
  chunkNumber += 1;
218
263
  for (i = 1; i < fileDescriptor.numberOfChunks; i++) {
219
264
  headers.set('ChunkNumber', chunkNumber.toString());
220
265
  chunk = getChunk(i);
221
- this.connection.publish(subject, chunk, opts);
266
+ this.natsConnection.publish(subject, chunk, opts);
222
267
  chunkNumber += 1;
223
268
  }
224
269
  // In the special case where the last published chunk was full, we need to publish
225
270
  // an empty message
226
271
  if (data.length > 0 && data.length % fileDescriptor.chunkSize === 0) {
227
272
  headers.set('ChunkNumber', chunkNumber.toString());
228
- this.connection.publish(subject, nats_ws_1.Empty, opts);
273
+ this.natsConnection.publish(subject, nats_ws_1.Empty, opts);
229
274
  }
230
275
  // Now that we have sent the terminating chunk, the result should arrive on our promise.
231
276
  return [2 /*return*/, this.withTimeout(responsePromise, timeout, subject).catch(function (err) {
@@ -281,12 +326,12 @@ var BaseClient = /** @class */ (function () {
281
326
  if (options === void 0) { options = {}; }
282
327
  if (!subject)
283
328
  throw Error('Subject is not defined!');
284
- if (!this.connection)
329
+ if (!this.natsConnection)
285
330
  throw Error('Connection is not up yet! Please try again later!');
286
- if (this.connection.isClosed())
331
+ if (this.natsConnection.isClosed())
287
332
  throw Error('Connection has been closed! Please reconnect!');
288
333
  var natsSubject = options.fullSubject ? subject : "".concat(this.baseSubject, ".").concat(subject);
289
- return this.connection.subscribe(natsSubject, options);
334
+ return this.natsConnection.subscribe(natsSubject, options);
290
335
  };
291
336
  /**
292
337
  * Subscribes to given subject.
@@ -298,14 +343,14 @@ var BaseClient = /** @class */ (function () {
298
343
  var _this = this;
299
344
  if (jetStreamOptions === void 0) { jetStreamOptions = {}; }
300
345
  if (consumerOptions === void 0) { consumerOptions = {}; }
301
- if (!this.connection) {
346
+ if (!this.natsConnection) {
302
347
  throw Error('Connection is not established');
303
348
  }
304
- return this.connection.jetstreamManager(__assign({}, jetStreamOptions)).then(function (jetStreamManager) {
349
+ return this.natsConnection.jetstreamManager(__assign({}, jetStreamOptions)).then(function (jetStreamManager) {
305
350
  return jetStreamManager.consumers
306
351
  .add(stream, __assign(__assign({}, consumerOptions), { filter_subject: subject, ack_policy: nats_ws_1.AckPolicy.None }))
307
352
  .then(function (consumerInfo) {
308
- return _this.connection.jetstream(jetStreamOptions).consumers.get(consumerInfo.stream_name, consumerInfo.name);
353
+ return _this.natsConnection.jetstream(jetStreamOptions).consumers.get(consumerInfo.stream_name, consumerInfo.name);
309
354
  });
310
355
  });
311
356
  };
@@ -322,7 +367,7 @@ var BaseClient = /** @class */ (function () {
322
367
  * Create a connection to the nats server.
323
368
  * @param {ConnectionOptions} options
324
369
  */
325
- BaseClient.prototype.connect = function () {
370
+ BaseClient.prototype.connect = function (connection) {
326
371
  return __awaiter(this, void 0, void 0, function () {
327
372
  var error_1;
328
373
  var _this = this;
@@ -331,14 +376,21 @@ var BaseClient = /** @class */ (function () {
331
376
  case 0:
332
377
  if (!this.baseSubject)
333
378
  return [2 /*return*/, Promise.reject('Subject must be given')];
334
- if (this.connection)
379
+ if (this.natsConnection)
380
+ return [2 /*return*/, Promise.resolve()];
381
+ if (connection) {
382
+ if (connection.isClosed()) {
383
+ return [2 /*return*/, Promise.reject('Provided connection is closed')];
384
+ }
385
+ this.natsConnection = connection;
335
386
  return [2 /*return*/, Promise.resolve()];
387
+ }
336
388
  _a.label = 1;
337
389
  case 1:
338
390
  _a.trys.push([1, 3, , 4]);
339
391
  return [4 /*yield*/, (0, nats_ws_1.connect)(this.connectionOptions)
340
392
  .then(function (connection) {
341
- _this.connection = connection;
393
+ _this.natsConnection = connection;
342
394
  return Promise.resolve();
343
395
  })
344
396
  .catch(function (error) { return Promise.reject("Failed to connect to ".concat(_this.connectionOptions.servers, " with ").concat(error)); })];
@@ -361,9 +413,9 @@ var BaseClient = /** @class */ (function () {
361
413
  return __generator(this, function (_b) {
362
414
  switch (_b.label) {
363
415
  case 0:
364
- if (!this.connection) return [3 /*break*/, 2];
365
- return [4 /*yield*/, ((_a = this.connection) === null || _a === void 0 ? void 0 : _a.close().then(function () {
366
- _this.connection = null;
416
+ if (!this.natsConnection) return [3 /*break*/, 2];
417
+ return [4 /*yield*/, ((_a = this.natsConnection) === null || _a === void 0 ? void 0 : _a.close().then(function () {
418
+ _this.natsConnection = null;
367
419
  }).catch(function (error) {
368
420
  throw new Error("failed to close connection: ".concat(error));
369
421
  }))];
@@ -699,6 +751,7 @@ var BaseClient = /** @class */ (function () {
699
751
  * Dispatches a request with the given subject and returns a Promise of type T
700
752
  * @param subject The subject to send the request to
701
753
  * @returns Promise<T> The response from the request
754
+ * @deprecated Use {@link request} instead.
702
755
  */
703
756
  BaseClient.prototype.dispatchRequest = function (subject, payload, options) {
704
757
  return __awaiter(this, void 0, void 0, function () {
@@ -876,7 +876,8 @@ export declare enum SessionState {
876
876
  Breaking = "Breaking",
877
877
  Aborting = "Aborting",
878
878
  WaitingForUserInput = "WaitingForUserInput",
879
- Loading = "Loading"
879
+ Loading = "Loading",
880
+ Restarting = "Restarting"
880
881
  }
881
882
  export declare class TestPlan implements ITestPlan {
882
883
  childTestSteps?: TestStep[] | undefined;
@@ -1207,7 +1208,9 @@ export declare enum SessionEventName {
1207
1208
  TestStepChanged = "TestStepChanged",
1208
1209
  Break = "Break",
1209
1210
  UserInputRequested = "UserInputRequested",
1210
- UserInputRequestCompleted = "UserInputRequestCompleted"
1211
+ UserInputRequestCompleted = "UserInputRequestCompleted",
1212
+ RestartInitiated = "RestartInitiated",
1213
+ RestartCompleted = "RestartCompleted"
1211
1214
  }
1212
1215
  export declare abstract class SessionEvent {
1213
1216
  readonly eventName: SessionEventName;
@@ -1315,6 +1318,21 @@ export declare class UserInputRequestCompletedEvent extends SessionEvent {
1315
1318
  static fromJS(data: any): UserInputRequestCompletedEvent;
1316
1319
  toJSON(data?: any): any;
1317
1320
  }
1321
+ export declare class RestartInitiatedEvent extends SessionEvent {
1322
+ oldProcessId?: number;
1323
+ constructor(data?: Partial<RestartInitiatedEvent>);
1324
+ init(_data?: any): void;
1325
+ static fromJS(data: any): RestartInitiatedEvent;
1326
+ toJSON(data?: any): any;
1327
+ }
1328
+ export declare class RestartCompletedEvent extends SessionEvent {
1329
+ success?: boolean;
1330
+ newProcessId?: number;
1331
+ constructor(data?: Partial<RestartCompletedEvent>);
1332
+ init(_data?: any): void;
1333
+ static fromJS(data: any): RestartCompletedEvent;
1334
+ toJSON(data?: any): any;
1335
+ }
1318
1336
  export type ISessionEvent = SessionEvent;
1319
1337
  export interface IOnTestPlanRun {
1320
1338
  status?: string;
package/dist/cjs/DTOs.js CHANGED
@@ -17,7 +17,7 @@ var __extends = (this && this.__extends) || (function () {
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.SettingsTapPackage = exports.SaveTestPlanToRepositoryResponse = exports.GetTestPlanReferenceResponse = exports.RepositorySettingsPackageDefinition = exports.RepositoryPackageDefinition = exports.RepositoryPackageReference = exports.ProfileGroup = exports.ListItemType = exports.ComponentSettings = exports.FileDescriptor = exports.Resource = exports.PluginTypeSelectorControl = exports.PictureControl = exports.PasswordControl = exports.MultiSelectControl = exports.DropdownControl = exports.EnabledControl = exports.DirectoryPathControl = exports.FilePathControl = exports.ComboBoxControl = exports.TextBoxControl = exports.DataGridControl = exports.DataGridReferenceControl = exports.CheckBoxControl = exports.AvailableValue = exports.ButtonsControl = exports.ButtonControl = exports.ExternalParameter = exports.MetaData = exports.DisplayAttribute = exports.VisualStatus = exports.UnitAttribute = exports.Icon = exports.ColumnDisplayName = exports.LayoutMode = exports.Layout = exports.Setting = exports.ComponentSettingsListItem = exports.AnnotatedObject = exports.ComponentSettingsList = exports.DisplayMode = exports.ComponentSettingsIdentifier = exports.ComponentSettingsBase = exports.Links = exports.Session = exports.ImageResolveErrorResponse = exports.NoResponderError = exports.ErrorResponse = exports.PackageSpecifier = exports.Image = void 0;
19
19
  exports.StartedEvent = exports.StartingEvent = exports.SessionTimeoutEvent = exports.TestPlanSettingsChangedEvent = exports.TypeCacheInvalidatedEvent = exports.SessionEvent = exports.SessionEventName = exports.MetricValue = exports.MetricsConfiguration = exports.SessionMetricInfo = exports.MetricsPollRate = exports.SessionMetricType = exports.SessionMetricKind = exports.ResultColumn = exports.Result = exports.LogEvent = exports.TestStepRun = exports.WatchDog = exports.Parameter = exports.BreakPoints = exports.InstalledFile = exports.Interaction = exports.CommonContext = exports.CommonSettings = exports.ValidationError = exports.TestStepValidationError = exports.TestStepCopy = exports.TestStepType = exports.TestStep = exports.TestPlan = exports.SessionState = exports.Verdict = exports.EditStatus = exports.RunStatus = exports.MissingLicenseResponse = exports.LogEntry = exports.LogList = exports.ApiException = exports.ImageCreationFailed = exports.ImageCreated = exports.ImageCreating = exports.ImageEventArgs = exports.SessionInactivityLimitHit = exports.SessionShutdownFailed = exports.SessionShutdown = exports.SessionShutdownInitiated = exports.SessionStartFailed = exports.SessionStarted = exports.SessionStartInitiated = exports.SessionEventArgs = void 0;
20
- exports.RunnerStatus = exports.StreamInfoStatus = exports.RemoteConnection = exports.SaveDefaultSettings = exports.AssetUpdatedEvent = exports.MetadataUpdatedEvent = exports.RunnerDeletedEvent = exports.RunnerUpdatedEvent = exports.RunnerRegisteredEvent = exports.RunnerEvent = exports.TestPlanRunCompletedEvent = exports.TestPlanRunStartEvent = exports.TestPlanRunEvent = exports.OnTestStepRun = exports.OnTestPlanRun = exports.UserInputRequestCompletedEvent = exports.UserInputRequestedEvent = exports.BreakEvent = exports.TestStepChangedEvent = exports.SettingsChangedEvent = exports.HeartbeatEvent = exports.SessionStateChangedEvent = exports.TestPlanReferenceChangedEvent = exports.TestPlanChangedEvent = exports.StoppedEvent = exports.StoppingEvent = void 0;
20
+ exports.RunnerStatus = exports.StreamInfoStatus = exports.RemoteConnection = exports.SaveDefaultSettings = exports.AssetUpdatedEvent = exports.MetadataUpdatedEvent = exports.RunnerDeletedEvent = exports.RunnerUpdatedEvent = exports.RunnerRegisteredEvent = exports.RunnerEvent = exports.TestPlanRunCompletedEvent = exports.TestPlanRunStartEvent = exports.TestPlanRunEvent = exports.OnTestStepRun = exports.OnTestPlanRun = exports.RestartCompletedEvent = exports.RestartInitiatedEvent = exports.UserInputRequestCompletedEvent = exports.UserInputRequestedEvent = exports.BreakEvent = exports.TestStepChangedEvent = exports.SettingsChangedEvent = exports.HeartbeatEvent = exports.SessionStateChangedEvent = exports.TestPlanReferenceChangedEvent = exports.TestPlanChangedEvent = exports.StoppedEvent = exports.StoppingEvent = void 0;
21
21
  var Image = /** @class */ (function () {
22
22
  function Image(data) {
23
23
  this.packages = [];
@@ -2444,6 +2444,7 @@ var SessionState;
2444
2444
  SessionState["Aborting"] = "Aborting";
2445
2445
  SessionState["WaitingForUserInput"] = "WaitingForUserInput";
2446
2446
  SessionState["Loading"] = "Loading";
2447
+ SessionState["Restarting"] = "Restarting";
2447
2448
  })(SessionState || (exports.SessionState = SessionState = {}));
2448
2449
  var TestPlan = /** @class */ (function () {
2449
2450
  function TestPlan(data) {
@@ -3326,6 +3327,8 @@ var SessionEventName;
3326
3327
  SessionEventName["Break"] = "Break";
3327
3328
  SessionEventName["UserInputRequested"] = "UserInputRequested";
3328
3329
  SessionEventName["UserInputRequestCompleted"] = "UserInputRequestCompleted";
3330
+ SessionEventName["RestartInitiated"] = "RestartInitiated";
3331
+ SessionEventName["RestartCompleted"] = "RestartCompleted";
3329
3332
  })(SessionEventName || (exports.SessionEventName = SessionEventName = {}));
3330
3333
  var SessionEvent = /** @class */ (function () {
3331
3334
  function SessionEvent(eventName) {
@@ -3659,6 +3662,60 @@ var UserInputRequestCompletedEvent = /** @class */ (function (_super) {
3659
3662
  return UserInputRequestCompletedEvent;
3660
3663
  }(SessionEvent));
3661
3664
  exports.UserInputRequestCompletedEvent = UserInputRequestCompletedEvent;
3665
+ var RestartInitiatedEvent = /** @class */ (function (_super) {
3666
+ __extends(RestartInitiatedEvent, _super);
3667
+ function RestartInitiatedEvent(data) {
3668
+ var _this = _super.call(this, SessionEventName.RestartInitiated) || this;
3669
+ if (data) {
3670
+ Object.assign(_this, data);
3671
+ }
3672
+ return _this;
3673
+ }
3674
+ RestartInitiatedEvent.prototype.init = function (_data) {
3675
+ var data = ensureObject(_data);
3676
+ this.oldProcessId = data['OldProcessId'];
3677
+ };
3678
+ RestartInitiatedEvent.fromJS = function (data) {
3679
+ var result = new RestartInitiatedEvent();
3680
+ result.init(data);
3681
+ return result;
3682
+ };
3683
+ RestartInitiatedEvent.prototype.toJSON = function (data) {
3684
+ var json = ensureObject(data);
3685
+ json['OldProcessId'] = this.oldProcessId;
3686
+ return json;
3687
+ };
3688
+ return RestartInitiatedEvent;
3689
+ }(SessionEvent));
3690
+ exports.RestartInitiatedEvent = RestartInitiatedEvent;
3691
+ var RestartCompletedEvent = /** @class */ (function (_super) {
3692
+ __extends(RestartCompletedEvent, _super);
3693
+ function RestartCompletedEvent(data) {
3694
+ var _this = _super.call(this, SessionEventName.RestartCompleted) || this;
3695
+ if (data) {
3696
+ Object.assign(_this, data);
3697
+ }
3698
+ return _this;
3699
+ }
3700
+ RestartCompletedEvent.prototype.init = function (_data) {
3701
+ var data = ensureObject(_data);
3702
+ this.success = data['Success'];
3703
+ this.newProcessId = data['NewProcessId'];
3704
+ };
3705
+ RestartCompletedEvent.fromJS = function (data) {
3706
+ var result = new RestartCompletedEvent();
3707
+ result.init(data);
3708
+ return result;
3709
+ };
3710
+ RestartCompletedEvent.prototype.toJSON = function (data) {
3711
+ var json = ensureObject(data);
3712
+ json['Success'] = this.success;
3713
+ json['NewProcessId'] = this.newProcessId;
3714
+ return json;
3715
+ };
3716
+ return RestartCompletedEvent;
3717
+ }(SessionEvent));
3718
+ exports.RestartCompletedEvent = RestartCompletedEvent;
3662
3719
  var OnTestPlanRun = /** @class */ (function () {
3663
3720
  function OnTestPlanRun(data) {
3664
3721
  if (data) {
@@ -58,6 +58,12 @@ export declare class RunnerClient extends BaseClient {
58
58
  * @returns {{Promise<void>}}
59
59
  */
60
60
  shutdownSession(sessionId: string, force?: boolean): Promise<void>;
61
+ /**
62
+ * Restart a session
63
+ * @param sessionId the ID of the session to restart
64
+ * @returns {{Promise<void>}}
65
+ */
66
+ restartSession(sessionId: string): Promise<void>;
61
67
  /**
62
68
  * Start a session
63
69
  * @returns {{Promise<Session>}}
@@ -232,6 +232,16 @@ var RunnerClient = /** @class */ (function (_super) {
232
232
  .catch(this.error())
233
233
  : Promise.reject('sessionId is not defined');
234
234
  };
235
+ /**
236
+ * Restart a session
237
+ * @param sessionId the ID of the session to restart
238
+ * @returns {{Promise<void>}}
239
+ */
240
+ RunnerClient.prototype.restartSession = function (sessionId) {
241
+ return (sessionId === null || sessionId === void 0 ? void 0 : sessionId.length) > 0
242
+ ? this.request('RestartSession', { SessionId: sessionId }).then(this.success()).catch(this.error())
243
+ : Promise.reject('sessionId is not defined');
244
+ };
235
245
  /**
236
246
  * Start a session
237
247
  * @returns {{Promise<Session>}}
@@ -847,6 +847,8 @@ var SessionClient = /** @class */ (function (_super) {
847
847
  _a[DTOs_1.SessionEventName.Break] = function (payload) { return DTOs_1.BreakEvent.fromJS(payload); },
848
848
  _a[DTOs_1.SessionEventName.UserInputRequested] = function (payload) { return DTOs_1.UserInputRequestedEvent.fromJS(payload); },
849
849
  _a[DTOs_1.SessionEventName.UserInputRequestCompleted] = function (payload) { return DTOs_1.UserInputRequestCompletedEvent.fromJS(payload); },
850
+ _a[DTOs_1.SessionEventName.RestartInitiated] = function (payload) { return DTOs_1.RestartInitiatedEvent.fromJS(payload); },
851
+ _a[DTOs_1.SessionEventName.RestartCompleted] = function (payload) { return DTOs_1.RestartCompletedEvent.fromJS(payload); },
850
852
  _a);
851
853
  return SessionClient;
852
854
  }(BaseClient_1.BaseClient));
@@ -1,4 +1,4 @@
1
- import { ConnectionOptions, Consumer, ConsumerConfig, JetStreamOptions, NatsError, PublishOptions, Subscription, SubscriptionOptions } from 'nats.ws';
1
+ import { ConnectionOptions, Consumer, ConsumerConfig, JetStreamOptions, NatsConnection, NatsError, PublishOptions, Subscription, SubscriptionOptions } from 'nats.ws';
2
2
  import { DownloadTapSettingsRequest } from './requestDTOs';
3
3
  import { ComponentSettingsBase, ComponentSettingsIdentifier, ComponentSettingsListItem, DataGridControl, ErrorResponse, FileParameter, ListItemType, ProfileGroup, RepositoryPackageReference, RepositorySettingsPackageDefinition } from './DTOs';
4
4
  interface BaseClientRequestOptions {
@@ -12,28 +12,23 @@ interface BaseClientRequestOptions {
12
12
  }
13
13
  export declare class BaseClient {
14
14
  readonly baseSubject: string;
15
- private connection;
15
+ private natsConnection;
16
16
  private connectionOptions;
17
17
  private domainAccess;
18
18
  private eventEmitter;
19
19
  private _accessToken;
20
20
  private _headers;
21
21
  private _timeout;
22
- /** Get request access token */
22
+ get connection(): NatsConnection | null;
23
23
  get accessToken(): string;
24
- /** Set request access token */
25
24
  set accessToken(value: string);
26
- /** Get request headers */
27
25
  get headers(): {
28
26
  [key: string]: string;
29
27
  };
30
- /** Set request headers */
31
28
  set headers(value: {
32
29
  [key: string]: string;
33
30
  });
34
- /** Get timeout */
35
31
  get timeout(): number;
36
- /** Set timeout in milliseconds. Default is 40000 milliseconds */
37
32
  set timeout(value: number);
38
33
  constructor(baseSubject: string, options: ConnectionOptions);
39
34
  private withTimeout;
@@ -44,7 +39,7 @@ export declare class BaseClient {
44
39
  * @param options (optional)
45
40
  * @returns Promise of an object
46
41
  */
47
- protected request<T>(subject: string, payload?: any, options?: BaseClientRequestOptions): Promise<T>;
42
+ request<T>(subject: string, payload?: any, options?: BaseClientRequestOptions): Promise<T>;
48
43
  /**
49
44
  * Handle the error
50
45
  * @param error
@@ -78,7 +73,7 @@ export declare class BaseClient {
78
73
  * Create a connection to the nats server.
79
74
  * @param {ConnectionOptions} options
80
75
  */
81
- connect(): Promise<void>;
76
+ connect(connection?: NatsConnection): Promise<void>;
82
77
  /**
83
78
  * Close the connection.
84
79
  */
@@ -258,6 +253,7 @@ export declare class BaseClient {
258
253
  * Dispatches a request with the given subject and returns a Promise of type T
259
254
  * @param subject The subject to send the request to
260
255
  * @returns Promise<T> The response from the request
256
+ * @deprecated Use {@link request} instead.
261
257
  */
262
258
  dispatchRequest<T>(subject: string, payload?: any, options?: BaseClientRequestOptions): Promise<T>;
263
259
  }
@@ -11,33 +11,52 @@ import { AckPolicy, Empty, ErrorCode, JSONCodec, StringCodec, connect, headers,
11
11
  import { ComponentSettingsBase, ComponentSettingsIdentifier, ComponentSettingsListItem, DataGridControl, ErrorResponse, FileDescriptor, ListItemType, NoResponderError, ProfileGroup, } from './DTOs';
12
12
  import { EventEmitter } from 'events';
13
13
  import { v4 as uuidv4 } from 'uuid';
14
+ // A browser extension like CrowdStrike may have already replaced globalThis.WebSocket before this module loads,
15
+ // so reading the global is unreliable. A freshly created same-origin iframe exposes the browser's
16
+ // pristine, un-patched WebSocket; NATS traffic is pinned to it to bypass any extension shim.
17
+ // The iframe is kept attached because a detached iframe's realm becomes unusable in some browsers.
18
+ function getNativeWebSocket() {
19
+ var _a, _b, _c;
20
+ const globalWebSocket = typeof globalThis !== 'undefined' ? globalThis.WebSocket : undefined;
21
+ const doc = globalThis.document;
22
+ if (!doc || typeof doc.createElement !== 'function') {
23
+ return globalWebSocket;
24
+ }
25
+ try {
26
+ const iframe = doc.createElement('iframe');
27
+ iframe.style.display = 'none';
28
+ ((_a = doc.body) !== null && _a !== void 0 ? _a : doc.documentElement).appendChild(iframe);
29
+ return (_c = (_b = iframe.contentWindow) === null || _b === void 0 ? void 0 : _b.WebSocket) !== null && _c !== void 0 ? _c : globalWebSocket;
30
+ }
31
+ catch (_d) {
32
+ return globalWebSocket;
33
+ }
34
+ }
35
+ const OriginalWebSocket = getNativeWebSocket();
14
36
  const DEFAULT_TIMEOUT = 40000; // default timeout of 40 seconds
15
37
  var Events;
16
38
  (function (Events) {
17
39
  Events["ERROR"] = "error_event";
18
40
  })(Events || (Events = {}));
19
41
  export class BaseClient {
20
- /** Get request access token */
42
+ get connection() {
43
+ return this.natsConnection;
44
+ }
21
45
  get accessToken() {
22
46
  return this._accessToken;
23
47
  }
24
- /** Set request access token */
25
48
  set accessToken(value) {
26
49
  this._accessToken = value;
27
50
  }
28
- /** Get request headers */
29
51
  get headers() {
30
52
  return this._headers;
31
53
  }
32
- /** Set request headers */
33
54
  set headers(value) {
34
55
  this._headers = value;
35
56
  }
36
- /** Get timeout */
37
57
  get timeout() {
38
58
  return this._timeout || DEFAULT_TIMEOUT;
39
59
  }
40
- /** Set timeout in milliseconds. Default is 40000 milliseconds */
41
60
  set timeout(value) {
42
61
  this._timeout = value;
43
62
  }
@@ -47,6 +66,13 @@ export class BaseClient {
47
66
  this.baseSubject = baseSubject;
48
67
  this.connectionOptions = Object.assign({}, options);
49
68
  this.connectionOptions.timeout = (options === null || options === void 0 ? void 0 : options.timeout) || DEFAULT_TIMEOUT;
69
+ // Force NATS to use the WebSocket captured at load time so an extension that later
70
+ // overrides globalThis.WebSocket cannot intercept NATS traffic. Respect a caller-provided factory.
71
+ // wsFactory is read by nats.ws's WsTransport at runtime but lives on WsConnectionOptions, which
72
+ // isn't re-exported, so it's absent from the public ConnectionOptions type and requires this cast.
73
+ if (OriginalWebSocket && !this.connectionOptions.wsFactory) {
74
+ this.connectionOptions.wsFactory = (url) => Promise.resolve({ socket: new OriginalWebSocket(url), encrypted: url.indexOf('wss://') === 0 });
75
+ }
50
76
  this.eventEmitter = new EventEmitter();
51
77
  }
52
78
  withTimeout(promise, timeout, subject) {
@@ -69,9 +95,9 @@ export class BaseClient {
69
95
  if (!(options === null || options === void 0 ? void 0 : options.fullSubject)) {
70
96
  subject = `${this.baseSubject}.Request.${subject}`;
71
97
  }
72
- if (!this.connection)
98
+ if (!this.natsConnection)
73
99
  return Promise.reject(`${subject}: Connection is down! Please try again!`);
74
- if (this.connection.isClosed())
100
+ if (this.natsConnection.isClosed())
75
101
  return Promise.reject(`${subject}: Connection has been closed! Please reconnect!`);
76
102
  const data = this.encode(payload);
77
103
  const headers = this.buildHeaders();
@@ -88,7 +114,7 @@ export class BaseClient {
88
114
  // If serverMaxPayload is not available for some reason, we just use a default chunk size of 512000.
89
115
  // We subtract 50000 from max_payload in order to leave room for headers, which
90
116
  // can be quite large since they can contain jwt tokens, which may contain all sorts of information.
91
- const serverMaxPayload = (_d = (_c = this.connection) === null || _c === void 0 ? void 0 : _c.info) === null || _d === void 0 ? void 0 : _d.max_payload;
117
+ const serverMaxPayload = (_d = (_c = this.natsConnection) === null || _c === void 0 ? void 0 : _c.info) === null || _d === void 0 ? void 0 : _d.max_payload;
92
118
  const chunkSize = serverMaxPayload ? serverMaxPayload - 50000 : 512000;
93
119
  // The Session and the Client need to agree on the chunk size. Put it in a header.
94
120
  headers.append('ChunkSize', chunkSize.toString());
@@ -105,11 +131,18 @@ export class BaseClient {
105
131
  return data.slice(offset, offset + fileDescriptor.chunkSize);
106
132
  };
107
133
  // Set up the subscription before we start publishing chunks
108
- const subscription = this.connection.subscribe(replySubject);
134
+ const subscription = this.natsConnection.subscribe(replySubject);
109
135
  // The response from the session will arrive in this promise after we have finished
110
136
  // publishing chunks
111
137
  const responsePromise = new Promise((resolve, reject) => {
138
+ // Chunk payloads stored at their sequence index so order is preserved
139
+ // regardless of the order in which messages arrive.
112
140
  const messages = [];
141
+ let receivedCount = 0;
142
+ // Total number of chunks and the size of the final chunk, both known
143
+ // once the final (smaller) chunk arrives.
144
+ let expectedCount;
145
+ let finalChunkLength = 0;
113
146
  subscription.callback = (error, message) => {
114
147
  var _a, _b, _c, _d;
115
148
  if (error) {
@@ -125,60 +158,66 @@ export class BaseClient {
125
158
  subscription.unsubscribe();
126
159
  return resolve({ byteArray: message.data, isErrorResponse: ((_c = message.headers) === null || _c === void 0 ? void 0 : _c.get('OpenTapNatsError')) === 'true' });
127
160
  }
128
- // Put all the response chunks in an array in the order they are received
129
- messages.push(message);
130
- // If the chunk has a size equal to the chunkSize, we should expect another message
131
- if (message.data.length === chunkSize) {
161
+ // Place each chunk at its sequence position (ChunkNumber is 1-based).
162
+ messages[parseInt(chunkNumber) - 1] = message.data;
163
+ receivedCount += 1;
164
+ // The final chunk is the only one smaller than chunkSize; its sequence
165
+ // number tells us how many chunks to expect and its length fixes the total size.
166
+ if (message.data.length < chunkSize) {
167
+ expectedCount = parseInt(chunkNumber);
168
+ finalChunkLength = message.data.length;
169
+ }
170
+ // Keep waiting until every expected chunk has been received.
171
+ if (expectedCount === undefined || receivedCount < expectedCount) {
132
172
  return;
133
173
  }
134
- // If the chunk has a length smaller than the chunkSize, the message is complete
135
- // If the final message was received, we can safely unsubscribe
174
+ // All expected chunks received; we can safely unsubscribe.
136
175
  subscription.unsubscribe();
137
- // Check if the number of the final message is equal to the number of
138
- // messages we received. If this is not the case, we dropped a chunk,
139
- // likely due to a network error. In this case, the entire message is invalid.
140
- if (parseInt(chunkNumber) !== messages.length) {
141
- return reject(Error(`Expected {finalMessageNumber} chunks, but received ${messages.length}. ` +
142
- `The connection may have been interrupted.`));
143
- }
144
- // Concatenate the payloads
145
- // When there are many chunks, doing a single allocation
146
- // is significantly faster than concatenating arrays in sequence
147
- const flattenedSize = messages.reduce((sum, array) => sum + array.data.length, 0);
176
+ // Every chunk before the last is exactly chunkSize, so the total size is
177
+ // deterministic and each chunk's offset is simply its index * chunkSize.
178
+ const flattenedSize = (expectedCount - 1) * chunkSize + finalChunkLength;
148
179
  const flattenedArray = new Uint8Array(flattenedSize);
149
- let k = 0;
150
- messages.forEach(m => {
151
- for (let i = 0; i < m.data.length; i++) {
152
- flattenedArray[k++] = m.data[i];
180
+ for (let i = 0; i < expectedCount; i++) {
181
+ const chunk = messages[i];
182
+ // A missing chunk means we dropped one, likely due to a network error,
183
+ // so the entire message is invalid.
184
+ if (!chunk) {
185
+ return reject(Error(`Expected ${expectedCount} chunks, but chunk ${i + 1} is missing. ` +
186
+ `The connection may have been interrupted.`));
153
187
  }
154
- });
188
+ flattenedArray.set(chunk, i * chunkSize);
189
+ }
155
190
  return resolve({ byteArray: flattenedArray, isErrorResponse: ((_d = message.headers) === null || _d === void 0 ? void 0 : _d.get('OpenTapNatsError')) === 'true' });
156
191
  };
157
192
  }).then(({ byteArray, isErrorResponse }) => {
193
+ const jsonCodec = JSONCodec();
194
+ if (isErrorResponse) {
195
+ return Promise.reject(ErrorResponse.fromJS(jsonCodec.decode(byteArray)));
196
+ }
158
197
  if (byteArray.length === 0) {
159
198
  return Promise.resolve(undefined);
160
199
  }
161
- const jsonCodec = JSONCodec();
162
- // If a raw response is requested, we should avoid decoding the bytes.
163
- const response = (options === null || options === void 0 ? void 0 : options.rawResponse) ? byteArray : jsonCodec.decode(byteArray);
164
- return isErrorResponse ? Promise.reject(ErrorResponse.fromJS(response)) : Promise.resolve(response);
200
+ if (options === null || options === void 0 ? void 0 : options.rawResponse) {
201
+ return Promise.resolve(byteArray);
202
+ }
203
+ return Promise.resolve(jsonCodec.decode(byteArray));
165
204
  });
166
205
  // 'Manually' publish the first chunk. This is to ensure that **at least** one chunk is published.
167
206
  // This is a special case for empty payloads (which are common)
168
207
  let chunk = getChunk(0);
169
- this.connection.publish(subject, chunk, opts);
208
+ this.natsConnection.publish(subject, chunk, opts);
170
209
  chunkNumber += 1;
171
210
  for (let i = 1; i < fileDescriptor.numberOfChunks; i++) {
172
211
  headers.set('ChunkNumber', chunkNumber.toString());
173
212
  chunk = getChunk(i);
174
- this.connection.publish(subject, chunk, opts);
213
+ this.natsConnection.publish(subject, chunk, opts);
175
214
  chunkNumber += 1;
176
215
  }
177
216
  // In the special case where the last published chunk was full, we need to publish
178
217
  // an empty message
179
218
  if (data.length > 0 && data.length % fileDescriptor.chunkSize === 0) {
180
219
  headers.set('ChunkNumber', chunkNumber.toString());
181
- this.connection.publish(subject, Empty, opts);
220
+ this.natsConnection.publish(subject, Empty, opts);
182
221
  }
183
222
  // Now that we have sent the terminating chunk, the result should arrive on our promise.
184
223
  return this.withTimeout(responsePromise, timeout, subject).catch(err => {
@@ -229,12 +268,12 @@ export class BaseClient {
229
268
  subscribe(subject, options = {}) {
230
269
  if (!subject)
231
270
  throw Error('Subject is not defined!');
232
- if (!this.connection)
271
+ if (!this.natsConnection)
233
272
  throw Error('Connection is not up yet! Please try again later!');
234
- if (this.connection.isClosed())
273
+ if (this.natsConnection.isClosed())
235
274
  throw Error('Connection has been closed! Please reconnect!');
236
275
  const natsSubject = options.fullSubject ? subject : `${this.baseSubject}.${subject}`;
237
- return this.connection.subscribe(natsSubject, options);
276
+ return this.natsConnection.subscribe(natsSubject, options);
238
277
  }
239
278
  /**
240
279
  * Subscribes to given subject.
@@ -243,12 +282,12 @@ export class BaseClient {
243
282
  * @returns Subscription object
244
283
  */
245
284
  createJetStreamConsumer(stream, subject, jetStreamOptions = {}, consumerOptions = {}) {
246
- if (!this.connection) {
285
+ if (!this.natsConnection) {
247
286
  throw Error('Connection is not established');
248
287
  }
249
- return this.connection.jetstreamManager(Object.assign({}, jetStreamOptions)).then(jetStreamManager => jetStreamManager.consumers
288
+ return this.natsConnection.jetstreamManager(Object.assign({}, jetStreamOptions)).then(jetStreamManager => jetStreamManager.consumers
250
289
  .add(stream, Object.assign(Object.assign({}, consumerOptions), { filter_subject: subject, ack_policy: AckPolicy.None }))
251
- .then(consumerInfo => this.connection.jetstream(jetStreamOptions).consumers.get(consumerInfo.stream_name, consumerInfo.name)));
290
+ .then(consumerInfo => this.natsConnection.jetstream(jetStreamOptions).consumers.get(consumerInfo.stream_name, consumerInfo.name)));
252
291
  }
253
292
  encode(payload) {
254
293
  if (!payload) {
@@ -263,16 +302,23 @@ export class BaseClient {
263
302
  * Create a connection to the nats server.
264
303
  * @param {ConnectionOptions} options
265
304
  */
266
- connect() {
305
+ connect(connection) {
267
306
  return __awaiter(this, void 0, void 0, function* () {
268
307
  if (!this.baseSubject)
269
308
  return Promise.reject('Subject must be given');
270
- if (this.connection)
309
+ if (this.natsConnection)
271
310
  return Promise.resolve();
311
+ if (connection) {
312
+ if (connection.isClosed()) {
313
+ return Promise.reject('Provided connection is closed');
314
+ }
315
+ this.natsConnection = connection;
316
+ return Promise.resolve();
317
+ }
272
318
  try {
273
319
  return yield connect(this.connectionOptions)
274
320
  .then((connection) => {
275
- this.connection = connection;
321
+ this.natsConnection = connection;
276
322
  return Promise.resolve();
277
323
  })
278
324
  .catch((error) => Promise.reject(`Failed to connect to ${this.connectionOptions.servers} with ${error}`));
@@ -288,9 +334,9 @@ export class BaseClient {
288
334
  close() {
289
335
  return __awaiter(this, void 0, void 0, function* () {
290
336
  var _a;
291
- if (this.connection) {
292
- yield ((_a = this.connection) === null || _a === void 0 ? void 0 : _a.close().then(() => {
293
- this.connection = null;
337
+ if (this.natsConnection) {
338
+ yield ((_a = this.natsConnection) === null || _a === void 0 ? void 0 : _a.close().then(() => {
339
+ this.natsConnection = null;
294
340
  }).catch((error) => {
295
341
  throw new Error(`failed to close connection: ${error}`);
296
342
  }));
@@ -617,6 +663,7 @@ export class BaseClient {
617
663
  * Dispatches a request with the given subject and returns a Promise of type T
618
664
  * @param subject The subject to send the request to
619
665
  * @returns Promise<T> The response from the request
666
+ * @deprecated Use {@link request} instead.
620
667
  */
621
668
  dispatchRequest(subject, payload, options) {
622
669
  return __awaiter(this, void 0, void 0, function* () {
@@ -876,7 +876,8 @@ export declare enum SessionState {
876
876
  Breaking = "Breaking",
877
877
  Aborting = "Aborting",
878
878
  WaitingForUserInput = "WaitingForUserInput",
879
- Loading = "Loading"
879
+ Loading = "Loading",
880
+ Restarting = "Restarting"
880
881
  }
881
882
  export declare class TestPlan implements ITestPlan {
882
883
  childTestSteps?: TestStep[] | undefined;
@@ -1207,7 +1208,9 @@ export declare enum SessionEventName {
1207
1208
  TestStepChanged = "TestStepChanged",
1208
1209
  Break = "Break",
1209
1210
  UserInputRequested = "UserInputRequested",
1210
- UserInputRequestCompleted = "UserInputRequestCompleted"
1211
+ UserInputRequestCompleted = "UserInputRequestCompleted",
1212
+ RestartInitiated = "RestartInitiated",
1213
+ RestartCompleted = "RestartCompleted"
1211
1214
  }
1212
1215
  export declare abstract class SessionEvent {
1213
1216
  readonly eventName: SessionEventName;
@@ -1315,6 +1318,21 @@ export declare class UserInputRequestCompletedEvent extends SessionEvent {
1315
1318
  static fromJS(data: any): UserInputRequestCompletedEvent;
1316
1319
  toJSON(data?: any): any;
1317
1320
  }
1321
+ export declare class RestartInitiatedEvent extends SessionEvent {
1322
+ oldProcessId?: number;
1323
+ constructor(data?: Partial<RestartInitiatedEvent>);
1324
+ init(_data?: any): void;
1325
+ static fromJS(data: any): RestartInitiatedEvent;
1326
+ toJSON(data?: any): any;
1327
+ }
1328
+ export declare class RestartCompletedEvent extends SessionEvent {
1329
+ success?: boolean;
1330
+ newProcessId?: number;
1331
+ constructor(data?: Partial<RestartCompletedEvent>);
1332
+ init(_data?: any): void;
1333
+ static fromJS(data: any): RestartCompletedEvent;
1334
+ toJSON(data?: any): any;
1335
+ }
1318
1336
  export type ISessionEvent = SessionEvent;
1319
1337
  export interface IOnTestPlanRun {
1320
1338
  status?: string;
package/dist/mjs/DTOs.js CHANGED
@@ -2143,6 +2143,7 @@ export var SessionState;
2143
2143
  SessionState["Aborting"] = "Aborting";
2144
2144
  SessionState["WaitingForUserInput"] = "WaitingForUserInput";
2145
2145
  SessionState["Loading"] = "Loading";
2146
+ SessionState["Restarting"] = "Restarting";
2146
2147
  })(SessionState || (SessionState = {}));
2147
2148
  export class TestPlan {
2148
2149
  constructor(data) {
@@ -2925,6 +2926,8 @@ export var SessionEventName;
2925
2926
  SessionEventName["Break"] = "Break";
2926
2927
  SessionEventName["UserInputRequested"] = "UserInputRequested";
2927
2928
  SessionEventName["UserInputRequestCompleted"] = "UserInputRequestCompleted";
2929
+ SessionEventName["RestartInitiated"] = "RestartInitiated";
2930
+ SessionEventName["RestartCompleted"] = "RestartCompleted";
2928
2931
  })(SessionEventName || (SessionEventName = {}));
2929
2932
  export class SessionEvent {
2930
2933
  constructor(eventName) {
@@ -3200,6 +3203,52 @@ export class UserInputRequestCompletedEvent extends SessionEvent {
3200
3203
  return json;
3201
3204
  }
3202
3205
  }
3206
+ export class RestartInitiatedEvent extends SessionEvent {
3207
+ constructor(data) {
3208
+ super(SessionEventName.RestartInitiated);
3209
+ if (data) {
3210
+ Object.assign(this, data);
3211
+ }
3212
+ }
3213
+ init(_data) {
3214
+ const data = ensureObject(_data);
3215
+ this.oldProcessId = data['OldProcessId'];
3216
+ }
3217
+ static fromJS(data) {
3218
+ const result = new RestartInitiatedEvent();
3219
+ result.init(data);
3220
+ return result;
3221
+ }
3222
+ toJSON(data) {
3223
+ const json = ensureObject(data);
3224
+ json['OldProcessId'] = this.oldProcessId;
3225
+ return json;
3226
+ }
3227
+ }
3228
+ export class RestartCompletedEvent extends SessionEvent {
3229
+ constructor(data) {
3230
+ super(SessionEventName.RestartCompleted);
3231
+ if (data) {
3232
+ Object.assign(this, data);
3233
+ }
3234
+ }
3235
+ init(_data) {
3236
+ const data = ensureObject(_data);
3237
+ this.success = data['Success'];
3238
+ this.newProcessId = data['NewProcessId'];
3239
+ }
3240
+ static fromJS(data) {
3241
+ const result = new RestartCompletedEvent();
3242
+ result.init(data);
3243
+ return result;
3244
+ }
3245
+ toJSON(data) {
3246
+ const json = ensureObject(data);
3247
+ json['Success'] = this.success;
3248
+ json['NewProcessId'] = this.newProcessId;
3249
+ return json;
3250
+ }
3251
+ }
3203
3252
  export class OnTestPlanRun {
3204
3253
  constructor(data) {
3205
3254
  if (data) {
@@ -58,6 +58,12 @@ export declare class RunnerClient extends BaseClient {
58
58
  * @returns {{Promise<void>}}
59
59
  */
60
60
  shutdownSession(sessionId: string, force?: boolean): Promise<void>;
61
+ /**
62
+ * Restart a session
63
+ * @param sessionId the ID of the session to restart
64
+ * @returns {{Promise<void>}}
65
+ */
66
+ restartSession(sessionId: string): Promise<void>;
61
67
  /**
62
68
  * Start a session
63
69
  * @returns {{Promise<Session>}}
@@ -171,6 +171,16 @@ export class RunnerClient extends BaseClient {
171
171
  .catch(this.error())
172
172
  : Promise.reject('sessionId is not defined');
173
173
  }
174
+ /**
175
+ * Restart a session
176
+ * @param sessionId the ID of the session to restart
177
+ * @returns {{Promise<void>}}
178
+ */
179
+ restartSession(sessionId) {
180
+ return (sessionId === null || sessionId === void 0 ? void 0 : sessionId.length) > 0
181
+ ? this.request('RestartSession', { SessionId: sessionId }).then(this.success()).catch(this.error())
182
+ : Promise.reject('sessionId is not defined');
183
+ }
174
184
  /**
175
185
  * Start a session
176
186
  * @returns {{Promise<Session>}}
@@ -1,4 +1,4 @@
1
- import { BreakEvent, BreakPoints, CommonContext, CommonSettings, DataGridControl, GetTestPlanReferenceResponse, HeartbeatEvent, Image, Interaction, ListItemType, LogList, MetricsConfiguration, OnTestPlanRun, OnTestStepRun, Result, RunStatus, SaveTestPlanToRepositoryResponse, SessionEventName, SessionStateChangedEvent, SessionTimeoutEvent, Setting, SettingsChangedEvent, StartingEvent, StartedEvent, StoppedEvent, StoppingEvent, TestPlan, TestPlanChangedEvent, TestPlanReferenceChangedEvent, TestPlanSettingsChangedEvent, TestStepChangedEvent, TestStepType, TestStepValidationError, TypeCacheInvalidatedEvent, UserInputRequestCompletedEvent, UserInputRequestedEvent, WatchDog, EditStatus, } from './DTOs';
1
+ import { BreakEvent, BreakPoints, CommonContext, CommonSettings, DataGridControl, GetTestPlanReferenceResponse, HeartbeatEvent, Image, Interaction, ListItemType, LogList, MetricsConfiguration, OnTestPlanRun, OnTestStepRun, Result, RunStatus, SaveTestPlanToRepositoryResponse, SessionEventName, SessionStateChangedEvent, SessionTimeoutEvent, Setting, SettingsChangedEvent, StartingEvent, StartedEvent, StoppedEvent, StoppingEvent, TestPlan, TestPlanChangedEvent, TestPlanReferenceChangedEvent, TestPlanSettingsChangedEvent, TestStepChangedEvent, TestStepType, TestStepValidationError, TypeCacheInvalidatedEvent, UserInputRequestCompletedEvent, UserInputRequestedEvent, RestartInitiatedEvent, RestartCompletedEvent, WatchDog, EditStatus, } from './DTOs';
2
2
  import { BaseClient } from './BaseClient';
3
3
  import { jsonCodec } from './encoders';
4
4
  import { NIL } from 'uuid';
@@ -808,4 +808,6 @@ SessionClient.sessionEventFactories = {
808
808
  [SessionEventName.Break]: payload => BreakEvent.fromJS(payload),
809
809
  [SessionEventName.UserInputRequested]: payload => UserInputRequestedEvent.fromJS(payload),
810
810
  [SessionEventName.UserInputRequestCompleted]: payload => UserInputRequestCompletedEvent.fromJS(payload),
811
+ [SessionEventName.RestartInitiated]: payload => RestartInitiatedEvent.fromJS(payload),
812
+ [SessionEventName.RestartCompleted]: payload => RestartCompletedEvent.fromJS(payload),
811
813
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentap/runner-client",
3
- "version": "4.2.0",
3
+ "version": "4.4.0-beta.1.34231471562",
4
4
  "description": "This is the web client for the OpenTAP Runner.",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/mjs/index.js",