@cratis/arc 22.150.0 → 22.152.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 (193) hide show
  1. package/Globals.ts +10 -0
  2. package/dist/cjs/Globals.d.ts +2 -0
  3. package/dist/cjs/Globals.d.ts.map +1 -1
  4. package/dist/cjs/Globals.js +7 -0
  5. package/dist/cjs/Globals.js.map +1 -1
  6. package/dist/cjs/queries/ObservableQueryConnectionFactory.d.ts +5 -0
  7. package/dist/cjs/queries/ObservableQueryConnectionFactory.d.ts.map +1 -1
  8. package/dist/cjs/queries/ObservableQueryConnectionFactory.js +16 -1
  9. package/dist/cjs/queries/ObservableQueryConnectionFactory.js.map +1 -1
  10. package/dist/cjs/queries/ObservableQueryFor.d.ts +3 -0
  11. package/dist/cjs/queries/ObservableQueryFor.d.ts.map +1 -1
  12. package/dist/cjs/queries/ObservableQueryFor.js +12 -3
  13. package/dist/cjs/queries/ObservableQueryFor.js.map +1 -1
  14. package/dist/cjs/queries/PollingOptions.d.ts +8 -0
  15. package/dist/cjs/queries/PollingOptions.d.ts.map +1 -0
  16. package/dist/cjs/queries/PollingQueryConnection.d.ts +33 -0
  17. package/dist/cjs/queries/PollingQueryConnection.d.ts.map +1 -0
  18. package/dist/cjs/queries/PollingQueryConnection.js +150 -0
  19. package/dist/cjs/queries/PollingQueryConnection.js.map +1 -0
  20. package/dist/cjs/queries/QueryTransportMethod.d.ts +2 -1
  21. package/dist/cjs/queries/QueryTransportMethod.d.ts.map +1 -1
  22. package/dist/cjs/queries/QueryTransportMethod.js +1 -0
  23. package/dist/cjs/queries/QueryTransportMethod.js.map +1 -1
  24. package/dist/cjs/queries/index.d.ts +2 -0
  25. package/dist/cjs/queries/index.d.ts.map +1 -1
  26. package/dist/cjs/queries/index.js +4 -0
  27. package/dist/cjs/queries/index.js.map +1 -1
  28. package/dist/esm/Globals.d.ts +2 -0
  29. package/dist/esm/Globals.d.ts.map +1 -1
  30. package/dist/esm/Globals.js +7 -0
  31. package/dist/esm/Globals.js.map +1 -1
  32. package/dist/esm/queries/ObservableQueryConnectionFactory.d.ts +5 -0
  33. package/dist/esm/queries/ObservableQueryConnectionFactory.d.ts.map +1 -1
  34. package/dist/esm/queries/ObservableQueryConnectionFactory.js +16 -2
  35. package/dist/esm/queries/ObservableQueryConnectionFactory.js.map +1 -1
  36. package/dist/esm/queries/ObservableQueryFor.d.ts +3 -0
  37. package/dist/esm/queries/ObservableQueryFor.d.ts.map +1 -1
  38. package/dist/esm/queries/ObservableQueryFor.js +13 -4
  39. package/dist/esm/queries/ObservableQueryFor.js.map +1 -1
  40. package/dist/esm/queries/PollingOptions.d.ts +8 -0
  41. package/dist/esm/queries/PollingOptions.d.ts.map +1 -0
  42. package/dist/esm/queries/PollingOptions.js +2 -0
  43. package/dist/esm/queries/PollingOptions.js.map +1 -0
  44. package/dist/esm/queries/PollingQueryConnection.d.ts +33 -0
  45. package/dist/esm/queries/PollingQueryConnection.d.ts.map +1 -0
  46. package/dist/esm/queries/PollingQueryConnection.js +147 -0
  47. package/dist/esm/queries/PollingQueryConnection.js.map +1 -0
  48. package/dist/esm/queries/QueryTransportMethod.d.ts +2 -1
  49. package/dist/esm/queries/QueryTransportMethod.d.ts.map +1 -1
  50. package/dist/esm/queries/QueryTransportMethod.js +1 -0
  51. package/dist/esm/queries/QueryTransportMethod.js.map +1 -1
  52. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_direct_mode_and_polling_transport.d.ts +2 -0
  53. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_direct_mode_and_polling_transport.d.ts.map +1 -0
  54. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_direct_mode_and_polling_transport.js +46 -0
  55. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_direct_mode_and_polling_transport.js.map +1 -0
  56. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_hub_mode_and_polling_transport.d.ts +2 -0
  57. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_hub_mode_and_polling_transport.d.ts.map +1 -0
  58. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_hub_mode_and_polling_transport.js +46 -0
  59. package/dist/esm/queries/for_ObservableQueryConnectionFactory/when_creating/with_hub_mode_and_polling_transport.js.map +1 -0
  60. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport.d.ts +2 -0
  61. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport.d.ts.map +1 -0
  62. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport.js +108 -0
  63. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport.js.map +1 -0
  64. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport_and_unauthorized_response.d.ts +2 -0
  65. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport_and_unauthorized_response.d.ts.map +1 -0
  66. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport_and_unauthorized_response.js +39 -0
  67. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport_and_unauthorized_response.js.map +1 -0
  68. package/dist/esm/queries/for_PollingQueryConnection/given/a_polling_query_connection.d.ts +31 -0
  69. package/dist/esm/queries/for_PollingQueryConnection/given/a_polling_query_connection.d.ts.map +1 -0
  70. package/dist/esm/queries/for_PollingQueryConnection/given/a_polling_query_connection.js +52 -0
  71. package/dist/esm/queries/for_PollingQueryConnection/given/a_polling_query_connection.js.map +1 -0
  72. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_network_error.d.ts +2 -0
  73. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_network_error.d.ts.map +1 -0
  74. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_network_error.js +16 -0
  75. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_network_error.js.map +1 -0
  76. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_server_error_with_an_envelope.d.ts +2 -0
  77. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_server_error_with_an_envelope.d.ts.map +1 -0
  78. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_server_error_with_an_envelope.js +22 -0
  79. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_a_server_error_with_an_envelope.js.map +1 -0
  80. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_not_ready.d.ts +2 -0
  81. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_not_ready.d.ts.map +1 -0
  82. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_not_ready.js +19 -0
  83. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_not_ready.js.map +1 -0
  84. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_repeated_failures.d.ts +2 -0
  85. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_repeated_failures.d.ts.map +1 -0
  86. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_repeated_failures.js +16 -0
  87. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_repeated_failures.js.map +1 -0
  88. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_request_timeout.d.ts +2 -0
  89. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_request_timeout.d.ts.map +1 -0
  90. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_request_timeout.js +19 -0
  91. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/after_request_timeout.js.map +1 -0
  92. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/with_jitter.d.ts +2 -0
  93. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/with_jitter.d.ts.map +1 -0
  94. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/with_jitter.js +16 -0
  95. package/dist/esm/queries/for_PollingQueryConnection/when_backing_off/with_jitter.js.map +1 -0
  96. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/and_fetch_rejects_on_abort.d.ts +2 -0
  97. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/and_fetch_rejects_on_abort.d.ts.map +1 -0
  98. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/and_fetch_rejects_on_abort.js +16 -0
  99. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/and_fetch_rejects_on_abort.js.map +1 -0
  100. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_a_request_is_in_flight.d.ts +2 -0
  101. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_a_request_is_in_flight.d.ts.map +1 -0
  102. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_a_request_is_in_flight.js +16 -0
  103. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_a_request_is_in_flight.js.map +1 -0
  104. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_waiting_for_the_next_poll.d.ts +2 -0
  105. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_waiting_for_the_next_poll.d.ts.map +1 -0
  106. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_waiting_for_the_next_poll.js +14 -0
  107. package/dist/esm/queries/for_PollingQueryConnection/when_disconnecting/while_waiting_for_the_next_poll.js.map +1 -0
  108. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_a_request_is_still_in_flight.d.ts +2 -0
  109. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_a_request_is_still_in_flight.d.ts.map +1 -0
  110. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_a_request_is_still_in_flight.js +12 -0
  111. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_a_request_is_still_in_flight.js.map +1 -0
  112. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_changes.d.ts +2 -0
  113. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_changes.d.ts.map +1 -0
  114. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_changes.js +47 -0
  115. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_changes.js.map +1 -0
  116. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_is_unchanged.d.ts +2 -0
  117. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_is_unchanged.d.ts.map +1 -0
  118. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_is_unchanged.js +21 -0
  119. package/dist/esm/queries/for_PollingQueryConnection/when_polling/and_data_is_unchanged.js.map +1 -0
  120. package/dist/esm/queries/for_PollingQueryConnection/when_polling/with_global_and_instance_headers.d.ts +2 -0
  121. package/dist/esm/queries/for_PollingQueryConnection/when_polling/with_global_and_instance_headers.d.ts.map +1 -0
  122. package/dist/esm/queries/for_PollingQueryConnection/when_polling/with_global_and_instance_headers.js +25 -0
  123. package/dist/esm/queries/for_PollingQueryConnection/when_polling/with_global_and_instance_headers.js.map +1 -0
  124. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/above_the_maximum.d.ts +2 -0
  125. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/above_the_maximum.d.ts.map +1 -0
  126. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/above_the_maximum.js +16 -0
  127. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/above_the_maximum.js.map +1 -0
  128. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/below_the_minimum.d.ts +2 -0
  129. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/below_the_minimum.d.ts.map +1 -0
  130. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/below_the_minimum.js +18 -0
  131. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/below_the_minimum.js.map +1 -0
  132. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/on_a_not_ready_response.d.ts +2 -0
  133. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/on_a_not_ready_response.d.ts.map +1 -0
  134. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/on_a_not_ready_response.js +16 -0
  135. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/on_a_not_ready_response.js.map +1 -0
  136. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/that_is_invalid.d.ts +2 -0
  137. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/that_is_invalid.d.ts.map +1 -0
  138. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/that_is_invalid.js +18 -0
  139. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/that_is_invalid.js.map +1 -0
  140. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/within_bounds.d.ts +2 -0
  141. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/within_bounds.d.ts.map +1 -0
  142. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/within_bounds.js +16 -0
  143. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/within_bounds.js.map +1 -0
  144. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_invalid_arguments/stops_polling.d.ts +2 -0
  145. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_invalid_arguments/stops_polling.d.ts.map +1 -0
  146. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_invalid_arguments/stops_polling.js +12 -0
  147. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_invalid_arguments/stops_polling.js.map +1 -0
  148. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/stops_polling.d.ts +2 -0
  149. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/stops_polling.d.ts.map +1 -0
  150. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/stops_polling.js +14 -0
  151. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/stops_polling.js.map +1 -0
  152. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/with_a_non_json_body.d.ts +2 -0
  153. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/with_a_non_json_body.d.ts.map +1 -0
  154. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/with_a_non_json_body.js +14 -0
  155. package/dist/esm/queries/for_PollingQueryConnection/when_receiving_unauthorized/with_a_non_json_body.js.map +1 -0
  156. package/dist/esm/queries/index.d.ts +2 -0
  157. package/dist/esm/queries/index.d.ts.map +1 -1
  158. package/dist/esm/queries/index.js +2 -1
  159. package/dist/esm/queries/index.js.map +1 -1
  160. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  161. package/package.json +1 -1
  162. package/queries/ObservableQueryConnectionFactory.ts +24 -1
  163. package/queries/ObservableQueryFor.ts +15 -3
  164. package/queries/PollingOptions.ts +16 -0
  165. package/queries/PollingQueryConnection.ts +149 -0
  166. package/queries/QueryTransportMethod.ts +3 -0
  167. package/queries/for_ObservableQueryConnectionFactory/when_creating/with_direct_mode_and_polling_transport.ts +47 -0
  168. package/queries/for_ObservableQueryConnectionFactory/when_creating/with_hub_mode_and_polling_transport.ts +47 -0
  169. package/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport.ts +115 -0
  170. package/queries/for_ObservableQueryFor/when_subscribing/with_polling_transport_and_unauthorized_response.ts +44 -0
  171. package/queries/for_PollingQueryConnection/given/a_polling_query_connection.ts +60 -0
  172. package/queries/for_PollingQueryConnection/when_backing_off/after_a_network_error.ts +19 -0
  173. package/queries/for_PollingQueryConnection/when_backing_off/after_a_server_error_with_an_envelope.ts +25 -0
  174. package/queries/for_PollingQueryConnection/when_backing_off/after_not_ready.ts +22 -0
  175. package/queries/for_PollingQueryConnection/when_backing_off/after_repeated_failures.ts +19 -0
  176. package/queries/for_PollingQueryConnection/when_backing_off/after_request_timeout.ts +22 -0
  177. package/queries/for_PollingQueryConnection/when_backing_off/with_jitter.ts +19 -0
  178. package/queries/for_PollingQueryConnection/when_disconnecting/and_fetch_rejects_on_abort.ts +19 -0
  179. package/queries/for_PollingQueryConnection/when_disconnecting/while_a_request_is_in_flight.ts +19 -0
  180. package/queries/for_PollingQueryConnection/when_disconnecting/while_waiting_for_the_next_poll.ts +17 -0
  181. package/queries/for_PollingQueryConnection/when_polling/and_a_request_is_still_in_flight.ts +15 -0
  182. package/queries/for_PollingQueryConnection/when_polling/and_data_changes.ts +51 -0
  183. package/queries/for_PollingQueryConnection/when_polling/and_data_is_unchanged.ts +24 -0
  184. package/queries/for_PollingQueryConnection/when_polling/with_global_and_instance_headers.ts +28 -0
  185. package/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/above_the_maximum.ts +19 -0
  186. package/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/below_the_minimum.ts +21 -0
  187. package/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/on_a_not_ready_response.ts +19 -0
  188. package/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/that_is_invalid.ts +21 -0
  189. package/queries/for_PollingQueryConnection/when_receiving_a_poll_hint/within_bounds.ts +19 -0
  190. package/queries/for_PollingQueryConnection/when_receiving_invalid_arguments/stops_polling.ts +15 -0
  191. package/queries/for_PollingQueryConnection/when_receiving_unauthorized/stops_polling.ts +17 -0
  192. package/queries/for_PollingQueryConnection/when_receiving_unauthorized/with_a_non_json_body.ts +17 -0
  193. package/queries/index.ts +2 -0
