@kinotic-ai/core 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -80,7 +80,6 @@ __export(exports_src, {
80
80
  OffsetPageable: () => OffsetPageable,
81
81
  NullHandling: () => NullHandling,
82
82
  KinoticSingleton: () => KinoticSingleton,
83
- KinoticError: () => KinoticError,
84
83
  Kinotic: () => Kinotic,
85
84
  JsonEventFactory: () => JsonEventFactory,
86
85
  FunctionalIterablePage: () => FunctionalIterablePage,
@@ -97,8 +96,6 @@ __export(exports_src, {
97
96
  ConnectionInfo: () => ConnectionInfo,
98
97
  ConnectedInfo: () => ConnectedInfo,
99
98
  CONTEXT_METADATA_KEY: () => CONTEXT_METADATA_KEY,
100
- AuthorizationError: () => AuthorizationError,
101
- AuthenticationError: () => AuthenticationError,
102
99
  AbstractIterablePage: () => AbstractIterablePage
103
100
  });
104
101
  module.exports = __toCommonJS(exports_src);
@@ -121,14 +118,6 @@ class ConnectionInfo extends ServerInfo {
121
118
  maxConnectionAttempts;
122
119
  sessionKeepAlive = "ACTIVITY" /* ACTIVITY */;
123
120
  }
124
- // packages/core/src/api/errors/KinoticError.ts
125
- class KinoticError extends Error {
126
- constructor(message) {
127
- super(message);
128
- Object.setPrototypeOf(this, KinoticError.prototype);
129
- }
130
- }
131
-
132
121
  // packages/core/src/api/event/IEventBus.ts
133
122
  var EventConstants;
134
123
  ((EventConstants2) => {
@@ -161,32 +150,38 @@ var EventConstants;
161
150
  var import_rx_stomp = require("@stomp/rx-stomp");
162
151
  var import_stompjs = require("@stomp/stompjs");
163
152
  var import_debug = __toESM(require("debug"));
153
+ var import_rxjs = require("rxjs");
164
154
  var import_uuid = require("uuid");
165
155
 
166
156
  class StompConnectionManager {
167
157
  lastWebsocketError = null;
168
158
  maxConnectionAttemptsReached = false;
159
+ replyToCriChangedHandler = null;
169
160
  rxStomp = null;
170
161
  INITIAL_RECONNECT_DELAY = 2000;
171
- MAX_RECONNECT_DELAY = 120000;
172
162
  JITTER_MAX = 5000;
163
+ MAX_RECONNECT_DELAY = 120000;
173
164
  connectionAttempts = 0;
174
- initialConnectionSuccessful = false;
175
165
  debugLogger = import_debug.default("kinoitc:stomp");
166
+ fatalErrorsSubject = new import_rxjs.Subject;
167
+ _fatalErrors = this.fatalErrorsSubject.asObservable();
168
+ initialConnectionSuccessful = false;
169
+ serverHeadersSubscription = null;
170
+ stompErrorsSubscription = null;
176
171
  uuidv4 = import_uuid.v4();
177
172
  _replyToCri = null;
178
- serverHeadersSubscription = null;
179
- deactivationHandler = null;
180
- replyToCriChangedHandler = null;
181
- get active() {
182
- return !!this.rxStomp;
183
- }
184
173
  get replyToCri() {
185
174
  return this._replyToCri;
186
175
  }
176
+ get active() {
177
+ return !!this.rxStomp;
178
+ }
187
179
  get connected() {
188
180
  return this.rxStomp != null && this.rxStomp.connected();
189
181
  }
182
+ get fatalErrors() {
183
+ return this._fatalErrors;
184
+ }
190
185
  activate(connectionInfo) {
191
186
  return new Promise((resolve, reject) => {
192
187
  if (!connectionInfo) {
@@ -205,9 +200,6 @@ class StompConnectionManager {
205
200
  this.initialConnectionSuccessful = false;
206
201
  this.lastWebsocketError = null;
207
202
  this.maxConnectionAttemptsReached = false;
208
- this._replyToCri = null;
209
- this.serverHeadersSubscription?.unsubscribe();
210
- this.serverHeadersSubscription = null;
211
203
  const url = "ws" + (connectionInfo.useSSL ? "s" : "") + "://" + connectionInfo.host + (connectionInfo.port ? ":" + connectionInfo.port : "") + "/v1";
212
204
  this.rxStomp = new import_rx_stomp.RxStomp;
213
205
  let preparedSocket = null;
@@ -220,17 +212,15 @@ class StompConnectionManager {
220
212
  heartbeatIncoming: 120000,
221
213
  heartbeatOutgoing: 30000,
222
214
  reconnectDelay: this.INITIAL_RECONNECT_DELAY,
215
+ maxReconnectDelay: this.MAX_RECONNECT_DELAY,
216
+ reconnectTimeMode: import_stompjs.ReconnectionTimeMode.EXPONENTIAL,
223
217
  webSocketFactory: userWebSocketFactory ? () => preparedSocket : undefined,
224
218
  beforeConnect: async () => {
225
219
  if (connectionInfo?.maxConnectionAttempts) {
226
220
  this.connectionAttempts++;
227
221
  if (this.connectionAttempts > connectionInfo.maxConnectionAttempts) {
228
222
  this.maxConnectionAttemptsReached = true;
229
- await this.deactivate();
230
- if (!this.initialConnectionSuccessful) {
231
- let message = this.lastWebsocketError?.message ? this.lastWebsocketError?.message : "UNKNOWN";
232
- reject(`Max number of reconnection attempts reached. Last WS Error ${message}`);
233
- }
223
+ await this.signalFatal(new Error("Max number of reconnection attempts reached", { cause: this.lastWebsocketError ?? undefined }));
234
224
  return;
235
225
  } else {
236
226
  await this.connectionJitterDelay();
@@ -242,10 +232,7 @@ class StompConnectionManager {
242
232
  try {
243
233
  preparedSocket = await userWebSocketFactory();
244
234
  } catch (e) {
245
- await this.deactivate();
246
- if (!this.initialConnectionSuccessful) {
247
- reject(e);
248
- }
235
+ await this.signalFatal(new Error("WebSocket factory failed", { cause: e }));
249
236
  }
250
237
  }
251
238
  }
@@ -256,42 +243,44 @@ class StompConnectionManager {
256
243
  };
257
244
  }
258
245
  this.rxStomp.configure(stompConfig);
259
- this.rxStomp.stompClient.maxReconnectDelay = this.MAX_RECONNECT_DELAY;
260
- this.rxStomp.stompClient.reconnectTimeMode = import_stompjs.ReconnectionTimeMode.EXPONENTIAL;
261
246
  this.rxStomp.webSocketErrors$.subscribe((value) => {
262
247
  this.lastWebsocketError = value;
263
248
  });
249
+ this.stompErrorsSubscription = this.rxStomp.stompErrors$.subscribe(async (frame) => {
250
+ const stompError = new Error(frame.headers["message"], { cause: frame });
251
+ await this.signalFatal(new Error("STOMP connection error", { cause: stompError }));
252
+ });
264
253
  const connectedSubscription = this.rxStomp.connected$.subscribe(() => {
265
254
  connectedSubscription.unsubscribe();
255
+ initialFailureSubscription.unsubscribe();
266
256
  if (!this.initialConnectionSuccessful) {
267
257
  this.initialConnectionSuccessful = true;
268
258
  }
269
259
  });
270
- const errorSubscription = this.rxStomp.stompErrors$.subscribe((value) => {
271
- errorSubscription.unsubscribe();
272
- const message = value.headers["message"];
273
- this.rxStomp?.deactivate();
274
- this.rxStomp = null;
275
- reject(message);
260
+ const initialFailureSubscription = this.fatalErrorsSubject.subscribe((err) => {
261
+ connectedSubscription.unsubscribe();
262
+ initialFailureSubscription.unsubscribe();
263
+ reject(err.message);
276
264
  });
277
- this.serverHeadersSubscription = this.rxStomp.serverHeaders$.subscribe((value) => {
265
+ this.serverHeadersSubscription = this.rxStomp.serverHeaders$.subscribe(async (value) => {
278
266
  const connectedInfoJson = value["connected-info" /* CONNECTED_INFO_HEADER */];
279
- const firstConnect = this._replyToCri == null;
280
267
  if (connectedInfoJson == null) {
281
- if (firstConnect) {
268
+ if (!this.initialConnectionSuccessful) {
269
+ await this.deactivate();
282
270
  reject("Server did not return proper data for successful login");
283
271
  }
284
272
  return;
285
273
  }
286
274
  const connectedInfo = JSON.parse(connectedInfoJson);
287
275
  if (connectedInfo.replyToId == null) {
288
- if (firstConnect) {
276
+ if (!this.initialConnectionSuccessful) {
277
+ await this.deactivate();
289
278
  reject("Server did not return a replyToId for successful login");
290
279
  }
291
280
  return;
292
281
  }
293
282
  const newReplyToCri = "reply://" /* REPLY_DESTINATION_PREFIX */ + connectedInfo.replyToId + ":" + this.uuidv4 + "@kinoitc.js.EventBus/replyHandler";
294
- if (firstConnect) {
283
+ if (!this.initialConnectionSuccessful) {
295
284
  this._replyToCri = newReplyToCri;
296
285
  resolve(connectedInfo);
297
286
  } else if (this._replyToCri !== newReplyToCri) {
@@ -307,10 +296,10 @@ class StompConnectionManager {
307
296
  await this.rxStomp.deactivate({ force });
308
297
  this.serverHeadersSubscription?.unsubscribe();
309
298
  this.serverHeadersSubscription = null;
310
- if (this.deactivationHandler) {
311
- this.deactivationHandler();
312
- }
299
+ this.stompErrorsSubscription?.unsubscribe();
300
+ this.stompErrorsSubscription = null;
313
301
  this.rxStomp = null;
302
+ this._replyToCri = null;
314
303
  }
315
304
  return;
316
305
  }
@@ -321,11 +310,18 @@ class StompConnectionManager {
321
310
  return new Promise((resolve) => setTimeout(resolve, randomJitter));
322
311
  }
323
312
  }
313
+ async signalFatal(err) {
314
+ if (console) {
315
+ console.error("StompConnectionManager fatal error, deactivating connection", err);
316
+ }
317
+ await this.deactivate();
318
+ this.fatalErrorsSubject.next(err);
319
+ }
324
320
  }
325
321
 
326
322
  // packages/core/src/api/event/EventBus.ts
327
323
  var import_api = require("@opentelemetry/api");
328
- var import_rxjs = require("rxjs");
324
+ var import_rxjs2 = require("rxjs");
329
325
  var import_operators = require("rxjs/operators");
330
326
  var import_typescript_optional = require("typescript-optional");
331
327
  var import_uuid2 = require("uuid");
@@ -366,32 +362,22 @@ class Event {
366
362
  }
367
363
 
368
364
  class EventBus {
369
- fatalErrors;
370
365
  serverInfo = null;
371
366
  stompConnectionManager = new StompConnectionManager;
372
367
  replyToCri = null;
373
368
  requestRepliesObservable = null;
374
369
  requestRepliesSubject = null;
375
370
  requestRepliesSubscription = null;
376
- errorSubject = new import_rxjs.Subject;
377
- errorSubjectSubscription = null;
378
371
  constructor() {
379
- this.fatalErrors = this.errorSubject.pipe(import_operators.map((frame) => {
380
- this.disconnect().catch((error) => {
381
- if (console) {
382
- console.error("Error disconnecting from Stomp: " + error);
383
- }
384
- });
385
- return new KinoticError(frame.headers["message"]);
386
- }));
387
- this.stompConnectionManager.deactivationHandler = () => {
388
- this.cleanup();
389
- };
372
+ this.stompConnectionManager.fatalErrors.subscribe(() => this.cleanup());
390
373
  this.stompConnectionManager.replyToCriChangedHandler = (replyToCri) => {
391
374
  this.replyToCri = replyToCri;
392
375
  this.resetRequestReplies("Reply destination changed");
393
376
  };
394
377
  }
378
+ get fatalErrors() {
379
+ return this.stompConnectionManager.fatalErrors;
380
+ }
395
381
  isConnectionActive() {
396
382
  return this.stompConnectionManager.active;
397
383
  }
@@ -407,7 +393,6 @@ class EventBus {
407
393
  this.serverInfo.port = connectionInfo.port;
408
394
  this.serverInfo.useSSL = connectionInfo.useSSL;
409
395
  this.replyToCri = this.stompConnectionManager.replyToCri;
410
- this.errorSubjectSubscription = this.stompConnectionManager.rxStomp?.stompErrors$.subscribe(this.errorSubject);
411
396
  return connectedInfo;
412
397
  } else {
413
398
  throw new Error("Event Bus connection already active");
@@ -441,13 +426,13 @@ class EventBus {
441
426
  }
442
427
  }
443
428
  request(event) {
444
- return import_rxjs.firstValueFrom(this.requestStream(event, false));
429
+ return import_rxjs2.firstValueFrom(this.requestStream(event, false));
445
430
  }
446
431
  requestStream(event, sendControlEvents = true) {
447
432
  if (this.stompConnectionManager?.rxStomp) {
448
- return new import_rxjs.Observable((subscriber) => {
433
+ return new import_rxjs2.Observable((subscriber) => {
449
434
  if (this.requestRepliesObservable == null) {
450
- this.requestRepliesSubject = new import_rxjs.Subject;
435
+ this.requestRepliesSubject = new import_rxjs2.Subject;
451
436
  this.requestRepliesObservable = this._observe(this.replyToCri).pipe(import_operators.multicast(this.requestRepliesSubject));
452
437
  this.requestRepliesSubscription = this.requestRepliesObservable.connect();
453
438
  }
@@ -492,7 +477,7 @@ class EventBus {
492
477
  };
493
478
  });
494
479
  } else {
495
- return import_rxjs.throwError(() => this.createSendUnavailableError());
480
+ return import_rxjs2.throwError(() => this.createSendUnavailableError());
496
481
  }
497
482
  }
498
483
  listen(_serverInfo) {
@@ -503,10 +488,6 @@ class EventBus {
503
488
  }
504
489
  cleanup() {
505
490
  this.resetRequestReplies("Connection disconnected");
506
- if (this.errorSubjectSubscription) {
507
- this.errorSubjectSubscription.unsubscribe();
508
- this.errorSubjectSubscription = null;
509
- }
510
491
  this.serverInfo = null;
511
492
  }
512
493
  resetRequestReplies(reason) {
@@ -1002,7 +983,7 @@ var import_operators2 = require("rxjs/operators");
1002
983
  // packages/core/package.json
1003
984
  var package_default = {
1004
985
  name: "@kinotic-ai/core",
1005
- version: "1.3.1",
986
+ version: "1.4.1",
1006
987
  type: "module",
1007
988
  files: [
1008
989
  "dist"
@@ -1059,7 +1040,7 @@ var package_default = {
1059
1040
  dependencies: {
1060
1041
  "@opentelemetry/api": "^1.9.1",
1061
1042
  "@opentelemetry/semantic-conventions": "^1.40.0",
1062
- "@stomp/rx-stomp": "^2.3.0",
1043
+ "@stomp/rx-stomp": "^2.4.0",
1063
1044
  "@stomp/stompjs": "^7.3.0",
1064
1045
  "@types/debug": "^4.1.13",
1065
1046
  debug: "^4.4.3",
@@ -1480,20 +1461,6 @@ class Order {
1480
1461
  class Sort {
1481
1462
  orders = [];
1482
1463
  }
1483
- // packages/core/src/api/errors/AuthenticationError.ts
1484
- class AuthenticationError extends KinoticError {
1485
- constructor(message) {
1486
- super(message);
1487
- Object.setPrototypeOf(this, AuthenticationError.prototype);
1488
- }
1489
- }
1490
- // packages/core/src/api/errors/AuthorizationError.ts
1491
- class AuthorizationError extends KinoticError {
1492
- constructor(message) {
1493
- super(message);
1494
- Object.setPrototypeOf(this, AuthorizationError.prototype);
1495
- }
1496
- }
1497
1464
  // packages/core/src/api/security/ConnectedInfo.ts
1498
1465
  class ConnectedInfo {
1499
1466
  replyToId;
package/dist/index.d.cts CHANGED
@@ -133,12 +133,6 @@ declare class ConnectedInfo {
133
133
  participant: Participant;
134
134
  }
135
135
  /**
136
- * Base error class for all Kinoitc errors
137
- */
138
- declare class KinoticError extends Error {
139
- constructor(message: string);
140
- }
141
- /**
142
136
  * Part of the low level portion of kinoitc representing data to be processed
143
137
  *
144
138
  * This is similar to a Stomp Frame but with more required information and no control plane semantics.
@@ -205,7 +199,7 @@ interface IEventBus {
205
199
  * Any errors emitted by this observable will be fatal and the connection will be closed.
206
200
  * You will need to resolve the problem and reconnect.
207
201
  */
208
- fatalErrors: Observable<KinoticError>;
202
+ fatalErrors: Observable<Error>;
209
203
  /**
210
204
  * The {@link ServerInfo} used when connecting, if connected or null
211
205
  */
@@ -1036,12 +1030,6 @@ declare class FunctionalIterablePage<T> extends AbstractIterablePage<T> {
1036
1030
  constructor(pageable: Pageable, page: Page<T>, pageFunction: (pageable: Pageable) => Promise<Page<T>>);
1037
1031
  protected findNext(pageable: Pageable): Promise<Page<T>>;
1038
1032
  }
1039
- declare class AuthenticationError extends KinoticError {
1040
- constructor(message: string);
1041
- }
1042
- declare class AuthorizationError extends KinoticError {
1043
- constructor(message: string);
1044
- }
1045
1033
  /**
1046
1034
  * Default implementation of the `CRI` interface.
1047
1035
  *
@@ -1094,16 +1082,14 @@ declare class Event implements IEvent {
1094
1082
  * Default implementation of {@link IEventBus}
1095
1083
  */
1096
1084
  declare class EventBus implements IEventBus {
1097
- fatalErrors: Observable3<Error>;
1098
1085
  serverInfo: ServerInfo | null;
1099
1086
  private stompConnectionManager;
1100
1087
  private replyToCri;
1101
1088
  private requestRepliesObservable;
1102
1089
  private requestRepliesSubject;
1103
1090
  private requestRepliesSubscription;
1104
- private errorSubject;
1105
- private errorSubjectSubscription;
1106
1091
  constructor();
1092
+ get fatalErrors(): Observable3<Error>;
1107
1093
  isConnectionActive(): boolean;
1108
1094
  isConnected(): boolean;
1109
1095
  connect(connectionInfo: ConnectionInfo): Promise<ConnectedInfo>;
@@ -1144,4 +1130,4 @@ declare class ParticipantConstants {
1144
1130
  static readonly PARTICIPANT_TYPE_NODE: string;
1145
1131
  static readonly CLI_PARTICIPANT_ID: string;
1146
1132
  }
1147
- export { createCRI, WebSocketFactory, Version, TextEventFactory, Sort, SessionKeepAliveMode, ServiceRegistry, ServiceContext, ServerInfo, Scope, Publish, ParticipantConstants, Participant, Pageable, Page, Order, OffsetPageable, NullHandling, KinoticSingleton, KinoticPlugin, KinoticError, Kinotic, JsonEventFactory, IterablePage, Identifiable, IWebSocket, IServiceRegistry, IServiceProxy, IParticipant, IKinotic, IEventFactory, IEventBus, IEvent, IEditableDataSource, IDataSource, ICrudServiceProxyFactory, ICrudServiceProxy, FunctionalIterablePage, EventConstants, EventBus, Event, Direction, DefaultCRI, DataSourceUtils, CursorPageable, CrudServiceProxyFactory, CrudServiceProxy, ContextInterceptor, Context, ConnectionInfo, ConnectedInfo, CRI, CONTEXT_METADATA_KEY, AuthorizationError, AuthenticationError, AbstractIterablePage };
1133
+ export { createCRI, WebSocketFactory, Version, TextEventFactory, Sort, SessionKeepAliveMode, ServiceRegistry, ServiceContext, ServerInfo, Scope, Publish, ParticipantConstants, Participant, Pageable, Page, Order, OffsetPageable, NullHandling, KinoticSingleton, KinoticPlugin, Kinotic, JsonEventFactory, IterablePage, Identifiable, IWebSocket, IServiceRegistry, IServiceProxy, IParticipant, IKinotic, IEventFactory, IEventBus, IEvent, IEditableDataSource, IDataSource, ICrudServiceProxyFactory, ICrudServiceProxy, FunctionalIterablePage, EventConstants, EventBus, Event, Direction, DefaultCRI, DataSourceUtils, CursorPageable, CrudServiceProxyFactory, CrudServiceProxy, ContextInterceptor, Context, ConnectionInfo, ConnectedInfo, CRI, CONTEXT_METADATA_KEY, AbstractIterablePage };
package/dist/index.d.ts CHANGED
@@ -133,12 +133,6 @@ declare class ConnectedInfo {
133
133
  participant: Participant;
134
134
  }
135
135
  /**
136
- * Base error class for all Kinoitc errors
137
- */
138
- declare class KinoticError extends Error {
139
- constructor(message: string);
140
- }
141
- /**
142
136
  * Part of the low level portion of kinoitc representing data to be processed
143
137
  *
144
138
  * This is similar to a Stomp Frame but with more required information and no control plane semantics.
@@ -205,7 +199,7 @@ interface IEventBus {
205
199
  * Any errors emitted by this observable will be fatal and the connection will be closed.
206
200
  * You will need to resolve the problem and reconnect.
207
201
  */
208
- fatalErrors: Observable<KinoticError>;
202
+ fatalErrors: Observable<Error>;
209
203
  /**
210
204
  * The {@link ServerInfo} used when connecting, if connected or null
211
205
  */
@@ -1036,12 +1030,6 @@ declare class FunctionalIterablePage<T> extends AbstractIterablePage<T> {
1036
1030
  constructor(pageable: Pageable, page: Page<T>, pageFunction: (pageable: Pageable) => Promise<Page<T>>);
1037
1031
  protected findNext(pageable: Pageable): Promise<Page<T>>;
1038
1032
  }
1039
- declare class AuthenticationError extends KinoticError {
1040
- constructor(message: string);
1041
- }
1042
- declare class AuthorizationError extends KinoticError {
1043
- constructor(message: string);
1044
- }
1045
1033
  /**
1046
1034
  * Default implementation of the `CRI` interface.
1047
1035
  *
@@ -1094,16 +1082,14 @@ declare class Event implements IEvent {
1094
1082
  * Default implementation of {@link IEventBus}
1095
1083
  */
1096
1084
  declare class EventBus implements IEventBus {
1097
- fatalErrors: Observable3<Error>;
1098
1085
  serverInfo: ServerInfo | null;
1099
1086
  private stompConnectionManager;
1100
1087
  private replyToCri;
1101
1088
  private requestRepliesObservable;
1102
1089
  private requestRepliesSubject;
1103
1090
  private requestRepliesSubscription;
1104
- private errorSubject;
1105
- private errorSubjectSubscription;
1106
1091
  constructor();
1092
+ get fatalErrors(): Observable3<Error>;
1107
1093
  isConnectionActive(): boolean;
1108
1094
  isConnected(): boolean;
1109
1095
  connect(connectionInfo: ConnectionInfo): Promise<ConnectedInfo>;
@@ -1144,4 +1130,4 @@ declare class ParticipantConstants {
1144
1130
  static readonly PARTICIPANT_TYPE_NODE: string;
1145
1131
  static readonly CLI_PARTICIPANT_ID: string;
1146
1132
  }
1147
- export { createCRI, WebSocketFactory, Version, TextEventFactory, Sort, SessionKeepAliveMode, ServiceRegistry, ServiceContext, ServerInfo, Scope, Publish, ParticipantConstants, Participant, Pageable, Page, Order, OffsetPageable, NullHandling, KinoticSingleton, KinoticPlugin, KinoticError, Kinotic, JsonEventFactory, IterablePage, Identifiable, IWebSocket, IServiceRegistry, IServiceProxy, IParticipant, IKinotic, IEventFactory, IEventBus, IEvent, IEditableDataSource, IDataSource, ICrudServiceProxyFactory, ICrudServiceProxy, FunctionalIterablePage, EventConstants, EventBus, Event, Direction, DefaultCRI, DataSourceUtils, CursorPageable, CrudServiceProxyFactory, CrudServiceProxy, ContextInterceptor, Context, ConnectionInfo, ConnectedInfo, CRI, CONTEXT_METADATA_KEY, AuthorizationError, AuthenticationError, AbstractIterablePage };
1133
+ export { createCRI, WebSocketFactory, Version, TextEventFactory, Sort, SessionKeepAliveMode, ServiceRegistry, ServiceContext, ServerInfo, Scope, Publish, ParticipantConstants, Participant, Pageable, Page, Order, OffsetPageable, NullHandling, KinoticSingleton, KinoticPlugin, Kinotic, JsonEventFactory, IterablePage, Identifiable, IWebSocket, IServiceRegistry, IServiceProxy, IParticipant, IKinotic, IEventFactory, IEventBus, IEvent, IEditableDataSource, IDataSource, ICrudServiceProxyFactory, ICrudServiceProxy, FunctionalIterablePage, EventConstants, EventBus, Event, Direction, DefaultCRI, DataSourceUtils, CursorPageable, CrudServiceProxyFactory, CrudServiceProxy, ContextInterceptor, Context, ConnectionInfo, ConnectedInfo, CRI, CONTEXT_METADATA_KEY, AbstractIterablePage };
package/dist/index.js CHANGED
@@ -19,14 +19,6 @@ class ConnectionInfo extends ServerInfo {
19
19
  maxConnectionAttempts;
20
20
  sessionKeepAlive = "ACTIVITY" /* ACTIVITY */;
21
21
  }
22
- // packages/core/src/api/errors/KinoticError.ts
23
- class KinoticError extends Error {
24
- constructor(message) {
25
- super(message);
26
- Object.setPrototypeOf(this, KinoticError.prototype);
27
- }
28
- }
29
-
30
22
  // packages/core/src/api/event/IEventBus.ts
31
23
  var EventConstants;
32
24
  ((EventConstants2) => {
@@ -59,32 +51,38 @@ var EventConstants;
59
51
  import { RxStomp } from "@stomp/rx-stomp";
60
52
  import { ReconnectionTimeMode } from "@stomp/stompjs";
61
53
  import debug from "debug";
54
+ import { Subject } from "rxjs";
62
55
  import { v4 as uuidv4 } from "uuid";
63
56
 
64
57
  class StompConnectionManager {
65
58
  lastWebsocketError = null;
66
59
  maxConnectionAttemptsReached = false;
60
+ replyToCriChangedHandler = null;
67
61
  rxStomp = null;
68
62
  INITIAL_RECONNECT_DELAY = 2000;
69
- MAX_RECONNECT_DELAY = 120000;
70
63
  JITTER_MAX = 5000;
64
+ MAX_RECONNECT_DELAY = 120000;
71
65
  connectionAttempts = 0;
72
- initialConnectionSuccessful = false;
73
66
  debugLogger = debug("kinoitc:stomp");
67
+ fatalErrorsSubject = new Subject;
68
+ _fatalErrors = this.fatalErrorsSubject.asObservable();
69
+ initialConnectionSuccessful = false;
70
+ serverHeadersSubscription = null;
71
+ stompErrorsSubscription = null;
74
72
  uuidv4 = uuidv4();
75
73
  _replyToCri = null;
76
- serverHeadersSubscription = null;
77
- deactivationHandler = null;
78
- replyToCriChangedHandler = null;
79
- get active() {
80
- return !!this.rxStomp;
81
- }
82
74
  get replyToCri() {
83
75
  return this._replyToCri;
84
76
  }
77
+ get active() {
78
+ return !!this.rxStomp;
79
+ }
85
80
  get connected() {
86
81
  return this.rxStomp != null && this.rxStomp.connected();
87
82
  }
83
+ get fatalErrors() {
84
+ return this._fatalErrors;
85
+ }
88
86
  activate(connectionInfo) {
89
87
  return new Promise((resolve, reject) => {
90
88
  if (!connectionInfo) {
@@ -103,9 +101,6 @@ class StompConnectionManager {
103
101
  this.initialConnectionSuccessful = false;
104
102
  this.lastWebsocketError = null;
105
103
  this.maxConnectionAttemptsReached = false;
106
- this._replyToCri = null;
107
- this.serverHeadersSubscription?.unsubscribe();
108
- this.serverHeadersSubscription = null;
109
104
  const url = "ws" + (connectionInfo.useSSL ? "s" : "") + "://" + connectionInfo.host + (connectionInfo.port ? ":" + connectionInfo.port : "") + "/v1";
110
105
  this.rxStomp = new RxStomp;
111
106
  let preparedSocket = null;
@@ -118,17 +113,15 @@ class StompConnectionManager {
118
113
  heartbeatIncoming: 120000,
119
114
  heartbeatOutgoing: 30000,
120
115
  reconnectDelay: this.INITIAL_RECONNECT_DELAY,
116
+ maxReconnectDelay: this.MAX_RECONNECT_DELAY,
117
+ reconnectTimeMode: ReconnectionTimeMode.EXPONENTIAL,
121
118
  webSocketFactory: userWebSocketFactory ? () => preparedSocket : undefined,
122
119
  beforeConnect: async () => {
123
120
  if (connectionInfo?.maxConnectionAttempts) {
124
121
  this.connectionAttempts++;
125
122
  if (this.connectionAttempts > connectionInfo.maxConnectionAttempts) {
126
123
  this.maxConnectionAttemptsReached = true;
127
- await this.deactivate();
128
- if (!this.initialConnectionSuccessful) {
129
- let message = this.lastWebsocketError?.message ? this.lastWebsocketError?.message : "UNKNOWN";
130
- reject(`Max number of reconnection attempts reached. Last WS Error ${message}`);
131
- }
124
+ await this.signalFatal(new Error("Max number of reconnection attempts reached", { cause: this.lastWebsocketError ?? undefined }));
132
125
  return;
133
126
  } else {
134
127
  await this.connectionJitterDelay();
@@ -140,10 +133,7 @@ class StompConnectionManager {
140
133
  try {
141
134
  preparedSocket = await userWebSocketFactory();
142
135
  } catch (e) {
143
- await this.deactivate();
144
- if (!this.initialConnectionSuccessful) {
145
- reject(e);
146
- }
136
+ await this.signalFatal(new Error("WebSocket factory failed", { cause: e }));
147
137
  }
148
138
  }
149
139
  }
@@ -154,42 +144,44 @@ class StompConnectionManager {
154
144
  };
155
145
  }
156
146
  this.rxStomp.configure(stompConfig);
157
- this.rxStomp.stompClient.maxReconnectDelay = this.MAX_RECONNECT_DELAY;
158
- this.rxStomp.stompClient.reconnectTimeMode = ReconnectionTimeMode.EXPONENTIAL;
159
147
  this.rxStomp.webSocketErrors$.subscribe((value) => {
160
148
  this.lastWebsocketError = value;
161
149
  });
150
+ this.stompErrorsSubscription = this.rxStomp.stompErrors$.subscribe(async (frame) => {
151
+ const stompError = new Error(frame.headers["message"], { cause: frame });
152
+ await this.signalFatal(new Error("STOMP connection error", { cause: stompError }));
153
+ });
162
154
  const connectedSubscription = this.rxStomp.connected$.subscribe(() => {
163
155
  connectedSubscription.unsubscribe();
156
+ initialFailureSubscription.unsubscribe();
164
157
  if (!this.initialConnectionSuccessful) {
165
158
  this.initialConnectionSuccessful = true;
166
159
  }
167
160
  });
168
- const errorSubscription = this.rxStomp.stompErrors$.subscribe((value) => {
169
- errorSubscription.unsubscribe();
170
- const message = value.headers["message"];
171
- this.rxStomp?.deactivate();
172
- this.rxStomp = null;
173
- reject(message);
161
+ const initialFailureSubscription = this.fatalErrorsSubject.subscribe((err) => {
162
+ connectedSubscription.unsubscribe();
163
+ initialFailureSubscription.unsubscribe();
164
+ reject(err.message);
174
165
  });
175
- this.serverHeadersSubscription = this.rxStomp.serverHeaders$.subscribe((value) => {
166
+ this.serverHeadersSubscription = this.rxStomp.serverHeaders$.subscribe(async (value) => {
176
167
  const connectedInfoJson = value["connected-info" /* CONNECTED_INFO_HEADER */];
177
- const firstConnect = this._replyToCri == null;
178
168
  if (connectedInfoJson == null) {
179
- if (firstConnect) {
169
+ if (!this.initialConnectionSuccessful) {
170
+ await this.deactivate();
180
171
  reject("Server did not return proper data for successful login");
181
172
  }
182
173
  return;
183
174
  }
184
175
  const connectedInfo = JSON.parse(connectedInfoJson);
185
176
  if (connectedInfo.replyToId == null) {
186
- if (firstConnect) {
177
+ if (!this.initialConnectionSuccessful) {
178
+ await this.deactivate();
187
179
  reject("Server did not return a replyToId for successful login");
188
180
  }
189
181
  return;
190
182
  }
191
183
  const newReplyToCri = "reply://" /* REPLY_DESTINATION_PREFIX */ + connectedInfo.replyToId + ":" + this.uuidv4 + "@kinoitc.js.EventBus/replyHandler";
192
- if (firstConnect) {
184
+ if (!this.initialConnectionSuccessful) {
193
185
  this._replyToCri = newReplyToCri;
194
186
  resolve(connectedInfo);
195
187
  } else if (this._replyToCri !== newReplyToCri) {
@@ -205,10 +197,10 @@ class StompConnectionManager {
205
197
  await this.rxStomp.deactivate({ force });
206
198
  this.serverHeadersSubscription?.unsubscribe();
207
199
  this.serverHeadersSubscription = null;
208
- if (this.deactivationHandler) {
209
- this.deactivationHandler();
210
- }
200
+ this.stompErrorsSubscription?.unsubscribe();
201
+ this.stompErrorsSubscription = null;
211
202
  this.rxStomp = null;
203
+ this._replyToCri = null;
212
204
  }
213
205
  return;
214
206
  }
@@ -219,11 +211,18 @@ class StompConnectionManager {
219
211
  return new Promise((resolve) => setTimeout(resolve, randomJitter));
220
212
  }
221
213
  }
214
+ async signalFatal(err) {
215
+ if (console) {
216
+ console.error("StompConnectionManager fatal error, deactivating connection", err);
217
+ }
218
+ await this.deactivate();
219
+ this.fatalErrorsSubject.next(err);
220
+ }
222
221
  }
223
222
 
224
223
  // packages/core/src/api/event/EventBus.ts
225
224
  import { context, propagation } from "@opentelemetry/api";
226
- import { firstValueFrom, Observable, Subject, throwError } from "rxjs";
225
+ import { firstValueFrom, Observable as Observable2, Subject as Subject2, throwError } from "rxjs";
227
226
  import { filter, map, multicast } from "rxjs/operators";
228
227
  import { Optional } from "typescript-optional";
229
228
  import { v4 as uuidv42 } from "uuid";
@@ -264,32 +263,22 @@ class Event {
264
263
  }
265
264
 
266
265
  class EventBus {
267
- fatalErrors;
268
266
  serverInfo = null;
269
267
  stompConnectionManager = new StompConnectionManager;
270
268
  replyToCri = null;
271
269
  requestRepliesObservable = null;
272
270
  requestRepliesSubject = null;
273
271
  requestRepliesSubscription = null;
274
- errorSubject = new Subject;
275
- errorSubjectSubscription = null;
276
272
  constructor() {
277
- this.fatalErrors = this.errorSubject.pipe(map((frame) => {
278
- this.disconnect().catch((error) => {
279
- if (console) {
280
- console.error("Error disconnecting from Stomp: " + error);
281
- }
282
- });
283
- return new KinoticError(frame.headers["message"]);
284
- }));
285
- this.stompConnectionManager.deactivationHandler = () => {
286
- this.cleanup();
287
- };
273
+ this.stompConnectionManager.fatalErrors.subscribe(() => this.cleanup());
288
274
  this.stompConnectionManager.replyToCriChangedHandler = (replyToCri) => {
289
275
  this.replyToCri = replyToCri;
290
276
  this.resetRequestReplies("Reply destination changed");
291
277
  };
292
278
  }
279
+ get fatalErrors() {
280
+ return this.stompConnectionManager.fatalErrors;
281
+ }
293
282
  isConnectionActive() {
294
283
  return this.stompConnectionManager.active;
295
284
  }
@@ -305,7 +294,6 @@ class EventBus {
305
294
  this.serverInfo.port = connectionInfo.port;
306
295
  this.serverInfo.useSSL = connectionInfo.useSSL;
307
296
  this.replyToCri = this.stompConnectionManager.replyToCri;
308
- this.errorSubjectSubscription = this.stompConnectionManager.rxStomp?.stompErrors$.subscribe(this.errorSubject);
309
297
  return connectedInfo;
310
298
  } else {
311
299
  throw new Error("Event Bus connection already active");
@@ -343,9 +331,9 @@ class EventBus {
343
331
  }
344
332
  requestStream(event, sendControlEvents = true) {
345
333
  if (this.stompConnectionManager?.rxStomp) {
346
- return new Observable((subscriber) => {
334
+ return new Observable2((subscriber) => {
347
335
  if (this.requestRepliesObservable == null) {
348
- this.requestRepliesSubject = new Subject;
336
+ this.requestRepliesSubject = new Subject2;
349
337
  this.requestRepliesObservable = this._observe(this.replyToCri).pipe(multicast(this.requestRepliesSubject));
350
338
  this.requestRepliesSubscription = this.requestRepliesObservable.connect();
351
339
  }
@@ -401,10 +389,6 @@ class EventBus {
401
389
  }
402
390
  cleanup() {
403
391
  this.resetRequestReplies("Connection disconnected");
404
- if (this.errorSubjectSubscription) {
405
- this.errorSubjectSubscription.unsubscribe();
406
- this.errorSubjectSubscription = null;
407
- }
408
392
  this.serverInfo = null;
409
393
  }
410
394
  resetRequestReplies(reason) {
@@ -903,7 +887,7 @@ import { first, map as map2 } from "rxjs/operators";
903
887
  // packages/core/package.json
904
888
  var package_default = {
905
889
  name: "@kinotic-ai/core",
906
- version: "1.3.1",
890
+ version: "1.4.1",
907
891
  type: "module",
908
892
  files: [
909
893
  "dist"
@@ -960,7 +944,7 @@ var package_default = {
960
944
  dependencies: {
961
945
  "@opentelemetry/api": "^1.9.1",
962
946
  "@opentelemetry/semantic-conventions": "^1.40.0",
963
- "@stomp/rx-stomp": "^2.3.0",
947
+ "@stomp/rx-stomp": "^2.4.0",
964
948
  "@stomp/stompjs": "^7.3.0",
965
949
  "@types/debug": "^4.1.13",
966
950
  debug: "^4.4.3",
@@ -1381,20 +1365,6 @@ class Order {
1381
1365
  class Sort {
1382
1366
  orders = [];
1383
1367
  }
1384
- // packages/core/src/api/errors/AuthenticationError.ts
1385
- class AuthenticationError extends KinoticError {
1386
- constructor(message) {
1387
- super(message);
1388
- Object.setPrototypeOf(this, AuthenticationError.prototype);
1389
- }
1390
- }
1391
- // packages/core/src/api/errors/AuthorizationError.ts
1392
- class AuthorizationError extends KinoticError {
1393
- constructor(message) {
1394
- super(message);
1395
- Object.setPrototypeOf(this, AuthorizationError.prototype);
1396
- }
1397
- }
1398
1368
  // packages/core/src/api/security/ConnectedInfo.ts
1399
1369
  class ConnectedInfo {
1400
1370
  replyToId;
@@ -1443,7 +1413,6 @@ export {
1443
1413
  OffsetPageable,
1444
1414
  NullHandling,
1445
1415
  KinoticSingleton,
1446
- KinoticError,
1447
1416
  Kinotic,
1448
1417
  JsonEventFactory,
1449
1418
  FunctionalIterablePage,
@@ -1460,7 +1429,5 @@ export {
1460
1429
  ConnectionInfo,
1461
1430
  ConnectedInfo,
1462
1431
  CONTEXT_METADATA_KEY,
1463
- AuthorizationError,
1464
- AuthenticationError,
1465
1432
  AbstractIterablePage
1466
1433
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kinotic-ai/core",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -57,7 +57,7 @@
57
57
  "dependencies": {
58
58
  "@opentelemetry/api": "^1.9.1",
59
59
  "@opentelemetry/semantic-conventions": "^1.40.0",
60
- "@stomp/rx-stomp": "^2.3.0",
60
+ "@stomp/rx-stomp": "^2.4.0",
61
61
  "@stomp/stompjs": "^7.3.0",
62
62
  "@types/debug": "^4.1.13",
63
63
  "debug": "^4.4.3",