@cratis/arc 22.125.3 → 22.126.0

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.
Files changed (30) hide show
  1. package/dist/cjs/queries/ServerSentEventHubConnection.d.ts +1 -0
  2. package/dist/cjs/queries/ServerSentEventHubConnection.d.ts.map +1 -1
  3. package/dist/cjs/queries/ServerSentEventHubConnection.js +23 -0
  4. package/dist/cjs/queries/ServerSentEventHubConnection.js.map +1 -1
  5. package/dist/cjs/queries/WebSocketHubConnection.d.ts +1 -0
  6. package/dist/cjs/queries/WebSocketHubConnection.d.ts.map +1 -1
  7. package/dist/cjs/queries/WebSocketHubConnection.js +26 -0
  8. package/dist/cjs/queries/WebSocketHubConnection.js.map +1 -1
  9. package/dist/esm/queries/ServerSentEventHubConnection.d.ts +1 -0
  10. package/dist/esm/queries/ServerSentEventHubConnection.d.ts.map +1 -1
  11. package/dist/esm/queries/ServerSentEventHubConnection.js +23 -0
  12. package/dist/esm/queries/ServerSentEventHubConnection.js.map +1 -1
  13. package/dist/esm/queries/WebSocketHubConnection.d.ts +1 -0
  14. package/dist/esm/queries/WebSocketHubConnection.d.ts.map +1 -1
  15. package/dist/esm/queries/WebSocketHubConnection.js +26 -0
  16. package/dist/esm/queries/WebSocketHubConnection.js.map +1 -1
  17. package/dist/esm/queries/for_ServerSentEventHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.d.ts +2 -0
  18. package/dist/esm/queries/for_ServerSentEventHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.d.ts.map +1 -0
  19. package/dist/esm/queries/for_ServerSentEventHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.js +69 -0
  20. package/dist/esm/queries/for_ServerSentEventHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.js.map +1 -0
  21. package/dist/esm/queries/for_WebSocketHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.d.ts +2 -0
  22. package/dist/esm/queries/for_WebSocketHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.d.ts.map +1 -0
  23. package/dist/esm/queries/for_WebSocketHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.js +68 -0
  24. package/dist/esm/queries/for_WebSocketHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.js.map +1 -0
  25. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  26. package/package.json +1 -1
  27. package/queries/ServerSentEventHubConnection.ts +21 -0
  28. package/queries/WebSocketHubConnection.ts +21 -0
  29. package/queries/for_ServerSentEventHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.ts +80 -0
  30. package/queries/for_WebSocketHubConnection/when_receiving_an_error_message/and_the_query_is_subscribed.ts +79 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@cratis/arc",
4
- "version": "22.125.3",
4
+ "version": "22.126.0",
5
5
  "description": "TypeScript command, query, validation, identity, and messaging runtime for Cratis Arc — the CQRS application framework for ASP.NET Core — used by generated proxies.",
6
6
  "keywords": [
7
7
  "cratis",
@@ -333,6 +333,7 @@ export class ServerSentEventHubConnection implements IObservableQueryHubConnecti
333
333
  message.queryId,
334
334
  message.payload,
335
335
  );
336
+ this.handleError(message);
336
337
  }
337
338
  break;
338
339
  }
@@ -394,6 +395,26 @@ export class ServerSentEventHubConnection implements IObservableQueryHubConnecti
394
395
  this.deliverResult(message, result, result?.isValid === false);
395
396
  }
396
397
 
398
+ private handleError(message: HubMessage): void {
399
+ const result = new QueryResult(
400
+ {
401
+ data: undefined,
402
+ isSuccess: false,
403
+ isReady: true,
404
+ isAuthorized: true,
405
+ isValid: true,
406
+ hasExceptions: true,
407
+ validationResults: [],
408
+ exceptionMessages: [message.payload as string],
409
+ exceptionStackTrace: '',
410
+ paging: { totalItems: 0, totalPages: 0, page: 0, size: 0 },
411
+ },
412
+ Object,
413
+ false,
414
+ );
415
+ this.deliverResult(message, result, false);
416
+ }
417
+
397
418
  private handleUnauthorized(message: HubMessage): void {
398
419
  this.deliverResult(message, QueryResult.unauthorized(), true);
399
420
  }