@@ -0,0 +1,25 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when backing off after a server error with an envelope', given(a_polling_query_connection, context => {
8
+ let beforeRetry: number;
9
+ beforeEach(async () => {
10
+ context.fetchStub.callsFake(async () => new Response(JSON.stringify(context.envelope(null, { hasExceptions: true })), { status: 500 }));
11
+ context.connection.connect(context.dataReceived);
12
+ await context.clock.tickAsync(0);
13
+ await context.clock.tickAsync(1999);
14
+ beforeRetry = context.fetchStub.callCount;
15
+ await context.clock.tickAsync(1);
16
+ });
17
+ it('should emit the error envelope once', () => {
18
+ context.dataReceived.callCount.should.equal(1);
19
+ context.dataReceived.firstCall.args[0].hasExceptions.should.be.true;
20
+ });
21
+ it('should back off before retrying', () => {
22
+ beforeRetry.should.equal(1);
23
+ context.fetchStub.callCount.should.equal(2);
24
+ });
25
+ }));
@@ -0,0 +1,22 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when backing off after not ready', given(a_polling_query_connection, context => {
8
+ let beforeRetry: number;
9
+ let emissionsBeforeRetry: number;
10
+ beforeEach(async () => {
11
+ context.respond(202);
12
+ context.connection.connect(context.dataReceived);
13
+ await context.clock.tickAsync(0);
14
+ await context.clock.tickAsync(1999);
15
+ beforeRetry = context.fetchStub.callCount;
16
+ emissionsBeforeRetry = context.dataReceived.callCount;
17
+ await context.clock.tickAsync(1001);
18
+ });
19
+ it('should wait twice the interval', () => beforeRetry.should.equal(1));
20
+ it('should not emit the not ready response', () => emissionsBeforeRetry.should.equal(0));
21
+ it('should return to the normal interval after recovery', () => context.fetchStub.callCount.should.equal(3));
22
+ }));
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when backing off after repeated failures', given(a_polling_query_connection, context => {
8
+ const requestTimes: number[] = [];
9
+ beforeEach(async () => {
10
+ requestTimes.length = 0;
11
+ context.fetchStub.callsFake(async () => {
12
+ requestTimes.push(context.clock.now);
13
+ throw new TypeError('offline');
14
+ });
15
+ context.connection.connect(context.dataReceived);
16
+ await context.clock.tickAsync(22000);
17
+ });
18
+ it('should double the delay up to the maximum', () => requestTimes.should.deep.equal([0, 2000, 6000, 14000, 22000]));
19
+ }));
@@ -0,0 +1,22 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when backing off after request timeout', given(a_polling_query_connection, context => {
8
+ let beforeRetry: number;
9
+ let emissionsBeforeRetry: number;
10
+ beforeEach(async () => {
11
+ context.respond(408);
12
+ context.connection.connect(context.dataReceived);
13
+ await context.clock.tickAsync(0);
14
+ await context.clock.tickAsync(1999);
15
+ beforeRetry = context.fetchStub.callCount;
16
+ emissionsBeforeRetry = context.dataReceived.callCount;
17
+ await context.clock.tickAsync(1001);
18
+ });
19
+ it('should wait twice the interval', () => beforeRetry.should.equal(1));
20
+ it('should not emit the timeout response', () => emissionsBeforeRetry.should.equal(0));
21
+ it('should return to the normal interval after recovery', () => context.fetchStub.callCount.should.equal(3));
22
+ }));
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when backing off with jitter', given(a_polling_query_connection, context => {
8
+ let beforeRetry: number;
9
+ beforeEach(async () => {
10
+ context.random.returns(1);
11
+ context.fetchStub.onFirstCall().rejects(new TypeError('offline'));
12
+ context.connection.connect(context.dataReceived);
13
+ await context.clock.tickAsync(2399);
14
+ beforeRetry = context.fetchStub.callCount;
15
+ await context.clock.tickAsync(1);
16
+ });
17
+ it('should not retry before the jittered delay', () => beforeRetry.should.equal(1));
18
+ it('should retry at the jittered delay', () => context.fetchStub.callCount.should.equal(2));
19
+ }));
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when disconnecting and fetch rejects on abort', given(a_polling_query_connection, context => {
8
+ beforeEach(async () => {
9
+ context.fetchStub.callsFake((_url: string, init: RequestInit) => new Promise<Response>((_resolve, reject) => {
10
+ init.signal!.addEventListener('abort', () => reject(new DOMException('The operation was aborted.', 'AbortError')), { once: true });
11
+ }));
12
+ context.connection.connect(context.dataReceived);
13
+ context.connection.disconnect();
14
+ await context.clock.tickAsync(60000);
15
+ });
16
+ it('should not deliver a result', () => context.dataReceived.called.should.be.false);
17
+ it('should not retry the aborted request', () => context.fetchStub.callCount.should.equal(1));
18
+ it('should leave no pending polling timer', () => context.clock.countTimers().should.equal(0));
19
+ }));
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when disconnecting while a request is in flight', given(a_polling_query_connection, context => {
8
+ beforeEach(async () => {
9
+ let resolveRequest!: (response: Response) => void;
10
+ context.fetchStub.returns(new Promise<Response>(resolve => { resolveRequest = resolve; }));
11
+ context.connection.connect(context.dataReceived);
12
+ context.connection.disconnect();
13
+ resolveRequest(new Response(JSON.stringify(context.envelope('late'))));
14
+ await context.clock.tickAsync(60000);
15
+ });
16
+ it('should abort the request', () => context.fetchStub.firstCall.args[1].signal.aborted.should.be.true);
17
+ it('should ignore a late result', () => context.dataReceived.called.should.be.false);
18
+ it('should not poll again', () => context.fetchStub.callCount.should.equal(1));
19
+ }));
@@ -0,0 +1,17 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when disconnecting while waiting for the next poll', given(a_polling_query_connection, context => {
8
+ beforeEach(async () => {
9
+ context.connection.connect(context.dataReceived);
10
+ await context.clock.tickAsync(0);
11
+ context.connection.disconnect();
12
+ context.connection.connect(context.dataReceived);
13
+ await context.clock.tickAsync(60000);
14
+ });
15
+ it('should not poll again even if connect is called', () => context.fetchStub.callCount.should.equal(1));
16
+ it('should clear the timer', () => context.clock.countTimers().should.equal(0));
17
+ }));
@@ -0,0 +1,15 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when polling and a request is still in flight', given(a_polling_query_connection, context => {
8
+ beforeEach(async () => {
9
+ context.fetchStub.returns(new Promise<Response>(() => {}));
10
+ context.connection.connect(context.dataReceived);
11
+ context.connection.connect(context.dataReceived);
12
+ await context.clock.tickAsync(5000);
13
+ });
14
+ it('should have only one request in flight', () => context.fetchStub.callCount.should.equal(1));
15
+ }));
@@ -0,0 +1,51 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when polling and data changes', given(a_polling_query_connection, context => {
8
+ beforeEach(async () => {
9
+ context.fetchStub.onFirstCall().resolves(new Response(JSON.stringify(context.envelope('first'))));
10
+ context.connection.connect(context.dataReceived, { filter: 'a', page: 1, pageSize: 10 });
11
+ await context.clock.tickAsync(0);
12
+ await context.clock.tickAsync(1000);
13
+ });
14
+ it('should get the query route with the HTTP arguments immediately', () => {
15
+ String(context.fetchStub.firstCall.args[0]).should.equal('https://example.com/api/items/42?filter=a&page=1&pageSize=10&waitForFirstResult=true');
16
+ context.fetchStub.firstCall.args[1].method.should.equal('GET');
17
+ });
18
+ it('should include custom and query headers', () => {
19
+ Object.fromEntries(context.fetchStub.firstCall.args[1].headers).should.deep.equal({
20
+ authorization: 'Bearer x', accept: 'application/json', 'content-type': 'application/json', 'x-cratis-microservice': 'svc'
21
+ });
22
+ });
23
+ it('should deliver changed data and paging metadata', () => {
24
+ context.dataReceived.callCount.should.equal(2);
25
+ context.dataReceived.secondCall.args[0].data.should.equal('same');
26
+ context.dataReceived.secondCall.args[0].paging.totalItems.should.equal(25);
27
+ });
28
+ it('should measure request latency', () => {
29
+ context.connection.lastPingLatency.should.be.at.least(0);
30
+ context.connection.averageLatency.should.be.at.least(0);
31
+ });
32
+ }));
33
+
34
+ for (const changes of [
35
+ { paging: { page: 2, size: 10, totalItems: 30, totalPages: 3 } },
36
+ { isSuccess: false }, { isAuthorized: false }, { isValid: false }, { hasExceptions: true },
37
+ { validationResults: [{ message: 'invalid' }] }, { exceptionMessages: ['failed'] }, { exceptionStackTrace: 'trace' }
38
+ ]) {
39
+ describe(`when polling and envelope metadata changes: ${Object.keys(changes)[0]}`, given(a_polling_query_connection, context => {
40
+ beforeEach(async () => {
41
+ context.responses = [
42
+ new Response(JSON.stringify(context.envelope('same'))),
43
+ new Response(JSON.stringify(context.envelope('same', changes)))
44
+ ];
45
+ context.connection.connect(context.dataReceived);
46
+ await context.clock.tickAsync(0);
47
+ await context.clock.tickAsync(1000);
48
+ });
49
+ it('should emit changed metadata even when the data is unchanged', () => context.dataReceived.callCount.should.equal(2));
50
+ }));
51
+ }
@@ -0,0 +1,24 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when polling and only the correlation id changes', given(a_polling_query_connection, context => {
8
+ beforeEach(async () => {
9
+ const first = context.envelope({ name: 'same', value: 1 });
10
+ const second = { ...context.envelope({ value: 1, name: 'same' }) };
11
+ context.responses = [new Response(JSON.stringify(first)), new Response(JSON.stringify(second))];
12
+ context.dataReceived.callsFake(result => {
13
+ result.isReady = true;
14
+ result.paging.totalItems = 999;
15
+ });
16
+ context.connection.connect(context.dataReceived);
17
+ await context.clock.tickAsync(0);
18
+ await context.clock.tickAsync(1000);
19
+ });
20
+ it('should ignore property order, correlation id and consumer mutation when comparing', () => {
21
+ context.fetchStub.callCount.should.equal(2);
22
+ context.dataReceived.callCount.should.equal(1);
23
+ });
24
+ }));
@@ -0,0 +1,28 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { Globals } from '../../../Globals.js';
6
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
7
+
8
+ describe('when polling with global and instance headers', given(a_polling_query_connection, context => {
9
+ let originalHeadersCallback: typeof Globals.httpHeadersCallback;
10
+ beforeEach(async () => {
11
+ originalHeadersCallback = Globals.httpHeadersCallback;
12
+ Globals.httpHeadersCallback = () => ({ 'X-Global': 'global', Authorization: 'Bearer global' });
13
+ context.connection.connect(context.dataReceived);
14
+ await context.clock.tickAsync(0);
15
+ await context.clock.tickAsync(1000);
16
+ });
17
+ afterEach(() => {
18
+ Globals.httpHeadersCallback = originalHeadersCallback;
19
+ });
20
+ it('should include global headers on every poll', () => {
21
+ context.fetchStub.firstCall.args[1].headers.get('X-Global').should.equal('global');
22
+ context.fetchStub.secondCall.args[1].headers.get('X-Global').should.equal('global');
23
+ });
24
+ it('should let instance headers override the same global header', () => {
25
+ context.fetchStub.firstCall.args[1].headers.get('Authorization').should.equal('Bearer x');
26
+ context.fetchStub.secondCall.args[1].headers.get('Authorization').should.equal('Bearer x');
27
+ });
28
+ }));
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when receiving a poll hint above the maximum', given(a_polling_query_connection, context => {
8
+ let beforeNextPoll: number;
9
+ beforeEach(async () => {
10
+ context.respond(200, { 'Cratis-Query-Poll-After': '60' });
11
+ context.connection.connect(context.dataReceived);
12
+ await context.clock.tickAsync(0);
13
+ await context.clock.tickAsync(7999);
14
+ beforeNextPoll = context.fetchStub.callCount;
15
+ await context.clock.tickAsync(1);
16
+ });
17
+ it('should wait until the maximum', () => beforeNextPoll.should.equal(1));
18
+ it('should poll at the maximum', () => context.fetchStub.callCount.should.equal(2));
19
+ }));
@@ -0,0 +1,21 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ for (const hint of ['0', '0.1']) {
8
+ describe(`when receiving a poll hint below the minimum: ${hint}`, given(a_polling_query_connection, context => {
9
+ let beforeNextPoll: number;
10
+ beforeEach(async () => {
11
+ context.respond(200, { 'Cratis-Query-Poll-After': hint });
12
+ context.connection.connect(context.dataReceived);
13
+ await context.clock.tickAsync(0);
14
+ await context.clock.tickAsync(499);
15
+ beforeNextPoll = context.fetchStub.callCount;
16
+ await context.clock.tickAsync(1);
17
+ });
18
+ it('should not poll before the minimum', () => beforeNextPoll.should.equal(1));
19
+ it('should poll at the minimum', () => context.fetchStub.callCount.should.equal(2));
20
+ }));
21
+ }
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when receiving a poll hint on a not ready response', given(a_polling_query_connection, context => {
8
+ let beforeNextPoll: number;
9
+ beforeEach(async () => {
10
+ context.respond(202, { 'Cratis-Query-Poll-After': '3' });
11
+ context.connection.connect(context.dataReceived);
12
+ await context.clock.tickAsync(0);
13
+ await context.clock.tickAsync(2999);
14
+ beforeNextPoll = context.fetchStub.callCount;
15
+ await context.clock.tickAsync(1);
16
+ });
17
+ it('should prefer the hint over backoff', () => beforeNextPoll.should.equal(1));
18
+ it('should poll at the hinted interval', () => context.fetchStub.callCount.should.equal(2));
19
+ }));
@@ -0,0 +1,21 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ for (const hint of ['abc', '-1', 'Infinity', '5abc', '', ' ']) {
8
+ describe(`when receiving a poll hint that is invalid: ${hint}`, given(a_polling_query_connection, context => {
9
+ let beforeNextPoll: number;
10
+ beforeEach(async () => {
11
+ context.respond(200, { 'Cratis-Query-Poll-After': hint });
12
+ context.connection.connect(context.dataReceived);
13
+ await context.clock.tickAsync(0);
14
+ await context.clock.tickAsync(999);
15
+ beforeNextPoll = context.fetchStub.callCount;
16
+ await context.clock.tickAsync(1);
17
+ });
18
+ it('should wait until the configured interval', () => beforeNextPoll.should.equal(1));
19
+ it('should poll at the configured interval', () => context.fetchStub.callCount.should.equal(2));
20
+ }));
21
+ }
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when receiving a poll hint within bounds', given(a_polling_query_connection, context => {
8
+ let beforeNextPoll: number;
9
+ beforeEach(async () => {
10
+ context.respond(200, { 'Cratis-Query-Poll-After': '3' });
11
+ context.connection.connect(context.dataReceived);
12
+ await context.clock.tickAsync(0);
13
+ await context.clock.tickAsync(2999);
14
+ beforeNextPoll = context.fetchStub.callCount;
15
+ await context.clock.tickAsync(1);
16
+ });
17
+ it('should wait for the hint in seconds', () => beforeNextPoll.should.equal(1));
18
+ it('should poll at the hinted interval', () => context.fetchStub.callCount.should.equal(2));
19
+ }));
@@ -0,0 +1,15 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ describe('when receiving invalid arguments', given(a_polling_query_connection, context => {
8
+ beforeEach(async () => {
9
+ context.respond(400, {}, { isValid: false });
10
+ context.connection.connect(context.dataReceived);
11
+ await context.clock.tickAsync(60000);
12
+ });
13
+ it('should deliver the validation result', () => context.dataReceived.firstCall.args[0].isValid.should.be.false);
14
+ it('should stop polling', () => context.fetchStub.callCount.should.equal(1));
15
+ }));
@@ -0,0 +1,17 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ for (const status of [200, 401, 403]) {
8
+ describe(`when receiving an unauthorized envelope with status ${status}`, given(a_polling_query_connection, context => {
9
+ beforeEach(async () => {
10
+ context.respond(status, {}, { isAuthorized: false });
11
+ context.connection.connect(context.dataReceived);
12
+ await context.clock.tickAsync(60000);
13
+ });
14
+ it('should deliver the unauthorized result', () => context.dataReceived.firstCall.args[0].isAuthorized.should.be.false);
15
+ it('should stop polling', () => context.fetchStub.callCount.should.equal(1));
16
+ }));
17
+ }
@@ -0,0 +1,17 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { given } from '../../../given.js';
5
+ import { a_polling_query_connection } from '../given/a_polling_query_connection.js';
6
+
7
+ for (const status of [401, 403]) {
8
+ describe(`when receiving unauthorized with a non JSON body and status ${status}`, given(a_polling_query_connection, context => {
9
+ beforeEach(async () => {
10
+ context.fetchStub.onFirstCall().resolves(new Response('Unauthorized', { status }));
11
+ context.connection.connect(context.dataReceived);
12
+ await context.clock.tickAsync(60000);
13
+ });
14
+ it('should deliver an unauthorized result', () => context.dataReceived.firstCall.args[0].isAuthorized.should.be.false);
15
+ it('should stop polling', () => context.fetchStub.callCount.should.equal(1));
16
+ }));
17
+ }
package/queries/index.ts CHANGED
@@ -34,6 +34,8 @@ export * from './ObservableQueryMultiplexer.js';
34
34
  export * from './ObservableQuerySubscription.js';
35
35
  export * from './WebSocketMessage.js';
36
36
  export * from './QueryTransportMethod.js';
37
+ export * from './PollingOptions.js';
38
+ export * from './PollingQueryConnection.js';
37
39
  export * from './QueryInstanceCache.js';
38
40
  export * from './reconcileQueryData.js';
39
41
  export * from './deserializeQueryModel.js';