@cratis/arc 22.0.2 → 22.2.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 (189) hide show
  1. package/dist/cjs/queries/ObservableQueryFor.js +6 -1
  2. package/dist/cjs/queries/ObservableQueryFor.js.map +1 -1
  3. package/dist/cjs/queries/QueryInstanceCache.js +6 -6
  4. package/dist/cjs/queries/QueryInstanceCache.js.map +1 -1
  5. package/dist/cjs/queries/QueryResult.js +23 -4
  6. package/dist/cjs/queries/QueryResult.js.map +1 -1
  7. package/dist/cjs/queries/QueryResultWithState.js +20 -7
  8. package/dist/cjs/queries/QueryResultWithState.js.map +1 -1
  9. package/dist/cjs/queries/ServerSentEventHubConnection.js +120 -58
  10. package/dist/cjs/queries/ServerSentEventHubConnection.js.map +1 -1
  11. package/dist/cjs/queries/WebSocketHubConnection.js +121 -51
  12. package/dist/cjs/queries/WebSocketHubConnection.js.map +1 -1
  13. package/dist/esm/queries/IQueryResult.d.ts +1 -0
  14. package/dist/esm/queries/IQueryResult.d.ts.map +1 -1
  15. package/dist/esm/queries/ObservableQueryFor.d.ts.map +1 -1
  16. package/dist/esm/queries/ObservableQueryFor.js +6 -1
  17. package/dist/esm/queries/ObservableQueryFor.js.map +1 -1
  18. package/dist/esm/queries/QueryInstanceCache.d.ts +1 -1
  19. package/dist/esm/queries/QueryInstanceCache.d.ts.map +1 -1
  20. package/dist/esm/queries/QueryInstanceCache.js +6 -6
  21. package/dist/esm/queries/QueryInstanceCache.js.map +1 -1
  22. package/dist/esm/queries/QueryResult.d.ts +2 -0
  23. package/dist/esm/queries/QueryResult.d.ts.map +1 -1
  24. package/dist/esm/queries/QueryResult.js +23 -4
  25. package/dist/esm/queries/QueryResult.js.map +1 -1
  26. package/dist/esm/queries/QueryResultWithState.d.ts +3 -3
  27. package/dist/esm/queries/QueryResultWithState.d.ts.map +1 -1
  28. package/dist/esm/queries/QueryResultWithState.js +20 -7
  29. package/dist/esm/queries/QueryResultWithState.js.map +1 -1
  30. package/dist/esm/queries/ServerSentEventHubConnection.d.ts +11 -4
  31. package/dist/esm/queries/ServerSentEventHubConnection.d.ts.map +1 -1
  32. package/dist/esm/queries/ServerSentEventHubConnection.js +120 -58
  33. package/dist/esm/queries/ServerSentEventHubConnection.js.map +1 -1
  34. package/dist/esm/queries/WebSocketHubConnection.d.ts +13 -2
  35. package/dist/esm/queries/WebSocketHubConnection.d.ts.map +1 -1
  36. package/dist/esm/queries/WebSocketHubConnection.js +121 -51
  37. package/dist/esm/queries/WebSocketHubConnection.js.map +1 -1
  38. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_a_not_ready_result.d.ts +2 -0
  39. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_a_not_ready_result.d.ts.map +1 -0
  40. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_a_not_ready_result.js +34 -0
  41. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_a_not_ready_result.js.map +1 -0
  42. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_direct_mode_and_sse_transport.js +26 -2
  43. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_direct_mode_and_sse_transport.js.map +1 -1
  44. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_direct_mode_disabled_and_sse_transport.js +60 -3
  45. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_direct_mode_disabled_and_sse_transport.js.map +1 -1
  46. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_web_socket_hub_payload_without_readiness.d.ts +2 -0
  47. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_web_socket_hub_payload_without_readiness.d.ts.map +1 -0
  48. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_web_socket_hub_payload_without_readiness.js +83 -0
  49. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_web_socket_hub_payload_without_readiness.js.map +1 -0
  50. package/dist/esm/queries/for_QueryInstanceCache/when_setting_last_result/with_only_readiness_changed.d.ts +2 -0
  51. package/dist/esm/queries/for_QueryInstanceCache/when_setting_last_result/with_only_readiness_changed.d.ts.map +1 -0
  52. package/dist/esm/queries/for_QueryInstanceCache/when_setting_last_result/with_only_readiness_changed.js +22 -0
  53. package/dist/esm/queries/for_QueryInstanceCache/when_setting_last_result/with_only_readiness_changed.js.map +1 -0
  54. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/with_readiness_false.d.ts +2 -0
  55. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/with_readiness_false.d.ts.map +1 -0
  56. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/with_readiness_false.js +17 -0
  57. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/with_readiness_false.js.map +1 -0
  58. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/without_readiness.d.ts +2 -0
  59. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/without_readiness.d.ts.map +1 -0
  60. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/without_readiness.js +16 -0
  61. package/dist/esm/queries/for_QueryResult/when_constructing_from_a_server_result/without_readiness.js.map +1 -0
  62. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/with_readiness_false.d.ts +2 -0
  63. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/with_readiness_false.d.ts.map +1 -0
  64. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/with_readiness_false.js +19 -0
  65. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/with_readiness_false.js.map +1 -0
  66. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/without_readiness.d.ts +2 -0
  67. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/without_readiness.d.ts.map +1 -0
  68. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/without_readiness.js +19 -0
  69. package/dist/esm/queries/for_QueryResultWithState/when_creating_from_query_result/without_readiness.js.map +1 -0
  70. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_deferred_promise.d.ts +7 -0
  71. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_deferred_promise.d.ts.map +1 -0
  72. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_deferred_promise.js +12 -0
  73. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_deferred_promise.js.map +1 -0
  74. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_server_sent_event_hub_connection.d.ts +2 -1
  75. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_server_sent_event_hub_connection.d.ts.map +1 -1
  76. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_server_sent_event_hub_connection.js +15 -4
  77. package/dist/esm/queries/for_ServerSentEventHubConnection/given/a_server_sent_event_hub_connection.js.map +1 -1
  78. package/dist/esm/queries/for_ServerSentEventHubConnection/when_a_retired_event_source_fires/ignores_connected_and_error_callbacks.d.ts +2 -0
  79. package/dist/esm/queries/for_ServerSentEventHubConnection/when_a_retired_event_source_fires/ignores_connected_and_error_callbacks.d.ts.map +1 -0
  80. package/dist/esm/queries/for_ServerSentEventHubConnection/when_a_retired_event_source_fires/ignores_connected_and_error_callbacks.js +44 -0
  81. package/dist/esm/queries/for_ServerSentEventHubConnection/when_a_retired_event_source_fires/ignores_connected_and_error_callbacks.js.map +1 -0
  82. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_replaced.d.ts +2 -0
  83. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_replaced.d.ts.map +1 -0
  84. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_replaced.js +74 -0
  85. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_replaced.js.map +1 -0
  86. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_unsubscribed.d.ts +2 -0
  87. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_unsubscribed.d.ts.map +1 -0
  88. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_unsubscribed.js +74 -0
  89. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_unsubscribed.js.map +1 -0
  90. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_is_rejected.d.ts +2 -0
  91. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_is_rejected.d.ts.map +1 -0
  92. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_is_rejected.js +59 -0
  93. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_is_rejected.js.map +1 -0
  94. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_returns_non_ok.d.ts +2 -0
  95. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_returns_non_ok.d.ts.map +1 -0
  96. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_returns_non_ok.js +58 -0
  97. package/dist/esm/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_returns_non_ok.js.map +1 -0
  98. package/dist/esm/queries/for_ServerSentEventHubConnection/when_disposing/cleans_up_resources.js +6 -3
  99. package/dist/esm/queries/for_ServerSentEventHubConnection/when_disposing/cleans_up_resources.js.map +1 -1
  100. package/dist/esm/queries/for_ServerSentEventHubConnection/when_receiving_unauthorized/notifies_subscriber_and_removes_subscription.js +23 -6
  101. package/dist/esm/queries/for_ServerSentEventHubConnection/when_receiving_unauthorized/notifies_subscriber_and_removes_subscription.js.map +1 -1
  102. package/dist/esm/queries/for_ServerSentEventHubConnection/when_reconnecting/after_error.js +20 -5
  103. package/dist/esm/queries/for_ServerSentEventHubConnection/when_reconnecting/after_error.js.map +1 -1
  104. package/dist/esm/queries/for_ServerSentEventHubConnection/when_reconnecting/and_an_immediate_open_wins_the_backoff_race.d.ts +2 -0
  105. package/dist/esm/queries/for_ServerSentEventHubConnection/when_reconnecting/and_an_immediate_open_wins_the_backoff_race.d.ts.map +1 -0
  106. package/dist/esm/queries/for_ServerSentEventHubConnection/when_reconnecting/and_an_immediate_open_wins_the_backoff_race.js +20 -0
  107. package/dist/esm/queries/for_ServerSentEventHubConnection/when_reconnecting/and_an_immediate_open_wins_the_backoff_race.js.map +1 -0
  108. package/dist/esm/queries/for_ServerSentEventHubConnection/when_replacing_a_subscription/ignores_messages_from_the_retired_generation.d.ts +2 -0
  109. package/dist/esm/queries/for_ServerSentEventHubConnection/when_replacing_a_subscription/ignores_messages_from_the_retired_generation.d.ts.map +1 -0
  110. package/dist/esm/queries/for_ServerSentEventHubConnection/when_replacing_a_subscription/ignores_messages_from_the_retired_generation.js +68 -0
  111. package/dist/esm/queries/for_ServerSentEventHubConnection/when_replacing_a_subscription/ignores_messages_from_the_retired_generation.js.map +1 -0
  112. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscribing/sends_subscribe_post.js +38 -13
  113. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscribing/sends_subscribe_post.js.map +1 -1
  114. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscription_revisions_are_not_advertised/uses_legacy_protocol.d.ts +2 -0
  115. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscription_revisions_are_not_advertised/uses_legacy_protocol.d.ts.map +1 -0
  116. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscription_revisions_are_not_advertised/uses_legacy_protocol.js +54 -0
  117. package/dist/esm/queries/for_ServerSentEventHubConnection/when_subscription_revisions_are_not_advertised/uses_legacy_protocol.js.map +1 -0
  118. package/dist/esm/queries/for_ServerSentEventHubConnection/when_unsubscribing/the_only_query.js +18 -4
  119. package/dist/esm/queries/for_ServerSentEventHubConnection/when_unsubscribing/the_only_query.js.map +1 -1
  120. package/dist/esm/queries/for_WebSocketHubConnection/when_receiving_unauthorized/notifies_subscriber_and_removes_subscription.js +22 -5
  121. package/dist/esm/queries/for_WebSocketHubConnection/when_receiving_unauthorized/notifies_subscriber_and_removes_subscription.js.map +1 -1
  122. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/ignores_a_pending_reconnect_and_stale_socket_callbacks.d.ts +2 -0
  123. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/ignores_a_pending_reconnect_and_stale_socket_callbacks.d.ts.map +1 -0
  124. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/ignores_a_pending_reconnect_and_stale_socket_callbacks.js +108 -0
  125. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/ignores_a_pending_reconnect_and_stale_socket_callbacks.js.map +1 -0
  126. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/replaces_a_closing_socket_safely.d.ts +2 -0
  127. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/replaces_a_closing_socket_safely.d.ts.map +1 -0
  128. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/replaces_a_closing_socket_safely.js +33 -0
  129. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/replaces_a_closing_socket_safely.js.map +1 -0
  130. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/resubscribes_all_queries.js +26 -4
  131. package/dist/esm/queries/for_WebSocketHubConnection/when_reconnecting/resubscribes_all_queries.js.map +1 -1
  132. package/dist/esm/queries/for_WebSocketHubConnection/when_replacing_a_subscription/ignores_stale_result_unauthorized_and_error.d.ts +2 -0
  133. package/dist/esm/queries/for_WebSocketHubConnection/when_replacing_a_subscription/ignores_stale_result_unauthorized_and_error.d.ts.map +1 -0
  134. package/dist/esm/queries/for_WebSocketHubConnection/when_replacing_a_subscription/ignores_stale_result_unauthorized_and_error.js +62 -0
  135. package/dist/esm/queries/for_WebSocketHubConnection/when_replacing_a_subscription/ignores_stale_result_unauthorized_and_error.js.map +1 -0
  136. package/dist/esm/queries/for_WebSocketHubConnection/when_subscribing/to_a_query.js +18 -5
  137. package/dist/esm/queries/for_WebSocketHubConnection/when_subscribing/to_a_query.js.map +1 -1
  138. package/dist/esm/queries/for_WebSocketHubConnection/when_subscription_revisions_are_supported/upgrades_active_subscriptions_to_strict_mode.d.ts +2 -0
  139. package/dist/esm/queries/for_WebSocketHubConnection/when_subscription_revisions_are_supported/upgrades_active_subscriptions_to_strict_mode.d.ts.map +1 -0
  140. package/dist/esm/queries/for_WebSocketHubConnection/when_subscription_revisions_are_supported/upgrades_active_subscriptions_to_strict_mode.js +56 -0
  141. package/dist/esm/queries/for_WebSocketHubConnection/when_subscription_revisions_are_supported/upgrades_active_subscriptions_to_strict_mode.js.map +1 -0
  142. package/dist/esm/queries/for_WebSocketHubConnection/when_unsubscribing/the_only_query.js +16 -3
  143. package/dist/esm/queries/for_WebSocketHubConnection/when_unsubscribing/the_only_query.js.map +1 -1
  144. package/dist/esm/queries/for_WebSocketHubConnection/when_unsubscribing/with_revision_support_not_advertised.d.ts +2 -0
  145. package/dist/esm/queries/for_WebSocketHubConnection/when_unsubscribing/with_revision_support_not_advertised.d.ts.map +1 -0
  146. package/dist/esm/queries/for_WebSocketHubConnection/when_unsubscribing/with_revision_support_not_advertised.js +33 -0
  147. package/dist/esm/queries/for_WebSocketHubConnection/when_unsubscribing/with_revision_support_not_advertised.js.map +1 -0
  148. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  149. package/package.json +1 -1
  150. package/queries/IQueryResult.ts +10 -0
  151. package/queries/ObservableQueryFor.ts +44 -16
  152. package/queries/QueryInstanceCache.ts +42 -19
  153. package/queries/QueryResult.ts +145 -79
  154. package/queries/QueryResultWithState.ts +32 -9
  155. package/queries/ServerSentEventHubConnection.ts +270 -83
  156. package/queries/WebSocketHubConnection.ts +188 -56
  157. package/queries/for_ObservableQueryFor/when_performing/with_a_not_ready_result.ts +46 -0
  158. package/queries/for_ObservableQueryFor/when_subscribing/with_direct_mode_and_sse_transport.ts +91 -57
  159. package/queries/for_ObservableQueryFor/when_subscribing/with_direct_mode_disabled_and_sse_transport.ts +125 -53
  160. package/queries/for_ObservableQueryFor/when_subscribing/with_web_socket_hub_payload_without_readiness.ts +107 -0
  161. package/queries/for_QueryInstanceCache/when_setting_last_result/with_only_readiness_changed.ts +63 -0
  162. package/queries/for_QueryResult/when_constructing_from_a_server_result/with_readiness_false.ts +25 -0
  163. package/queries/for_QueryResult/when_constructing_from_a_server_result/without_readiness.ts +24 -0
  164. package/queries/for_QueryResultWithState/when_creating_from_query_result/with_readiness_false.ts +28 -0
  165. package/queries/for_QueryResultWithState/when_creating_from_query_result/without_readiness.ts +25 -0
  166. package/queries/for_ServerSentEventHubConnection/given/a_deferred_promise.ts +15 -0
  167. package/queries/for_ServerSentEventHubConnection/given/a_server_sent_event_hub_connection.ts +18 -7
  168. package/queries/for_ServerSentEventHubConnection/when_a_retired_event_source_fires/ignores_connected_and_error_callbacks.ts +59 -0
  169. package/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_replaced.ts +113 -0
  170. package/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_query_is_unsubscribed.ts +109 -0
  171. package/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_is_rejected.ts +81 -0
  172. package/queries/for_ServerSentEventHubConnection/when_connection_changes_while_subscribe_is_in_flight/and_the_stale_request_returns_non_ok.ts +83 -0
  173. package/queries/for_ServerSentEventHubConnection/when_disposing/cleans_up_resources.ts +30 -21
  174. package/queries/for_ServerSentEventHubConnection/when_receiving_unauthorized/notifies_subscriber_and_removes_subscription.ts +56 -32
  175. package/queries/for_ServerSentEventHubConnection/when_reconnecting/after_error.ts +23 -6
  176. package/queries/for_ServerSentEventHubConnection/when_reconnecting/and_an_immediate_open_wins_the_backoff_race.ts +41 -0
  177. package/queries/for_ServerSentEventHubConnection/when_replacing_a_subscription/ignores_messages_from_the_retired_generation.ts +92 -0
  178. package/queries/for_ServerSentEventHubConnection/when_subscribing/sends_subscribe_post.ts +69 -30
  179. package/queries/for_ServerSentEventHubConnection/when_subscription_revisions_are_not_advertised/uses_legacy_protocol.ts +69 -0
  180. package/queries/for_ServerSentEventHubConnection/when_unsubscribing/the_only_query.ts +43 -24
  181. package/queries/for_WebSocketHubConnection/when_receiving_unauthorized/notifies_subscriber_and_removes_subscription.ts +53 -29
  182. package/queries/for_WebSocketHubConnection/when_reconnecting/ignores_a_pending_reconnect_and_stale_socket_callbacks.ts +131 -0
  183. package/queries/for_WebSocketHubConnection/when_reconnecting/replaces_a_closing_socket_safely.ts +39 -0
  184. package/queries/for_WebSocketHubConnection/when_reconnecting/resubscribes_all_queries.ts +72 -36
  185. package/queries/for_WebSocketHubConnection/when_replacing_a_subscription/ignores_stale_result_unauthorized_and_error.ts +88 -0
  186. package/queries/for_WebSocketHubConnection/when_subscribing/to_a_query.ts +54 -27
  187. package/queries/for_WebSocketHubConnection/when_subscription_revisions_are_supported/upgrades_active_subscriptions_to_strict_mode.ts +72 -0
  188. package/queries/for_WebSocketHubConnection/when_unsubscribing/the_only_query.ts +43 -18
  189. package/queries/for_WebSocketHubConnection/when_unsubscribing/with_revision_support_not_advertised.ts +44 -0