@@ -372,6 +372,7 @@ export class WebSocketHubConnection {
372
372
  message.queryId,
373
373
  message.payload,
374
374
  );
375
+ this.handleError(message);
375
376
  }
376
377
  break;
377
378
  }
@@ -408,6 +409,26 @@ export class WebSocketHubConnection {
408
409
  sub.callback(result);
409
410
  }
410
411
 
412
+ private handleError(message: HubMessage): void {
413
+ const result = new QueryResult(
414
+ {
415
+ data: undefined,
416
+ isSuccess: false,
417
+ isReady: true,
418
+ isAuthorized: true,
419
+ isValid: true,
420
+ hasExceptions: true,
421
+ validationResults: [],
422
+ exceptionMessages: [message.payload as string],
423
+ exceptionStackTrace: '',
424
+ paging: { totalItems: 0, totalPages: 0, page: 0, size: 0 },
425
+ },
426
+ Object,
427
+ false,
428
+ );
429
+ this.handleQueryResult({ ...message, payload: result });
430
+ }
431
+
411
432
  private handleUnauthorized(message: HubMessage): void {
412
433
  if (!message.queryId) return;
413
434
 
@@ -0,0 +1,80 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import sinon from 'sinon';
5
+ import { a_server_sent_event_hub_connection } from '../given/a_server_sent_event_hub_connection.js';
6
+ import { given } from '../../../given.js';
7
+ import { HubMessageType } from '../../WebSocketHubConnection.js';
8
+ import { QueryResult } from '../../QueryResult.js';
9
+
10
+ for (const supportsRevisions of [false, true]) {
11
+ describe(
12
+ `when receiving an SSE query error with revision support ${supportsRevisions}`,
13
+ given(a_server_sent_event_hub_connection, (context) => {
14
+ const queryId = 'query-failed';
15
+ const failure = 'MongoDB is unreachable.';
16
+ let callback: sinon.SinonStub;
17
+ let otherCallback: sinon.SinonStub;
18
+ let result: QueryResult<unknown>;
19
+ let revision: number | undefined;
20
+
21
+ beforeEach(() => {
22
+ context.setup();
23
+ sinon.stub(console, 'error');
24
+ callback = sinon.stub();
25
+ otherCallback = sinon.stub();
26
+ context.connection.subscribe(queryId, { queryName: 'Authors' }, callback);
27
+ context.simulateOpen();
28
+ context.simulateMessage({
29
+ type: HubMessageType.Connected,
30
+ payload: 'connection-a',
31
+ supportsSubscriptionRevisions: supportsRevisions,
32
+ });
33
+ try {
34
+ revision = (JSON.parse(context.fetchStub.firstCall.args[1].body as string) as { revision?: number }).revision;
35
+ } catch (error) {
36
+ throw new Error('Expected a valid subscribe body', { cause: error });
37
+ }
38
+ context.connection.subscribe('other-query', { queryName: 'Other' }, otherCallback);
39
+
40
+ context.simulateMessage({ type: HubMessageType.Error, queryId, revision, payload: failure });
41
+
42
+ result = callback.firstCall?.args[0] as QueryResult<unknown>;
43
+ });
44
+
45
+ afterEach(() => {
46
+ context.connection.dispose();
47
+ sinon.restore();
48
+ });
49
+
50
+ it('should deliver one QueryResult to the subscriber', () => {
51
+ callback.calledOnce.should.be.true;
52
+ result.should.be.instanceOf(QueryResult);
53
+ });
54
+ it('should report a ready failed result', () => {
55
+ result.isReady.should.be.true;
56
+ result.isSuccess.should.be.false;
57
+ result.hasExceptions.should.be.true;
58
+ });
59
+ it('should carry the server error message', () =>
60
+ result.exceptionMessages.should.deep.equal([failure]));
61
+ it('should not report a validation or authorization rejection', () => {
62
+ result.isValid.should.be.true;
63
+ result.isAuthorized.should.be.true;
64
+ });
65
+ it('should have no result data', () => result.hasData.should.be.false);
66
+ it('should not notify another query', () => otherCallback.called.should.be.false);
67
+ it('should retain subscriptions for later results', () => {
68
+ context.connection.queryCount.should.equal(2);
69
+ context.simulateMessage({
70
+ type: HubMessageType.QueryResult,
71
+ queryId,
72
+ revision,
73
+ payload: { isSuccess: true, data: ['recovered'] },
74
+ });
75
+ callback.calledTwice.should.be.true;
76
+ callback.secondCall.args[0].isSuccess.should.be.true;
77
+ });
78
+ }),
79
+ );
80
+ }
@@ -0,0 +1,79 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import sinon from 'sinon';
5
+ import { a_web_socket_hub_connection } from '../given/a_web_socket_hub_connection.js';
6
+ import { given } from '../../../given.js';
7
+ import { HubMessageType } from '../../WebSocketHubConnection.js';
8
+ import { QueryResult } from '../../QueryResult.js';
9
+
10
+ for (const supportsRevisions of [false, true]) {
11
+ describe(
12
+ `when receiving a WebSocket query error with revision support ${supportsRevisions}`,
13
+ given(a_web_socket_hub_connection, (context) => {
14
+ const queryId = 'query-failed';
15
+ const failure = 'MongoDB is unreachable.';
16
+ let callback: sinon.SinonStub;
17
+ let otherCallback: sinon.SinonStub;
18
+ let result: QueryResult<unknown>;
19
+ let revision: number | undefined;
20
+
21
+ beforeEach(() => {
22
+ context.setup();
23
+ sinon.stub(console, 'error');
24
+ callback = sinon.stub();
25
+ otherCallback = sinon.stub();
26
+ context.connection.subscribe(queryId, { queryName: 'Authors' }, callback);
27
+ context.simulateOpen();
28
+ context.simulateMessage({
29
+ type: HubMessageType.Connected,
30
+ supportsSubscriptionRevisions: supportsRevisions,
31
+ });
32
+ try {
33
+ revision = (JSON.parse(context.fakeSocket.send.lastCall.args[0] as string) as { revision?: number }).revision;
34
+ } catch (error) {
35
+ throw new Error('Expected a valid subscribe message', { cause: error });
36
+ }
37
+ context.connection.subscribe('other-query', { queryName: 'Other' }, otherCallback);
38
+
39
+ context.simulateMessage({ type: HubMessageType.Error, queryId, revision, payload: failure });
40
+
41
+ result = callback.firstCall?.args[0] as QueryResult<unknown>;
42
+ });
43
+
44
+ afterEach(() => {
45
+ context.connection.dispose();
46
+ sinon.restore();
47
+ });
48
+
49
+ it('should deliver one QueryResult to the subscriber', () => {
50
+ callback.calledOnce.should.be.true;
51
+ result.should.be.instanceOf(QueryResult);
52
+ });
53
+ it('should report a ready failed result', () => {
54
+ result.isReady.should.be.true;
55
+ result.isSuccess.should.be.false;
56
+ result.hasExceptions.should.be.true;
57
+ });
58
+ it('should carry the server error message', () =>
59
+ result.exceptionMessages.should.deep.equal([failure]));
60
+ it('should not report a validation or authorization rejection', () => {
61
+ result.isValid.should.be.true;
62
+ result.isAuthorized.should.be.true;
63
+ });
64
+ it('should have no result data', () => result.hasData.should.be.false);
65
+ it('should not notify another query', () => otherCallback.called.should.be.false);
66
+ it('should retain subscriptions for later results', () => {
67
+ context.connection.queryCount.should.equal(2);
68
+ context.simulateMessage({
69
+ type: HubMessageType.QueryResult,
70
+ queryId,
71
+ revision,
72
+ payload: { isSuccess: true, data: ['recovered'] },
73
+ });
74
+ callback.calledTwice.should.be.true;
75
+ callback.secondCall.args[0].isSuccess.should.be.true;
76
+ });
77
+ }),
78
+ );
79
+ }