@cratis/arc 20.63.0 → 20.64.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 (36) hide show
  1. package/EventSourceFactory.ts +12 -0
  2. package/Globals.ts +8 -0
  3. package/dist/cjs/Globals.js.map +1 -1
  4. package/dist/cjs/queries/ServerSentEventHubConnection.js +1 -1
  5. package/dist/cjs/queries/ServerSentEventHubConnection.js.map +1 -1
  6. package/dist/cjs/queries/ServerSentEventQueryConnection.js +6 -3
  7. package/dist/cjs/queries/ServerSentEventQueryConnection.js.map +1 -1
  8. package/dist/esm/EventSourceFactory.d.ts +2 -0
  9. package/dist/esm/EventSourceFactory.d.ts.map +1 -0
  10. package/dist/esm/EventSourceFactory.js +2 -0
  11. package/dist/esm/EventSourceFactory.js.map +1 -0
  12. package/dist/esm/Globals.d.ts +2 -0
  13. package/dist/esm/Globals.d.ts.map +1 -1
  14. package/dist/esm/Globals.js.map +1 -1
  15. package/dist/esm/index.d.ts +1 -0
  16. package/dist/esm/index.d.ts.map +1 -1
  17. package/dist/esm/queries/ServerSentEventHubConnection.js +1 -1
  18. package/dist/esm/queries/ServerSentEventHubConnection.js.map +1 -1
  19. package/dist/esm/queries/ServerSentEventQueryConnection.d.ts.map +1 -1
  20. package/dist/esm/queries/ServerSentEventQueryConnection.js +6 -3
  21. package/dist/esm/queries/ServerSentEventQueryConnection.js.map +1 -1
  22. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscribing/uses_custom_event_source_factory.d.ts +2 -0
  23. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscribing/uses_custom_event_source_factory.d.ts.map +1 -0
  24. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscribing/uses_custom_event_source_factory.js +38 -0
  25. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscribing/uses_custom_event_source_factory.js.map +1 -0
  26. package/dist/esm/queries/for_ServerSentEventQueryConnection/when_connecting/with_custom_event_source_factory.d.ts +2 -0
  27. package/dist/esm/queries/for_ServerSentEventQueryConnection/when_connecting/with_custom_event_source_factory.d.ts.map +1 -0
  28. package/dist/esm/queries/for_ServerSentEventQueryConnection/when_connecting/with_custom_event_source_factory.js +43 -0
  29. package/dist/esm/queries/for_ServerSentEventQueryConnection/when_connecting/with_custom_event_source_factory.js.map +1 -0
  30. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  31. package/index.ts +1 -0
  32. package/package.json +1 -1
  33. package/queries/ServerSentEventHubConnection.ts +1 -1
  34. package/queries/ServerSentEventQueryConnection.ts +5 -3
  35. package/queries/for_ServerSentEventHubConnection/when_subscribing/uses_custom_event_source_factory.ts +57 -0
  36. package/queries/for_ServerSentEventQueryConnection/when_connecting/with_custom_event_source_factory.ts +63 -0
package/index.ts CHANGED
@@ -13,6 +13,7 @@ export * from './deepEqual';
13
13
  export * from './Globals';
14
14
  export * from './ICanBeConfigured';
15
15
  export * from './GetHttpHeaders';
16
+ export * from './EventSourceFactory';
16
17
 
17
18
  export {
18
19
  commands,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratis/arc",
3
- "version": "20.63.0",
3
+ "version": "20.64.0",
4
4
  "description": "",
5
5
  "author": "Cratis",
6
6
  "license": "MIT",
@@ -192,7 +192,7 @@ export class ServerSentEventHubConnection implements IObservableQueryHubConnecti
192
192
  }
193
193
 
194
194
  this._connectionId = undefined;
195
- this._eventSource = new EventSource(url);
195
+ this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);
196
196
 
197
197
  this._eventSource.onopen = () => {
198
198
  if (this._disconnected) return;
@@ -1,6 +1,7 @@
1
1
  // Copyright (c) Cratis. All rights reserved.
2
2
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
3
 
4
+ import { Globals } from '../Globals';
4
5
  import { IObservableQueryConnection } from './IObservableQueryConnection';
5
6
  import { DataReceived } from './ObservableQueryConnection';
6
7
  import { QueryResult } from './QueryResult';
@@ -39,8 +40,9 @@ export class ServerSentEventQueryConnection<TDataType> implements IObservableQue
39
40
  connect(dataReceived: DataReceived<TDataType>, queryArguments?: object): void {
40
41
  if (this._disconnected) return;
41
42
 
42
- // Guard against environments where EventSource is not available (e.g. Node.js, SSR).
43
- if (typeof EventSource === 'undefined') {
43
+ // Guard against environments where EventSource is not available (e.g. Node.js, SSR)
44
+ // and no custom factory has been supplied to substitute it.
45
+ if (!Globals.eventSourceFactory && typeof EventSource === 'undefined') {
44
46
  return;
45
47
  }
46
48
 
@@ -56,7 +58,7 @@ export class ServerSentEventQueryConnection<TDataType> implements IObservableQue
56
58
  }
57
59
  }
58
60
 
59
- this._eventSource = new EventSource(url);
61
+ this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);
60
62
 
