@cratis/arc 20.63.1 → 20.65.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
@@ -0,0 +1,12 @@
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
+ /**
5
+ * Represents a function that creates an {@link EventSource} for a given URL.
6
+ *
7
+ * Arc uses the global {@link EventSource} constructor by default. Provide a factory to
8
+ * substitute a custom implementation — for example a native SSE client on React Native,
9
+ * where {@link EventSource} is unavailable and JS-based polyfills built on
10
+ * `XMLHttpRequest` have unreliable streaming behavior on Android.
11
+ */
12
+ export type EventSourceFactory = (url: string) => EventSource;
package/Globals.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
3
 
4
4
  import { GetHttpHeaders } from './GetHttpHeaders';
5
+ import { EventSourceFactory } from './EventSourceFactory';
5
6
  import { QueryTransportMethod } from './queries/QueryTransportMethod';
6
7
  import { QueryHttpMethod } from './queries/QueryHttpMethod';
7
8
  import { QueryHttpMethodResolver } from './queries/QueryHttpMethodResolver';
@@ -67,6 +68,13 @@ export interface IGlobals {
67
68
  * (e.g. SSE subscribe/unsubscribe POST calls).
68
69
  */
69
70
  httpHeadersCallback: GetHttpHeaders;
71
+ /**
72
+ * Optional factory used to create the {@link EventSource} instances that back SSE
73
+ * observable query connections. Falls back to the global {@link EventSource}
74
+ * constructor when not set — override it to supply a custom SSE client (e.g. a
75
+ * native implementation on React Native, where the global constructor is unavailable).
76
+ */
77
+ eventSourceFactory?: EventSourceFactory;
70
78
  /**
71
79
  * How long in milliseconds to retain a query cache entry after the last subscriber
72
80
  * releases it before evicting the subscription and the cached data.
@@ -1 +1 @@
1
- {"version":3,"file":"Globals.js","sources":["../../Globals.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { GetHttpHeaders } from './GetHttpHeaders';\nimport { QueryTransportMethod } from './queries/QueryTransportMethod';\nimport { QueryHttpMethod } from './queries/QueryHttpMethod';\nimport { QueryHttpMethodResolver } from './queries/QueryHttpMethodResolver';\n\n/**\n * Defines the transfer mode used for observable query subscriptions.\n *\n * - {@link ObservableQueryTransferMode.Delta} (default): Only the items that changed since\n * the previous update (added, replaced, removed) are exposed via {@code useChangeStream}.\n * The full collection state is still maintained internally by {@code useObservableQuery}.\n *\n * - {@link ObservableQueryTransferMode.Full}: Every update delivers the complete current\n * collection. The change set returned by {@code useChangeStream} treats the entire new\n * collection as {@code added} and the previous collection as {@code removed}.\n */\nexport enum ObservableQueryTransferMode {\n /** Compute and expose only the items that changed since the previous update (default). */\n Delta = 'delta',\n /** Expose the full collection on every update. */\n Full = 'full',\n}\n\nexport interface IGlobals {\n microservice: string;\n apiBasePath: string;\n origin: string;\n microserviceHttpHeader: string;\n microserviceWSQueryArgument: string;\n queryTransportMethod: QueryTransportMethod;\n /**\n * The HTTP method used to perform non-streaming queries. Defaults to {@link QueryHttpMethod.Get}.\n * Set to {@link QueryHttpMethod.Query} to carry arguments in a JSON request body (RFC 10008)\n * instead of the URL query string. Individual queries can override this via {@code setHttpMethod}.\n */\n queryHttpMethod: QueryHttpMethod;\n /**\n * Optional per-query policy for choosing the query HTTP method from the request (e.g. by URL length).\n * Consulted only when a query has no explicit method set via {@code setHttpMethod}; it takes\n * precedence over {@link queryHttpMethod}. See {@link lengthBasedQueryHttpMethod} for a built-in.\n */\n queryHttpMethodResolver?: QueryHttpMethodResolver;\n /**\n * Number of hub connections maintained for observable queries.\n * When greater than one, queries are distributed across the pool round-robin.\n * Only applies when {@link queryTransportMethod} is a centralized hub transport.\n * Defaults to 1.\n */\n queryConnectionCount: number;\n /**\n * When true, observable queries connect directly to the per-query WebSocket URL\n * instead of routing through the centralized hub endpoint.\n * Defaults to false (use the centralized hub).\n */\n queryDirectMode: boolean;\n /**\n * Controls how observable query updates are transferred and exposed.\n * {@link ObservableQueryTransferMode.Delta} (default) computes per-update deltas;\n * {@link ObservableQueryTransferMode.Full} delivers the whole collection on every update.\n */\n observableQueryTransferMode: ObservableQueryTransferMode;\n /**\n * Callback that returns custom HTTP headers to include in hub transport requests\n * (e.g. SSE subscribe/unsubscribe POST calls).\n */\n httpHeadersCallback: GetHttpHeaders;\n /**\n * How long in milliseconds to retain a query cache entry after the last subscriber\n * releases it before evicting the subscription and the cached data.\n *\n * A non-zero value allows a user navigating away and back quickly to see cached\n * data immediately instead of waiting for a fresh server round-trip. The entry is\n * still evicted once the window expires, so memory is eventually reclaimed.\n *\n * Defaults to 30 000 ms (30 seconds). Set to 0 to restore the previous\n * immediate-eviction behaviour.\n */\n queryCacheRetentionMs: number;\n}\n\nexport const Globals: IGlobals = {\n microservice: '',\n apiBasePath: '',\n origin: '',\n microserviceHttpHeader: 'x-cratis-microservice',\n microserviceWSQueryArgument: 'x-cratis-microservice',\n queryTransportMethod: QueryTransportMethod.WebSocket,\n queryHttpMethod: QueryHttpMethod.Get,\n queryConnectionCount: 1,\n queryDirectMode: false,\n observableQueryTransferMode: ObservableQueryTransferMode.Delta,\n httpHeadersCallback: () => ({}),\n queryCacheRetentionMs: 30_000,\n};"],"names":["ObservableQueryTransferMode","Globals","microservice","apiBasePath","origin","microserviceHttpHeader","microserviceWSQueryArgument","queryTransportMethod","QueryTransportMethod","WebSocket","queryHttpMethod","QueryHttpMethod","Get","queryConnectionCount","queryDirectMode","observableQueryTransferMode","httpHeadersCallback","queryCacheRetentionMs"],"mappings":";;;;;AAAA;AACA;AAOA;;;;;;;;;;IAWO,IAAKA,2BAAAA,iBAAAA,SAAAA,2BAAAA,EAAAA;+FACgF,2BAAA,CAAA,OAAA,CAAA,GAAA,OAAA;uDAExC,2BAAA,CAAA,MAAA,CAAA,GAAA,MAAA;AAHxCA,IAAAA,OAAAA,2BAAAA;AAKX,CAAA,CAAA,EAAA;MA2DYC,OAAAA,GAAoB;IAC7BC,YAAAA,EAAc,EAAA;IACdC,WAAAA,EAAa,EAAA;IACbC,MAAAA,EAAQ,EAAA;IACRC,sBAAAA,EAAwB,uBAAA;IACxBC,2BAAAA,EAA6B,uBAAA;AAC7BC,IAAAA,oBAAAA,EAAsBC,0CAAqBC,SAAS;AACpDC,IAAAA,eAAAA,EAAiBC,gCAAgBC,GAAG;IACpCC,oBAAAA,EAAsB,CAAA;IACtBC,eAAAA,EAAiB,KAAA;IACjBC,2BAA2B,EAAA,OAAA;IAC3BC,mBAAAA,EAAqB,KAAO,EAAC,CAAA;IAC7BC,qBAAAA,EAAuB;AAC3B;;;;;"}
1
+ {"version":3,"file":"Globals.js","sources":["../../Globals.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { GetHttpHeaders } from './GetHttpHeaders';\nimport { EventSourceFactory } from './EventSourceFactory';\nimport { QueryTransportMethod } from './queries/QueryTransportMethod';\nimport { QueryHttpMethod } from './queries/QueryHttpMethod';\nimport { QueryHttpMethodResolver } from './queries/QueryHttpMethodResolver';\n\n/**\n * Defines the transfer mode used for observable query subscriptions.\n *\n * - {@link ObservableQueryTransferMode.Delta} (default): Only the items that changed since\n * the previous update (added, replaced, removed) are exposed via {@code useChangeStream}.\n * The full collection state is still maintained internally by {@code useObservableQuery}.\n *\n * - {@link ObservableQueryTransferMode.Full}: Every update delivers the complete current\n * collection. The change set returned by {@code useChangeStream} treats the entire new\n * collection as {@code added} and the previous collection as {@code removed}.\n */\nexport enum ObservableQueryTransferMode {\n /** Compute and expose only the items that changed since the previous update (default). */\n Delta = 'delta',\n /** Expose the full collection on every update. */\n Full = 'full',\n}\n\nexport interface IGlobals {\n microservice: string;\n apiBasePath: string;\n origin: string;\n microserviceHttpHeader: string;\n microserviceWSQueryArgument: string;\n queryTransportMethod: QueryTransportMethod;\n /**\n * The HTTP method used to perform non-streaming queries. Defaults to {@link QueryHttpMethod.Get}.\n * Set to {@link QueryHttpMethod.Query} to carry arguments in a JSON request body (RFC 10008)\n * instead of the URL query string. Individual queries can override this via {@code setHttpMethod}.\n */\n queryHttpMethod: QueryHttpMethod;\n /**\n * Optional per-query policy for choosing the query HTTP method from the request (e.g. by URL length).\n * Consulted only when a query has no explicit method set via {@code setHttpMethod}; it takes\n * precedence over {@link queryHttpMethod}. See {@link lengthBasedQueryHttpMethod} for a built-in.\n */\n queryHttpMethodResolver?: QueryHttpMethodResolver;\n /**\n * Number of hub connections maintained for observable queries.\n * When greater than one, queries are distributed across the pool round-robin.\n * Only applies when {@link queryTransportMethod} is a centralized hub transport.\n * Defaults to 1.\n */\n queryConnectionCount: number;\n /**\n * When true, observable queries connect directly to the per-query WebSocket URL\n * instead of routing through the centralized hub endpoint.\n * Defaults to false (use the centralized hub).\n */\n queryDirectMode: boolean;\n /**\n * Controls how observable query updates are transferred and exposed.\n * {@link ObservableQueryTransferMode.Delta} (default) computes per-update deltas;\n * {@link ObservableQueryTransferMode.Full} delivers the whole collection on every update.\n */\n observableQueryTransferMode: ObservableQueryTransferMode;\n /**\n * Callback that returns custom HTTP headers to include in hub transport requests\n * (e.g. SSE subscribe/unsubscribe POST calls).\n */\n httpHeadersCallback: GetHttpHeaders;\n /**\n * Optional factory used to create the {@link EventSource} instances that back SSE\n * observable query connections. Falls back to the global {@link EventSource}\n * constructor when not set — override it to supply a custom SSE client (e.g. a\n * native implementation on React Native, where the global constructor is unavailable).\n */\n eventSourceFactory?: EventSourceFactory;\n /**\n * How long in milliseconds to retain a query cache entry after the last subscriber\n * releases it before evicting the subscription and the cached data.\n *\n * A non-zero value allows a user navigating away and back quickly to see cached\n * data immediately instead of waiting for a fresh server round-trip. The entry is\n * still evicted once the window expires, so memory is eventually reclaimed.\n *\n * Defaults to 30 000 ms (30 seconds). Set to 0 to restore the previous\n * immediate-eviction behaviour.\n */\n queryCacheRetentionMs: number;\n}\n\nexport const Globals: IGlobals = {\n microservice: '',\n apiBasePath: '',\n origin: '',\n microserviceHttpHeader: 'x-cratis-microservice',\n microserviceWSQueryArgument: 'x-cratis-microservice',\n queryTransportMethod: QueryTransportMethod.WebSocket,\n queryHttpMethod: QueryHttpMethod.Get,\n queryConnectionCount: 1,\n queryDirectMode: false,\n observableQueryTransferMode: ObservableQueryTransferMode.Delta,\n httpHeadersCallback: () => ({}),\n queryCacheRetentionMs: 30_000,\n};"],"names":["ObservableQueryTransferMode","Globals","microservice","apiBasePath","origin","microserviceHttpHeader","microserviceWSQueryArgument","queryTransportMethod","QueryTransportMethod","WebSocket","queryHttpMethod","QueryHttpMethod","Get","queryConnectionCount","queryDirectMode","observableQueryTransferMode","httpHeadersCallback","queryCacheRetentionMs"],"mappings":";;;;;AAAA;AACA;AAQA;;;;;;;;;;IAWO,IAAKA,2BAAAA,iBAAAA,SAAAA,2BAAAA,EAAAA;+FACgF,2BAAA,CAAA,OAAA,CAAA,GAAA,OAAA;uDAExC,2BAAA,CAAA,MAAA,CAAA,GAAA,MAAA;AAHxCA,IAAAA,OAAAA,2BAAAA;AAKX,CAAA,CAAA,EAAA;MAkEYC,OAAAA,GAAoB;IAC7BC,YAAAA,EAAc,EAAA;IACdC,WAAAA,EAAa,EAAA;IACbC,MAAAA,EAAQ,EAAA;IACRC,sBAAAA,EAAwB,uBAAA;IACxBC,2BAAAA,EAA6B,uBAAA;AAC7BC,IAAAA,oBAAAA,EAAsBC,0CAAqBC,SAAS;AACpDC,IAAAA,eAAAA,EAAiBC,gCAAgBC,GAAG;IACpCC,oBAAAA,EAAsB,CAAA;IACtBC,eAAAA,EAAiB,KAAA;IACjBC,2BAA2B,EAAA,OAAA;IAC3BC,mBAAAA,EAAqB,KAAO,EAAC,CAAA;IAC7BC,qBAAAA,EAAuB;AAC3B;;;;;"}
@@ -161,7 +161,7 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
161
161
  url += (url.includes('?') ? '&' : '?') + param;
162
162
  }
163
163
  this._connectionId = undefined;