@@ -38,6 +38,8 @@ import { HubMessageType } from './WebSocketHubConnection.js';
38
38
  _lastPongLatency = 0;
39
39
  _latencySamples = [];
40
40
  _connectTimeoutTimer;
41
+ _nextRevision = 0;
42
+ _supportsSubscriptionRevisions = false;
41
43
  _keepAlive;
42
44
  /**
43
45
  * Initializes a new instance of {@link ServerSentEventHubConnection}.
@@ -48,7 +50,7 @@ import { HubMessageType } from './WebSocketHubConnection.js';
48
50
  * @param {number} keepAliveIntervalMs The keep-alive cadence to assume until the server advertises
49
51
  * its own on the {@link HubMessageType.Connected} message (default: 30 000 ms). The connection is
50
52
  * considered stale after {@link IDLE_THRESHOLD_FACTOR} times this without any server message.
51
- * @param {number} connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}
53
+ * @param {number} _connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}
52
54
  * message after the HTTP connection opens before giving up and retrying (default: 15 000 ms).
53
55
  * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).
54
56
  */ constructor(_sseUrl, _subscribeUrl, _unsubscribeUrl, _microservice, keepAliveIntervalMs = 30000, _connectTimeoutMs = 15000, _policy = new ReconnectPolicy()){
@@ -72,7 +74,7 @@ import { HubMessageType } from './WebSocketHubConnection.js';
72
74
  // cadence on the Connected message and {@link handleConnected} reconfigures from it.
73
75
  this._keepAlive = new HubConnectionKeepAlive(keepAliveIntervalMs, ()=>{
74
76
  if (!this._disconnected && this._subscriptions.size > 0) {
75
- console.warn(`SSE hub: no messages received for ${this._keepAlive.idleThresholdMs}ms, reconnecting '${this._sseUrl}'`);
77
+ console.warn('SSE hub: no messages received; reconnecting', this._keepAlive.idleThresholdMs, this._sseUrl);
76
78
  this.reconnect();
77
79
  }
78
80
  }, keepAliveIntervalMs * IDLE_THRESHOLD_FACTOR);
@@ -93,22 +95,24 @@ import { HubMessageType } from './WebSocketHubConnection.js';
93
95
  /** @inheritdoc */ subscribe(queryId, request, callback) {
94
96
  const sub = {
95
97
  request,
96
- callback
98
+ callback,
99
+ revision: this.getNextRevision()
97
100
  };
98
101
  this._subscriptions.set(queryId, sub);
99
102
  this.ensureConnected();
100
103
  if (this._connectionId) {
101
- this.sendSubscribe(queryId, request);
104
+ this.sendSubscribe(queryId, sub);
102
105
  } else {
103
106
  // Not yet connected, queue for when Connected message arrives.
104
107
  this._pendingSubscriptions.set(queryId, sub);
105
108
  }
106
109
  }
107
110
  /** @inheritdoc */ unsubscribe(queryId) {
111
+ const subscription = this._subscriptions.get(queryId);
108
112
  this._subscriptions.delete(queryId);
109
113
  this._pendingSubscriptions.delete(queryId);
110
- if (this._connectionId) {
111
- this.sendUnsubscribe(queryId);
114
+ if (this._connectionId && subscription) {
115
+ this.sendUnsubscribe(queryId, subscription.revision);
112
116
  }
113
117
  if (this._subscriptions.size === 0) {
114
118
  this.close();
@@ -121,10 +125,20 @@ import { HubMessageType } from './WebSocketHubConnection.js';
121
125
  this._policy.cancel();
122
126
  this._keepAlive.stop();
123
127
  this.clearConnectTimeout();
124
- this._eventSource?.close();
125
- this._eventSource = undefined;
128
+ this.detachAndCloseEventSource();
126
129
  this._connectionId = undefined;
127
130
  }
131
+ detachAndCloseEventSource() {
132
+ const eventSource = this._eventSource;
133
+ if (!eventSource) return;
134
+ eventSource.onopen = null;
135
+ eventSource.onmessage = null;
136
+ eventSource.onerror = null;
137
+ eventSource.close();
138
+ if (this._eventSource === eventSource) {
139
+ this._eventSource = undefined;
140
+ }
141
+ }
128
142
  ensureConnected() {
129
143
  if (this._disconnected) {
130
144
  this._disconnected = false;
@@ -132,6 +146,9 @@ import { HubMessageType } from './WebSocketHubConnection.js';
132
146
  if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {
133
147
  return;
134
148
  }
149
+ // An immediate subscription can win while a back-off callback is pending. Cancel that callback before
150
+ // opening, and let openEventSource perform the same live-source guard for already-queued callbacks.
151
+ this._policy.cancel();
135
152
  this.openEventSource();
136
153
  }
137
154
  close() {
@@ -139,59 +156,54 @@ import { HubMessageType } from './WebSocketHubConnection.js';
139
156
  this._policy.cancel();
140
157
  this._keepAlive.stop();
141
158
  this.clearConnectTimeout();
142
- if (this._eventSource) {
143
- // Detach all handlers BEFORE closing so that the async onerror / onmessage
144
- // events that fire after close() cannot observe the new _disconnected=false
145
- // state set by an immediately following ensureConnected() call. Without this,
146
- // a stale onerror triggers an unintended reconnect with exponential back-off.
147
- this._eventSource.onopen = null;
148
- this._eventSource.onmessage = null;
149
- this._eventSource.onerror = null;
150
- this._eventSource.close();
151
- }
152
- this._eventSource = undefined;
159
+ this.detachAndCloseEventSource();
153
160
  this._connectionId = undefined;
154
161
  }
155
162
  openEventSource() {
163
+ if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {
164
+ return;
165
+ }
166
+ this._policy.cancel();
156
167
  let url = this._sseUrl;
157
168
  if (this._microservice?.length > 0) {
158
169
  const param = `${Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;
159
170
  url += (url.includes('?') ? '&' : '?') + param;
160
171
  }
161
172
  this._connectionId = undefined;
162
- this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);
163
- this._eventSource.onopen = ()=>{
164
- if (this._disconnected) return;
165
- console.log(`SSE hub connection established: '${url}'`);
173
+ this._supportsSubscriptionRevisions = false;
174
+ const eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);
175
+ this._eventSource = eventSource;
176
+ eventSource.onopen = ()=>{
177
+ if (this._disconnected || this._eventSource !== eventSource) return;
178
+ console.log('SSE hub connection established', url);
166
179
  this._policy.reset();
167
180
  this._keepAlive.start();
168
181
  // If the server does not send a Connected message within the timeout, the
169
182
  // connection is broken. Close and retry via the reconnect policy.
170
183
  this.clearConnectTimeout();
171
184
  this._connectTimeoutTimer = setTimeout(()=>{
172
- if (!this._disconnected && !this._connectionId) {
173
- console.warn(`SSE hub: no Connected message within ${this._connectTimeoutMs}ms, retrying '${url}'`);
185
+ if (!this._disconnected && this._eventSource === eventSource && !this._connectionId) {
186
+ console.warn('SSE hub: no Connected message within timeout; retrying', this._connectTimeoutMs, url);
174
187
  this.reconnect();
175
188
  }
176
189
  }, this._connectTimeoutMs);
177
190
  };
178
- this._eventSource.onmessage = (event)=>{
179
- if (this._disconnected) return;
191
+ eventSource.onmessage = (event)=>{
192
+ if (this._disconnected || this._eventSource !== eventSource) return;
180
193
  this._keepAlive.recordActivity();
181
194
  this.handleMessage(event.data);
182
195
  };
183
- this._eventSource.onerror = ()=>{
184
- if (this._disconnected) return;
185
- console.warn(`SSE hub connection error: '${url}'`);
196
+ eventSource.onerror = ()=>{
197
+ if (this._disconnected || this._eventSource !== eventSource) return;
198
+ console.warn('SSE hub connection error', url);
186
199
  this.reconnect();
187
200
  };
188
201
  }
189
202
  reconnect() {
190
203
  this._keepAlive.stop();
191
204
  this.clearConnectTimeout();
192
- // Close the EventSource so the reconnect policy manages the schedule.
193
- this._eventSource?.close();
194
- this._eventSource = undefined;
205
+ // Detach before closing so callbacks already queued by the retired source are inert.
206
+ this.detachAndCloseEventSource();
195
207
  this._connectionId = undefined;
196
208
  // Move all active subscriptions to pending so they re-subscribe when
197
209
  // the next Connected message arrives after the managed reconnect.
@@ -201,7 +213,7 @@ import { HubMessageType } from './WebSocketHubConnection.js';
201
213
  if (this._subscriptions.size === 0) return;
202
214
  this._policy.schedule(()=>{
203
215
  if (!this._disconnected && this._subscriptions.size > 0) {
204
- this.openEventSource();
216
+ this.ensureConnected();
205
217
  }
206
218
  }, this._sseUrl);
207
219
  }
@@ -224,11 +236,15 @@ import { HubMessageType } from './WebSocketHubConnection.js';
224
236
  case HubMessageType.Ping:
225
237
  break;
226
238
  case HubMessageType.Unauthorized:
227
- console.warn(`SSE hub: query '${message.queryId}' unauthorized`);
228
- this.handleUnauthorized(message);
239
+ if (this.isMessageForCurrentSubscription(message)) {
240
+ console.warn('SSE hub: query unauthorized', message.queryId);
241
+ this.handleUnauthorized(message);
242
+ }
229
243
  break;
230
244
  case HubMessageType.Error:
231
- console.error(`SSE hub: query '${message.queryId}' error:`, message.payload);
245
+ if (this.isMessageForCurrentSubscription(message)) {
246
+ console.error('SSE hub: query error', message.queryId, message.payload);
247
+ }
232
248
  break;
233
249
  }
234
250
  } catch (error) {
@@ -236,14 +252,21 @@ import { HubMessageType } from './WebSocketHubConnection.js';
236
252
  }
237
253
  }
238
254
  handleConnected(message) {
239
- this._connectionId = message.payload;
240
- console.log(`SSE hub: connected with id '${this._connectionId}'`);
255
+ const connectionId = message.payload;
256
+ const connectionIdChanged = this._connectionId !== connectionId;
257
+ this._connectionId = connectionId;
258
+ this._supportsSubscriptionRevisions = message.supportsSubscriptionRevisions === true;
259
+ console.log('SSE hub: connected', this._connectionId);
241
260
  // Connected message arrived — cancel the connect timeout.
242
261
  this.clearConnectTimeout();
243
262
  this.applyServerKeepAliveInterval(message.keepAliveIntervalMs);
244
- // Send all pending subscriptions now that we have a connection ID.
245
- for (const [queryId, sub] of this._pendingSubscriptions){
246
- this.sendSubscribe(queryId, sub.request);
263
+ // The active collection is authoritative. A previous connection's subscribe POST may
264
+ // still be in flight, so relying only on pending subscriptions can orphan a query when
265
+ // the server assigns a new connection ID before that POST completes.
266
+ if (connectionIdChanged) {
267
+ for (const [queryId, subscription] of this._subscriptions){
268
+ this.sendSubscribe(queryId, subscription);
269
+ }
247
270
  }
248
271
  this._pendingSubscriptions.clear();
249
272
  }
@@ -267,28 +290,31 @@ import { HubMessageType } from './WebSocketHubConnection.js';
267
290
  handleQueryResult(message) {
268
291
  if (!message.queryId) return;
269
292
  const sub = this._subscriptions.get(message.queryId);
270
- if (!sub) return;
293
+ if (!sub || !this.isMessageForCurrentSubscription(message)) return;
271
294
  const result = message.payload;
272
295
  sub.callback(result);
273
296
  }
274
297
  handleUnauthorized(message) {
275
298
  if (!message.queryId) return;
276
299
  const sub = this._subscriptions.get(message.queryId);
277
- if (!sub) return;
300
+ if (!sub || !this.isMessageForCurrentSubscription(message)) return;
278
301
  this._subscriptions.delete(message.queryId);
279
302
  this._pendingSubscriptions.delete(message.queryId);
280
303
  sub.callback(QueryResult.unauthorized());
281
304
  }
282
- sendSubscribe(queryId, request, attempt = 0) {
305
+ sendSubscribe(queryId, subscription, attempt = 0) {
283
306
  if (!this._connectionId || this._disconnected) return;
284
- // Capture the connection ID so retries can detect if a reconnect has already fired
285
- // for a different reason and made this retry obsolete.
307
+ // Capture the connection ID and subscription instance so retries can detect whether
308
+ // either has been replaced while this request is in flight.
286
309
  const connectionId = this._connectionId;
287
310
  const body = {
288
311
  connectionId,
289
312
  queryId,
290
- request
313
+ request: subscription.request
291
314
  };
315
+ if (this._supportsSubscriptionRevisions) {
316
+ body.revision = subscription.revision;
317
+ }
292
318
  const customHeaders = Globals.httpHeadersCallback?.() ?? {};
293
319
  // Maximum number of subscribe retries before falling back to a full SSE reconnect.
294
320
  // In a round-robin load-balanced deployment the subscribe POST may land on a different
@@ -307,28 +333,64 @@ import { HubMessageType } from './WebSocketHubConnection.js';
307
333
  body: JSON.stringify(body)
308
334
  }).then((response)=>{
309
335
  if (!response.ok) {
310
- if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {
311
- setTimeout(()=>this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));
312
- } else if (this._connectionId === connectionId && !this._disconnected) {
313
- console.warn(`SSE hub: subscribe POST for '${queryId}' returned ${response.status} after ${attempt + 1} attempt(s), reconnecting`);
336
+ if (!this.isCurrentSubscription(queryId, subscription, connectionId)) {
337
+ console.warn('SSE hub: subscribe POST returned a failure for an obsolete connection or subscription; ignoring', queryId, response.status);
338
+ } else if (attempt < maxRetries) {
339
+ setTimeout(()=>{
340
+ if (this.isCurrentSubscription(queryId, subscription, connectionId)) {
341
+ this.sendSubscribe(queryId, subscription, attempt + 1);
342
+ }
343
+ }, retryDelayMs * (attempt + 1));
344
+ } else {
345
+ console.warn('SSE hub: subscribe POST failed after retries; reconnecting', queryId, response.status, attempt + 1);
314
346
  this.reconnect();
315
347
  }
316
348
  }
317
349
  }).catch((error)=>{
318
- if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {
319
- setTimeout(()=>this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));
320
- } else if (this._connectionId === connectionId && !this._disconnected) {
321
- console.error(`SSE hub: subscribe POST failed for '${queryId}' after ${attempt + 1} attempt(s), reconnecting`, error);
350
+ if (!this.isCurrentSubscription(queryId, subscription, connectionId)) {
351
+ console.warn('SSE hub: subscribe POST failed for an obsolete connection or subscription; ignoring', queryId, error);
352
+ } else if (attempt < maxRetries) {
353
+ setTimeout(()=>{
354
+ if (this.isCurrentSubscription(queryId, subscription, connectionId)) {
355
+ this.sendSubscribe(queryId, subscription, attempt + 1);
356
+ }
357
+ }, retryDelayMs * (attempt + 1));
358
+ } else {
359
+ console.error('SSE hub: subscribe POST failed after retries; reconnecting', queryId, attempt + 1, error);
322
360
  this.reconnect();
323
361
  }
324
362
  });
325
363
  }
326
- sendUnsubscribe(queryId) {
364
+ isMessageForCurrentSubscription(message) {
365
+ if (!message.queryId) return false;
366
+ const subscription = this._subscriptions.get(message.queryId);
367
+ if (!subscription) return false;
368
+ if (!this._supportsSubscriptionRevisions) {
369
+ return message.revision === undefined;
370
+ }
371
+ return this.isValidRevision(message.revision) && message.revision === subscription.revision;
372
+ }
373
+ isCurrentSubscription(queryId, subscription, connectionId) {
374
+ return !this._disconnected && this._connectionId === connectionId && this._subscriptions.get(queryId) === subscription;
375
+ }
376
+ getNextRevision() {
377
+ if (this._nextRevision >= Number.MAX_SAFE_INTEGER) {
378
+ throw new RangeError('SSE hub subscription revision exhausted the safe integer range');
379
+ }
380
+ return ++this._nextRevision;
381
+ }
382
+ isValidRevision(revision) {
383
+ return revision !== undefined && Number.isSafeInteger(revision) && revision > 0;
384
+ }
385
+ sendUnsubscribe(queryId, revision) {
327
386
  if (!this._connectionId) return;
328
387
  const body = {
329
388
  connectionId: this._connectionId,
330
389
  queryId
331
390
  };
391
+ if (this._supportsSubscriptionRevisions) {
392
+ body.revision = revision;
393
+ }
332
394
  const customHeaders = Globals.httpHeadersCallback?.() ?? {};
333
395
  fetch(this._unsubscribeUrl, {
334
396
  method: 'POST',
@@ -338,7 +400,7 @@ import { HubMessageType } from './WebSocketHubConnection.js';
338
400
  },
339
401
  body: JSON.stringify(body)
340
402
  }).catch((error)=>{
341
- console.error(`SSE hub: unsubscribe POST failed for '${queryId}'`, error);
403
+ console.error('SSE hub: unsubscribe POST failed', queryId, error);
342
404
  });
343
405
  }
344
406
  }
@@ -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 = 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
+ {"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 type { IObservableQueryHubConnection } from './IObservableQueryHubConnection';\nimport type { DataReceived } from './ObservableQueryConnection';\nimport { HubConnectionKeepAlive } from './HubConnectionKeepAlive';\nimport type { IReconnectPolicy } from './IReconnectPolicy';\nimport { ReconnectPolicy } from './ReconnectPolicy';\nimport { QueryResult } from './QueryResult';\nimport {\n type HubMessage,\n HubMessageType,\n type SubscriptionRequest,\n} from './WebSocketHubConnection';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface ActiveSubscription {\n request: SubscriptionRequest;\n callback: DataReceived<any>;\n revision: number;\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 _nextRevision = 0;\n private _supportsSubscriptionRevisions = false;\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(\n keepAliveIntervalMs,\n () => {\n if (!this._disconnected && this._subscriptions.size > 0) {\n console.warn(\n 'SSE hub: no messages received; reconnecting',\n this._keepAlive.idleThresholdMs,\n this._sseUrl,\n );\n this.reconnect();\n }\n },\n keepAliveIntervalMs * IDLE_THRESHOLD_FACTOR,\n );\n }\n\n /** @inheritdoc */\n get queryCount(): number {\n return this._subscriptions.size;\n }\n\n /** @inheritdoc */\n get isConnected(): boolean {\n return (\n this._connectionId !== undefined &&\n this._eventSource?.readyState === EventSource.OPEN\n );\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 (\n this._latencySamples.reduce((a, b) => a + b, 0) / this._latencySamples.length\n );\n }\n\n /** @inheritdoc */\n subscribe(\n queryId: string,\n request: SubscriptionRequest,\n callback: DataReceived<any>,\n ): void {\n const sub: ActiveSubscription = {\n request,\n callback,\n revision: this.getNextRevision(),\n };\n this._subscriptions.set(queryId, sub);\n\n this.ensureConnected();\n\n if (this._connectionId) {\n this.sendSubscribe(queryId, sub);\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 const subscription = this._subscriptions.get(queryId);\n this._subscriptions.delete(queryId);\n this._pendingSubscriptions.delete(queryId);\n\n if (this._connectionId && subscription) {\n this.sendUnsubscribe(queryId, subscription.revision);\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.detachAndCloseEventSource();\n this._connectionId = undefined;\n }\n\n private detachAndCloseEventSource(): void {\n const eventSource = this._eventSource;\n if (!eventSource) return;\n\n eventSource.onopen = null;\n eventSource.onmessage = null;\n eventSource.onerror = null;\n eventSource.close();\n\n if (this._eventSource === eventSource) {\n this._eventSource = undefined;\n }\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 // An immediate subscription can win while a back-off callback is pending. Cancel that callback before\n // opening, and let openEventSource perform the same live-source guard for already-queued callbacks.\n this._policy.cancel();\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 this.detachAndCloseEventSource();\n this._connectionId = undefined;\n }\n\n private openEventSource(): void {\n if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {\n return;\n }\n\n this._policy.cancel();\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._supportsSubscriptionRevisions = false;\n const eventSource = Globals.eventSourceFactory\n ? Globals.eventSourceFactory(url)\n : new EventSource(url);\n this._eventSource = eventSource;\n\n eventSource.onopen = () => {\n if (this._disconnected || this._eventSource !== eventSource) 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 (\n !this._disconnected &&\n this._eventSource === eventSource &&\n !this._connectionId\n ) {\n console.warn(\n 'SSE hub: no Connected message within timeout; retrying',\n this._connectTimeoutMs,\n url,\n );\n this.reconnect();\n }\n }, this._connectTimeoutMs);\n };\n\n eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected || this._eventSource !== eventSource) return;\n this._keepAlive.recordActivity();\n this.handleMessage(event.data as string);\n };\n\n eventSource.onerror = () => {\n if (this._disconnected || this._eventSource !== eventSource) 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 // Detach before closing so callbacks already queued by the retired source are inert.\n this.detachAndCloseEventSource();\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.ensureConnected();\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 if (this.isMessageForCurrentSubscription(message)) {\n console.warn('SSE hub: query unauthorized', message.queryId);\n this.handleUnauthorized(message);\n }\n break;\n case HubMessageType.Error:\n if (this.isMessageForCurrentSubscription(message)) {\n console.error(\n 'SSE hub: query error',\n message.queryId,\n message.payload,\n );\n }\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 const connectionId = message.payload as string;\n const connectionIdChanged = this._connectionId !== connectionId;\n this._connectionId = connectionId;\n this._supportsSubscriptionRevisions =\n message.supportsSubscriptionRevisions === true;\n console.log('SSE hub: connected', this._connectionId);\n\n // Connected message arrived — cancel the connect timeout.\n this.clearConnectTimeout();\n\n this.applyServerKeepAliveInterval(message.keepAliveIntervalMs);\n\n // The active collection is authoritative. A previous connection's subscribe POST may\n // still be in flight, so relying only on pending subscriptions can orphan a query when\n // the server assigns a new connection ID before that POST completes.\n if (connectionIdChanged) {\n for (const [queryId, subscription] of this._subscriptions) {\n this.sendSubscribe(queryId, subscription);\n }\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(\n serverIntervalMs,\n serverIntervalMs * IDLE_THRESHOLD_FACTOR,\n );\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 || !this.isMessageForCurrentSubscription(message)) 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 || !this.isMessageForCurrentSubscription(message)) return;\n\n this._subscriptions.delete(message.queryId);\n this._pendingSubscriptions.delete(message.queryId);\n sub.callback(QueryResult.unauthorized());\n }\n\n private sendSubscribe(\n queryId: string,\n subscription: ActiveSubscription,\n attempt: number = 0,\n ): void {\n if (!this._connectionId || this._disconnected) return;\n\n // Capture the connection ID and subscription instance so retries can detect whether\n // either has been replaced while this request is in flight.\n const connectionId = this._connectionId;\n\n const body: {\n connectionId: string;\n queryId: string;\n request: SubscriptionRequest;\n revision?: number;\n } = {\n connectionId,\n queryId,\n request: subscription.request,\n };\n if (this._supportsSubscriptionRevisions) {\n body.revision = subscription.revision;\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 })\n .then((response) => {\n if (!response.ok) {\n if (\n !this.isCurrentSubscription(queryId, subscription, connectionId)\n ) {\n console.warn(\n 'SSE hub: subscribe POST returned a failure for an obsolete connection or subscription; ignoring',\n queryId,\n response.status,\n );\n } else if (attempt < maxRetries) {\n setTimeout(\n () => {\n if (\n this.isCurrentSubscription(\n queryId,\n subscription,\n connectionId,\n )\n ) {\n this.sendSubscribe(\n queryId,\n subscription,\n attempt + 1,\n );\n }\n },\n retryDelayMs * (attempt + 1),\n );\n } else {\n console.warn(\n 'SSE hub: subscribe POST failed after retries; reconnecting',\n queryId,\n response.status,\n attempt + 1,\n );\n this.reconnect();\n }\n }\n })\n .catch((error) => {\n if (!this.isCurrentSubscription(queryId, subscription, connectionId)) {\n console.warn(\n 'SSE hub: subscribe POST failed for an obsolete connection or subscription; ignoring',\n queryId,\n error,\n );\n } else if (attempt < maxRetries) {\n setTimeout(\n () => {\n if (\n this.isCurrentSubscription(\n queryId,\n subscription,\n connectionId,\n )\n ) {\n this.sendSubscribe(queryId, subscription, attempt + 1);\n }\n },\n retryDelayMs * (attempt + 1),\n );\n } else {\n console.error(\n 'SSE hub: subscribe POST failed after retries; reconnecting',\n queryId,\n attempt + 1,\n error,\n );\n this.reconnect();\n }\n });\n }\n\n private isMessageForCurrentSubscription(message: HubMessage): boolean {\n if (!message.queryId) return false;\n\n const subscription = this._subscriptions.get(message.queryId);\n if (!subscription) return false;\n\n if (!this._supportsSubscriptionRevisions) {\n return message.revision === undefined;\n }\n\n return (\n this.isValidRevision(message.revision) &&\n message.revision === subscription.revision\n );\n }\n\n private isCurrentSubscription(\n queryId: string,\n subscription: ActiveSubscription,\n connectionId: string,\n ): boolean {\n return (\n !this._disconnected &&\n this._connectionId === connectionId &&\n this._subscriptions.get(queryId) === subscription\n );\n }\n\n private getNextRevision(): number {\n if (this._nextRevision >= Number.MAX_SAFE_INTEGER) {\n throw new RangeError(\n 'SSE hub subscription revision exhausted the safe integer range',\n );\n }\n\n return ++this._nextRevision;\n }\n\n private isValidRevision(revision: number | undefined): revision is number {\n return revision !== undefined && Number.isSafeInteger(revision) && revision > 0;\n }\n\n private sendUnsubscribe(queryId: string, revision: number): void {\n if (!this._connectionId) return;\n\n const body: {\n connectionId: string;\n queryId: string;\n revision?: number;\n } = {\n connectionId: this._connectionId,\n queryId,\n };\n if (this._supportsSubscriptionRevisions) {\n body.revision = revision;\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', queryId, error);\n });\n }\n}\n"],"names":["IDLE_THRESHOLD_FACTOR","ServerSentEventHubConnection","_eventSource","_connectionId","_disconnected","_subscriptions","Map","_pendingSubscriptions","_lastPongLatency","_latencySamples","_connectTimeoutTimer","_nextRevision","_supportsSubscriptionRevisions","_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","revision","getNextRevision","set","ensureConnected","sendSubscribe","unsubscribe","subscription","get","delete","sendUnsubscribe","close","dispose","clear","cancel","stop","clearConnectTimeout","detachAndCloseEventSource","eventSource","onopen","onmessage","onerror","CLOSED","openEventSource","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","isMessageForCurrentSubscription","handleUnauthorized","Error","error","payload","connectionId","connectionIdChanged","supportsSubscriptionRevisions","applyServerKeepAliveInterval","serverIntervalMs","reconfigure","result","unauthorized","attempt","body","customHeaders","httpHeadersCallback","maxRetries","retryDelayMs","fetch","method","headers","stringify","then","response","ok","isCurrentSubscription","status","catch","isValidRevision","Number","MAX_SAFE_INTEGER","RangeError","isSafeInteger"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { DataReceived } from './ObservableQueryConnection';
2
- import { IReconnectPolicy } from './IReconnectPolicy';
1
+ import type { DataReceived } from './ObservableQueryConnection';
2
+ import type { IReconnectPolicy } from './IReconnectPolicy';
3
3
  export declare enum HubMessageType {
4
4
  Subscribe = "Subscribe",
5
5
  Unsubscribe = "Unsubscribe",
@@ -13,6 +13,8 @@ export declare enum HubMessageType {
13
13
  export interface HubMessage {
14
14
  type: HubMessageType;
15
15
  queryId?: string;
16
+ revision?: number;
17
+ supportsSubscriptionRevisions?: boolean;
16
18
  payload?: any;
17
19
  timestamp?: number;
18
20
  keepAliveIntervalMs?: number;
@@ -37,6 +39,9 @@ export declare class WebSocketHubConnection {
37
39
  private _lastPingSentTime?;
38
40
  private _lastPongLatency;
39
41
  private _latencySamples;
42
+ private _nextRevision;
43
+ private _supportsSubscriptionRevisions;
44
+ private _reconnectPending;
40
45
  constructor(_url: string, _microservice: string, pingIntervalMs?: number, _policy?: IReconnectPolicy);
41
46
  get queryCount(): number;
42
47
  get isConnected(): boolean;
@@ -48,12 +53,18 @@ export declare class WebSocketHubConnection {
48
53
  private ensureConnected;
49
54
  private close;
50
55
  private openSocket;
56
+ private cancelPendingReconnect;
57
+ private detachAndCloseSocket;
51
58
  private sendAllSubscriptions;
52
59
  private sendSubscribeMessage;
53
60
  private sendMessage;
54
61
  private handleMessage;
62
+ private handleConnected;
55
63
  private handleQueryResult;
56
64
  private handleUnauthorized;
65
+ private isMessageForCurrentSubscription;
66
+ private isValidRevision;
67
+ private getNextRevision;
57
68
  private handlePong;
58
69
  }
59
70
  //# sourceMappingURL=WebSocketHubConnection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketHubConnection.d.ts","sourceRoot":"","sources":["../../../queries/WebSocketHubConnection.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAUtD,oBAAY,cAAc;IACtB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;IACb,SAAS,cAAc;CAC1B;AAKD,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IAMnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAKD,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAeD,qBAAa,sBAAsB;IAiB3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAnB5B,OAAO,CAAC,OAAO,CAAC,CAAY;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,eAAe,CAAgB;IASvC,YACqB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACtC,cAAc,GAAE,MAAc,EACb,OAAO,GAAE,gBAAwC,EAQrE;IAKD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAKD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAKD,IAAI,eAAe,IAAI,MAAM,CAE5B;IAKD,IAAI,cAAc,IAAI,MAAM,CAG3B;IASD,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,GAAG,IAAI,CAQ1F;IAMD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAWjC;IAKD,OAAO,IAAI,IAAI,CAOd;IAED,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,KAAK;IAmBb,OAAO,CAAC,UAAU;IA0ClB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IA2BrB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,UAAU;CAWrB"}
1
+ {"version":3,"file":"WebSocketHubConnection.d.ts","sourceRoot":"","sources":["../../../queries/WebSocketHubConnection.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAU3D,oBAAY,cAAc;IACtB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;IACb,SAAS,cAAc;CAC1B;AAKD,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAMlB,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IAMnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAKD,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAkBD,qBAAa,sBAAsB;IAoB3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAtB5B,OAAO,CAAC,OAAO,CAAC,CAAY;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,8BAA8B,CAAS;IAC/C,OAAO,CAAC,iBAAiB,CAAS;IASlC,YACqB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACtC,cAAc,GAAE,MAAc,EACb,OAAO,GAAE,gBAAwC,EAWrE;IAKD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAKD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAKD,IAAI,eAAe,IAAI,MAAM,CAE5B;IAKD,IAAI,cAAc,IAAI,MAAM,CAK3B;IASD,SAAS,CACL,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,GAC5B,IAAI,CASN;IAMD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAmBjC;IAKD,OAAO,IAAI,IAAI,CAGd;IAED,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,KAAK;IAab,OAAO,CAAC,UAAU;IAmElB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,+BAA+B;IAgBvC,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,UAAU;CAWrB"}