@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
@@ -40,6 +40,8 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
40
40
  _lastPongLatency = 0;
41
41
  _latencySamples = [];
42
42
  _connectTimeoutTimer;
43
+ _nextRevision = 0;
44
+ _supportsSubscriptionRevisions = false;
43
45
  _keepAlive;
44
46
  /**
45
47
  * Initializes a new instance of {@link ServerSentEventHubConnection}.
@@ -50,7 +52,7 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
50
52
  * @param {number} keepAliveIntervalMs The keep-alive cadence to assume until the server advertises
51
53
  * its own on the {@link HubMessageType.Connected} message (default: 30 000 ms). The connection is
52
54
  * considered stale after {@link IDLE_THRESHOLD_FACTOR} times this without any server message.
53
- * @param {number} connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}
55
+ * @param {number} _connectTimeoutMs How long to wait for the {@link HubMessageType.Connected}
54
56
  * message after the HTTP connection opens before giving up and retrying (default: 15 000 ms).
55
57
  * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).
56
58
  */ constructor(_sseUrl, _subscribeUrl, _unsubscribeUrl, _microservice, keepAliveIntervalMs = 30000, _connectTimeoutMs = 15000, _policy = new ReconnectPolicy.ReconnectPolicy()){
@@ -74,7 +76,7 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
74
76
  // cadence on the Connected message and {@link handleConnected} reconfigures from it.
75
77
  this._keepAlive = new HubConnectionKeepAlive.HubConnectionKeepAlive(keepAliveIntervalMs, ()=>{
76
78
  if (!this._disconnected && this._subscriptions.size > 0) {
77
- console.warn(`SSE hub: no messages received for ${this._keepAlive.idleThresholdMs}ms, reconnecting '${this._sseUrl}'`);
79
+ console.warn('SSE hub: no messages received; reconnecting', this._keepAlive.idleThresholdMs, this._sseUrl);
78
80
  this.reconnect();
79
81
  }
80
82
  }, keepAliveIntervalMs * IDLE_THRESHOLD_FACTOR);
@@ -95,22 +97,24 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
95
97
  /** @inheritdoc */ subscribe(queryId, request, callback) {
96
98
  const sub = {
97
99
  request,
98
- callback
100
+ callback,
101
+ revision: this.getNextRevision()
99
102
  };
100
103
  this._subscriptions.set(queryId, sub);
101
104
  this.ensureConnected();
102
105
  if (this._connectionId) {
103
- this.sendSubscribe(queryId, request);
106
+ this.sendSubscribe(queryId, sub);
104
107
  } else {
105
108
  // Not yet connected, queue for when Connected message arrives.
106
109
  this._pendingSubscriptions.set(queryId, sub);
107
110
  }
108
111
  }
109
112
  /** @inheritdoc */ unsubscribe(queryId) {
113
+ const subscription = this._subscriptions.get(queryId);
110
114
  this._subscriptions.delete(queryId);
111
115
  this._pendingSubscriptions.delete(queryId);
112
- if (this._connectionId) {
113
- this.sendUnsubscribe(queryId);
116
+ if (this._connectionId && subscription) {
117
+ this.sendUnsubscribe(queryId, subscription.revision);
114
118
  }
115
119
  if (this._subscriptions.size === 0) {
116
120
  this.close();
@@ -123,10 +127,20 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
123
127
  this._policy.cancel();
124
128
  this._keepAlive.stop();
125
129
  this.clearConnectTimeout();
126
- this._eventSource?.close();
127
- this._eventSource = undefined;
130
+ this.detachAndCloseEventSource();
128
131
  this._connectionId = undefined;
129
132
  }
133
+ detachAndCloseEventSource() {
134
+ const eventSource = this._eventSource;
135
+ if (!eventSource) return;
136
+ eventSource.onopen = null;
137
+ eventSource.onmessage = null;
138
+ eventSource.onerror = null;
139
+ eventSource.close();
140
+ if (this._eventSource === eventSource) {
141
+ this._eventSource = undefined;
142
+ }
143
+ }
130
144
  ensureConnected() {
131
145
  if (this._disconnected) {
132
146
  this._disconnected = false;
@@ -134,6 +148,9 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
134
148
  if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {
135
149
  return;
136
150
  }
151
+ // An immediate subscription can win while a back-off callback is pending. Cancel that callback before
152
+ // opening, and let openEventSource perform the same live-source guard for already-queued callbacks.
153
+ this._policy.cancel();
137
154
  this.openEventSource();
138
155
  }
139
156
  close() {
@@ -141,59 +158,54 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
141
158
  this._policy.cancel();
142
159
  this._keepAlive.stop();
143
160
  this.clearConnectTimeout();
144
- if (this._eventSource) {
145
- // Detach all handlers BEFORE closing so that the async onerror / onmessage
146
- // events that fire after close() cannot observe the new _disconnected=false
147
- // state set by an immediately following ensureConnected() call. Without this,
148
- // a stale onerror triggers an unintended reconnect with exponential back-off.
149
- this._eventSource.onopen = null;
150
- this._eventSource.onmessage = null;
151
- this._eventSource.onerror = null;
152
- this._eventSource.close();
153
- }
154
- this._eventSource = undefined;
161
+ this.detachAndCloseEventSource();
155
162
  this._connectionId = undefined;
156
163
  }
157
164
  openEventSource() {
165
+ if (this._eventSource && this._eventSource.readyState !== EventSource.CLOSED) {
166
+ return;
167
+ }
168
+ this._policy.cancel();
158
169
  let url = this._sseUrl;
159
170
  if (this._microservice?.length > 0) {
160
171
  const param = `${Globals.Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;
161
172
  url += (url.includes('?') ? '&' : '?') + param;
162
173
  }
163
174
  this._connectionId = undefined;
164
- this._eventSource = Globals.Globals.eventSourceFactory ? Globals.Globals.eventSourceFactory(url) : new EventSource(url);
165
- this._eventSource.onopen = ()=>{
166
- if (this._disconnected) return;
167
- console.log(`SSE hub connection established: '${url}'`);
175
+ this._supportsSubscriptionRevisions = false;
176
+ const eventSource = Globals.Globals.eventSourceFactory ? Globals.Globals.eventSourceFactory(url) : new EventSource(url);
177
+ this._eventSource = eventSource;
178
+ eventSource.onopen = ()=>{
179
+ if (this._disconnected || this._eventSource !== eventSource) return;
180
+ console.log('SSE hub connection established', url);
168
181
  this._policy.reset();
169
182
  this._keepAlive.start();
170
183
  // If the server does not send a Connected message within the timeout, the
171
184
  // connection is broken. Close and retry via the reconnect policy.
172
185
  this.clearConnectTimeout();
173
186
  this._connectTimeoutTimer = setTimeout(()=>{
174
- if (!this._disconnected && !this._connectionId) {
175
- console.warn(`SSE hub: no Connected message within ${this._connectTimeoutMs}ms, retrying '${url}'`);
187
+ if (!this._disconnected && this._eventSource === eventSource && !this._connectionId) {
188
+ console.warn('SSE hub: no Connected message within timeout; retrying', this._connectTimeoutMs, url);
176
189
  this.reconnect();
177
190
  }
178
191
  }, this._connectTimeoutMs);
179
192
  };
180
- this._eventSource.onmessage = (event)=>{
181
- if (this._disconnected) return;
193
+ eventSource.onmessage = (event)=>{
194
+ if (this._disconnected || this._eventSource !== eventSource) return;
182
195
  this._keepAlive.recordActivity();
183
196
  this.handleMessage(event.data);
184
197
  };
185
- this._eventSource.onerror = ()=>{
186
- if (this._disconnected) return;
187
- console.warn(`SSE hub connection error: '${url}'`);
198
+ eventSource.onerror = ()=>{
199
+ if (this._disconnected || this._eventSource !== eventSource) return;
200
+ console.warn('SSE hub connection error', url);
188
201
  this.reconnect();
189
202
  };
190
203
  }
191
204
  reconnect() {
192
205
  this._keepAlive.stop();
193
206
  this.clearConnectTimeout();
194
- // Close the EventSource so the reconnect policy manages the schedule.
195
- this._eventSource?.close();
196
- this._eventSource = undefined;
207
+ // Detach before closing so callbacks already queued by the retired source are inert.
208
+ this.detachAndCloseEventSource();
197
209
  this._connectionId = undefined;
198
210
  // Move all active subscriptions to pending so they re-subscribe when
199
211
  // the next Connected message arrives after the managed reconnect.
@@ -203,7 +215,7 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
203
215
  if (this._subscriptions.size === 0) return;
204
216
  this._policy.schedule(()=>{
205
217
  if (!this._disconnected && this._subscriptions.size > 0) {
206
- this.openEventSource();
218
+ this.ensureConnected();
207
219
  }
208
220
  }, this._sseUrl);
209
221
  }
@@ -226,11 +238,15 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
226
238
  case WebSocketHubConnection.HubMessageType.Ping:
227
239
  break;
228
240
  case WebSocketHubConnection.HubMessageType.Unauthorized:
229
- console.warn(`SSE hub: query '${message.queryId}' unauthorized`);
230
- this.handleUnauthorized(message);
241
+ if (this.isMessageForCurrentSubscription(message)) {
242
+ console.warn('SSE hub: query unauthorized', message.queryId);
243
+ this.handleUnauthorized(message);
244
+ }
231
245
  break;
232
246
  case WebSocketHubConnection.HubMessageType.Error:
233
- console.error(`SSE hub: query '${message.queryId}' error:`, message.payload);
247
+ if (this.isMessageForCurrentSubscription(message)) {
248
+ console.error('SSE hub: query error', message.queryId, message.payload);
249
+ }
234
250
  break;
235
251
  }
236
252
  } catch (error) {
@@ -238,14 +254,21 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
238
254
  }
239
255
  }
240
256
  handleConnected(message) {
241
- this._connectionId = message.payload;
242
- console.log(`SSE hub: connected with id '${this._connectionId}'`);
257
+ const connectionId = message.payload;
258
+ const connectionIdChanged = this._connectionId !== connectionId;
259
+ this._connectionId = connectionId;
260
+ this._supportsSubscriptionRevisions = message.supportsSubscriptionRevisions === true;
261
+ console.log('SSE hub: connected', this._connectionId);
243
262
  // Connected message arrived — cancel the connect timeout.
244
263
  this.clearConnectTimeout();
245
264
  this.applyServerKeepAliveInterval(message.keepAliveIntervalMs);
246
- // Send all pending subscriptions now that we have a connection ID.
247
- for (const [queryId, sub] of this._pendingSubscriptions){
248
- this.sendSubscribe(queryId, sub.request);
265
+ // The active collection is authoritative. A previous connection's subscribe POST may
266
+ // still be in flight, so relying only on pending subscriptions can orphan a query when
267
+ // the server assigns a new connection ID before that POST completes.
268
+ if (connectionIdChanged) {
269
+ for (const [queryId, subscription] of this._subscriptions){
270
+ this.sendSubscribe(queryId, subscription);
271
+ }
249
272
  }
250
273
  this._pendingSubscriptions.clear();
251
274
  }
@@ -269,28 +292,31 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
269
292
  handleQueryResult(message) {
270
293
  if (!message.queryId) return;
271
294
  const sub = this._subscriptions.get(message.queryId);
272
- if (!sub) return;
295
+ if (!sub || !this.isMessageForCurrentSubscription(message)) return;
273
296
  const result = message.payload;
274
297
  sub.callback(result);
275
298
  }
276
299
  handleUnauthorized(message) {
277
300
  if (!message.queryId) return;
278
301
  const sub = this._subscriptions.get(message.queryId);
279
- if (!sub) return;
302
+ if (!sub || !this.isMessageForCurrentSubscription(message)) return;
280
303
  this._subscriptions.delete(message.queryId);
281
304
  this._pendingSubscriptions.delete(message.queryId);
282
305
  sub.callback(QueryResult.QueryResult.unauthorized());
283
306
  }
284
- sendSubscribe(queryId, request, attempt = 0) {
307
+ sendSubscribe(queryId, subscription, attempt = 0) {
285
308
  if (!this._connectionId || this._disconnected) return;
286
- // Capture the connection ID so retries can detect if a reconnect has already fired
287
- // for a different reason and made this retry obsolete.
309
+ // Capture the connection ID and subscription instance so retries can detect whether
310
+ // either has been replaced while this request is in flight.
288
311
  const connectionId = this._connectionId;
289
312
  const body = {
290
313
  connectionId,
291
314
  queryId,
292
- request
315
+ request: subscription.request
293
316
  };
317
+ if (this._supportsSubscriptionRevisions) {
318
+ body.revision = subscription.revision;
319
+ }
294
320
  const customHeaders = Globals.Globals.httpHeadersCallback?.() ?? {};
295
321
  // Maximum number of subscribe retries before falling back to a full SSE reconnect.
296
322
  // In a round-robin load-balanced deployment the subscribe POST may land on a different
@@ -309,28 +335,64 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
309
335
  body: JSON.stringify(body)
310
336
  }).then((response)=>{
311
337
  if (!response.ok) {
312
- if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {
313
- setTimeout(()=>this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));
314
- } else if (this._connectionId === connectionId && !this._disconnected) {
315
- console.warn(`SSE hub: subscribe POST for '${queryId}' returned ${response.status} after ${attempt + 1} attempt(s), reconnecting`);
338
+ if (!this.isCurrentSubscription(queryId, subscription, connectionId)) {
339
+ console.warn('SSE hub: subscribe POST returned a failure for an obsolete connection or subscription; ignoring', queryId, response.status);
340
+ } else if (attempt < maxRetries) {
341
+ setTimeout(()=>{
342
+ if (this.isCurrentSubscription(queryId, subscription, connectionId)) {
343
+ this.sendSubscribe(queryId, subscription, attempt + 1);
344
+ }
345
+ }, retryDelayMs * (attempt + 1));
346
+ } else {
347
+ console.warn('SSE hub: subscribe POST failed after retries; reconnecting', queryId, response.status, attempt + 1);
316
348
  this.reconnect();
317
349
  }
318
350
  }
319
351
  }).catch((error)=>{
320
- if (attempt < maxRetries && this._connectionId === connectionId && !this._disconnected) {
321
- setTimeout(()=>this.sendSubscribe(queryId, request, attempt + 1), retryDelayMs * (attempt + 1));
322
- } else if (this._connectionId === connectionId && !this._disconnected) {
323
- console.error(`SSE hub: subscribe POST failed for '${queryId}' after ${attempt + 1} attempt(s), reconnecting`, error);
352
+ if (!this.isCurrentSubscription(queryId, subscription, connectionId)) {
353
+ console.warn('SSE hub: subscribe POST failed for an obsolete connection or subscription; ignoring', queryId, error);
354
+ } else if (attempt < maxRetries) {
355
+ setTimeout(()=>{
356
+ if (this.isCurrentSubscription(queryId, subscription, connectionId)) {
357
+ this.sendSubscribe(queryId, subscription, attempt + 1);
358
+ }
359
+ }, retryDelayMs * (attempt + 1));
360
+ } else {
361
+ console.error('SSE hub: subscribe POST failed after retries; reconnecting', queryId, attempt + 1, error);
324
362
  this.reconnect();
325
363
  }
326
364
  });
327
365
  }
328
- sendUnsubscribe(queryId) {
366
+ isMessageForCurrentSubscription(message) {
367
+ if (!message.queryId) return false;
368
+ const subscription = this._subscriptions.get(message.queryId);
369
+ if (!subscription) return false;
370
+ if (!this._supportsSubscriptionRevisions) {
371
+ return message.revision === undefined;
372
+ }
373
+ return this.isValidRevision(message.revision) && message.revision === subscription.revision;
374
+ }
375
+ isCurrentSubscription(queryId, subscription, connectionId) {
376
+ return !this._disconnected && this._connectionId === connectionId && this._subscriptions.get(queryId) === subscription;
377
+ }
378
+ getNextRevision() {
379
+ if (this._nextRevision >= Number.MAX_SAFE_INTEGER) {
380
+ throw new RangeError('SSE hub subscription revision exhausted the safe integer range');
381
+ }
382
+ return ++this._nextRevision;
383
+ }
384
+ isValidRevision(revision) {
385
+ return revision !== undefined && Number.isSafeInteger(revision) && revision > 0;
386
+ }
387
+ sendUnsubscribe(queryId, revision) {
329
388
  if (!this._connectionId) return;
330
389
  const body = {
331
390
  connectionId: this._connectionId,
332
391
  queryId
333
392
  };
393
+ if (this._supportsSubscriptionRevisions) {
394
+ body.revision = revision;
395
+ }
334
396
  const customHeaders = Globals.Globals.httpHeadersCallback?.() ?? {};
335
397
  fetch(this._unsubscribeUrl, {
336
398
  method: 'POST',
@@ -340,7 +402,7 @@ var WebSocketHubConnection = require('./WebSocketHubConnection.js');
340
402
  },
341
403
  body: JSON.stringify(body)
342
404
  }).catch((error)=>{
343
- console.error(`SSE hub: unsubscribe POST failed for '${queryId}'`, error);
405
+ console.error('SSE hub: unsubscribe POST failed', queryId, error);
344
406
  });
345
407
  }
346
408
  }
@@ -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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"}