164
- this._eventSource = new EventSource(url);
164
+ this._eventSource = Globals.Globals.eventSourceFactory ? Globals.Globals.eventSourceFactory(url) : new EventSource(url);
165
165
  this._eventSource.onopen = ()=>{
166
166
  if (this._disconnected) return;
167
167
  console.log(`SSE hub connection established: '${url}'`);
@@ -1 +1 @@
1
- {"version":3,"file":"ServerSentEventHubConnection.js","sources":["../../../queries/ServerSentEventHubConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Globals } from '../Globals';\nimport { IObservableQueryHubConnection } from './IObservableQueryHubConnection';\nimport { DataReceived } from './ObservableQueryConnection';\nimport { HubConnectionKeepAlive } from './HubConnectionKeepAlive';\nimport { IReconnectPolicy } from './IReconnectPolicy';\nimport { ReconnectPolicy } from './ReconnectPolicy';\nimport { QueryResult } from './QueryResult';\nimport { HubMessage, HubMessageType, SubscriptionRequest } from './WebSocketHubConnection';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface ActiveSubscription {\n request: SubscriptionRequest;\n callback: DataReceived<any>;\n}\n\n/**\n * How many keep-alive intervals of silence are tolerated before the connection is considered dead.\n *\n * The server guarantees a message every interval, so this is pure slack for latency and jitter.\n * It must stay above 1 — a threshold at or below the server's own cadence makes the client and\n * server timers race, and the client tears down connections the server considers healthy.\n */\nconst IDLE_THRESHOLD_FACTOR = 2;\n\n/**\n * A multiplexed SSE hub connection that uses EventSource for server→client streaming\n * and fetch POST requests for client→server subscribe/unsubscribe commands.\n *\n * Protocol:\n * 1. Open EventSource to the SSE hub endpoint.\n * 2. Server sends a {@link HubMessageType.Connected} message with the connection identifier.\n * 3. Client sends POST to subscribe/unsubscribe endpoints using the connection identifier.\n * 4. Server streams {@link HubMessageType.QueryResult} messages tagged with queryId.\n * 5. When EventSource closes, server cleans up all subscriptions for this connection.\n */\nexport class ServerSentEventHubConnection implements IObservableQueryHubConnection {\n private _eventSource?: EventSource;\n private _connectionId?: string;\n private _disconnected = false;\n private _subscriptions: Map<string, ActiveSubscription> = new Map();\n private _pendingSubscriptions: Map<string, ActiveSubscription> = new Map();\n private _lastPongLatency: number = 0;\n private _latencySamples: number[] = [];\n private _connectTimeoutTimer?: ReturnType<typeof setTimeout>;\n private readonly _keepAlive: HubConnectionKeepAlive;\n\n /**\n * Initializes a new instance of {@link ServerSentEventHubConnection}.\n * @param {string} _sseUrl The SSE hub endpoint URL (e.g. `http://localhost:5000/.cratis/queries/sse`).\n * @param {string} _subscribeUrl The subscribe POST endpoint URL.\n * @param {string} _unsubscribeUrl The unsubscribe POST endpoint URL.\n * @param {string} _microservice The microservice name to pass as a query argument.\n * @param {number} keepAliveIntervalMs The keep-alive cadence to assume until the server advertises\n * its own on the {@link HubMessageType.Connected} message (default: 30 000 ms). The connection is\n * considered stale after {@link IDLE_THRESHOLD_FACTOR} times this without any server message.\n * @param {number} connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}\n * message after the HTTP connection opens before giving up and retrying (default: 15 000 ms).\n * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).\n */\n constructor(\n private readonly _sseUrl: string,\n private readonly _subscribeUrl: string,\n private readonly _unsubscribeUrl: string,\n private readonly _microservice: string,\n keepAliveIntervalMs: number = 30000,\n private readonly _connectTimeoutMs: number = 15000,\n private readonly _policy: IReconnectPolicy = new ReconnectPolicy()\n ) {\n // SSE is server→client only: the client cannot send pings. Instead we watch for\n // inactivity — if the server stops sending messages (including its own keep-alive\n // pings) for the entire idle threshold, the connection is stale and we reconnect.\n //\n // The server guarantees a message at least every keep-alive interval, so the threshold\n // only has to absorb network latency, timer jitter and server-side scheduling hiccups.\n // A hard TCP drop surfaces immediately through `onerror`, so this watchdog only needs to\n // catch silent black-holes — that makes a generous tolerance strictly better than a tight\n // one, which would tear down healthy connections.\n //\n // The interval below is only the starting assumption; the server advertises its real\n // cadence on the Connected message and {@link handleConnected} reconfigures from it.\n this._keepAlive = new HubConnectionKeepAlive(keepAliveIntervalMs, () => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n console.warn(`SSE hub: no messages received for ${this._keepAlive.idleThresholdMs}ms, reconnecting '${this._sseUrl}'`);\n this.reconnect();\n }\n }, keepAliveIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n /** @inheritdoc */\n get queryCount(): number {\n return this._subscriptions.size;\n }\n\n /** @inheritdoc */\n get isConnected(): boolean {\n return this._connectionId !== undefined && this._eventSource?.readyState === EventSource.OPEN;\n }\n\n /** @inheritdoc */\n get lastPingLatency(): number {\n return this._lastPongLatency;\n }\n\n /** @inheritdoc */\n get averageLatency(): number {\n if (this._latencySamples.length === 0) return 0;\n return this._latencySamples.reduce((a, b) => a + b, 0) / this._latencySamples.length;\n }\n\n /** @inheritdoc */\n subscribe(queryId: string, request: SubscriptionRequest, callback: DataReceived<any>): void {\n const sub: ActiveSubscription = { request, callback };\n this._subscriptions.set(queryId, sub);\n\n this.ensureConnected();\n\n if (this._connectionId) {\n this.sendSubscribe(queryId, request);\n } else {\n // Not yet connected, queue for when Connected message arrives.\n this._pendingSubscriptions.set(queryId, sub);\n }\n }\n\n /** @inheritdoc */\n unsubscribe(queryId: string): void {\n this._subscriptions.delete(queryId);\n this._pendingSubscriptions.delete(queryId);\n\n if (this._connectionId) {\n this.sendUnsubscribe(queryId);\n }\n\n if (this._subscriptions.size === 0) {\n this.close();\n }\n }\n\n /** @inheritdoc */\n dispose(): void {\n this._disconnected = true;\n this._subscriptions.clear();\n this._pendingSubscriptions.clear();\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private ensureConnected(): void {\n if (this._disconnected) {\n this._disconnected = false;\n }\n\n if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {\n return;\n }\n\n this.openEventSource();\n }\n\n private close(): void {\n this._disconnected = true;\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n if (this._eventSource) {\n // Detach all handlers BEFORE closing so that the async onerror / onmessage\n // events that fire after close() cannot observe the new _disconnected=false\n // state set by an immediately following ensureConnected() call. Without this,\n // a stale onerror triggers an unintended reconnect with exponential back-off.\n this._eventSource.onopen = null;\n this._eventSource.onmessage = null;\n this._eventSource.onerror = null;\n this._eventSource.close();\n }\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private openEventSource(): void {\n let url = this._sseUrl;\n if (this._microservice?.length > 0) {\n const param = `${Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;\n url += (url.includes('?') ? '&' : '?') + param;\n }\n\n this._connectionId = undefined;\n this._eventSource = new EventSource(url);\n\n this._eventSource.onopen = () => {\n if (this._disconnected) return;\n console.log(`SSE hub connection established: '${url}'`);\n this._policy.reset();\n this._keepAlive.start();\n\n // If the server does not send a Connected message within the timeout, the\n // connection is broken. Close and retry via the reconnect policy.\n this.clearConnectTimeout();\n this._connectTimeoutTimer = setTimeout(() => {\n if (!this._disconnected && !this._connectionId) {\n console.warn(`SSE hub: no Connected message within ${this._connectTimeoutMs}ms, retrying '${url}'`);\n this.reconnect();\n }\n }, this._connectTimeoutMs);\n };\n\n this._eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected) return;\n this._keepAlive.recordActivity();\n this.handleMessage(event.data as string);\n };\n\n this._eventSource.onerror = () => {\n if (this._disconnected) return;\n console.warn(`SSE hub connection error: '${url}'`);\n this.reconnect();\n };\n }\n\n private reconnect(): void {\n this._keepAlive.stop();\n this.clearConnectTimeout();\n\n // Close the EventSource so the reconnect policy manages the schedule.\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n\n // Move all active subscriptions to pending so they re-subscribe when\n // the next Connected message arrives after the managed reconnect.\n for (const [queryId, sub] of this._subscriptions) {\n this._pendingSubscriptions.set(queryId, sub);\n }\n\n if (this._subscriptions.size === 0) return;\n\n this._policy.schedule(() => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n this.openEventSource();\n }\n }, this._sseUrl);\n }\n\n private clearConnectTimeout(): void {\n if (this._connectTimeoutTimer !== undefined) {\n clearTimeout(this._connectTimeoutTimer);\n this._connectTimeoutTimer = undefined;\n }\n }\n\n private handleMessage(rawData: string): void {\n try {\n const message = JSON.parse(rawData) as HubMessage;\n\n switch (message.type) {\n case HubMessageType.Connected:\n this.handleConnected(message);\n break;\n case HubMessageType.QueryResult:\n this.handleQueryResult(message);\n break;\n case HubMessageType.Ping:\n // Server-sent keep-alive ping — activity already recorded in onmessage.\n break;\n case HubMessageType.Unauthorized:\n console.warn(`SSE hub: query '${message.queryId}' unauthorized`);\n this.handleUnauthorized(message);\n break;\n case HubMessageType.Error:\n console.error(`SSE hub: query '${message.queryId}' error:`, message.payload);\n break;\n }\n } catch (error) {\n console.error('SSE hub: error parsing message', error);\n }\n }\n\n private handleConnected(message: HubMessage): void {\n this._connectionId = message.payload as string;\n console.log(`SSE hub: connected with id '${this._connectionId}'`);\n\n // Connected message arrived — cancel the connect timeout.\n this.clearConnectTimeout();\n\n this.applyServerKeepAliveInterval(message.keepAliveIntervalMs);\n\n // Send all pending subscriptions now that we have a connection ID.\n for (const [queryId, sub] of this._pendingSubscriptions) {\n this.sendSubscribe(queryId, sub.request);\n }\n this._pendingSubscriptions.clear();\n }\n\n /**\n * Align the idle watchdog with the keep-alive cadence the server actually runs on.\n *\n * Without this the client assumes the default interval, so a server configured with a longer\n * interval — or with keep-alive switched off entirely — would look silent and be reconnected\n * on a loop even though it is perfectly healthy.\n * @param {number | undefined} serverIntervalMs The interval advertised by the server, if any.\n */\n private applyServerKeepAliveInterval(serverIntervalMs?: number): void {\n if (serverIntervalMs === undefined) return;\n\n // Keep-alive disabled server-side: silence is expected, so watching for it would guarantee\n // an endless reconnect loop. Hard drops still surface through `onerror`.\n if (serverIntervalMs <= 0) {\n this._keepAlive.stop();\n return;\n }\n\n this._keepAlive.reconfigure(serverIntervalMs, serverIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n private handleQueryResult(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n const result = message.payload as QueryResult<any>;\n sub.callback(result);\n }\n\n private handleUnauthorized(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n this._subscriptions.delete(message.queryId);\n this._pendingSubscriptions.delete(message.queryId);\n sub.callback(QueryResult.unauthorized());\n }\n\n private sendSubscribe(queryId: string, request: SubscriptionRequest, attempt: number = 0): void {\n if (!this._connectionId || this._disconnected) return;\n\n // Capture the connection ID so retries can detect if a reconnect has already fired\n // for a different reason and made this retry obsolete.\n const connectionId = this._connectionId;\n\n const body = {\n connectionId,\n queryId,\n request,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n // Maximum number of subscribe retries before falling back to a full SSE reconnect.\n // In a round-robin load-balanced deployment the subscribe POST may land on a different\n // backend instance than the one holding the SSE connection. Retrying gives the load\n // balancer the chance to route a subsequent attempt to the correct instance without\n // tearing down the SSE connection unnecessarily. With N backend instances at most\n // N-1 retries are needed, so 3 retries covers deployments with up to 4 replicas.\n const maxRetries = 3;\n const retryDelayMs = 200;\n\n fetch(this._subscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).then(response => {\n if (!response.ok) {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.warn(`SSE hub: subscribe POST for '${queryId}' returned ${response.status} after ${attempt + 1} attempt(s), reconnecting`);\n this.reconnect();\n }\n }\n }).catch(error => {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.error(`SSE hub: subscribe POST failed for '${queryId}' after ${attempt + 1} attempt(s), reconnecting`, error);\n this.reconnect();\n }\n });\n }\n\n private sendUnsubscribe(queryId: string): void {\n if (!this._connectionId) return;\n\n const body = {\n connectionId: this._connectionId,\n queryId,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n fetch(this._unsubscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).catch(error => {\n console.error(`SSE hub: unsubscribe POST failed for '${queryId}'`, error);\n });\n }\n}\n"],"names":["IDLE_THRESHOLD_FACTOR","ServerSentEventHubConnection","_eventSource","_connectionId","_disconnected","_subscriptions","Map","_pendingSubscriptions","_lastPongLatency","_latencySamples","_connectTimeoutTimer","_keepAlive","_subscribeUrl","_unsubscribeUrl","keepAliveIntervalMs","_connectTimeoutMs","_policy","ReconnectPolicy","_sseUrl","_microservice","HubConnectionKeepAlive","size","console","warn","idleThresholdMs","reconnect","queryCount","isConnected","undefined","readyState","EventSource","OPEN","lastPingLatency","averageLatency","length","reduce","a","b","subscribe","queryId","request","callback","sub","set","ensureConnected","sendSubscribe","unsubscribe","delete","sendUnsubscribe","close","dispose","clear","cancel","stop","clearConnectTimeout","CLOSED","openEventSource","onopen","onmessage","onerror","url","param","Globals","microserviceWSQueryArgument","encodeURIComponent","includes","log","reset","start","setTimeout","event","recordActivity","handleMessage","data","schedule","clearTimeout","rawData","message","JSON","parse","type","HubMessageType","Connected","handleConnected","QueryResult","handleQueryResult","Ping","Unauthorized","handleUnauthorized","Error","error","payload","applyServerKeepAliveInterval","serverIntervalMs","reconfigure","get","result","unauthorized","attempt","connectionId","body","customHeaders","httpHeadersCallback","maxRetries","retryDelayMs","fetch","method","headers","stringify","then","response","ok","status","catch"],"mappings":";;;;;;;;AAAA;AACA;AAkBA;;;;;;AAMC,IACD,MAAMA,qBAAAA,GAAwB,CAAA;AAE9B;;;;;;;;;;AAUC,IACM,MAAMC,4BAAAA,CAAAA;;;;;;;IACDC,YAAAA;IACAC,aAAAA;AACAC,IAAAA,aAAAA,GAAgB,KAAA;AAChBC,IAAAA,cAAAA,GAAkD,IAAIC,GAAAA,EAAAA;AACtDC,IAAAA,qBAAAA,GAAyD,IAAID,GAAAA,EAAAA;AAC7DE,IAAAA,gBAAAA,GAA2B,CAAA;AAC3BC,IAAAA,eAAAA,GAA4B,EAAE;IAC9BC,oBAAAA;IACSC,UAAAA;AAEjB;;;;;;;;;;;;QAaA,WAAA,CACI,OAAgC,EACfC,aAAqB,EACrBC,eAAuB,EACxC,aAAsC,EACtCC,mBAAAA,GAA8B,KAAK,EAClBC,iBAAAA,GAA4B,KAAK,EAClD,OAAiBC,GAA4B,IAAIC,+BAAAA,EAAiB,CACpE;aAPmBC,OAAAA,GAAAA,OAAAA;aACAN,aAAAA,GAAAA,aAAAA;aACAC,eAAAA,GAAAA,eAAAA;aACAM,aAAAA,GAAAA,aAAAA;aAEAJ,iBAAAA,GAAAA,iBAAAA;aACAC,OAAAA,GAAAA,OAAAA;;;;;;;;;;;;;AAcjB,QAAA,IAAI,CAACL,UAAU,GAAG,IAAIS,8CAAuBN,mBAAAA,EAAqB,IAAA;YAC9D,IAAI,CAAC,IAAI,CAACV,aAAa,IAAI,IAAI,CAACC,cAAc,CAACgB,IAAI,GAAG,CAAA,EAAG;AACrDC,gBAAAA,OAAAA,CAAQC,IAAI,CAAC,CAAC,kCAAkC,EAAE,IAAI,CAACZ,UAAU,CAACa,eAAe,CAAC,kBAAkB,EAAE,IAAI,CAACN,OAAO,CAAC,CAAC,CAAC,CAAA;AACrH,gBAAA,IAAI,CAACO,SAAS,EAAA;AAClB,YAAA;AACJ,QAAA,CAAA,EAAGX,mBAAAA,GAAsBd,qBAAAA,CAAAA;AAC7B,IAAA;uBAGA,IAAI0B,UAAAA,GAAqB;AACrB,QAAA,OAAO,IAAI,CAACrB,cAAc,CAACgB,IAAI;AACnC,IAAA;uBAGA,IAAIM,WAAAA,GAAuB;QACvB,OAAO,IAAI,CAACxB,aAAa,KAAKyB,SAAAA,IAAa,IAAI,CAAC1B,YAAY,EAAE2B,UAAAA,KAAeC,WAAAA,CAAYC,IAAI;AACjG,IAAA;uBAGA,IAAIC,eAAAA,GAA0B;QAC1B,OAAO,IAAI,CAACxB,gBAAgB;AAChC,IAAA;uBAGA,IAAIyB,cAAAA,GAAyB;AACzB,QAAA,IAAI,IAAI,CAACxB,eAAe,CAACyB,MAAM,KAAK,GAAG,OAAO,CAAA;AAC9C,QAAA,OAAO,IAAI,CAACzB,eAAe,CAAC0B,MAAM,CAAC,CAACC,CAAAA,EAAGC,CAAAA,GAAMD,CAAAA,GAAIC,GAAG,CAAA,CAAA,GAAK,IAAI,CAAC5B,eAAe,CAACyB,MAAM;AACxF,IAAA;AAEA,uBACAI,SAAAA,CAAUC,OAAe,EAAEC,OAA4B,EAAEC,QAA2B,EAAQ;AACxF,QAAA,MAAMC,GAAAA,GAA0B;AAAEF,YAAAA,OAAAA;AAASC,YAAAA;AAAS,SAAA;AACpD,QAAA,IAAI,CAACpC,cAAc,CAACsC,GAAG,CAACJ,OAAAA,EAASG,GAAAA,CAAAA;AAEjC,QAAA,IAAI,CAACE,eAAe,EAAA;QAEpB,IAAI,IAAI,CAACzC,aAAa,EAAE;YACpB,IAAI,CAAC0C,aAAa,CAACN,OAAAA,EAASC,OAAAA,CAAAA;QAChC,CAAA,MAAO;;AAEH,YAAA,IAAI,CAACjC,qBAAqB,CAACoC,GAAG,CAACJ,OAAAA,EAASG,GAAAA,CAAAA;AAC5C,QAAA;AACJ,IAAA;uBAGAI,WAAAA,CAAYP,OAAe,EAAQ;AAC/B,QAAA,IAAI,CAAClC,cAAc,CAAC0C,MAAM,CAACR,OAAAA,CAAAA;AAC3B,QAAA,IAAI,CAAChC,qBAAqB,CAACwC,MAAM,CAACR,OAAAA,CAAAA;QAElC,IAAI,IAAI,CAACpC,aAAa,EAAE;YACpB,IAAI,CAAC6C,eAAe,CAACT,OAAAA,CAAAA;AACzB,QAAA;AAEA,QAAA,IAAI,IAAI,CAAClC,cAAc,CAACgB,IAAI,KAAK,CAAA,EAAG;AAChC,YAAA,IAAI,CAAC4B,KAAK,EAAA;AACd,QAAA;AACJ,IAAA;AAEA,uBACAC,OAAAA,GAAgB;QACZ,IAAI,CAAC9C,aAAa,GAAG,IAAA;QACrB,IAAI,CAACC,cAAc,CAAC8C,KAAK,EAAA;QACzB,IAAI,CAAC5C,qBAAqB,CAAC4C,KAAK,EAAA;QAChC,IAAI,CAACnC,OAAO,CAACoC,MAAM,EAAA;QACnB,IAAI,CAACzC,UAAU,CAAC0C,IAAI,EAAA;AACpB,QAAA,IAAI,CAACC,mBAAmB,EAAA;QACxB,IAAI,CAACpD,YAAY,EAAE+C,KAAAA,EAAAA;QACnB,IAAI,CAAC/C,YAAY,GAAG0B,SAAAA;QACpB,IAAI,CAACzB,aAAa,GAAGyB,SAAAA;AACzB,IAAA;IAEQgB,eAAAA,GAAwB;QAC5B,IAAI,IAAI,CAACxC,aAAa,EAAE;YACpB,IAAI,CAACA,aAAa,GAAG,KAAA;AACzB,QAAA;AAEA,QAAA,IAAI,IAAI,CAACF,YAAY,IAAI,IAAI,CAACA,YAAY,CAAC2B,UAAU,KAAKC,WAAAA,CAAYyB,MAAM,EAAE;AAC1E,YAAA;AACJ,QAAA;AAEA,QAAA,IAAI,CAACC,eAAe,EAAA;AACxB,IAAA;IAEQP,KAAAA,GAAc;QAClB,IAAI,CAAC7C,aAAa,GAAG,IAAA;QACrB,IAAI,CAACY,OAAO,CAACoC,MAAM,EAAA;QACnB,IAAI,CAACzC,UAAU,CAAC0C,IAAI,EAAA;AACpB,QAAA,IAAI,CAACC,mBAAmB,EAAA;QACxB,IAAI,IAAI,CAACpD,YAAY,EAAE;;;;;AAKnB,YAAA,IAAI,CAACA,YAAY,CAACuD,MAAM,GAAG,IAAA;AAC3B,YAAA,IAAI,CAACvD,YAAY,CAACwD,SAAS,GAAG,IAAA;AAC9B,YAAA,IAAI,CAACxD,YAAY,CAACyD,OAAO,GAAG,IAAA;YAC5B,IAAI,CAACzD,YAAY,CAAC+C,KAAK,EAAA;AAC3B,QAAA;QACA,IAAI,CAAC/C,YAAY,GAAG0B,SAAAA;QACpB,IAAI,CAACzB,aAAa,GAAGyB,SAAAA;AACzB,IAAA;IAEQ4B,eAAAA,GAAwB;QAC5B,IAAII,GAAAA,GAAM,IAAI,CAAC1C,OAAO;AACtB,QAAA,IAAI,IAAI,CAACC,aAAa,EAAEe,SAAS,CAAA,EAAG;YAChC,MAAM2B,KAAAA,GAAQ,CAAA,EAAGC,eAAAA,CAAQC,2BAA2B,CAAC,CAAC,EAAEC,kBAAAA,CAAmB,IAAI,CAAC7C,aAAa,CAAA,CAAA,CAAG;YAChGyC,GAAAA,IAAQA,CAAAA,GAAAA,CAAIK,QAAQ,CAAC,GAAA,CAAA,GAAO,GAAA,GAAM,GAAE,IAAKJ,KAAAA;AAC7C,QAAA;QAEA,IAAI,CAAC1D,aAAa,GAAGyB,SAAAA;AACrB,QAAA,IAAI,CAAC1B,YAAY,GAAG,IAAI4B,WAAAA,CAAY8B,GAAAA,CAAAA;AAEpC,QAAA,IAAI,CAAC1D,YAAY,CAACuD,MAAM,GAAG,IAAA;YACvB,IAAI,IAAI,CAACrD,aAAa,EAAE;AACxBkB,YAAAA,OAAAA,CAAQ4C,GAAG,CAAC,CAAC,iCAAiC,EAAEN,GAAAA,CAAI,CAAC,CAAC,CAAA;YACtD,IAAI,CAAC5C,OAAO,CAACmD,KAAK,EAAA;YAClB,IAAI,CAACxD,UAAU,CAACyD,KAAK,EAAA;;;AAIrB,YAAA,IAAI,CAACd,mBAAmB,EAAA;YACxB,IAAI,CAAC5C,oBAAoB,GAAG2D,UAAAA,CAAW,IAAA;gBACnC,IAAI,CAAC,IAAI,CAACjE,aAAa,IAAI,CAAC,IAAI,CAACD,aAAa,EAAE;AAC5CmB,oBAAAA,OAAAA,CAAQC,IAAI,CAAC,CAAC,qCAAqC,EAAE,IAAI,CAACR,iBAAiB,CAAC,cAAc,EAAE6C,GAAAA,CAAI,CAAC,CAAC,CAAA;AAClG,oBAAA,IAAI,CAACnC,SAAS,EAAA;AAClB,gBAAA;YACJ,CAAA,EAAG,IAAI,CAACV,iBAAiB,CAAA;AAC7B,QAAA,CAAA;AAEA,QAAA,IAAI,CAACb,YAAY,CAACwD,SAAS,GAAG,CAACY,KAAAA,GAAAA;YAC3B,IAAI,IAAI,CAAClE,aAAa,EAAE;YACxB,IAAI,CAACO,UAAU,CAAC4D,cAAc,EAAA;AAC9B,YAAA,IAAI,CAACC,aAAa,CAACF,KAAAA,CAAMG,IAAI,CAAA;AACjC,QAAA,CAAA;AAEA,QAAA,IAAI,CAACvE,YAAY,CAACyD,OAAO,GAAG,IAAA;YACxB,IAAI,IAAI,CAACvD,aAAa,EAAE;AACxBkB,YAAAA,OAAAA,CAAQC,IAAI,CAAC,CAAC,2BAA2B,EAAEqC,GAAAA,CAAI,CAAC,CAAC,CAAA;AACjD,YAAA,IAAI,CAACnC,SAAS,EAAA;AAClB,QAAA,CAAA;AACJ,IAAA;IAEQA,SAAAA,GAAkB;QACtB,IAAI,CAACd,UAAU,CAAC0C,IAAI,EAAA;AACpB,QAAA,IAAI,CAACC,mBAAmB,EAAA;;QAGxB,IAAI,CAACpD,YAAY,EAAE+C,KAAAA,EAAAA;QACnB,IAAI,CAAC/C,YAAY,GAAG0B,SAAAA;QACpB,IAAI,CAACzB,aAAa,GAAGyB,SAAAA;;;QAIrB,KAAK,MAAM,CAACW,OAAAA,EAASG,GAAAA,CAAI,IAAI,IAAI,CAACrC,cAAc,CAAE;AAC9C,YAAA,IAAI,CAACE,qBAAqB,CAACoC,GAAG,CAACJ,OAAAA,EAASG,GAAAA,CAAAA;AAC5C,QAAA;AAEA,QAAA,IAAI,IAAI,CAACrC,cAAc,CAACgB,IAAI,KAAK,CAAA,EAAG;AAEpC,QAAA,IAAI,CAACL,OAAO,CAAC0D,QAAQ,CAAC,IAAA;YAClB,IAAI,CAAC,IAAI,CAACtE,aAAa,IAAI,IAAI,CAACC,cAAc,CAACgB,IAAI,GAAG,CAAA,EAAG;AACrD,gBAAA,IAAI,CAACmC,eAAe,EAAA;AACxB,YAAA;QACJ,CAAA,EAAG,IAAI,CAACtC,OAAO,CAAA;AACnB,IAAA;IAEQoC,mBAAAA,GAA4B;AAChC,QAAA,IAAI,IAAI,CAAC5C,oBAAoB,KAAKkB,SAAAA,EAAW;YACzC+C,YAAAA,CAAa,IAAI,CAACjE,oBAAoB,CAAA;YACtC,IAAI,CAACA,oBAAoB,GAAGkB,SAAAA;AAChC,QAAA;AACJ,IAAA;AAEQ4C,IAAAA,aAAAA,CAAcI,OAAe,EAAQ;QACzC,IAAI;YACA,MAAMC,OAAAA,GAAUC,IAAAA,CAAKC,KAAK,CAACH,OAAAA,CAAAA;AAE3B,YAAA,OAAQC,QAAQG,IAAI;AAChB,gBAAA,KAAKC,sCAAeC,SAAS;oBACzB,IAAI,CAACC,eAAe,CAACN,OAAAA,CAAAA;AACrB,oBAAA;AACJ,gBAAA,KAAKI,sCAAeG,WAAW;oBAC3B,IAAI,CAACC,iBAAiB,CAACR,OAAAA,CAAAA;AACvB,oBAAA;AACJ,gBAAA,KAAKI,sCAAeK,IAAI;AAEpB,oBAAA;AACJ,gBAAA,KAAKL,sCAAeM,YAAY;oBAC5BjE,OAAAA,CAAQC,IAAI,CAAC,CAAC,gBAAgB,EAAEsD,OAAAA,CAAQtC,OAAO,CAAC,cAAc,CAAC,CAAA;oBAC/D,IAAI,CAACiD,kBAAkB,CAACX,OAAAA,CAAAA;AACxB,oBAAA;AACJ,gBAAA,KAAKI,sCAAeQ,KAAK;AACrBnE,oBAAAA,OAAAA,CAAQoE,KAAK,CAAC,CAAC,gBAAgB,EAAEb,OAAAA,CAAQtC,OAAO,CAAC,QAAQ,CAAC,EAAEsC,OAAAA,CAAQc,OAAO,CAAA;AAC3E,oBAAA;AACR;AACJ,QAAA,CAAA,CAAE,OAAOD,KAAAA,EAAO;YACZpE,OAAAA,CAAQoE,KAAK,CAAC,gCAAA,EAAkCA,KAAAA,CAAAA;AACpD,QAAA;AACJ,IAAA;AAEQP,IAAAA,eAAAA,CAAgBN,OAAmB,EAAQ;AAC/C,QAAA,IAAI,CAAC1E,aAAa,GAAG0E,OAAAA,CAAQc,OAAO;QACpCrE,OAAAA,CAAQ4C,GAAG,CAAC,CAAC,4BAA4B,EAAE,IAAI,CAAC/D,aAAa,CAAC,CAAC,CAAC,CAAA;;AAGhE,QAAA,IAAI,CAACmD,mBAAmB,EAAA;AAExB,QAAA,IAAI,CAACsC,4BAA4B,CAACf,OAAAA,CAAQ/D,mBAAmB,CAAA;;QAG7D,KAAK,MAAM,CAACyB,OAAAA,EAASG,GAAAA,CAAI,IAAI,IAAI,CAACnC,qBAAqB,CAAE;AACrD,YAAA,IAAI,CAACsC,aAAa,CAACN,OAAAA,EAASG,IAAIF,OAAO,CAAA;AAC3C,QAAA;QACA,IAAI,CAACjC,qBAAqB,CAAC4C,KAAK,EAAA;AACpC,IAAA;AAEA;;;;;;;QAQQyC,4BAAAA,CAA6BC,gBAAyB,EAAQ;AAClE,QAAA,IAAIA,qBAAqBjE,SAAAA,EAAW;;;AAIpC,QAAA,IAAIiE,oBAAoB,CAAA,EAAG;YACvB,IAAI,CAAClF,UAAU,CAAC0C,IAAI,EAAA;AACpB,YAAA;AACJ,QAAA;AAEA,QAAA,IAAI,CAAC1C,UAAU,CAACmF,WAAW,CAACD,kBAAkBA,gBAAAA,GAAmB7F,qBAAAA,CAAAA;AACrE,IAAA;AAEQqF,IAAAA,iBAAAA,CAAkBR,OAAmB,EAAQ;QACjD,IAAI,CAACA,OAAAA,CAAQtC,OAAO,EAAE;QAEtB,MAAMG,GAAAA,GAAM,IAAI,CAACrC,cAAc,CAAC0F,GAAG,CAAClB,QAAQtC,OAAO,CAAA;AACnD,QAAA,IAAI,CAACG,GAAAA,EAAK;QAEV,MAAMsD,MAAAA,GAASnB,QAAQc,OAAO;AAC9BjD,QAAAA,GAAAA,CAAID,QAAQ,CAACuD,MAAAA,CAAAA;AACjB,IAAA;AAEQR,IAAAA,kBAAAA,CAAmBX,OAAmB,EAAQ;QAClD,IAAI,CAACA,OAAAA,CAAQtC,OAAO,EAAE;QAEtB,MAAMG,GAAAA,GAAM,IAAI,CAACrC,cAAc,CAAC0F,GAAG,CAAClB,QAAQtC,OAAO,CAAA;AACnD,QAAA,IAAI,CAACG,GAAAA,EAAK;AAEV,QAAA,IAAI,CAACrC,cAAc,CAAC0C,MAAM,CAAC8B,QAAQtC,OAAO,CAAA;AAC1C,QAAA,IAAI,CAAChC,qBAAqB,CAACwC,MAAM,CAAC8B,QAAQtC,OAAO,CAAA;QACjDG,GAAAA,CAAID,QAAQ,CAAC2C,uBAAAA,CAAYa,YAAY,EAAA,CAAA;AACzC,IAAA;AAEQpD,IAAAA,aAAAA,CAAcN,OAAe,EAAEC,OAA4B,EAAE0D,OAAAA,GAAkB,CAAC,EAAQ;QAC5F,IAAI,CAAC,IAAI,CAAC/F,aAAa,IAAI,IAAI,CAACC,aAAa,EAAE;;;QAI/C,MAAM+F,YAAAA,GAAe,IAAI,CAAChG,aAAa;AAEvC,QAAA,MAAMiG,IAAAA,GAAO;AACTD,YAAAA,YAAAA;AACA5D,YAAAA,OAAAA;AACAC,YAAAA;AACJ,SAAA;AAEA,QAAA,MAAM6D,aAAAA,GAAgBvC,eAAAA,CAAQwC,mBAAmB,IAAA,IAAQ,EAAC;;;;;;;AAQ1D,QAAA,MAAMC,UAAAA,GAAa,CAAA;AACnB,QAAA,MAAMC,YAAAA,GAAe,GAAA;QAErBC,KAAAA,CAAM,IAAI,CAAC7F,aAAa,EAAE;YACtB8F,MAAAA,EAAQ,MAAA;YACRC,OAAAA,EAAS;gBAAE,cAAA,EAAgB,kBAAA;AAAoB,gBAAA,GAAGN;AAAc,aAAA;YAChED,IAAAA,EAAMtB,IAAAA,CAAK8B,SAAS,CAACR,IAAAA;SACzB,CAAA,CAAGS,IAAI,CAACC,CAAAA,QAAAA,GAAAA;YACJ,IAAI,CAACA,QAAAA,CAASC,EAAE,EAAE;gBACd,IAAIb,OAAAA,GAAUK,UAAAA,IAAc,IAAI,CAACpG,aAAa,KAAKgG,YAAAA,IAAgB,CAAC,IAAI,CAAC/F,aAAa,EAAE;AACpFiE,oBAAAA,UAAAA,CAAW,IAAM,IAAI,CAACxB,aAAa,CAACN,OAAAA,EAASC,OAAAA,EAAS0D,OAAAA,GAAU,CAAA,CAAA,EAAIM,YAAAA,IAAgBN,OAAAA,GAAU,CAAA,CAAA,CAAA;gBAClG,CAAA,MAAO,IAAI,IAAI,CAAC/F,aAAa,KAAKgG,gBAAgB,CAAC,IAAI,CAAC/F,aAAa,EAAE;AACnEkB,oBAAAA,OAAAA,CAAQC,IAAI,CAAC,CAAC,6BAA6B,EAAEgB,QAAQ,WAAW,EAAEuE,QAAAA,CAASE,MAAM,CAAC,OAAO,EAAEd,OAAAA,GAAU,CAAA,CAAE,yBAAyB,CAAC,CAAA;AACjI,oBAAA,IAAI,CAACzE,SAAS,EAAA;AAClB,gBAAA;AACJ,YAAA;QACJ,CAAA,CAAA,CAAGwF,KAAK,CAACvB,CAAAA,KAAAA,GAAAA;YACL,IAAIQ,OAAAA,GAAUK,UAAAA,IAAc,IAAI,CAACpG,aAAa,KAAKgG,YAAAA,IAAgB,CAAC,IAAI,CAAC/F,aAAa,EAAE;AACpFiE,gBAAAA,UAAAA,CAAW,IAAM,IAAI,CAACxB,aAAa,CAACN,OAAAA,EAASC,OAAAA,EAAS0D,OAAAA,GAAU,CAAA,CAAA,EAAIM,YAAAA,IAAgBN,OAAAA,GAAU,CAAA,CAAA,CAAA;YAClG,CAAA,MAAO,IAAI,IAAI,CAAC/F,aAAa,KAAKgG,gBAAgB,CAAC,IAAI,CAAC/F,aAAa,EAAE;AACnEkB,gBAAAA,OAAAA,CAAQoE,KAAK,CAAC,CAAC,oCAAoC,EAAEnD,OAAAA,CAAQ,QAAQ,EAAE2D,OAAAA,GAAU,CAAA,CAAE,yBAAyB,CAAC,EAAER,KAAAA,CAAAA;AAC/G,gBAAA,IAAI,CAACjE,SAAS,EAAA;AAClB,YAAA;AACJ,QAAA,CAAA,CAAA;AACJ,IAAA;AAEQuB,IAAAA,eAAAA,CAAgBT,OAAe,EAAQ;AAC3C,QAAA,IAAI,CAAC,IAAI,CAACpC,aAAa,EAAE;AAEzB,QAAA,MAAMiG,IAAAA,GAAO;YACTD,YAAAA,EAAc,IAAI,CAAChG,aAAa;AAChCoC,YAAAA;AACJ,SAAA;AAEA,QAAA,MAAM8D,aAAAA,GAAgBvC,eAAAA,CAAQwC,mBAAmB,IAAA,IAAQ,EAAC;QAE1DG,KAAAA,CAAM,IAAI,CAAC5F,eAAe,EAAE;YACxB6F,MAAAA,EAAQ,MAAA;YACRC,OAAAA,EAAS;gBAAE,cAAA,EAAgB,kBAAA;AAAoB,gBAAA,GAAGN;AAAc,aAAA;YAChED,IAAAA,EAAMtB,IAAAA,CAAK8B,SAAS,CAACR,IAAAA;SACzB,CAAA,CAAGa,KAAK,CAACvB,CAAAA,KAAAA,GAAAA;YACLpE,OAAAA,CAAQoE,KAAK,CAAC,CAAC,sCAAsC,EAAEnD,OAAAA,CAAQ,CAAC,CAAC,EAAEmD,KAAAA,CAAAA;AACvE,QAAA,CAAA,CAAA;AACJ,IAAA;AACJ;;;;"}
1
+ {"version":3,"file":"ServerSentEventHubConnection.js","sources":["../../../queries/ServerSentEventHubConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Globals } from '../Globals';\nimport { IObservableQueryHubConnection } from './IObservableQueryHubConnection';\nimport { DataReceived } from './ObservableQueryConnection';\nimport { HubConnectionKeepAlive } from './HubConnectionKeepAlive';\nimport { IReconnectPolicy } from './IReconnectPolicy';\nimport { ReconnectPolicy } from './ReconnectPolicy';\nimport { QueryResult } from './QueryResult';\nimport { HubMessage, HubMessageType, SubscriptionRequest } from './WebSocketHubConnection';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface ActiveSubscription {\n request: SubscriptionRequest;\n callback: DataReceived<any>;\n}\n\n/**\n * How many keep-alive intervals of silence are tolerated before the connection is considered dead.\n *\n * The server guarantees a message every interval, so this is pure slack for latency and jitter.\n * It must stay above 1 — a threshold at or below the server's own cadence makes the client and\n * server timers race, and the client tears down connections the server considers healthy.\n */\nconst IDLE_THRESHOLD_FACTOR = 2;\n\n/**\n * A multiplexed SSE hub connection that uses EventSource for server→client streaming\n * and fetch POST requests for client→server subscribe/unsubscribe commands.\n *\n * Protocol:\n * 1. Open EventSource to the SSE hub endpoint.\n * 2. Server sends a {@link HubMessageType.Connected} message with the connection identifier.\n * 3. Client sends POST to subscribe/unsubscribe endpoints using the connection identifier.\n * 4. Server streams {@link HubMessageType.QueryResult} messages tagged with queryId.\n * 5. When EventSource closes, server cleans up all subscriptions for this connection.\n */\nexport class ServerSentEventHubConnection implements IObservableQueryHubConnection {\n private _eventSource?: EventSource;\n private _connectionId?: string;\n private _disconnected = false;\n private _subscriptions: Map<string, ActiveSubscription> = new Map();\n private _pendingSubscriptions: Map<string, ActiveSubscription> = new Map();\n private _lastPongLatency: number = 0;\n private _latencySamples: number[] = [];\n private _connectTimeoutTimer?: ReturnType<typeof setTimeout>;\n private readonly _keepAlive: HubConnectionKeepAlive;\n\n /**\n * Initializes a new instance of {@link ServerSentEventHubConnection}.\n * @param {string} _sseUrl The SSE hub endpoint URL (e.g. `http://localhost:5000/.cratis/queries/sse`).\n * @param {string} _subscribeUrl The subscribe POST endpoint URL.\n * @param {string} _unsubscribeUrl The unsubscribe POST endpoint URL.\n * @param {string} _microservice The microservice name to pass as a query argument.\n * @param {number} keepAliveIntervalMs The keep-alive cadence to assume until the server advertises\n * its own on the {@link HubMessageType.Connected} message (default: 30 000 ms). The connection is\n * considered stale after {@link IDLE_THRESHOLD_FACTOR} times this without any server message.\n * @param {number} connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}\n * message after the HTTP connection opens before giving up and retrying (default: 15 000 ms).\n * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).\n */\n constructor(\n private readonly _sseUrl: string,\n private readonly _subscribeUrl: string,\n private readonly _unsubscribeUrl: string,\n private readonly _microservice: string,\n keepAliveIntervalMs: number = 30000,\n private readonly _connectTimeoutMs: number = 15000,\n private readonly _policy: IReconnectPolicy = new ReconnectPolicy()\n ) {\n // SSE is server→client only: the client cannot send pings. Instead we watch for\n // inactivity — if the server stops sending messages (including its own keep-alive\n // pings) for the entire idle threshold, the connection is stale and we reconnect.\n //\n // The server guarantees a message at least every keep-alive interval, so the threshold\n // only has to absorb network latency, timer jitter and server-side scheduling hiccups.\n // A hard TCP drop surfaces immediately through `onerror`, so this watchdog only needs to\n // catch silent black-holes — that makes a generous tolerance strictly better than a tight\n // one, which would tear down healthy connections.\n //\n // The interval below is only the starting assumption; the server advertises its real\n // cadence on the Connected message and {@link handleConnected} reconfigures from it.\n this._keepAlive = new HubConnectionKeepAlive(keepAliveIntervalMs, () => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n console.warn(`SSE hub: no messages received for ${this._keepAlive.idleThresholdMs}ms, reconnecting '${this._sseUrl}'`);\n this.reconnect();\n }\n }, keepAliveIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n /** @inheritdoc */\n get queryCount(): number {\n return this._subscriptions.size;\n }\n\n /** @inheritdoc */\n get isConnected(): boolean {\n return this._connectionId !== undefined && this._eventSource?.readyState === EventSource.OPEN;\n }\n\n /** @inheritdoc */\n get lastPingLatency(): number {\n return this._lastPongLatency;\n }\n\n /** @inheritdoc */\n get averageLatency(): number {\n if (this._latencySamples.length === 0) return 0;\n return this._latencySamples.reduce((a, b) => a + b, 0) / this._latencySamples.length;\n }\n\n /** @inheritdoc */\n subscribe(queryId: string, request: SubscriptionRequest, callback: DataReceived<any>): void {\n const sub: ActiveSubscription = { request, callback };\n this._subscriptions.set(queryId, sub);\n\n this.ensureConnected();\n\n if (this._connectionId) {\n this.sendSubscribe(queryId, request);\n } else {\n // Not yet connected, queue for when Connected message arrives.\n this._pendingSubscriptions.set(queryId, sub);\n }\n }\n\n /** @inheritdoc */\n unsubscribe(queryId: string): void {\n this._subscriptions.delete(queryId);\n this._pendingSubscriptions.delete(queryId);\n\n if (this._connectionId) {\n this.sendUnsubscribe(queryId);\n }\n\n if (this._subscriptions.size === 0) {\n this.close();\n }\n }\n\n /** @inheritdoc */\n dispose(): void {\n this._disconnected = true;\n this._subscriptions.clear();\n this._pendingSubscriptions.clear();\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private ensureConnected(): void {\n if (this._disconnected) {\n this._disconnected = false;\n }\n\n if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {\n return;\n }\n\n this.openEventSource();\n }\n\n private close(): void {\n this._disconnected = true;\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n if (this._eventSource) {\n // Detach all handlers BEFORE closing so that the async onerror / onmessage\n // events that fire after close() cannot observe the new _disconnected=false\n // state set by an immediately following ensureConnected() call. Without this,\n // a stale onerror triggers an unintended reconnect with exponential back-off.\n this._eventSource.onopen = null;\n this._eventSource.onmessage = null;\n this._eventSource.onerror = null;\n this._eventSource.close();\n }\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private openEventSource(): void {\n let url = this._sseUrl;\n if (this._microservice?.length > 0) {\n const param = `${Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;\n url += (url.includes('?') ? '&' : '?') + param;\n }\n\n this._connectionId = undefined;\n this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);\n\n this._eventSource.onopen = () => {\n if (this._disconnected) return;\n console.log(`SSE hub connection established: '${url}'`);\n this._policy.reset();\n this._keepAlive.start();\n\n // If the server does not send a Connected message within the timeout, the\n // connection is broken. Close and retry via the reconnect policy.\n this.clearConnectTimeout();\n this._connectTimeoutTimer = setTimeout(() => {\n if (!this._disconnected && !this._connectionId) {\n console.warn(`SSE hub: no Connected message within ${this._connectTimeoutMs}ms, retrying '${url}'`);\n this.reconnect();\n }\n }, this._connectTimeoutMs);\n };\n\n this._eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected) return;\n this._keepAlive.recordActivity();\n this.handleMessage(event.data as string);\n };\n\n this._eventSource.onerror = () => {\n if (this._disconnected) return;\n console.warn(`SSE hub connection error: '${url}'`);\n this.reconnect();\n };\n }\n\n private reconnect(): void {\n this._keepAlive.stop();\n this.clearConnectTimeout();\n\n // Close the EventSource so the reconnect policy manages the schedule.\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n\n // Move all active subscriptions to pending so they re-subscribe when\n // the next Connected message arrives after the managed reconnect.\n for (const [queryId, sub] of this._subscriptions) {\n this._pendingSubscriptions.set(queryId, sub);\n }\n\n if (this._subscriptions.size === 0) return;\n\n this._policy.schedule(() => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n this.openEventSource();\n }\n }, this._sseUrl);\n }\n\n private clearConnectTimeout(): void {\n if (this._connectTimeoutTimer !== undefined) {\n clearTimeout(this._connectTimeoutTimer);\n this._connectTimeoutTimer = undefined;\n }\n }\n\n private handleMessage(rawData: string): void {\n try {\n const message = JSON.parse(rawData) as HubMessage;\n\n switch (message.type) {\n case HubMessageType.Connected:\n this.handleConnected(message);\n break;\n case HubMessageType.QueryResult:\n this.handleQueryResult(message);\n break;\n case HubMessageType.Ping:\n // Server-sent keep-alive ping — activity already recorded in onmessage.\n break;\n case HubMessageType.Unauthorized:\n console.warn(`SSE hub: query '${message.queryId}' unauthorized`);\n this.handleUnauthorized(message);\n break;\n case HubMessageType.Error:\n console.error(`SSE hub: query '${message.queryId}' error:`, message.payload);\n break;\n }\n } catch (error) {\n console.error('SSE hub: error parsing message', error);\n }\n }\n\n private handleConnected(message: HubMessage): void {\n this._connectionId = message.payload as string;\n console.log(`SSE hub: connected with id '${this._connectionId}'`);\n\n // Connected message arrived — cancel the connect timeout.\n this.clearConnectTimeout();\n\n this.applyServerKeepAliveInterval(message.keepAliveIntervalMs);\n\n // Send all pending subscriptions now that we have a connection ID.\n for (const [queryId, sub] of this._pendingSubscriptions) {\n this.sendSubscribe(queryId, sub.request);\n }\n this._pendingSubscriptions.clear();\n }\n\n /**\n * Align the idle watchdog with the keep-alive cadence the server actually runs on.\n *\n * Without this the client assumes the default interval, so a server configured with a longer\n * interval — or with keep-alive switched off entirely — would look silent and be reconnected\n * on a loop even though it is perfectly healthy.\n * @param {number | undefined} serverIntervalMs The interval advertised by the server, if any.\n */\n private applyServerKeepAliveInterval(serverIntervalMs?: number): void {\n if (serverIntervalMs === undefined) return;\n\n // Keep-alive disabled server-side: silence is expected, so watching for it would guarantee\n // an endless reconnect loop. Hard drops still surface through `onerror`.\n if (serverIntervalMs <= 0) {\n this._keepAlive.stop();\n return;\n }\n\n this._keepAlive.reconfigure(serverIntervalMs, serverIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n private handleQueryResult(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n const result = message.payload as QueryResult<any>;\n sub.callback(result);\n }\n\n private handleUnauthorized(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n this._subscriptions.delete(message.queryId);\n this._pendingSubscriptions.delete(message.queryId);\n sub.callback(QueryResult.unauthorized());\n }\n\n private sendSubscribe(queryId: string, request: SubscriptionRequest, attempt: number = 0): void {\n if (!this._connectionId || this._disconnected) return;\n\n // Capture the connection ID so retries can detect if a reconnect has already fired\n // for a different reason and made this retry obsolete.\n const connectionId = this._connectionId;\n\n const body = {\n connectionId,\n queryId,\n request,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n // Maximum number of subscribe retries before falling back to a full SSE reconnect.\n // In a round-robin load-balanced deployment the subscribe POST may land on a different\n // backend instance than the one holding the SSE connection. Retrying gives the load\n // balancer the chance to route a subsequent attempt to the correct instance without\n // tearing down the SSE connection unnecessarily. With N backend instances at most\n // N-1 retries are needed, so 3 retries covers deployments with up to 4 replicas.\n const maxRetries = 3;\n const retryDelayMs = 200;\n\n fetch(this._subscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).then(response => {\n if (!response.ok) {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.warn(`SSE hub: subscribe POST for '${queryId}' returned ${response.status} after ${attempt + 1} attempt(s), reconnecting`);\n this.reconnect();\n }\n }\n }).catch(error => {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.error(`SSE hub: subscribe POST failed for '${queryId}' after ${attempt + 1} attempt(s), reconnecting`, error);\n this.reconnect();\n }\n });\n }\n\n private sendUnsubscribe(queryId: string): void {\n if (!this._connectionId) return;\n\n const body = {\n connectionId: this._connectionId,\n queryId,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n fetch(this._unsubscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).catch(error => {\n console.error(`SSE hub: unsubscribe POST failed for '${queryId}'`, error);\n });\n }\n}\n"],"names":["IDLE_THRESHOLD_FACTOR","ServerSentEventHubConnection","_eventSource","_connectionId","_disconnected","_subscriptions","Map","_pendingSubscriptions","_lastPongLatency","_latencySamples","_connectTimeoutTimer","_keepAlive","_subscribeUrl","_unsubscribeUrl","keepAliveIntervalMs","_connectTimeoutMs","_policy","ReconnectPolicy","_sseUrl","_microservice","HubConnectionKeepAlive","size","console","warn","idleThresholdMs","reconnect","queryCount","isConnected","undefined","readyState","EventSource","OPEN","lastPingLatency","averageLatency","length","reduce","a","b","subscribe","queryId","request","callback","sub","set","ensureConnected","sendSubscribe","unsubscribe","delete","sendUnsubscribe","close","dispose","clear","cancel","stop","clearConnectTimeout","CLOSED","openEventSource","onopen","onmessage","onerror","url","param","Globals","microserviceWSQueryArgument","encodeURIComponent","includes","eventSourceFactory","log","reset","start","setTimeout","event","recordActivity","handleMessage","data","schedule","clearTimeout","rawData","message","JSON","parse","type","HubMessageType","Connected","handleConnected","QueryResult","handleQueryResult","Ping","Unauthorized","handleUnauthorized","Error","error","payload","applyServerKeepAliveInterval","serverIntervalMs","reconfigure","get","result","unauthorized","attempt","connectionId","body","customHeaders","httpHeadersCallback","maxRetries","retryDelayMs","fetch","method","headers","stringify","then","response","ok","status","catch"],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var Globals = require('../Globals.js');
4
+
3
5
  // Copyright (c) Cratis. All rights reserved.
4
6
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
7
  /**
@@ -27,8 +29,9 @@
27
29
  }
28
30
  /** @inheritdoc */ connect(dataReceived, queryArguments) {
29
31
  if (this._disconnected) return;
30
- // Guard against environments where EventSource is not available (e.g. Node.js, SSR).
31
- if (typeof EventSource === 'undefined') {
32
+ // Guard against environments where EventSource is not available (e.g. Node.js, SSR)
33
+ // and no custom factory has been supplied to substitute it.
34
+ if (!Globals.Globals.eventSourceFactory && typeof EventSource === 'undefined') {
32
35
  return;
33
36
  }
34
37
  let url = this._url.toString();
@@ -39,7 +42,7 @@
39
42
  url = `${url}${separator}${query}`;
40
43
  }
41
44
  }
42
- this._eventSource = new EventSource(url);
45
+ this._eventSource = Globals.Globals.eventSourceFactory ? Globals.Globals.eventSourceFactory(url) : new EventSource(url);
43
46
  this._eventSource.onmessage = (event)=>{
44
47
  if (this._disconnected) return;
45
48
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"ServerSentEventQueryConnection.js","sources":["../../../queries/ServerSentEventQueryConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { IObservableQueryConnection } from './IObservableQueryConnection';\nimport { DataReceived } from './ObservableQueryConnection';\nimport { QueryResult } from './QueryResult';\n\n/**\n * The SSE demultiplexer route used when connecting through the multiplexed observable query endpoint.\n */\nexport const SSE_HUB_ROUTE = '/.cratis/queries/sse';\n\n/**\n * Represents a direct Server-Sent Events (SSE) connection for a single observable query.\n *\n * In direct mode the URL points to the per-query endpoint (e.g. `/api/queries/latest`).\n * The backend detects the `Accept: text/event-stream` header and streams results directly.\n *\n * The caller (typically {@link createObservableQueryConnection}) decides which URL to use;\n * this class is transport-agnostic beyond being SSE.\n */\nexport class ServerSentEventQueryConnection<TDataType> implements IObservableQueryConnection<TDataType> {\n private _eventSource?: EventSource;\n private _disconnected = false;\n\n /** @inheritdoc */\n readonly lastPingLatency: number = 0;\n\n /** @inheritdoc */\n readonly averageLatency: number = 0;\n\n /**\n * Initializes a new instance of {@link ServerSentEventQueryConnection}.\n * @param {URL} url The fully qualified URL of the SSE endpoint (including query parameters).\n */\n constructor(private readonly _url: URL) {}\n\n /** @inheritdoc */\n connect(dataReceived: DataReceived<TDataType>, queryArguments?: object): void {\n if (this._disconnected) return;\n\n // Guard against environments where EventSource is not available (e.g. Node.js, SSR).\n if (typeof EventSource === 'undefined') {\n return;\n }\n\n let url = this._url.toString();\n if (queryArguments) {\n const separator = url.includes('?') ? '&' : '?';\n const query = Object.entries(queryArguments)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n .join('&');\n if (query) {\n url = `${url}${separator}${query}`;\n }\n }\n\n this._eventSource = new EventSource(url);\n\n this._eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected) return;\n try {\n const result = JSON.parse(event.data as string) as QueryResult<TDataType>;\n dataReceived(result);\n } catch (error) {\n console.error('SSE: error parsing message', error);\n }\n };\n\n this._eventSource.onerror = () => {\n if (this._disconnected) return;\n console.warn(`SSE: connection error for '${url}', EventSource will retry automatically.`);\n };\n }\n\n /** @inheritdoc */\n disconnect(): void {\n if (this._disconnected) return;\n this._disconnected = true;\n this._eventSource?.close();\n this._eventSource = undefined;\n }\n}\n"],"names":["SSE_HUB_ROUTE","ServerSentEventQueryConnection","_eventSource","_disconnected","lastPingLatency","averageLatency","_url","connect","dataReceived","queryArguments","EventSource","url","toString","separator","includes","query","Object","entries","filter","value","undefined","map","key","encodeURIComponent","String","join","onmessage","event","result","JSON","parse","data","error","console","onerror","warn","disconnect","close"],"mappings":";;AAAA;AACA;AAMA;;IAGO,MAAMA,aAAAA,GAAgB;AAE7B;;;;;;;;AAQC,IACM,MAAMC,8BAAAA,CAAAA;;IACDC,YAAAA;AACAC,IAAAA,aAAAA,GAAgB,KAAA;uBAGxB,eAASC,GAA0B,CAAA;uBAGnC,cAASC,GAAyB,CAAA;AAElC;;;QAIA,WAAA,CAAY,IAA0B,CAAE;aAAXC,IAAAA,GAAAA,IAAAA;AAAY,IAAA;AAEzC,uBACAC,OAAAA,CAAQC,YAAqC,EAAEC,cAAuB,EAAQ;QAC1E,IAAI,IAAI,CAACN,aAAa,EAAE;;QAGxB,IAAI,OAAOO,gBAAgB,WAAA,EAAa;AACpC,YAAA;AACJ,QAAA;AAEA,QAAA,IAAIC,GAAAA,GAAM,IAAI,CAACL,IAAI,CAACM,QAAQ,EAAA;AAC5B,QAAA,IAAIH,cAAAA,EAAgB;AAChB,YAAA,MAAMI,SAAAA,GAAYF,GAAAA,CAAIG,QAAQ,CAAC,OAAO,GAAA,GAAM,GAAA;AAC5C,YAAA,MAAMC,KAAAA,GAAQC,MAAAA,CAAOC,OAAO,CAACR,gBACxBS,MAAM,CAAC,CAAC,GAAGC,KAAAA,CAAM,GAAKA,KAAAA,KAAUC,SAAAA,IAAaD,UAAU,IAAA,CAAA,CACvDE,GAAG,CAAC,CAAC,CAACC,GAAAA,EAAKH,KAAAA,CAAM,GAAK,GAAGI,kBAAAA,CAAmBD,GAAAA,CAAAA,CAAK,CAAC,EAAEC,kBAAAA,CAAmBC,MAAAA,CAAOL,KAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAA,CACvFM,IAAI,CAAC,GAAA,CAAA;AACV,YAAA,IAAIV,KAAAA,EAAO;gBACPJ,GAAAA,GAAM,CAAA,EAAGA,GAAAA,CAAAA,EAAME,SAAAA,CAAAA,EAAYE,KAAAA,CAAAA,CAAO;AACtC,YAAA;AACJ,QAAA;AAEA,QAAA,IAAI,CAACb,YAAY,GAAG,IAAIQ,WAAAA,CAAYC,GAAAA,CAAAA;AAEpC,QAAA,IAAI,CAACT,YAAY,CAACwB,SAAS,GAAG,CAACC,KAAAA,GAAAA;YAC3B,IAAI,IAAI,CAACxB,aAAa,EAAE;YACxB,IAAI;AACA,gBAAA,MAAMyB,MAAAA,GAASC,IAAAA,CAAKC,KAAK,CAACH,MAAMI,IAAI,CAAA;gBACpCvB,YAAAA,CAAaoB,MAAAA,CAAAA;AACjB,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;gBACZC,OAAAA,CAAQD,KAAK,CAAC,4BAAA,EAA8BA,KAAAA,CAAAA;AAChD,YAAA;AACJ,QAAA,CAAA;AAEA,QAAA,IAAI,CAAC9B,YAAY,CAACgC,OAAO,GAAG,IAAA;YACxB,IAAI,IAAI,CAAC/B,aAAa,EAAE;AACxB8B,YAAAA,OAAAA,CAAQE,IAAI,CAAC,CAAC,2BAA2B,EAAExB,GAAAA,CAAI,wCAAwC,CAAC,CAAA;AAC5F,QAAA,CAAA;AACJ,IAAA;AAEA,uBACAyB,UAAAA,GAAmB;QACf,IAAI,IAAI,CAACjC,aAAa,EAAE;QACxB,IAAI,CAACA,aAAa,GAAG,IAAA;QACrB,IAAI,CAACD,YAAY,EAAEmC,KAAAA,EAAAA;QACnB,IAAI,CAACnC,YAAY,GAAGkB,SAAAA;AACxB,IAAA;AACJ;;;;;"}
1
+ {"version":3,"file":"ServerSentEventQueryConnection.js","sources":["../../../queries/ServerSentEventQueryConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Globals } from '../Globals';\nimport { IObservableQueryConnection } from './IObservableQueryConnection';\nimport { DataReceived } from './ObservableQueryConnection';\nimport { QueryResult } from './QueryResult';\n\n/**\n * The SSE demultiplexer route used when connecting through the multiplexed observable query endpoint.\n */\nexport const SSE_HUB_ROUTE = '/.cratis/queries/sse';\n\n/**\n * Represents a direct Server-Sent Events (SSE) connection for a single observable query.\n *\n * In direct mode the URL points to the per-query endpoint (e.g. `/api/queries/latest`).\n * The backend detects the `Accept: text/event-stream` header and streams results directly.\n *\n * The caller (typically {@link createObservableQueryConnection}) decides which URL to use;\n * this class is transport-agnostic beyond being SSE.\n */\nexport class ServerSentEventQueryConnection<TDataType> implements IObservableQueryConnection<TDataType> {\n private _eventSource?: EventSource;\n private _disconnected = false;\n\n /** @inheritdoc */\n readonly lastPingLatency: number = 0;\n\n /** @inheritdoc */\n readonly averageLatency: number = 0;\n\n /**\n * Initializes a new instance of {@link ServerSentEventQueryConnection}.\n * @param {URL} url The fully qualified URL of the SSE endpoint (including query parameters).\n */\n constructor(private readonly _url: URL) {}\n\n /** @inheritdoc */\n connect(dataReceived: DataReceived<TDataType>, queryArguments?: object): void {\n if (this._disconnected) return;\n\n // Guard against environments where EventSource is not available (e.g. Node.js, SSR)\n // and no custom factory has been supplied to substitute it.\n if (!Globals.eventSourceFactory && typeof EventSource === 'undefined') {\n return;\n }\n\n let url = this._url.toString();\n if (queryArguments) {\n const separator = url.includes('?') ? '&' : '?';\n const query = Object.entries(queryArguments)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n .join('&');\n if (query) {\n url = `${url}${separator}${query}`;\n }\n }\n\n this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);\n\n this._eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected) return;\n try {\n const result = JSON.parse(event.data as string) as QueryResult<TDataType>;\n dataReceived(result);\n } catch (error) {\n console.error('SSE: error parsing message', error);\n }\n };\n\n this._eventSource.onerror = () => {\n if (this._disconnected) return;\n console.warn(`SSE: connection error for '${url}', EventSource will retry automatically.`);\n };\n }\n\n /** @inheritdoc */\n disconnect(): void {\n if (this._disconnected) return;\n this._disconnected = true;\n this._eventSource?.close();\n this._eventSource = undefined;\n }\n}\n"],"names":["SSE_HUB_ROUTE","ServerSentEventQueryConnection","_eventSource","_disconnected","lastPingLatency","averageLatency","_url","connect","dataReceived","queryArguments","Globals","eventSourceFactory","EventSource","url","toString","separator","includes","query","Object","entries","filter","value","undefined","map","key","encodeURIComponent","String","join","onmessage","event","result","JSON","parse","data","error","console","onerror","warn","disconnect","close"],"mappings":";;;;AAAA;AACA;AAOA;;IAGO,MAAMA,aAAAA,GAAgB;AAE7B;;;;;;;;AAQC,IACM,MAAMC,8BAAAA,CAAAA;;IACDC,YAAAA;AACAC,IAAAA,aAAAA,GAAgB,KAAA;uBAGxB,eAASC,GAA0B,CAAA;uBAGnC,cAASC,GAAyB,CAAA;AAElC;;;QAIA,WAAA,CAAY,IAA0B,CAAE;aAAXC,IAAAA,GAAAA,IAAAA;AAAY,IAAA;AAEzC,uBACAC,OAAAA,CAAQC,YAAqC,EAAEC,cAAuB,EAAQ;QAC1E,IAAI,IAAI,CAACN,aAAa,EAAE;;;AAIxB,QAAA,IAAI,CAACO,eAAAA,CAAQC,kBAAkB,IAAI,OAAOC,gBAAgB,WAAA,EAAa;AACnE,YAAA;AACJ,QAAA;AAEA,QAAA,IAAIC,GAAAA,GAAM,IAAI,CAACP,IAAI,CAACQ,QAAQ,EAAA;AAC5B,QAAA,IAAIL,cAAAA,EAAgB;AAChB,YAAA,MAAMM,SAAAA,GAAYF,GAAAA,CAAIG,QAAQ,CAAC,OAAO,GAAA,GAAM,GAAA;AAC5C,YAAA,MAAMC,KAAAA,GAAQC,MAAAA,CAAOC,OAAO,CAACV,gBACxBW,MAAM,CAAC,CAAC,GAAGC,KAAAA,CAAM,GAAKA,KAAAA,KAAUC,SAAAA,IAAaD,UAAU,IAAA,CAAA,CACvDE,GAAG,CAAC,CAAC,CAACC,GAAAA,EAAKH,KAAAA,CAAM,GAAK,GAAGI,kBAAAA,CAAmBD,GAAAA,CAAAA,CAAK,CAAC,EAAEC,kBAAAA,CAAmBC,MAAAA,CAAOL,KAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAA,CACvFM,IAAI,CAAC,GAAA,CAAA;AACV,YAAA,IAAIV,KAAAA,EAAO;gBACPJ,GAAAA,GAAM,CAAA,EAAGA,GAAAA,CAAAA,EAAME,SAAAA,CAAAA,EAAYE,KAAAA,CAAAA,CAAO;AACtC,YAAA;AACJ,QAAA;QAEA,IAAI,CAACf,YAAY,GAAGQ,eAAAA,CAAQC,kBAAkB,GAAGD,eAAAA,CAAQC,kBAAkB,CAACE,GAAAA,CAAAA,GAAO,IAAID,WAAAA,CAAYC,GAAAA,CAAAA;AAEnG,QAAA,IAAI,CAACX,YAAY,CAAC0B,SAAS,GAAG,CAACC,KAAAA,GAAAA;YAC3B,IAAI,IAAI,CAAC1B,aAAa,EAAE;YACxB,IAAI;AACA,gBAAA,MAAM2B,MAAAA,GAASC,IAAAA,CAAKC,KAAK,CAACH,MAAMI,IAAI,CAAA;gBACpCzB,YAAAA,CAAasB,MAAAA,CAAAA;AACjB,YAAA,CAAA,CAAE,OAAOI,KAAAA,EAAO;gBACZC,OAAAA,CAAQD,KAAK,CAAC,4BAAA,EAA8BA,KAAAA,CAAAA;AAChD,YAAA;AACJ,QAAA,CAAA;AAEA,QAAA,IAAI,CAAChC,YAAY,CAACkC,OAAO,GAAG,IAAA;YACxB,IAAI,IAAI,CAACjC,aAAa,EAAE;AACxBgC,YAAAA,OAAAA,CAAQE,IAAI,CAAC,CAAC,2BAA2B,EAAExB,GAAAA,CAAI,wCAAwC,CAAC,CAAA;AAC5F,QAAA,CAAA;AACJ,IAAA;AAEA,uBACAyB,UAAAA,GAAmB;QACf,IAAI,IAAI,CAACnC,aAAa,EAAE;QACxB,IAAI,CAACA,aAAa,GAAG,IAAA;QACrB,IAAI,CAACD,YAAY,EAAEqC,KAAAA,EAAAA;QACnB,IAAI,CAACrC,YAAY,GAAGoB,SAAAA;AACxB,IAAA;AACJ;;;;;"}
@@ -0,0 +1,2 @@
1
+ export type EventSourceFactory = (url: string) => EventSource;
2
+ //# sourceMappingURL=EventSourceFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventSourceFactory.d.ts","sourceRoot":"","sources":["../../EventSourceFactory.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=EventSourceFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventSourceFactory.js","sourceRoot":"","sources":["../../EventSourceFactory.ts"],"names":[],"mappings":""}
@@ -1,4 +1,5 @@
1
1
  import { GetHttpHeaders } from './GetHttpHeaders';
2
+ import { EventSourceFactory } from './EventSourceFactory';
2
3
  import { QueryTransportMethod } from './queries/QueryTransportMethod';
3
4
  import { QueryHttpMethod } from './queries/QueryHttpMethod';
4
5
  import { QueryHttpMethodResolver } from './queries/QueryHttpMethodResolver';
@@ -19,6 +20,7 @@ export interface IGlobals {
19
20
  queryDirectMode: boolean;
20
21
  observableQueryTransferMode: ObservableQueryTransferMode;
21
22
  httpHeadersCallback: GetHttpHeaders;
23
+ eventSourceFactory?: EventSourceFactory;
22
24
  queryCacheRetentionMs: number;
23
25
  }
24
26
  export declare const Globals: IGlobals;
@@ -1 +1 @@
1
- {"version":3,"file":"Globals.d.ts","sourceRoot":"","sources":["../../Globals.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAa5E,oBAAY,2BAA2B;IAEnC,KAAK,UAAU;IAEf,IAAI,SAAS;CAChB;AAED,MAAM,WAAW,QAAQ;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,2BAA2B,EAAE,MAAM,CAAC;IACpC,oBAAoB,EAAE,oBAAoB,CAAC;IAM3C,eAAe,EAAE,eAAe,CAAC;IAMjC,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;IAOlD,oBAAoB,EAAE,MAAM,CAAC;IAM7B,eAAe,EAAE,OAAO,CAAC;IAMzB,2BAA2B,EAAE,2BAA2B,CAAC;IAKzD,mBAAmB,EAAE,cAAc,CAAC;IAYpC,qBAAqB,EAAE,MAAM,CAAC;CACjC;AAED,eAAO,MAAM,OAAO,EAAE,QAarB,CAAC"}
1
+ {"version":3,"file":"Globals.d.ts","sourceRoot":"","sources":["../../Globals.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAa5E,oBAAY,2BAA2B;IAEnC,KAAK,UAAU;IAEf,IAAI,SAAS;CAChB;AAED,MAAM,WAAW,QAAQ;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,2BAA2B,EAAE,MAAM,CAAC;IACpC,oBAAoB,EAAE,oBAAoB,CAAC;IAM3C,eAAe,EAAE,eAAe,CAAC;IAMjC,uBAAuB,CAAC,EAAE,uBAAuB,CAAC;IAOlD,oBAAoB,EAAE,MAAM,CAAC;IAM7B,eAAe,EAAE,OAAO,CAAC;IAMzB,2BAA2B,EAAE,2BAA2B,CAAC;IAKzD,mBAAmB,EAAE,cAAc,CAAC;IAOpC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAYxC,qBAAqB,EAAE,MAAM,CAAC;CACjC;AAED,eAAO,MAAM,OAAO,EAAE,QAarB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Globals.js","sources":["../../Globals.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { GetHttpHeaders } from './GetHttpHeaders';\nimport { QueryTransportMethod } from './queries/QueryTransportMethod';\nimport { QueryHttpMethod } from './queries/QueryHttpMethod';\nimport { QueryHttpMethodResolver } from './queries/QueryHttpMethodResolver';\n\n/**\n * Defines the transfer mode used for observable query subscriptions.\n *\n * - {@link ObservableQueryTransferMode.Delta} (default): Only the items that changed since\n * the previous update (added, replaced, removed) are exposed via {@code useChangeStream}.\n * The full collection state is still maintained internally by {@code useObservableQuery}.\n *\n * - {@link ObservableQueryTransferMode.Full}: Every update delivers the complete current\n * collection. The change set returned by {@code useChangeStream} treats the entire new\n * collection as {@code added} and the previous collection as {@code removed}.\n */\nexport enum ObservableQueryTransferMode {\n /** Compute and expose only the items that changed since the previous update (default). */\n Delta = 'delta',\n /** Expose the full collection on every update. */\n Full = 'full',\n}\n\nexport interface IGlobals {\n microservice: string;\n apiBasePath: string;\n origin: string;\n microserviceHttpHeader: string;\n microserviceWSQueryArgument: string;\n queryTransportMethod: QueryTransportMethod;\n /**\n * The HTTP method used to perform non-streaming queries. Defaults to {@link QueryHttpMethod.Get}.\n * Set to {@link QueryHttpMethod.Query} to carry arguments in a JSON request body (RFC 10008)\n * instead of the URL query string. Individual queries can override this via {@code setHttpMethod}.\n */\n queryHttpMethod: QueryHttpMethod;\n /**\n * Optional per-query policy for choosing the query HTTP method from the request (e.g. by URL length).\n * Consulted only when a query has no explicit method set via {@code setHttpMethod}; it takes\n * precedence over {@link queryHttpMethod}. See {@link lengthBasedQueryHttpMethod} for a built-in.\n */\n queryHttpMethodResolver?: QueryHttpMethodResolver;\n /**\n * Number of hub connections maintained for observable queries.\n * When greater than one, queries are distributed across the pool round-robin.\n * Only applies when {@link queryTransportMethod} is a centralized hub transport.\n * Defaults to 1.\n */\n queryConnectionCount: number;\n /**\n * When true, observable queries connect directly to the per-query WebSocket URL\n * instead of routing through the centralized hub endpoint.\n * Defaults to false (use the centralized hub).\n */\n queryDirectMode: boolean;\n /**\n * Controls how observable query updates are transferred and exposed.\n * {@link ObservableQueryTransferMode.Delta} (default) computes per-update deltas;\n * {@link ObservableQueryTransferMode.Full} delivers the whole collection on every update.\n */\n observableQueryTransferMode: ObservableQueryTransferMode;\n /**\n * Callback that returns custom HTTP headers to include in hub transport requests\n * (e.g. SSE subscribe/unsubscribe POST calls).\n */\n httpHeadersCallback: GetHttpHeaders;\n /**\n * How long in milliseconds to retain a query cache entry after the last subscriber\n * releases it before evicting the subscription and the cached data.\n *\n * A non-zero value allows a user navigating away and back quickly to see cached\n * data immediately instead of waiting for a fresh server round-trip. The entry is\n * still evicted once the window expires, so memory is eventually reclaimed.\n *\n * Defaults to 30 000 ms (30 seconds). Set to 0 to restore the previous\n * immediate-eviction behaviour.\n */\n queryCacheRetentionMs: number;\n}\n\nexport const Globals: IGlobals = {\n microservice: '',\n apiBasePath: '',\n origin: '',\n microserviceHttpHeader: 'x-cratis-microservice',\n microserviceWSQueryArgument: 'x-cratis-microservice',\n queryTransportMethod: QueryTransportMethod.WebSocket,\n queryHttpMethod: QueryHttpMethod.Get,\n queryConnectionCount: 1,\n queryDirectMode: false,\n observableQueryTransferMode: ObservableQueryTransferMode.Delta,\n httpHeadersCallback: () => ({}),\n queryCacheRetentionMs: 30_000,\n};"],"names":["ObservableQueryTransferMode","Globals","microservice","apiBasePath","origin","microserviceHttpHeader","microserviceWSQueryArgument","queryTransportMethod","QueryTransportMethod","WebSocket","queryHttpMethod","QueryHttpMethod","Get","queryConnectionCount","queryDirectMode","observableQueryTransferMode","httpHeadersCallback","queryCacheRetentionMs"],"mappings":";;;AAAA;AACA;AAOA;;;;;;;;;;IAWO,IAAKA,2BAAAA,iBAAAA,SAAAA,2BAAAA,EAAAA;+FACgF,2BAAA,CAAA,OAAA,CAAA,GAAA,OAAA;uDAExC,2BAAA,CAAA,MAAA,CAAA,GAAA,MAAA;AAHxCA,IAAAA,OAAAA,2BAAAA;AAKX,CAAA,CAAA,EAAA;MA2DYC,OAAAA,GAAoB;IAC7BC,YAAAA,EAAc,EAAA;IACdC,WAAAA,EAAa,EAAA;IACbC,MAAAA,EAAQ,EAAA;IACRC,sBAAAA,EAAwB,uBAAA;IACxBC,2BAAAA,EAA6B,uBAAA;AAC7BC,IAAAA,oBAAAA,EAAsBC,qBAAqBC,SAAS;AACpDC,IAAAA,eAAAA,EAAiBC,gBAAgBC,GAAG;IACpCC,oBAAAA,EAAsB,CAAA;IACtBC,eAAAA,EAAiB,KAAA;IACjBC,2BAA2B,EAAA,OAAA;IAC3BC,mBAAAA,EAAqB,KAAO,EAAC,CAAA;IAC7BC,qBAAAA,EAAuB;AAC3B;;;;"}
1
+ {"version":3,"file":"Globals.js","sources":["../../Globals.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { GetHttpHeaders } from './GetHttpHeaders';\nimport { EventSourceFactory } from './EventSourceFactory';\nimport { QueryTransportMethod } from './queries/QueryTransportMethod';\nimport { QueryHttpMethod } from './queries/QueryHttpMethod';\nimport { QueryHttpMethodResolver } from './queries/QueryHttpMethodResolver';\n\n/**\n * Defines the transfer mode used for observable query subscriptions.\n *\n * - {@link ObservableQueryTransferMode.Delta} (default): Only the items that changed since\n * the previous update (added, replaced, removed) are exposed via {@code useChangeStream}.\n * The full collection state is still maintained internally by {@code useObservableQuery}.\n *\n * - {@link ObservableQueryTransferMode.Full}: Every update delivers the complete current\n * collection. The change set returned by {@code useChangeStream} treats the entire new\n * collection as {@code added} and the previous collection as {@code removed}.\n */\nexport enum ObservableQueryTransferMode {\n /** Compute and expose only the items that changed since the previous update (default). */\n Delta = 'delta',\n /** Expose the full collection on every update. */\n Full = 'full',\n}\n\nexport interface IGlobals {\n microservice: string;\n apiBasePath: string;\n origin: string;\n microserviceHttpHeader: string;\n microserviceWSQueryArgument: string;\n queryTransportMethod: QueryTransportMethod;\n /**\n * The HTTP method used to perform non-streaming queries. Defaults to {@link QueryHttpMethod.Get}.\n * Set to {@link QueryHttpMethod.Query} to carry arguments in a JSON request body (RFC 10008)\n * instead of the URL query string. Individual queries can override this via {@code setHttpMethod}.\n */\n queryHttpMethod: QueryHttpMethod;\n /**\n * Optional per-query policy for choosing the query HTTP method from the request (e.g. by URL length).\n * Consulted only when a query has no explicit method set via {@code setHttpMethod}; it takes\n * precedence over {@link queryHttpMethod}. See {@link lengthBasedQueryHttpMethod} for a built-in.\n */\n queryHttpMethodResolver?: QueryHttpMethodResolver;\n /**\n * Number of hub connections maintained for observable queries.\n * When greater than one, queries are distributed across the pool round-robin.\n * Only applies when {@link queryTransportMethod} is a centralized hub transport.\n * Defaults to 1.\n */\n queryConnectionCount: number;\n /**\n * When true, observable queries connect directly to the per-query WebSocket URL\n * instead of routing through the centralized hub endpoint.\n * Defaults to false (use the centralized hub).\n */\n queryDirectMode: boolean;\n /**\n * Controls how observable query updates are transferred and exposed.\n * {@link ObservableQueryTransferMode.Delta} (default) computes per-update deltas;\n * {@link ObservableQueryTransferMode.Full} delivers the whole collection on every update.\n */\n observableQueryTransferMode: ObservableQueryTransferMode;\n /**\n * Callback that returns custom HTTP headers to include in hub transport requests\n * (e.g. SSE subscribe/unsubscribe POST calls).\n */\n httpHeadersCallback: GetHttpHeaders;\n /**\n * Optional factory used to create the {@link EventSource} instances that back SSE\n * observable query connections. Falls back to the global {@link EventSource}\n * constructor when not set — override it to supply a custom SSE client (e.g. a\n * native implementation on React Native, where the global constructor is unavailable).\n */\n eventSourceFactory?: EventSourceFactory;\n /**\n * How long in milliseconds to retain a query cache entry after the last subscriber\n * releases it before evicting the subscription and the cached data.\n *\n * A non-zero value allows a user navigating away and back quickly to see cached\n * data immediately instead of waiting for a fresh server round-trip. The entry is\n * still evicted once the window expires, so memory is eventually reclaimed.\n *\n * Defaults to 30 000 ms (30 seconds). Set to 0 to restore the previous\n * immediate-eviction behaviour.\n */\n queryCacheRetentionMs: number;\n}\n\nexport const Globals: IGlobals = {\n microservice: '',\n apiBasePath: '',\n origin: '',\n microserviceHttpHeader: 'x-cratis-microservice',\n microserviceWSQueryArgument: 'x-cratis-microservice',\n queryTransportMethod: QueryTransportMethod.WebSocket,\n queryHttpMethod: QueryHttpMethod.Get,\n queryConnectionCount: 1,\n queryDirectMode: false,\n observableQueryTransferMode: ObservableQueryTransferMode.Delta,\n httpHeadersCallback: () => ({}),\n queryCacheRetentionMs: 30_000,\n};"],"names":["ObservableQueryTransferMode","Globals","microservice","apiBasePath","origin","microserviceHttpHeader","microserviceWSQueryArgument","queryTransportMethod","QueryTransportMethod","WebSocket","queryHttpMethod","QueryHttpMethod","Get","queryConnectionCount","queryDirectMode","observableQueryTransferMode","httpHeadersCallback","queryCacheRetentionMs"],"mappings":";;;AAAA;AACA;AAQA;;;;;;;;;;IAWO,IAAKA,2BAAAA,iBAAAA,SAAAA,2BAAAA,EAAAA;+FACgF,2BAAA,CAAA,OAAA,CAAA,GAAA,OAAA;uDAExC,2BAAA,CAAA,MAAA,CAAA,GAAA,MAAA;AAHxCA,IAAAA,OAAAA,2BAAAA;AAKX,CAAA,CAAA,EAAA;MAkEYC,OAAAA,GAAoB;IAC7BC,YAAAA,EAAc,EAAA;IACdC,WAAAA,EAAa,EAAA;IACbC,MAAAA,EAAQ,EAAA;IACRC,sBAAAA,EAAwB,uBAAA;IACxBC,2BAAAA,EAA6B,uBAAA;AAC7BC,IAAAA,oBAAAA,EAAsBC,qBAAqBC,SAAS;AACpDC,IAAAA,eAAAA,EAAiBC,gBAAgBC,GAAG;IACpCC,oBAAAA,EAAsB,CAAA;IACtBC,eAAAA,EAAiB,KAAA;IACjBC,2BAA2B,EAAA,OAAA;IAC3BC,mBAAAA,EAAqB,KAAO,EAAC,CAAA;IAC7BC,qBAAAA,EAAuB;AAC3B;;;;"}
@@ -10,5 +10,6 @@ export * from './deepEqual';
10
10
  export * from './Globals';
11
11
  export * from './ICanBeConfigured';
12
12
  export * from './GetHttpHeaders';
13
+ export * from './EventSourceFactory';
13
14
  export { commands, identity, messaging, queries, validation, reflection, };
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAGA,OAAO,iCAAiC,CAAC;AACzC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AAEjC,OAAO,EACH,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,OAAO,EACP,UAAU,EACV,UAAU,GACb,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../index.ts"],"names":[],"mappings":"AAGA,OAAO,iCAAiC,CAAC;AACzC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,OAAO,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,UAAU,MAAM,cAAc,CAAC;AAC3C,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AAErC,OAAO,EACH,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,OAAO,EACP,UAAU,EACV,UAAU,GACb,CAAC"}
@@ -159,7 +159,7 @@ import { HubMessageType } from './WebSocketHubConnection.js';
159
159
  url += (url.includes('?') ? '&' : '?') + param;
160
160
  }
161
161
  this._connectionId = undefined;
162
- this._eventSource = new EventSource(url);
162
+ this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);
163
163
  this._eventSource.onopen = ()=>{
164
164
  if (this._disconnected) return;
165
165
  console.log(`SSE hub connection established: '${url}'`);
@@ -1 +1 @@
1
- {"version":3,"file":"ServerSentEventHubConnection.js","sources":["../../../queries/ServerSentEventHubConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Globals } from '../Globals';\nimport { IObservableQueryHubConnection } from './IObservableQueryHubConnection';\nimport { DataReceived } from './ObservableQueryConnection';\nimport { HubConnectionKeepAlive } from './HubConnectionKeepAlive';\nimport { IReconnectPolicy } from './IReconnectPolicy';\nimport { ReconnectPolicy } from './ReconnectPolicy';\nimport { QueryResult } from './QueryResult';\nimport { HubMessage, HubMessageType, SubscriptionRequest } from './WebSocketHubConnection';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface ActiveSubscription {\n request: SubscriptionRequest;\n callback: DataReceived<any>;\n}\n\n/**\n * How many keep-alive intervals of silence are tolerated before the connection is considered dead.\n *\n * The server guarantees a message every interval, so this is pure slack for latency and jitter.\n * It must stay above 1 — a threshold at or below the server's own cadence makes the client and\n * server timers race, and the client tears down connections the server considers healthy.\n */\nconst IDLE_THRESHOLD_FACTOR = 2;\n\n/**\n * A multiplexed SSE hub connection that uses EventSource for server→client streaming\n * and fetch POST requests for client→server subscribe/unsubscribe commands.\n *\n * Protocol:\n * 1. Open EventSource to the SSE hub endpoint.\n * 2. Server sends a {@link HubMessageType.Connected} message with the connection identifier.\n * 3. Client sends POST to subscribe/unsubscribe endpoints using the connection identifier.\n * 4. Server streams {@link HubMessageType.QueryResult} messages tagged with queryId.\n * 5. When EventSource closes, server cleans up all subscriptions for this connection.\n */\nexport class ServerSentEventHubConnection implements IObservableQueryHubConnection {\n private _eventSource?: EventSource;\n private _connectionId?: string;\n private _disconnected = false;\n private _subscriptions: Map<string, ActiveSubscription> = new Map();\n private _pendingSubscriptions: Map<string, ActiveSubscription> = new Map();\n private _lastPongLatency: number = 0;\n private _latencySamples: number[] = [];\n private _connectTimeoutTimer?: ReturnType<typeof setTimeout>;\n private readonly _keepAlive: HubConnectionKeepAlive;\n\n /**\n * Initializes a new instance of {@link ServerSentEventHubConnection}.\n * @param {string} _sseUrl The SSE hub endpoint URL (e.g. `http://localhost:5000/.cratis/queries/sse`).\n * @param {string} _subscribeUrl The subscribe POST endpoint URL.\n * @param {string} _unsubscribeUrl The unsubscribe POST endpoint URL.\n * @param {string} _microservice The microservice name to pass as a query argument.\n * @param {number} keepAliveIntervalMs The keep-alive cadence to assume until the server advertises\n * its own on the {@link HubMessageType.Connected} message (default: 30 000 ms). The connection is\n * considered stale after {@link IDLE_THRESHOLD_FACTOR} times this without any server message.\n * @param {number} connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}\n * message after the HTTP connection opens before giving up and retrying (default: 15 000 ms).\n * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).\n */\n constructor(\n private readonly _sseUrl: string,\n private readonly _subscribeUrl: string,\n private readonly _unsubscribeUrl: string,\n private readonly _microservice: string,\n keepAliveIntervalMs: number = 30000,\n private readonly _connectTimeoutMs: number = 15000,\n private readonly _policy: IReconnectPolicy = new ReconnectPolicy()\n ) {\n // SSE is server→client only: the client cannot send pings. Instead we watch for\n // inactivity — if the server stops sending messages (including its own keep-alive\n // pings) for the entire idle threshold, the connection is stale and we reconnect.\n //\n // The server guarantees a message at least every keep-alive interval, so the threshold\n // only has to absorb network latency, timer jitter and server-side scheduling hiccups.\n // A hard TCP drop surfaces immediately through `onerror`, so this watchdog only needs to\n // catch silent black-holes — that makes a generous tolerance strictly better than a tight\n // one, which would tear down healthy connections.\n //\n // The interval below is only the starting assumption; the server advertises its real\n // cadence on the Connected message and {@link handleConnected} reconfigures from it.\n this._keepAlive = new HubConnectionKeepAlive(keepAliveIntervalMs, () => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n console.warn(`SSE hub: no messages received for ${this._keepAlive.idleThresholdMs}ms, reconnecting '${this._sseUrl}'`);\n this.reconnect();\n }\n }, keepAliveIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n /** @inheritdoc */\n get queryCount(): number {\n return this._subscriptions.size;\n }\n\n /** @inheritdoc */\n get isConnected(): boolean {\n return this._connectionId !== undefined && this._eventSource?.readyState === EventSource.OPEN;\n }\n\n /** @inheritdoc */\n get lastPingLatency(): number {\n return this._lastPongLatency;\n }\n\n /** @inheritdoc */\n get averageLatency(): number {\n if (this._latencySamples.length === 0) return 0;\n return this._latencySamples.reduce((a, b) => a + b, 0) / this._latencySamples.length;\n }\n\n /** @inheritdoc */\n subscribe(queryId: string, request: SubscriptionRequest, callback: DataReceived<any>): void {\n const sub: ActiveSubscription = { request, callback };\n this._subscriptions.set(queryId, sub);\n\n this.ensureConnected();\n\n if (this._connectionId) {\n this.sendSubscribe(queryId, request);\n } else {\n // Not yet connected, queue for when Connected message arrives.\n this._pendingSubscriptions.set(queryId, sub);\n }\n }\n\n /** @inheritdoc */\n unsubscribe(queryId: string): void {\n this._subscriptions.delete(queryId);\n this._pendingSubscriptions.delete(queryId);\n\n if (this._connectionId) {\n this.sendUnsubscribe(queryId);\n }\n\n if (this._subscriptions.size === 0) {\n this.close();\n }\n }\n\n /** @inheritdoc */\n dispose(): void {\n this._disconnected = true;\n this._subscriptions.clear();\n this._pendingSubscriptions.clear();\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private ensureConnected(): void {\n if (this._disconnected) {\n this._disconnected = false;\n }\n\n if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {\n return;\n }\n\n this.openEventSource();\n }\n\n private close(): void {\n this._disconnected = true;\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n if (this._eventSource) {\n // Detach all handlers BEFORE closing so that the async onerror / onmessage\n // events that fire after close() cannot observe the new _disconnected=false\n // state set by an immediately following ensureConnected() call. Without this,\n // a stale onerror triggers an unintended reconnect with exponential back-off.\n this._eventSource.onopen = null;\n this._eventSource.onmessage = null;\n this._eventSource.onerror = null;\n this._eventSource.close();\n }\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private openEventSource(): void {\n let url = this._sseUrl;\n if (this._microservice?.length > 0) {\n const param = `${Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;\n url += (url.includes('?') ? '&' : '?') + param;\n }\n\n this._connectionId = undefined;\n this._eventSource = new EventSource(url);\n\n this._eventSource.onopen = () => {\n if (this._disconnected) return;\n console.log(`SSE hub connection established: '${url}'`);\n this._policy.reset();\n this._keepAlive.start();\n\n // If the server does not send a Connected message within the timeout, the\n // connection is broken. Close and retry via the reconnect policy.\n this.clearConnectTimeout();\n this._connectTimeoutTimer = setTimeout(() => {\n if (!this._disconnected && !this._connectionId) {\n console.warn(`SSE hub: no Connected message within ${this._connectTimeoutMs}ms, retrying '${url}'`);\n this.reconnect();\n }\n }, this._connectTimeoutMs);\n };\n\n this._eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected) return;\n this._keepAlive.recordActivity();\n this.handleMessage(event.data as string);\n };\n\n this._eventSource.onerror = () => {\n if (this._disconnected) return;\n console.warn(`SSE hub connection error: '${url}'`);\n this.reconnect();\n };\n }\n\n private reconnect(): void {\n this._keepAlive.stop();\n this.clearConnectTimeout();\n\n // Close the EventSource so the reconnect policy manages the schedule.\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n\n // Move all active subscriptions to pending so they re-subscribe when\n // the next Connected message arrives after the managed reconnect.\n for (const [queryId, sub] of this._subscriptions) {\n this._pendingSubscriptions.set(queryId, sub);\n }\n\n if (this._subscriptions.size === 0) return;\n\n this._policy.schedule(() => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n this.openEventSource();\n }\n }, this._sseUrl);\n }\n\n private clearConnectTimeout(): void {\n if (this._connectTimeoutTimer !== undefined) {\n clearTimeout(this._connectTimeoutTimer);\n this._connectTimeoutTimer = undefined;\n }\n }\n\n private handleMessage(rawData: string): void {\n try {\n const message = JSON.parse(rawData) as HubMessage;\n\n switch (message.type) {\n case HubMessageType.Connected:\n this.handleConnected(message);\n break;\n case HubMessageType.QueryResult:\n this.handleQueryResult(message);\n break;\n case HubMessageType.Ping:\n // Server-sent keep-alive ping — activity already recorded in onmessage.\n break;\n case HubMessageType.Unauthorized:\n console.warn(`SSE hub: query '${message.queryId}' unauthorized`);\n this.handleUnauthorized(message);\n break;\n case HubMessageType.Error:\n console.error(`SSE hub: query '${message.queryId}' error:`, message.payload);\n break;\n }\n } catch (error) {\n console.error('SSE hub: error parsing message', error);\n }\n }\n\n private handleConnected(message: HubMessage): void {\n this._connectionId = message.payload as string;\n console.log(`SSE hub: connected with id '${this._connectionId}'`);\n\n // Connected message arrived — cancel the connect timeout.\n this.clearConnectTimeout();\n\n this.applyServerKeepAliveInterval(message.keepAliveIntervalMs);\n\n // Send all pending subscriptions now that we have a connection ID.\n for (const [queryId, sub] of this._pendingSubscriptions) {\n this.sendSubscribe(queryId, sub.request);\n }\n this._pendingSubscriptions.clear();\n }\n\n /**\n * Align the idle watchdog with the keep-alive cadence the server actually runs on.\n *\n * Without this the client assumes the default interval, so a server configured with a longer\n * interval — or with keep-alive switched off entirely — would look silent and be reconnected\n * on a loop even though it is perfectly healthy.\n * @param {number | undefined} serverIntervalMs The interval advertised by the server, if any.\n */\n private applyServerKeepAliveInterval(serverIntervalMs?: number): void {\n if (serverIntervalMs === undefined) return;\n\n // Keep-alive disabled server-side: silence is expected, so watching for it would guarantee\n // an endless reconnect loop. Hard drops still surface through `onerror`.\n if (serverIntervalMs <= 0) {\n this._keepAlive.stop();\n return;\n }\n\n this._keepAlive.reconfigure(serverIntervalMs, serverIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n private handleQueryResult(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n const result = message.payload as QueryResult<any>;\n sub.callback(result);\n }\n\n private handleUnauthorized(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n this._subscriptions.delete(message.queryId);\n this._pendingSubscriptions.delete(message.queryId);\n sub.callback(QueryResult.unauthorized());\n }\n\n private sendSubscribe(queryId: string, request: SubscriptionRequest, attempt: number = 0): void {\n if (!this._connectionId || this._disconnected) return;\n\n // Capture the connection ID so retries can detect if a reconnect has already fired\n // for a different reason and made this retry obsolete.\n const connectionId = this._connectionId;\n\n const body = {\n connectionId,\n queryId,\n request,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n // Maximum number of subscribe retries before falling back to a full SSE reconnect.\n // In a round-robin load-balanced deployment the subscribe POST may land on a different\n // backend instance than the one holding the SSE connection. Retrying gives the load\n // balancer the chance to route a subsequent attempt to the correct instance without\n // tearing down the SSE connection unnecessarily. With N backend instances at most\n // N-1 retries are needed, so 3 retries covers deployments with up to 4 replicas.\n const maxRetries = 3;\n const retryDelayMs = 200;\n\n fetch(this._subscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).then(response => {\n if (!response.ok) {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.warn(`SSE hub: subscribe POST for '${queryId}' returned ${response.status} after ${attempt + 1} attempt(s), reconnecting`);\n this.reconnect();\n }\n }\n }).catch(error => {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.error(`SSE hub: subscribe POST failed for '${queryId}' after ${attempt + 1} attempt(s), reconnecting`, error);\n this.reconnect();\n }\n });\n }\n\n private sendUnsubscribe(queryId: string): void {\n if (!this._connectionId) return;\n\n const body = {\n connectionId: this._connectionId,\n queryId,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n fetch(this._unsubscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).catch(error => {\n console.error(`SSE hub: unsubscribe POST failed for '${queryId}'`, error);\n });\n }\n}\n"],"names":["IDLE_THRESHOLD_FACTOR","ServerSentEventHubConnection","_eventSource","_connectionId","_disconnected","_subscriptions","Map","_pendingSubscriptions","_lastPongLatency","_latencySamples","_connectTimeoutTimer","_keepAlive","_subscribeUrl","_unsubscribeUrl","keepAliveIntervalMs","_connectTimeoutMs","_policy","ReconnectPolicy","_sseUrl","_microservice","HubConnectionKeepAlive","size","console","warn","idleThresholdMs","reconnect","queryCount","isConnected","undefined","readyState","EventSource","OPEN","lastPingLatency","averageLatency","length","reduce","a","b","subscribe","queryId","request","callback","sub","set","ensureConnected","sendSubscribe","unsubscribe","delete","sendUnsubscribe","close","dispose","clear","cancel","stop","clearConnectTimeout","CLOSED","openEventSource","onopen","onmessage","onerror","url","param","Globals","microserviceWSQueryArgument","encodeURIComponent","includes","log","reset","start","setTimeout","event","recordActivity","handleMessage","data","schedule","clearTimeout","rawData","message","JSON","parse","type","HubMessageType","Connected","handleConnected","QueryResult","handleQueryResult","Ping","Unauthorized","handleUnauthorized","Error","error","payload","applyServerKeepAliveInterval","serverIntervalMs","reconfigure","get","result","unauthorized","attempt","connectionId","body","customHeaders","httpHeadersCallback","maxRetries","retryDelayMs","fetch","method","headers","stringify","then","response","ok","status","catch"],"mappings":"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"}
1
+ {"version":3,"file":"ServerSentEventHubConnection.js","sources":["../../../queries/ServerSentEventHubConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Globals } from '../Globals';\nimport { IObservableQueryHubConnection } from './IObservableQueryHubConnection';\nimport { DataReceived } from './ObservableQueryConnection';\nimport { HubConnectionKeepAlive } from './HubConnectionKeepAlive';\nimport { IReconnectPolicy } from './IReconnectPolicy';\nimport { ReconnectPolicy } from './ReconnectPolicy';\nimport { QueryResult } from './QueryResult';\nimport { HubMessage, HubMessageType, SubscriptionRequest } from './WebSocketHubConnection';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface ActiveSubscription {\n request: SubscriptionRequest;\n callback: DataReceived<any>;\n}\n\n/**\n * How many keep-alive intervals of silence are tolerated before the connection is considered dead.\n *\n * The server guarantees a message every interval, so this is pure slack for latency and jitter.\n * It must stay above 1 — a threshold at or below the server's own cadence makes the client and\n * server timers race, and the client tears down connections the server considers healthy.\n */\nconst IDLE_THRESHOLD_FACTOR = 2;\n\n/**\n * A multiplexed SSE hub connection that uses EventSource for server→client streaming\n * and fetch POST requests for client→server subscribe/unsubscribe commands.\n *\n * Protocol:\n * 1. Open EventSource to the SSE hub endpoint.\n * 2. Server sends a {@link HubMessageType.Connected} message with the connection identifier.\n * 3. Client sends POST to subscribe/unsubscribe endpoints using the connection identifier.\n * 4. Server streams {@link HubMessageType.QueryResult} messages tagged with queryId.\n * 5. When EventSource closes, server cleans up all subscriptions for this connection.\n */\nexport class ServerSentEventHubConnection implements IObservableQueryHubConnection {\n private _eventSource?: EventSource;\n private _connectionId?: string;\n private _disconnected = false;\n private _subscriptions: Map<string, ActiveSubscription> = new Map();\n private _pendingSubscriptions: Map<string, ActiveSubscription> = new Map();\n private _lastPongLatency: number = 0;\n private _latencySamples: number[] = [];\n private _connectTimeoutTimer?: ReturnType<typeof setTimeout>;\n private readonly _keepAlive: HubConnectionKeepAlive;\n\n /**\n * Initializes a new instance of {@link ServerSentEventHubConnection}.\n * @param {string} _sseUrl The SSE hub endpoint URL (e.g. `http://localhost:5000/.cratis/queries/sse`).\n * @param {string} _subscribeUrl The subscribe POST endpoint URL.\n * @param {string} _unsubscribeUrl The unsubscribe POST endpoint URL.\n * @param {string} _microservice The microservice name to pass as a query argument.\n * @param {number} keepAliveIntervalMs The keep-alive cadence to assume until the server advertises\n * its own on the {@link HubMessageType.Connected} message (default: 30 000 ms). The connection is\n * considered stale after {@link IDLE_THRESHOLD_FACTOR} times this without any server message.\n * @param {number} connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}\n * message after the HTTP connection opens before giving up and retrying (default: 15 000 ms).\n * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).\n */\n constructor(\n private readonly _sseUrl: string,\n private readonly _subscribeUrl: string,\n private readonly _unsubscribeUrl: string,\n private readonly _microservice: string,\n keepAliveIntervalMs: number = 30000,\n private readonly _connectTimeoutMs: number = 15000,\n private readonly _policy: IReconnectPolicy = new ReconnectPolicy()\n ) {\n // SSE is server→client only: the client cannot send pings. Instead we watch for\n // inactivity — if the server stops sending messages (including its own keep-alive\n // pings) for the entire idle threshold, the connection is stale and we reconnect.\n //\n // The server guarantees a message at least every keep-alive interval, so the threshold\n // only has to absorb network latency, timer jitter and server-side scheduling hiccups.\n // A hard TCP drop surfaces immediately through `onerror`, so this watchdog only needs to\n // catch silent black-holes — that makes a generous tolerance strictly better than a tight\n // one, which would tear down healthy connections.\n //\n // The interval below is only the starting assumption; the server advertises its real\n // cadence on the Connected message and {@link handleConnected} reconfigures from it.\n this._keepAlive = new HubConnectionKeepAlive(keepAliveIntervalMs, () => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n console.warn(`SSE hub: no messages received for ${this._keepAlive.idleThresholdMs}ms, reconnecting '${this._sseUrl}'`);\n this.reconnect();\n }\n }, keepAliveIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n /** @inheritdoc */\n get queryCount(): number {\n return this._subscriptions.size;\n }\n\n /** @inheritdoc */\n get isConnected(): boolean {\n return this._connectionId !== undefined && this._eventSource?.readyState === EventSource.OPEN;\n }\n\n /** @inheritdoc */\n get lastPingLatency(): number {\n return this._lastPongLatency;\n }\n\n /** @inheritdoc */\n get averageLatency(): number {\n if (this._latencySamples.length === 0) return 0;\n return this._latencySamples.reduce((a, b) => a + b, 0) / this._latencySamples.length;\n }\n\n /** @inheritdoc */\n subscribe(queryId: string, request: SubscriptionRequest, callback: DataReceived<any>): void {\n const sub: ActiveSubscription = { request, callback };\n this._subscriptions.set(queryId, sub);\n\n this.ensureConnected();\n\n if (this._connectionId) {\n this.sendSubscribe(queryId, request);\n } else {\n // Not yet connected, queue for when Connected message arrives.\n this._pendingSubscriptions.set(queryId, sub);\n }\n }\n\n /** @inheritdoc */\n unsubscribe(queryId: string): void {\n this._subscriptions.delete(queryId);\n this._pendingSubscriptions.delete(queryId);\n\n if (this._connectionId) {\n this.sendUnsubscribe(queryId);\n }\n\n if (this._subscriptions.size === 0) {\n this.close();\n }\n }\n\n /** @inheritdoc */\n dispose(): void {\n this._disconnected = true;\n this._subscriptions.clear();\n this._pendingSubscriptions.clear();\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private ensureConnected(): void {\n if (this._disconnected) {\n this._disconnected = false;\n }\n\n if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {\n return;\n }\n\n this.openEventSource();\n }\n\n private close(): void {\n this._disconnected = true;\n this._policy.cancel();\n this._keepAlive.stop();\n this.clearConnectTimeout();\n if (this._eventSource) {\n // Detach all handlers BEFORE closing so that the async onerror / onmessage\n // events that fire after close() cannot observe the new _disconnected=false\n // state set by an immediately following ensureConnected() call. Without this,\n // a stale onerror triggers an unintended reconnect with exponential back-off.\n this._eventSource.onopen = null;\n this._eventSource.onmessage = null;\n this._eventSource.onerror = null;\n this._eventSource.close();\n }\n this._eventSource = undefined;\n this._connectionId = undefined;\n }\n\n private openEventSource(): void {\n let url = this._sseUrl;\n if (this._microservice?.length > 0) {\n const param = `${Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;\n url += (url.includes('?') ? '&' : '?') + param;\n }\n\n this._connectionId = undefined;\n this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);\n\n this._eventSource.onopen = () => {\n if (this._disconnected) return;\n console.log(`SSE hub connection established: '${url}'`);\n this._policy.reset();\n this._keepAlive.start();\n\n // If the server does not send a Connected message within the timeout, the\n // connection is broken. Close and retry via the reconnect policy.\n this.clearConnectTimeout();\n this._connectTimeoutTimer = setTimeout(() => {\n if (!this._disconnected && !this._connectionId) {\n console.warn(`SSE hub: no Connected message within ${this._connectTimeoutMs}ms, retrying '${url}'`);\n this.reconnect();\n }\n }, this._connectTimeoutMs);\n };\n\n this._eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected) return;\n this._keepAlive.recordActivity();\n this.handleMessage(event.data as string);\n };\n\n this._eventSource.onerror = () => {\n if (this._disconnected) return;\n console.warn(`SSE hub connection error: '${url}'`);\n this.reconnect();\n };\n }\n\n private reconnect(): void {\n this._keepAlive.stop();\n this.clearConnectTimeout();\n\n // Close the EventSource so the reconnect policy manages the schedule.\n this._eventSource?.close();\n this._eventSource = undefined;\n this._connectionId = undefined;\n\n // Move all active subscriptions to pending so they re-subscribe when\n // the next Connected message arrives after the managed reconnect.\n for (const [queryId, sub] of this._subscriptions) {\n this._pendingSubscriptions.set(queryId, sub);\n }\n\n if (this._subscriptions.size === 0) return;\n\n this._policy.schedule(() => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n this.openEventSource();\n }\n }, this._sseUrl);\n }\n\n private clearConnectTimeout(): void {\n if (this._connectTimeoutTimer !== undefined) {\n clearTimeout(this._connectTimeoutTimer);\n this._connectTimeoutTimer = undefined;\n }\n }\n\n private handleMessage(rawData: string): void {\n try {\n const message = JSON.parse(rawData) as HubMessage;\n\n switch (message.type) {\n case HubMessageType.Connected:\n this.handleConnected(message);\n break;\n case HubMessageType.QueryResult:\n this.handleQueryResult(message);\n break;\n case HubMessageType.Ping:\n // Server-sent keep-alive ping — activity already recorded in onmessage.\n break;\n case HubMessageType.Unauthorized:\n console.warn(`SSE hub: query '${message.queryId}' unauthorized`);\n this.handleUnauthorized(message);\n break;\n case HubMessageType.Error:\n console.error(`SSE hub: query '${message.queryId}' error:`, message.payload);\n break;\n }\n } catch (error) {\n console.error('SSE hub: error parsing message', error);\n }\n }\n\n private handleConnected(message: HubMessage): void {\n this._connectionId = message.payload as string;\n console.log(`SSE hub: connected with id '${this._connectionId}'`);\n\n // Connected message arrived — cancel the connect timeout.\n this.clearConnectTimeout();\n\n this.applyServerKeepAliveInterval(message.keepAliveIntervalMs);\n\n // Send all pending subscriptions now that we have a connection ID.\n for (const [queryId, sub] of this._pendingSubscriptions) {\n this.sendSubscribe(queryId, sub.request);\n }\n this._pendingSubscriptions.clear();\n }\n\n /**\n * Align the idle watchdog with the keep-alive cadence the server actually runs on.\n *\n * Without this the client assumes the default interval, so a server configured with a longer\n * interval — or with keep-alive switched off entirely — would look silent and be reconnected\n * on a loop even though it is perfectly healthy.\n * @param {number | undefined} serverIntervalMs The interval advertised by the server, if any.\n */\n private applyServerKeepAliveInterval(serverIntervalMs?: number): void {\n if (serverIntervalMs === undefined) return;\n\n // Keep-alive disabled server-side: silence is expected, so watching for it would guarantee\n // an endless reconnect loop. Hard drops still surface through `onerror`.\n if (serverIntervalMs <= 0) {\n this._keepAlive.stop();\n return;\n }\n\n this._keepAlive.reconfigure(serverIntervalMs, serverIntervalMs * IDLE_THRESHOLD_FACTOR);\n }\n\n private handleQueryResult(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n const result = message.payload as QueryResult<any>;\n sub.callback(result);\n }\n\n private handleUnauthorized(message: HubMessage): void {\n if (!message.queryId) return;\n\n const sub = this._subscriptions.get(message.queryId);\n if (!sub) return;\n\n this._subscriptions.delete(message.queryId);\n this._pendingSubscriptions.delete(message.queryId);\n sub.callback(QueryResult.unauthorized());\n }\n\n private sendSubscribe(queryId: string, request: SubscriptionRequest, attempt: number = 0): void {\n if (!this._connectionId || this._disconnected) return;\n\n // Capture the connection ID so retries can detect if a reconnect has already fired\n // for a different reason and made this retry obsolete.\n const connectionId = this._connectionId;\n\n const body = {\n connectionId,\n queryId,\n request,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n // Maximum number of subscribe retries before falling back to a full SSE reconnect.\n // In a round-robin load-balanced deployment the subscribe POST may land on a different\n // backend instance than the one holding the SSE connection. Retrying gives the load\n // balancer the chance to route a subsequent attempt to the correct instance without\n // tearing down the SSE connection unnecessarily. With N backend instances at most\n // N-1 retries are needed, so 3 retries covers deployments with up to 4 replicas.\n const maxRetries = 3;\n const retryDelayMs = 200;\n\n fetch(this._subscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).then(response => {\n if (!response.ok) {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.warn(`SSE hub: subscribe POST for '${queryId}' returned ${response.status} after ${attempt + 1} attempt(s), reconnecting`);\n this.reconnect();\n }\n }\n }).catch(error => {\n if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {\n setTimeout(() => this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));\n } else if (this._connectionId === connectionId && !this._disconnected) {\n console.error(`SSE hub: subscribe POST failed for '${queryId}' after ${attempt + 1} attempt(s), reconnecting`, error);\n this.reconnect();\n }\n });\n }\n\n private sendUnsubscribe(queryId: string): void {\n if (!this._connectionId) return;\n\n const body = {\n connectionId: this._connectionId,\n queryId,\n };\n\n const customHeaders = Globals.httpHeadersCallback?.() ?? {};\n\n fetch(this._unsubscribeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...customHeaders },\n body: JSON.stringify(body),\n }).catch(error => {\n console.error(`SSE hub: unsubscribe POST failed for '${queryId}'`, error);\n });\n }\n}\n"],"names":["IDLE_THRESHOLD_FACTOR","ServerSentEventHubConnection","_eventSource","_connectionId","_disconnected","_subscriptions","Map","_pendingSubscriptions","_lastPongLatency","_latencySamples","_connectTimeoutTimer","_keepAlive","_subscribeUrl","_unsubscribeUrl","keepAliveIntervalMs","_connectTimeoutMs","_policy","ReconnectPolicy","_sseUrl","_microservice","HubConnectionKeepAlive","size","console","warn","idleThresholdMs","reconnect","queryCount","isConnected","undefined","readyState","EventSource","OPEN","lastPingLatency","averageLatency","length","reduce","a","b","subscribe","queryId","request","callback","sub","set","ensureConnected","sendSubscribe","unsubscribe","delete","sendUnsubscribe","close","dispose","clear","cancel","stop","clearConnectTimeout","CLOSED","openEventSource","onopen","onmessage","onerror","url","param","Globals","microserviceWSQueryArgument","encodeURIComponent","includes","eventSourceFactory","log","reset","start","setTimeout","event","recordActivity","handleMessage","data","schedule","clearTimeout","rawData","message","JSON","parse","type","HubMessageType","Connected","handleConnected","QueryResult","handleQueryResult","Ping","Unauthorized","handleUnauthorized","Error","error","payload","applyServerKeepAliveInterval","serverIntervalMs","reconfigure","get","result","unauthorized","attempt","connectionId","body","customHeaders","httpHeadersCallback","maxRetries","retryDelayMs","fetch","method","headers","stringify","then","response","ok","status","catch"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ServerSentEventQueryConnection.d.ts","sourceRoot":"","sources":["../../../queries/ServerSentEventQueryConnection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAM3D,eAAO,MAAM,aAAa,yBAAyB,CAAC;AAWpD,qBAAa,8BAA8B,CAAC,SAAS,CAAE,YAAW,0BAA0B,CAAC,SAAS,CAAC;IAcvF,OAAO,CAAC,QAAQ,CAAC,IAAI;IAbjC,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,aAAa,CAAS;IAG9B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAK;IAGrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAK;IAMpC,YAA6B,IAAI,EAAE,GAAG,EAAI;IAG1C,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAoC5E;IAGD,UAAU,IAAI,IAAI,CAKjB;CACJ"}
1
+ {"version":3,"file":"ServerSentEventQueryConnection.d.ts","sourceRoot":"","sources":["../../../queries/ServerSentEventQueryConnection.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAM3D,eAAO,MAAM,aAAa,yBAAyB,CAAC;AAWpD,qBAAa,8BAA8B,CAAC,SAAS,CAAE,YAAW,0BAA0B,CAAC,SAAS,CAAC;IAcvF,OAAO,CAAC,QAAQ,CAAC,IAAI;IAbjC,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,aAAa,CAAS;IAG9B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAK;IAGrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAK;IAMpC,YAA6B,IAAI,EAAE,GAAG,EAAI;IAG1C,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAqC5E;IAGD,UAAU,IAAI,IAAI,CAKjB;CACJ"}
@@ -1,3 +1,5 @@
1
+ import { Globals } from '../Globals.js';
2
+
1
3
  // Copyright (c) Cratis. All rights reserved.
2
4
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
5
  /**
@@ -25,8 +27,9 @@
25
27
  }
26
28
  /** @inheritdoc */ connect(dataReceived, queryArguments) {
27
29
  if (this._disconnected) return;
28
- // Guard against environments where EventSource is not available (e.g. Node.js, SSR).
29
- if (typeof EventSource === 'undefined') {
30
+ // Guard against environments where EventSource is not available (e.g. Node.js, SSR)
31
+ // and no custom factory has been supplied to substitute it.
32
+ if (!Globals.eventSourceFactory && typeof EventSource === 'undefined') {
30
33
  return;
31
34
  }
32
35
  let url = this._url.toString();
@@ -37,7 +40,7 @@
37
40
  url = `${url}${separator}${query}`;
38
41
  }
39
42
  }
40
- this._eventSource = new EventSource(url);
43
+ this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);
41
44
  this._eventSource.onmessage = (event)=>{
42
45
  if (this._disconnected) return;
43
46
  try {