61
63
  this._eventSource.onmessage = (event: MessageEvent) => {
62
64
  if (this._disconnected) return;
@@ -0,0 +1,57 @@
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 { Globals } from '../../../Globals';
6
+ import { EventSourceFactory } from '../../../EventSourceFactory';
7
+ import { a_server_sent_event_hub_connection } from '../given/a_server_sent_event_hub_connection';
8
+ import { given } from '../../../given';
9
+ import { HubMessageType } from '../../WebSocketHubConnection';
10
+
11
+ interface FakeEventSource {
12
+ onopen: (() => void) | null;
13
+ onmessage: ((event: MessageEvent) => void) | null;
14
+ onerror: (() => void) | null;
15
+ close: sinon.SinonStub;
16
+ readyState: number;
17
+ }
18
+
19
+ describe('when subscribing with a custom event source factory configured', given(a_server_sent_event_hub_connection, context => {
20
+ let customEventSource: FakeEventSource;
21
+ let factoryStub: sinon.SinonStub;
22
+ let originalFactory: EventSourceFactory | undefined;
23
+
24
+ beforeEach(() => {
25
+ originalFactory = Globals.eventSourceFactory;
26
+
27
+ customEventSource = {
28
+ onopen: null,
29
+ onmessage: null,
30
+ onerror: null,
31
+ close: sinon.stub(),
32
+ readyState: 1, // OPEN
33
+ };
34
+ factoryStub = sinon.stub().returns(customEventSource);
35
+ Globals.eventSourceFactory = factoryStub as unknown as EventSourceFactory;
36
+
37
+ context.setup();
38
+ context.connection.subscribe('q1', { queryName: 'MyQuery' }, sinon.stub());
39
+ });
40
+
41
+ afterEach(() => {
42
+ Globals.eventSourceFactory = originalFactory;
43
+ sinon.restore();
44
+ });
45
+
46
+ it('should call the custom factory with the SSE hub url', () => factoryStub.calledOnce.should.be.true);
47
+ it('should pass the hub url to the factory', () => factoryStub.getCall(0).args[0].should.equal('http://localhost/.cratis/queries/sse'));
48
+ it('should not use the default global EventSource', () => (context.fakeEventSource.onopen === null).should.be.true);
49
+
50
+ describe('when the custom event source receives the Connected message', () => {
51
+ beforeEach(() => {
52
+ customEventSource.onmessage!({ data: JSON.stringify({ type: HubMessageType.Connected, payload: 'conn-1' }) } as MessageEvent);
53
+ });
54
+
55
+ it('should record the connection as open', () => context.connection.isConnected.should.be.true);
56
+ });
57
+ }));
@@ -0,0 +1,63 @@
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 { Globals } from '../../../Globals';
6
+ import { EventSourceFactory } from '../../../EventSourceFactory';
7
+ import { ServerSentEventQueryConnection } from '../../ServerSentEventQueryConnection';
8
+ import { QueryResult } from '../../QueryResult';
9
+
10
+ interface FakeEventSource {
11
+ onmessage: ((event: MessageEvent) => void) | null;
12
+ onerror: (() => void) | null;
13
+ close: sinon.SinonStub;
14
+ }
15
+
16
+ describe('when connecting with a custom event source factory configured and no global EventSource available', () => {
17
+ let originalEventSource: typeof EventSource;
18
+ let originalFactory: EventSourceFactory | undefined;
19
+ let fakeEventSource: FakeEventSource;
20
+ let factoryStub: sinon.SinonStub;
21
+ let connection: ServerSentEventQueryConnection<string[]>;
22
+ let receivedData: QueryResult<string[]>[];
23
+
24
+ beforeEach(() => {
25
+ originalEventSource = (globalThis as Record<string, unknown>)['EventSource'] as typeof EventSource;
26
+ delete (globalThis as Record<string, unknown>)['EventSource'];
27
+
28
+ originalFactory = Globals.eventSourceFactory;
29
+
30
+ fakeEventSource = {
31
+ onmessage: null,
32
+ onerror: null,
33
+ close: sinon.stub(),
34
+ };
35
+ factoryStub = sinon.stub().returns(fakeEventSource);
36
+ Globals.eventSourceFactory = factoryStub as unknown as EventSourceFactory;
37
+
38
+ receivedData = [];
39
+ connection = new ServerSentEventQueryConnection<string[]>(new URL('http://localhost/.cratis/queries/sse?query=Test'));
40
+ connection.connect((result: QueryResult<string[]>) => receivedData.push(result));
41
+ });
42
+
43
+ afterEach(() => {
44
+ if (originalEventSource !== undefined) {
45
+ (globalThis as Record<string, unknown>)['EventSource'] = originalEventSource;
46
+ }
47
+ Globals.eventSourceFactory = originalFactory;
48
+ sinon.restore();
49
+ });
50
+
51
+ it('should call the custom factory instead of the global EventSource constructor', () => factoryStub.calledOnce.should.be.true);
52
+ it('should pass the connection url to the factory', () => (factoryStub.getCall(0).args[0] as string).should.contain('/.cratis/queries/sse'));
53
+
54
+ describe('when a message arrives on the custom event source', () => {
55
+ const result = { data: ['a', 'b'], isSuccess: true, isAuthorized: true, isValid: true, hasExceptions: false, hasData: true, validationResults: [], exceptionMessages: [], exceptionStackTrace: '', paging: { page: 0, size: 0, totalItems: 0, totalPages: 0 } };
56
+
57
+ beforeEach(() => {
58
+ fakeEventSource.onmessage!({ data: JSON.stringify(result) } as MessageEvent);
59
+ });
60
+
61
+ it('should deliver the payload to the callback', () => receivedData.length.should.equal(1));
62
+ });
63
+ });