@cratis/arc 22.87.0 → 22.87.2

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 (77) hide show
  1. package/commands/for_Command/when_executing/and_fetch_throws_exception.ts +2 -0
  2. package/commands/for_Command/when_validating/and_fetch_throws_exception.ts +2 -0
  3. package/dist/cjs/queries/ObservableQueryConnection.d.ts +1 -0
  4. package/dist/cjs/queries/ObservableQueryConnection.d.ts.map +1 -1
  5. package/dist/cjs/queries/ObservableQueryConnection.js +11 -6
  6. package/dist/cjs/queries/ObservableQueryConnection.js.map +1 -1
  7. package/dist/cjs/queries/ServerSentEventHubConnection.d.ts +1 -0
  8. package/dist/cjs/queries/ServerSentEventHubConnection.d.ts.map +1 -1
  9. package/dist/cjs/queries/ServerSentEventHubConnection.js +9 -7
  10. package/dist/cjs/queries/ServerSentEventHubConnection.js.map +1 -1
  11. package/dist/cjs/queries/ServerSentEventQueryConnection.d.ts +1 -0
  12. package/dist/cjs/queries/ServerSentEventQueryConnection.d.ts.map +1 -1
  13. package/dist/cjs/queries/ServerSentEventQueryConnection.js +17 -13
  14. package/dist/cjs/queries/ServerSentEventQueryConnection.js.map +1 -1
  15. package/dist/cjs/queries/WebSocketHubConnection.d.ts.map +1 -1
  16. package/dist/cjs/queries/WebSocketHubConnection.js +3 -0
  17. package/dist/cjs/queries/WebSocketHubConnection.js.map +1 -1
  18. package/dist/cjs/validation/rules/NotEmptyRule.js +1 -1
  19. package/dist/cjs/validation/rules/NotEmptyRule.js.map +1 -1
  20. package/dist/esm/commands/for_Command/when_executing/and_fetch_throws_exception.js +1 -0
  21. package/dist/esm/commands/for_Command/when_executing/and_fetch_throws_exception.js.map +1 -1
  22. package/dist/esm/commands/for_Command/when_validating/and_fetch_throws_exception.js +1 -0
  23. package/dist/esm/commands/for_Command/when_validating/and_fetch_throws_exception.js.map +1 -1
  24. package/dist/esm/queries/ObservableQueryConnection.d.ts +1 -0
  25. package/dist/esm/queries/ObservableQueryConnection.d.ts.map +1 -1
  26. package/dist/esm/queries/ObservableQueryConnection.js +11 -6
  27. package/dist/esm/queries/ObservableQueryConnection.js.map +1 -1
  28. package/dist/esm/queries/ServerSentEventHubConnection.d.ts +1 -0
  29. package/dist/esm/queries/ServerSentEventHubConnection.d.ts.map +1 -1
  30. package/dist/esm/queries/ServerSentEventHubConnection.js +9 -7
  31. package/dist/esm/queries/ServerSentEventHubConnection.js.map +1 -1
  32. package/dist/esm/queries/ServerSentEventQueryConnection.d.ts +1 -0
  33. package/dist/esm/queries/ServerSentEventQueryConnection.d.ts.map +1 -1
  34. package/dist/esm/queries/ServerSentEventQueryConnection.js +17 -13
  35. package/dist/esm/queries/ServerSentEventQueryConnection.js.map +1 -1
  36. package/dist/esm/queries/WebSocketHubConnection.d.ts.map +1 -1
  37. package/dist/esm/queries/WebSocketHubConnection.js +3 -0
  38. package/dist/esm/queries/WebSocketHubConnection.js.map +1 -1
  39. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_server_validation_failing.d.ts +2 -0
  40. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_server_validation_failing.d.ts.map +1 -0
  41. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_server_validation_failing.js +36 -0
  42. package/dist/esm/queries/for_ObservableQueryFor/when_performing/with_server_validation_failing.js.map +1 -0
  43. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_server_validation_failing.d.ts +2 -0
  44. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_server_validation_failing.d.ts.map +1 -0
  45. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_server_validation_failing.js +110 -0
  46. package/dist/esm/queries/for_ObservableQueryFor/when_subscribing/with_server_validation_failing.js.map +1 -0
  47. package/dist/esm/queries/for_QueryFor/when_performing/with_server_validation_failing.d.ts +2 -0
  48. package/dist/esm/queries/for_QueryFor/when_performing/with_server_validation_failing.d.ts.map +1 -0
  49. package/dist/esm/queries/for_QueryFor/when_performing/with_server_validation_failing.js +36 -0
  50. package/dist/esm/queries/for_QueryFor/when_performing/with_server_validation_failing.js.map +1 -0
  51. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  52. package/dist/esm/validation/rules/NotEmptyRule.js +1 -1
  53. package/dist/esm/validation/rules/NotEmptyRule.js.map +1 -1
  54. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_a_byte_order_mark.d.ts +2 -0
  55. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_a_byte_order_mark.d.ts.map +1 -0
  56. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_a_byte_order_mark.js +8 -0
  57. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_a_byte_order_mark.js.map +1 -0
  58. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_mixed_unicode_whitespace.d.ts +2 -0
  59. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_mixed_unicode_whitespace.d.ts.map +1 -0
  60. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_mixed_unicode_whitespace.js +8 -0
  61. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_mixed_unicode_whitespace.js.map +1 -0
  62. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_next_line_whitespace.d.ts +2 -0
  63. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_next_line_whitespace.d.ts.map +1 -0
  64. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_next_line_whitespace.js +8 -0
  65. package/dist/esm/validation/rules/for_NotEmptyRule/when_validating/with_next_line_whitespace.js.map +1 -0
  66. package/package.json +1 -1
  67. package/queries/ObservableQueryConnection.ts +13 -8
  68. package/queries/ServerSentEventHubConnection.ts +10 -9
  69. package/queries/ServerSentEventQueryConnection.ts +18 -13
  70. package/queries/WebSocketHubConnection.ts +3 -0
  71. package/queries/for_ObservableQueryFor/when_performing/with_server_validation_failing.ts +43 -0
  72. package/queries/for_ObservableQueryFor/when_subscribing/with_server_validation_failing.ts +130 -0
  73. package/queries/for_QueryFor/when_performing/with_server_validation_failing.ts +43 -0
  74. package/validation/rules/NotEmptyRule.ts +1 -1
  75. package/validation/rules/for_NotEmptyRule/when_validating/with_a_byte_order_mark.ts +11 -0
  76. package/validation/rules/for_NotEmptyRule/when_validating/with_mixed_unicode_whitespace.ts +11 -0
  77. package/validation/rules/for_NotEmptyRule/when_validating/with_next_line_whitespace.ts +11 -0
@@ -42,19 +42,7 @@ import { Globals } from '../Globals.js';
42
42
  }
43
43
  }
44
44
  this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);
45
- this._eventSource.onmessage = (event)=>{
46
- if (this._disconnected) return;
47
- try {
48
- const result = JSON.parse(event.data);
49
- if (result?.isAuthorized === false) {
50
- this.handleUnauthorized(url, result, dataReceived);
51
- return;
52
- }
53
- dataReceived(result);
54
- } catch (error) {
55
- console.error('SSE: error parsing message', error);
56
- }
57
- };
45
+ this._eventSource.onmessage = (event)=>this.handleMessage(event, url, dataReceived);
58
46
  this._eventSource.onerror = ()=>{
59
47
  if (this._disconnected || this._unauthorized) return;
60
48
  console.warn(`SSE: connection error for '${url}', EventSource will retry automatically.`);
@@ -66,6 +54,22 @@ import { Globals } from '../Globals.js';
66
54
  this._eventSource?.close();
67
55
  this._eventSource = undefined;
68
56
  }
57
+ handleMessage(event, url, dataReceived) {
58
+ if (this._disconnected) return;
59
+ try {
60
+ const result = JSON.parse(event.data);
61
+ if (result?.isAuthorized === false) {
62
+ this.handleUnauthorized(url, result, dataReceived);
63
+ return;
64
+ }
65
+ if (result?.isValid === false) {
66
+ this.disconnect();
67
+ }
68
+ dataReceived(result);
69
+ } catch (error) {
70
+ console.error('SSE: error parsing message', error);
71
+ }
72
+ }
69
73
  /**
70
74
  * Handles the terminal result the server sends when the caller is no longer authorized for the query it is
71
75
  * subscribed to.
@@ -1 +1 @@
1
- {"version":3,"file":"ServerSentEventQueryConnection.js","sources":["../../../queries/ServerSentEventQueryConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Globals } from '../Globals.js';\nimport { IObservableQueryConnection } from './IObservableQueryConnection.js';\nimport { DataReceived } from './ObservableQueryConnection.js';\nimport { QueryResult } from './QueryResult.js';\n\n/**\n * The SSE demultiplexer route used when connecting through the multiplexed observable query endpoint.\n */\nexport const SSE_HUB_ROUTE = '/.cratis/queries/sse';\n\n/**\n * Represents a direct Server-Sent Events (SSE) connection for a single observable query.\n *\n * In direct mode the URL points to the per-query endpoint (e.g. `/api/queries/latest`).\n * The backend detects the `Accept: text/event-stream` header and streams results directly.\n *\n * The caller (typically {@link createObservableQueryConnection}) decides which URL to use;\n * this class is transport-agnostic beyond being SSE.\n */\nexport class ServerSentEventQueryConnection<TDataType> implements IObservableQueryConnection<TDataType> {\n private _eventSource?: EventSource;\n private _disconnected = false;\n private _unauthorized = false;\n\n /** @inheritdoc */\n readonly lastPingLatency: number = 0;\n\n /** @inheritdoc */\n readonly averageLatency: number = 0;\n\n /**\n * Initializes a new instance of {@link ServerSentEventQueryConnection}.\n * @param {URL} url The fully qualified URL of the SSE endpoint (including query parameters).\n */\n constructor(private readonly _url: URL) {}\n\n /** @inheritdoc */\n connect(dataReceived: DataReceived<TDataType>, queryArguments?: object): void {\n if (this._disconnected || this._unauthorized) return;\n\n // Guard against environments where EventSource is not available (e.g. Node.js, SSR)\n // and no custom factory has been supplied to substitute it.\n if (!Globals.eventSourceFactory && typeof EventSource === 'undefined') {\n return;\n }\n\n let url = this._url.toString();\n if (queryArguments) {\n const separator = url.includes('?') ? '&' : '?';\n const query = Object.entries(queryArguments)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n .join('&');\n if (query) {\n url = `${url}${separator}${query}`;\n }\n }\n\n this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);\n\n this._eventSource.onmessage = (event: MessageEvent) => {\n if (this._disconnected) return;\n try {\n const result = JSON.parse(event.data as string) as QueryResult<TDataType>;\n if ((result as unknown as { isAuthorized?: boolean })?.isAuthorized === false) {\n this.handleUnauthorized(url, result, dataReceived);\n return;\n }\n dataReceived(result);\n } catch (error) {\n console.error('SSE: error parsing message', error);\n }\n };\n\n this._eventSource.onerror = () => {\n if (this._disconnected || this._unauthorized) return;\n console.warn(`SSE: connection error for '${url}', EventSource will retry automatically.`);\n };\n }\n\n /** @inheritdoc */\n disconnect(): void {\n if (this._disconnected) return;\n this._disconnected = true;\n this._eventSource?.close();\n this._eventSource = undefined;\n }\n\n /**\n * Handles the terminal result the server sends when the caller is no longer authorized for the query it is\n * subscribed to.\n *\n * Unlike a WebSocket, an `EventSource` re-establishes a stream the server ended - the server closing its response\n * is precisely the signal the browser retries on, roughly every three seconds. Each retry re-runs the whole query\n * pipeline server side just to be denied again, so the stream is only actually terminal if this client closes it.\n * @param {string} url The stream url, for diagnostics.\n * @param {QueryResult<TDataType>} result The unauthorized result to deliver.\n * @param {DataReceived<TDataType>} dataReceived Callback that receives the result.\n */\n private handleUnauthorized(url: string, result: QueryResult<TDataType>, dataReceived: DataReceived<TDataType>): void {\n console.warn(`SSE: stream for '${url}' was ended by the server - no longer authorized`);\n this._unauthorized = true;\n this._eventSource?.close();\n this._eventSource = undefined;\n dataReceived(result);\n }\n}\n"],"names":["SSE_HUB_ROUTE","ServerSentEventQueryConnection","_eventSource","_disconnected","_unauthorized","lastPingLatency","averageLatency","_url","connect","dataReceived","queryArguments","Globals","eventSourceFactory","EventSource","url","toString","separator","includes","query","Object","entries","filter","value","undefined","map","key","encodeURIComponent","String","join","onmessage","event","result","JSON","parse","data","isAuthorized","handleUnauthorized","error","console","onerror","warn","disconnect","close"],"mappings":"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"}
1
+ {"version":3,"file":"ServerSentEventQueryConnection.js","sources":["../../../queries/ServerSentEventQueryConnection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { Globals } from '../Globals.js';\nimport { IObservableQueryConnection } from './IObservableQueryConnection.js';\nimport { DataReceived } from './ObservableQueryConnection.js';\nimport { QueryResult } from './QueryResult.js';\n\n/**\n * The SSE demultiplexer route used when connecting through the multiplexed observable query endpoint.\n */\nexport const SSE_HUB_ROUTE = '/.cratis/queries/sse';\n\n/**\n * Represents a direct Server-Sent Events (SSE) connection for a single observable query.\n *\n * In direct mode the URL points to the per-query endpoint (e.g. `/api/queries/latest`).\n * The backend detects the `Accept: text/event-stream` header and streams results directly.\n *\n * The caller (typically {@link createObservableQueryConnection}) decides which URL to use;\n * this class is transport-agnostic beyond being SSE.\n */\nexport class ServerSentEventQueryConnection<TDataType> implements IObservableQueryConnection<TDataType> {\n private _eventSource?: EventSource;\n private _disconnected = false;\n private _unauthorized = false;\n\n /** @inheritdoc */\n readonly lastPingLatency: number = 0;\n\n /** @inheritdoc */\n readonly averageLatency: number = 0;\n\n /**\n * Initializes a new instance of {@link ServerSentEventQueryConnection}.\n * @param {URL} url The fully qualified URL of the SSE endpoint (including query parameters).\n */\n constructor(private readonly _url: URL) {}\n\n /** @inheritdoc */\n connect(dataReceived: DataReceived<TDataType>, queryArguments?: object): void {\n if (this._disconnected || this._unauthorized) return;\n\n // Guard against environments where EventSource is not available (e.g. Node.js, SSR)\n // and no custom factory has been supplied to substitute it.\n if (!Globals.eventSourceFactory && typeof EventSource === 'undefined') {\n return;\n }\n\n let url = this._url.toString();\n if (queryArguments) {\n const separator = url.includes('?') ? '&' : '?';\n const query = Object.entries(queryArguments)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n .join('&');\n if (query) {\n url = `${url}${separator}${query}`;\n }\n }\n\n this._eventSource = Globals.eventSourceFactory ? Globals.eventSourceFactory(url) : new EventSource(url);\n\n this._eventSource.onmessage = (event: MessageEvent) => this.handleMessage(event, url, dataReceived);\n\n this._eventSource.onerror = () => {\n if (this._disconnected || this._unauthorized) return;\n console.warn(`SSE: connection error for '${url}', EventSource will retry automatically.`);\n };\n }\n\n /** @inheritdoc */\n disconnect(): void {\n if (this._disconnected) return;\n this._disconnected = true;\n this._eventSource?.close();\n this._eventSource = undefined;\n }\n\n private handleMessage(event: MessageEvent, url: string, dataReceived: DataReceived<TDataType>): void {\n if (this._disconnected) return;\n try {\n const result = JSON.parse(event.data as string) as QueryResult<TDataType>;\n if ((result as unknown as { isAuthorized?: boolean })?.isAuthorized === false) {\n this.handleUnauthorized(url, result, dataReceived);\n return;\n }\n if (result?.isValid === false) {\n this.disconnect();\n }\n dataReceived(result);\n } catch (error) {\n console.error('SSE: error parsing message', error);\n }\n }\n\n /**\n * Handles the terminal result the server sends when the caller is no longer authorized for the query it is\n * subscribed to.\n *\n * Unlike a WebSocket, an `EventSource` re-establishes a stream the server ended - the server closing its response\n * is precisely the signal the browser retries on, roughly every three seconds. Each retry re-runs the whole query\n * pipeline server side just to be denied again, so the stream is only actually terminal if this client closes it.\n * @param {string} url The stream url, for diagnostics.\n * @param {QueryResult<TDataType>} result The unauthorized result to deliver.\n * @param {DataReceived<TDataType>} dataReceived Callback that receives the result.\n */\n private handleUnauthorized(url: string, result: QueryResult<TDataType>, dataReceived: DataReceived<TDataType>): void {\n console.warn(`SSE: stream for '${url}' was ended by the server - no longer authorized`);\n this._unauthorized = true;\n this._eventSource?.close();\n this._eventSource = undefined;\n dataReceived(result);\n }\n}\n"],"names":["SSE_HUB_ROUTE","ServerSentEventQueryConnection","_eventSource","_disconnected","_unauthorized","lastPingLatency","averageLatency","_url","connect","dataReceived","queryArguments","Globals","eventSourceFactory","EventSource","url","toString","separator","includes","query","Object","entries","filter","value","undefined","map","key","encodeURIComponent","String","join","onmessage","event","handleMessage","onerror","console","warn","disconnect","close","result","JSON","parse","data","isAuthorized","handleUnauthorized","isValid","error"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketHubConnection.d.ts","sourceRoot":"","sources":["../../../queries/WebSocketHubConnection.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAU9D,oBAAY,cAAc;IACtB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;IACb,SAAS,cAAc;CAC1B;AAKD,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAMlB,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IAMnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAKD,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAkBD,qBAAa,sBAAsB;IAoB3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAtB5B,OAAO,CAAC,OAAO,CAAC,CAAY;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,8BAA8B,CAAS;IAC/C,OAAO,CAAC,iBAAiB,CAAS;IASlC,YACqB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACtC,cAAc,GAAE,MAAc,EACb,OAAO,GAAE,gBAAwC,EAWrE;IAKD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAKD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAKD,IAAI,eAAe,IAAI,MAAM,CAE5B;IAKD,IAAI,cAAc,IAAI,MAAM,CAK3B;IASD,SAAS,CACL,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,GAC5B,IAAI,CASN;IAMD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAmBjC;IAKD,OAAO,IAAI,IAAI,CAGd;IAED,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,KAAK;IAab,OAAO,CAAC,UAAU;IAmElB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,+BAA+B;IAgBvC,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,UAAU;CAWrB"}
1
+ {"version":3,"file":"WebSocketHubConnection.d.ts","sourceRoot":"","sources":["../../../queries/WebSocketHubConnection.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAU9D,oBAAY,cAAc;IACtB,SAAS,cAAc;IACvB,WAAW,gBAAgB;IAC3B,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,KAAK,UAAU;IACf,IAAI,SAAS;IACb,IAAI,SAAS;IACb,SAAS,cAAc;CAC1B;AAKD,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAMlB,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IAMnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAKD,MAAM,WAAW,mBAAmB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAkBD,qBAAa,sBAAsB;IAoB3B,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAtB5B,OAAO,CAAC,OAAO,CAAC,CAAY;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,iBAAiB,CAAC,CAAS;IACnC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,eAAe,CAAgB;IACvC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,8BAA8B,CAAS;IAC/C,OAAO,CAAC,iBAAiB,CAAS;IASlC,YACqB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACtC,cAAc,GAAE,MAAc,EACb,OAAO,GAAE,gBAAwC,EAWrE;IAKD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAKD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAKD,IAAI,eAAe,IAAI,MAAM,CAE5B;IAKD,IAAI,cAAc,IAAI,MAAM,CAK3B;IASD,SAAS,CACL,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,GAC5B,IAAI,CASN;IAMD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAmBjC;IAKD,OAAO,IAAI,IAAI,CAGd;IAED,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,KAAK;IAab,OAAO,CAAC,UAAU;IAmElB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,+BAA+B;IAgBvC,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,UAAU;CAWrB"}
@@ -285,6 +285,9 @@ import { QueryResult } from './QueryResult.js';
285
285
  const sub = this._subscriptions.get(message.queryId);
286
286
  if (!sub || !this.isMessageForCurrentSubscription(message)) return;
287
287
  const result = message.payload;
288
+ if (result?.isValid === false) {
289
+ this._subscriptions.delete(message.queryId);
290
+ }
288
291
  sub.callback(result);
289
292
  }
290
293
  handleUnauthorized(message) {
@@ -1 +1 @@
1
- {"version":3,"file":"WebSocketHubConnection.js","sources":["../../../queries/WebSocketHubConnection.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.js';\nimport type { DataReceived } from './ObservableQueryConnection.js';\nimport { HubConnectionKeepAlive } from './HubConnectionKeepAlive.js';\nimport type { IReconnectPolicy } from './IReconnectPolicy.js';\nimport { ReconnectPolicy } from './ReconnectPolicy.js';\nimport { QueryResult } from './QueryResult.js';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Message types matching the backend {@link ObservableQueryHubMessageType} enum.\n * Serialized as strings by the JsonStringEnumConverter on the server.\n */\nexport enum HubMessageType {\n Subscribe = 'Subscribe',\n Unsubscribe = 'Unsubscribe',\n QueryResult = 'QueryResult',\n Unauthorized = 'Unauthorized',\n Error = 'Error',\n Ping = 'Ping',\n Pong = 'Pong',\n Connected = 'Connected',\n}\n\n/**\n * Wire format for messages exchanged over the observable query WebSocket and SSE hub transports.\n */\nexport interface HubMessage {\n type: HubMessageType;\n queryId?: string;\n\n /** Optional positive safe-integer revision used to reject stale replacement messages. */\n revision?: number;\n\n /**\n * Whether the server supports revision-aware subscription operations and result frames.\n * Only present on {@link HubMessageType.Connected} messages from capable servers.\n */\n supportsSubscriptionRevisions?: boolean;\n payload?: any;\n timestamp?: number;\n\n /**\n * The server's keep-alive interval in milliseconds, or 0 when keep-alive is disabled.\n * Only present on {@link HubMessageType.Connected} messages.\n */\n keepAliveIntervalMs?: number;\n}\n\n/**\n * Matches the backend {@link ObservableQuerySubscriptionRequest} record.\n */\nexport interface SubscriptionRequest {\n queryName: string;\n arguments?: Record<string, string | null>;\n page?: number;\n pageSize?: number;\n sortBy?: string;\n sortDirection?: string;\n transferMode?: string;\n}\n\ninterface ActiveSubscription {\n request: SubscriptionRequest;\n callback: DataReceived<any>;\n revision: number;\n}\n\n/**\n * Represents a single multiplexed WebSocket connection to the observable query hub\n * at {@code /.cratis/queries/ws}.\n *\n * Multiple query subscriptions are carried over the same physical WebSocket. Each subscription\n * is identified by a client-generated {@code queryId}; the server tags every result message with\n * the same id so responses can be routed to the correct callback. The client initially subscribes\n * without revisions for compatibility with older servers, then replaces active subscriptions with\n * revision-aware operations when the server advertises support in a Connected message.\n */\nexport class WebSocketHubConnection {\n private _socket?: WebSocket;\n private _disconnected = false;\n private _subscriptions: Map<string, ActiveSubscription> = new Map();\n private readonly _keepAlive: HubConnectionKeepAlive;\n private _lastPingSentTime?: number;\n private _lastPongLatency: number = 0;\n private _latencySamples: number[] = [];\n private _nextRevision = 0;\n private _supportsSubscriptionRevisions = false;\n private _reconnectPending = false;\n\n /**\n * Initializes a new instance of {@link WebSocketHubConnection}.\n * @param {string} _url The WebSocket URL of the hub endpoint (e.g. {@code ws://localhost:5000/.cratis/queries/ws}).\n * @param {string} _microservice The microservice name to pass as a query argument.\n * @param {number} pingIntervalMs How often to send keep-alive pings when the connection is idle (default: 10 000 ms).\n * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).\n */\n constructor(\n private readonly _url: string,\n private readonly _microservice: string,\n pingIntervalMs: number = 10000,\n private readonly _policy: IReconnectPolicy = new ReconnectPolicy(),\n ) {\n this._keepAlive = new HubConnectionKeepAlive(pingIntervalMs, () => {\n if (this._socket?.readyState === WebSocket.OPEN) {\n this._lastPingSentTime = Date.now();\n this.sendMessage({\n type: HubMessageType.Ping,\n timestamp: this._lastPingSentTime,\n });\n }\n });\n }\n\n /**\n * Gets the number of active query subscriptions on this connection.\n */\n get queryCount(): number {\n return this._subscriptions.size;\n }\n\n /**\n * Gets whether the WebSocket connection is currently open.\n */\n get isConnected(): boolean {\n return this._socket?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Gets the latency of the last ping/pong sequence in milliseconds.\n */\n get lastPingLatency(): number {\n return this._lastPongLatency;\n }\n\n /**\n * Gets the rolling average latency in milliseconds.\n */\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 /**\n * Subscribe to a query on this hub connection.\n * If the WebSocket is not yet open, the subscribe message will be sent once the connection is established.\n * @param {string} queryId Client-generated unique identifier for this subscription.\n * @param {SubscriptionRequest} request The subscription request payload.\n * @param {DataReceived<any>} callback Callback invoked whenever the server pushes a result for this query.\n */\n subscribe(\n queryId: string,\n request: SubscriptionRequest,\n callback: DataReceived<any>,\n ): void {\n const subscription = { request, callback, revision: this.getNextRevision() };\n this._subscriptions.set(queryId, subscription);\n this.ensureConnected();\n\n if (this._socket?.readyState === WebSocket.OPEN) {\n this.sendSubscribeMessage(queryId, subscription);\n }\n // If not yet open, sendAllSubscriptions will fire in onopen.\n }\n\n /**\n * Unsubscribe from a query on this hub connection.\n * @param {string} queryId The identifier of the subscription to cancel.\n */\n unsubscribe(queryId: string): void {\n const subscription = this._subscriptions.get(queryId);\n this._subscriptions.delete(queryId);\n\n if (this._socket?.readyState === WebSocket.OPEN && subscription) {\n const message: HubMessage = {\n type: HubMessageType.Unsubscribe,\n queryId,\n };\n if (this._supportsSubscriptionRevisions) {\n message.revision = subscription.revision;\n }\n this.sendMessage(message);\n }\n\n // If no subscriptions remain, close the connection to free resources.\n if (this._subscriptions.size === 0) {\n this.close();\n }\n }\n\n /**\n * Permanently close this hub connection and clean up all subscriptions.\n */\n dispose(): void {\n this._subscriptions.clear();\n this.close();\n }\n\n private ensureConnected(): void {\n if (this._disconnected) {\n // Reset disconnected flag when a new subscription comes in\n this._disconnected = false;\n }\n\n if (\n this._socket &&\n (this._socket.readyState === WebSocket.OPEN ||\n this._socket.readyState === WebSocket.CONNECTING)\n ) {\n this.cancelPendingReconnect();\n return;\n }\n\n // A subscription can arrive while an earlier close is waiting in reconnect backoff. The immediate open owns\n // the connection now, so the delayed callback must not be allowed to create a competing socket later.\n this.cancelPendingReconnect();\n this.openSocket();\n }\n\n private close(): void {\n this._disconnected = true;\n this._keepAlive.stop();\n this._policy.cancel();\n this._reconnectPending = false;\n const socket = this._socket;\n this._socket = undefined;\n this._supportsSubscriptionRevisions = false;\n if (socket) {\n this.detachAndCloseSocket(socket);\n }\n }\n\n private openSocket(): void {\n const currentSocket = this._socket;\n if (\n currentSocket &&\n (currentSocket.readyState === WebSocket.OPEN ||\n currentSocket.readyState === WebSocket.CONNECTING)\n ) {\n return;\n }\n\n if (currentSocket) {\n this._socket = undefined;\n this.detachAndCloseSocket(currentSocket);\n }\n\n this._supportsSubscriptionRevisions = false;\n\n let url = this._url;\n if (this._microservice?.length > 0) {\n const param = `${Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;\n url += (url.includes('?') ? '&' : '?') + param;\n }\n\n const socket = new WebSocket(url);\n this._socket = socket;\n\n socket.onopen = () => {\n if (this._socket !== socket || this._disconnected) return;\n console.log('Hub connection established', url);\n this.cancelPendingReconnect();\n this._policy.reset();\n this._keepAlive.start();\n this.sendAllSubscriptions();\n };\n\n socket.onclose = () => {\n if (this._socket !== socket || this._disconnected) return;\n console.log('Hub connection closed', url);\n this._socket = undefined;\n this._supportsSubscriptionRevisions = false;\n this._keepAlive.stop();\n if (this._subscriptions.size === 0) return;\n this._reconnectPending = true;\n const scheduled = this._policy.schedule(() => {\n this._reconnectPending = false;\n if (!this._disconnected && this._subscriptions.size > 0) {\n this.ensureConnected();\n }\n }, this._url);\n if (!scheduled) {\n this._reconnectPending = false;\n }\n };\n\n socket.onerror = (error) => {\n if (this._socket !== socket || this._disconnected) return;\n console.error('Hub connection error', url, error);\n this._keepAlive.stop();\n // onclose will fire after onerror, triggering reconnect\n };\n\n socket.onmessage = (ev) => {\n if (this._socket !== socket || this._disconnected) return;\n this.handleMessage(ev.data as string);\n };\n }\n\n private cancelPendingReconnect(): void {\n if (!this._reconnectPending) return;\n\n this._policy.cancel();\n this._reconnectPending = false;\n }\n\n private detachAndCloseSocket(socket: WebSocket): void {\n socket.onopen = null;\n socket.onclose = null;\n socket.onerror = null;\n socket.onmessage = null;\n socket.close();\n }\n\n private sendAllSubscriptions(): void {\n for (const [queryId, sub] of this._subscriptions) {\n this.sendSubscribeMessage(queryId, sub);\n }\n }\n\n private sendSubscribeMessage(\n queryId: string,\n subscription: ActiveSubscription,\n ): void {\n const message: HubMessage = {\n type: HubMessageType.Subscribe,\n queryId,\n payload: subscription.request,\n };\n if (this._supportsSubscriptionRevisions) {\n message.revision = subscription.revision;\n }\n this.sendMessage(message);\n }\n\n private sendMessage(message: HubMessage): void {\n if (this._socket?.readyState === WebSocket.OPEN) {\n this._socket.send(JSON.stringify(message));\n }\n }\n\n private handleMessage(rawData: string): void {\n try {\n const message = JSON.parse(rawData) as HubMessage;\n\n // Every received message is activity — skip keep-alive ping if data is flowing.\n this._keepAlive.recordActivity();\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.Pong:\n this.handlePong(message);\n break;\n case HubMessageType.Unauthorized:\n console.warn('Hub: query unauthorized', message.queryId);\n this.handleUnauthorized(message);\n break;\n case HubMessageType.Error:\n if (this.isMessageForCurrentSubscription(message)) {\n console.error(\n 'Hub: query error',\n message.queryId,\n message.payload,\n );\n }\n break;\n }\n } catch (error) {\n console.error('Hub: error parsing message', error);\n }\n }\n\n private handleConnected(message: HubMessage): void {\n if (\n message.supportsSubscriptionRevisions !== true ||\n this._supportsSubscriptionRevisions\n ) {\n return;\n }\n\n this._supportsSubscriptionRevisions = true;\n\n // The legacy subscriptions sent on socket open keep this client compatible with older servers.\n // Ordered WebSocket delivery means these revision-aware replacements are processed afterwards.\n this.sendAllSubscriptions();\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 sub.callback(QueryResult.unauthorized());\n }\n\n private isMessageForCurrentSubscription(message: HubMessage): boolean {\n if (!message.queryId) return false;\n\n if (!this._supportsSubscriptionRevisions) {\n return (\n message.revision === undefined &&\n this._subscriptions.has(message.queryId)\n );\n }\n\n return (\n this.isValidRevision(message.revision) &&\n this._subscriptions.get(message.queryId)?.revision === message.revision\n );\n }\n\n private isValidRevision(revision: number | undefined): revision is number {\n return revision !== undefined && Number.isSafeInteger(revision) && revision > 0;\n }\n\n private getNextRevision(): number {\n if (this._nextRevision >= Number.MAX_SAFE_INTEGER) {\n throw new RangeError(\n 'WebSocket hub subscription revision exhausted the safe integer range',\n );\n }\n\n return ++this._nextRevision;\n }\n\n private handlePong(message: HubMessage): void {\n if (message.timestamp && this._lastPingSentTime) {\n const latency = Date.now() - message.timestamp;\n this._lastPongLatency = latency;\n this._latencySamples.push(latency);\n\n if (this._latencySamples.length > 100) {\n this._latencySamples.shift();\n }\n }\n }\n}\n"],"names":["HubMessageType","WebSocketHubConnection","_socket","_disconnected","_subscriptions","Map","_keepAlive","_lastPingSentTime","_lastPongLatency","_latencySamples","_nextRevision","_supportsSubscriptionRevisions","_reconnectPending","_url","pingIntervalMs","_policy","ReconnectPolicy","_microservice","HubConnectionKeepAlive","readyState","WebSocket","OPEN","Date","now","sendMessage","type","timestamp","queryCount","size","isConnected","lastPingLatency","averageLatency","length","reduce","a","b","subscribe","queryId","request","callback","subscription","revision","getNextRevision","set","ensureConnected","sendSubscribeMessage","unsubscribe","get","delete","message","close","dispose","clear","CONNECTING","cancelPendingReconnect","openSocket","stop","cancel","socket","undefined","detachAndCloseSocket","currentSocket","url","param","Globals","microserviceWSQueryArgument","encodeURIComponent","includes","onopen","console","log","reset","start","sendAllSubscriptions","onclose","scheduled","schedule","onerror","error","onmessage","ev","handleMessage","data","sub","payload","send","JSON","stringify","rawData","parse","recordActivity","handleConnected","handleQueryResult","handlePong","warn","handleUnauthorized","isMessageForCurrentSubscription","supportsSubscriptionRevisions","result","QueryResult","unauthorized","has","isValidRevision","Number","isSafeInteger","MAX_SAFE_INTEGER","RangeError","latency","push","shift"],"mappings":"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"}
1
+ {"version":3,"file":"WebSocketHubConnection.js","sources":["../../../queries/WebSocketHubConnection.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.js';\nimport type { DataReceived } from './ObservableQueryConnection.js';\nimport { HubConnectionKeepAlive } from './HubConnectionKeepAlive.js';\nimport type { IReconnectPolicy } from './IReconnectPolicy.js';\nimport { ReconnectPolicy } from './ReconnectPolicy.js';\nimport { QueryResult } from './QueryResult.js';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Message types matching the backend {@link ObservableQueryHubMessageType} enum.\n * Serialized as strings by the JsonStringEnumConverter on the server.\n */\nexport enum HubMessageType {\n Subscribe = 'Subscribe',\n Unsubscribe = 'Unsubscribe',\n QueryResult = 'QueryResult',\n Unauthorized = 'Unauthorized',\n Error = 'Error',\n Ping = 'Ping',\n Pong = 'Pong',\n Connected = 'Connected',\n}\n\n/**\n * Wire format for messages exchanged over the observable query WebSocket and SSE hub transports.\n */\nexport interface HubMessage {\n type: HubMessageType;\n queryId?: string;\n\n /** Optional positive safe-integer revision used to reject stale replacement messages. */\n revision?: number;\n\n /**\n * Whether the server supports revision-aware subscription operations and result frames.\n * Only present on {@link HubMessageType.Connected} messages from capable servers.\n */\n supportsSubscriptionRevisions?: boolean;\n payload?: any;\n timestamp?: number;\n\n /**\n * The server's keep-alive interval in milliseconds, or 0 when keep-alive is disabled.\n * Only present on {@link HubMessageType.Connected} messages.\n */\n keepAliveIntervalMs?: number;\n}\n\n/**\n * Matches the backend {@link ObservableQuerySubscriptionRequest} record.\n */\nexport interface SubscriptionRequest {\n queryName: string;\n arguments?: Record<string, string | null>;\n page?: number;\n pageSize?: number;\n sortBy?: string;\n sortDirection?: string;\n transferMode?: string;\n}\n\ninterface ActiveSubscription {\n request: SubscriptionRequest;\n callback: DataReceived<any>;\n revision: number;\n}\n\n/**\n * Represents a single multiplexed WebSocket connection to the observable query hub\n * at {@code /.cratis/queries/ws}.\n *\n * Multiple query subscriptions are carried over the same physical WebSocket. Each subscription\n * is identified by a client-generated {@code queryId}; the server tags every result message with\n * the same id so responses can be routed to the correct callback. The client initially subscribes\n * without revisions for compatibility with older servers, then replaces active subscriptions with\n * revision-aware operations when the server advertises support in a Connected message.\n */\nexport class WebSocketHubConnection {\n private _socket?: WebSocket;\n private _disconnected = false;\n private _subscriptions: Map<string, ActiveSubscription> = new Map();\n private readonly _keepAlive: HubConnectionKeepAlive;\n private _lastPingSentTime?: number;\n private _lastPongLatency: number = 0;\n private _latencySamples: number[] = [];\n private _nextRevision = 0;\n private _supportsSubscriptionRevisions = false;\n private _reconnectPending = false;\n\n /**\n * Initializes a new instance of {@link WebSocketHubConnection}.\n * @param {string} _url The WebSocket URL of the hub endpoint (e.g. {@code ws://localhost:5000/.cratis/queries/ws}).\n * @param {string} _microservice The microservice name to pass as a query argument.\n * @param {number} pingIntervalMs How often to send keep-alive pings when the connection is idle (default: 10 000 ms).\n * @param {IReconnectPolicy} _policy The reconnect policy to use (default: {@link ReconnectPolicy}).\n */\n constructor(\n private readonly _url: string,\n private readonly _microservice: string,\n pingIntervalMs: number = 10000,\n private readonly _policy: IReconnectPolicy = new ReconnectPolicy(),\n ) {\n this._keepAlive = new HubConnectionKeepAlive(pingIntervalMs, () => {\n if (this._socket?.readyState === WebSocket.OPEN) {\n this._lastPingSentTime = Date.now();\n this.sendMessage({\n type: HubMessageType.Ping,\n timestamp: this._lastPingSentTime,\n });\n }\n });\n }\n\n /**\n * Gets the number of active query subscriptions on this connection.\n */\n get queryCount(): number {\n return this._subscriptions.size;\n }\n\n /**\n * Gets whether the WebSocket connection is currently open.\n */\n get isConnected(): boolean {\n return this._socket?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Gets the latency of the last ping/pong sequence in milliseconds.\n */\n get lastPingLatency(): number {\n return this._lastPongLatency;\n }\n\n /**\n * Gets the rolling average latency in milliseconds.\n */\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 /**\n * Subscribe to a query on this hub connection.\n * If the WebSocket is not yet open, the subscribe message will be sent once the connection is established.\n * @param {string} queryId Client-generated unique identifier for this subscription.\n * @param {SubscriptionRequest} request The subscription request payload.\n * @param {DataReceived<any>} callback Callback invoked whenever the server pushes a result for this query.\n */\n subscribe(\n queryId: string,\n request: SubscriptionRequest,\n callback: DataReceived<any>,\n ): void {\n const subscription = { request, callback, revision: this.getNextRevision() };\n this._subscriptions.set(queryId, subscription);\n this.ensureConnected();\n\n if (this._socket?.readyState === WebSocket.OPEN) {\n this.sendSubscribeMessage(queryId, subscription);\n }\n // If not yet open, sendAllSubscriptions will fire in onopen.\n }\n\n /**\n * Unsubscribe from a query on this hub connection.\n * @param {string} queryId The identifier of the subscription to cancel.\n */\n unsubscribe(queryId: string): void {\n const subscription = this._subscriptions.get(queryId);\n this._subscriptions.delete(queryId);\n\n if (this._socket?.readyState === WebSocket.OPEN && subscription) {\n const message: HubMessage = {\n type: HubMessageType.Unsubscribe,\n queryId,\n };\n if (this._supportsSubscriptionRevisions) {\n message.revision = subscription.revision;\n }\n this.sendMessage(message);\n }\n\n // If no subscriptions remain, close the connection to free resources.\n if (this._subscriptions.size === 0) {\n this.close();\n }\n }\n\n /**\n * Permanently close this hub connection and clean up all subscriptions.\n */\n dispose(): void {\n this._subscriptions.clear();\n this.close();\n }\n\n private ensureConnected(): void {\n if (this._disconnected) {\n // Reset disconnected flag when a new subscription comes in\n this._disconnected = false;\n }\n\n if (\n this._socket &&\n (this._socket.readyState === WebSocket.OPEN ||\n this._socket.readyState === WebSocket.CONNECTING)\n ) {\n this.cancelPendingReconnect();\n return;\n }\n\n // A subscription can arrive while an earlier close is waiting in reconnect backoff. The immediate open owns\n // the connection now, so the delayed callback must not be allowed to create a competing socket later.\n this.cancelPendingReconnect();\n this.openSocket();\n }\n\n private close(): void {\n this._disconnected = true;\n this._keepAlive.stop();\n this._policy.cancel();\n this._reconnectPending = false;\n const socket = this._socket;\n this._socket = undefined;\n this._supportsSubscriptionRevisions = false;\n if (socket) {\n this.detachAndCloseSocket(socket);\n }\n }\n\n private openSocket(): void {\n const currentSocket = this._socket;\n if (\n currentSocket &&\n (currentSocket.readyState === WebSocket.OPEN ||\n currentSocket.readyState === WebSocket.CONNECTING)\n ) {\n return;\n }\n\n if (currentSocket) {\n this._socket = undefined;\n this.detachAndCloseSocket(currentSocket);\n }\n\n this._supportsSubscriptionRevisions = false;\n\n let url = this._url;\n if (this._microservice?.length > 0) {\n const param = `${Globals.microserviceWSQueryArgument}=${encodeURIComponent(this._microservice)}`;\n url += (url.includes('?') ? '&' : '?') + param;\n }\n\n const socket = new WebSocket(url);\n this._socket = socket;\n\n socket.onopen = () => {\n if (this._socket !== socket || this._disconnected) return;\n console.log('Hub connection established', url);\n this.cancelPendingReconnect();\n this._policy.reset();\n this._keepAlive.start();\n this.sendAllSubscriptions();\n };\n\n socket.onclose = () => {\n if (this._socket !== socket || this._disconnected) return;\n console.log('Hub connection closed', url);\n this._socket = undefined;\n this._supportsSubscriptionRevisions = false;\n this._keepAlive.stop();\n if (this._subscriptions.size === 0) return;\n this._reconnectPending = true;\n const scheduled = this._policy.schedule(() => {\n this._reconnectPending = false;\n if (!this._disconnected && this._subscriptions.size > 0) {\n this.ensureConnected();\n }\n }, this._url);\n if (!scheduled) {\n this._reconnectPending = false;\n }\n };\n\n socket.onerror = (error) => {\n if (this._socket !== socket || this._disconnected) return;\n console.error('Hub connection error', url, error);\n this._keepAlive.stop();\n // onclose will fire after onerror, triggering reconnect\n };\n\n socket.onmessage = (ev) => {\n if (this._socket !== socket || this._disconnected) return;\n this.handleMessage(ev.data as string);\n };\n }\n\n private cancelPendingReconnect(): void {\n if (!this._reconnectPending) return;\n\n this._policy.cancel();\n this._reconnectPending = false;\n }\n\n private detachAndCloseSocket(socket: WebSocket): void {\n socket.onopen = null;\n socket.onclose = null;\n socket.onerror = null;\n socket.onmessage = null;\n socket.close();\n }\n\n private sendAllSubscriptions(): void {\n for (const [queryId, sub] of this._subscriptions) {\n this.sendSubscribeMessage(queryId, sub);\n }\n }\n\n private sendSubscribeMessage(\n queryId: string,\n subscription: ActiveSubscription,\n ): void {\n const message: HubMessage = {\n type: HubMessageType.Subscribe,\n queryId,\n payload: subscription.request,\n };\n if (this._supportsSubscriptionRevisions) {\n message.revision = subscription.revision;\n }\n this.sendMessage(message);\n }\n\n private sendMessage(message: HubMessage): void {\n if (this._socket?.readyState === WebSocket.OPEN) {\n this._socket.send(JSON.stringify(message));\n }\n }\n\n private handleMessage(rawData: string): void {\n try {\n const message = JSON.parse(rawData) as HubMessage;\n\n // Every received message is activity — skip keep-alive ping if data is flowing.\n this._keepAlive.recordActivity();\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.Pong:\n this.handlePong(message);\n break;\n case HubMessageType.Unauthorized:\n console.warn('Hub: query unauthorized', message.queryId);\n this.handleUnauthorized(message);\n break;\n case HubMessageType.Error:\n if (this.isMessageForCurrentSubscription(message)) {\n console.error(\n 'Hub: query error',\n message.queryId,\n message.payload,\n );\n }\n break;\n }\n } catch (error) {\n console.error('Hub: error parsing message', error);\n }\n }\n\n private handleConnected(message: HubMessage): void {\n if (\n message.supportsSubscriptionRevisions !== true ||\n this._supportsSubscriptionRevisions\n ) {\n return;\n }\n\n this._supportsSubscriptionRevisions = true;\n\n // The legacy subscriptions sent on socket open keep this client compatible with older servers.\n // Ordered WebSocket delivery means these revision-aware replacements are processed afterwards.\n this.sendAllSubscriptions();\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 if (result?.isValid === false) {\n this._subscriptions.delete(message.queryId);\n }\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 sub.callback(QueryResult.unauthorized());\n }\n\n private isMessageForCurrentSubscription(message: HubMessage): boolean {\n if (!message.queryId) return false;\n\n if (!this._supportsSubscriptionRevisions) {\n return (\n message.revision === undefined &&\n this._subscriptions.has(message.queryId)\n );\n }\n\n return (\n this.isValidRevision(message.revision) &&\n this._subscriptions.get(message.queryId)?.revision === message.revision\n );\n }\n\n private isValidRevision(revision: number | undefined): revision is number {\n return revision !== undefined && Number.isSafeInteger(revision) && revision > 0;\n }\n\n private getNextRevision(): number {\n if (this._nextRevision >= Number.MAX_SAFE_INTEGER) {\n throw new RangeError(\n 'WebSocket hub subscription revision exhausted the safe integer range',\n );\n }\n\n return ++this._nextRevision;\n }\n\n private handlePong(message: HubMessage): void {\n if (message.timestamp && this._lastPingSentTime) {\n const latency = Date.now() - message.timestamp;\n this._lastPongLatency = latency;\n this._latencySamples.push(latency);\n\n if (this._latencySamples.length > 100) {\n this._latencySamples.shift();\n }\n }\n }\n}\n"],"names":["HubMessageType","WebSocketHubConnection","_socket","_disconnected","_subscriptions","Map","_keepAlive","_lastPingSentTime","_lastPongLatency","_latencySamples","_nextRevision","_supportsSubscriptionRevisions","_reconnectPending","_url","pingIntervalMs","_policy","ReconnectPolicy","_microservice","HubConnectionKeepAlive","readyState","WebSocket","OPEN","Date","now","sendMessage","type","timestamp","queryCount","size","isConnected","lastPingLatency","averageLatency","length","reduce","a","b","subscribe","queryId","request","callback","subscription","revision","getNextRevision","set","ensureConnected","sendSubscribeMessage","unsubscribe","get","delete","message","close","dispose","clear","CONNECTING","cancelPendingReconnect","openSocket","stop","cancel","socket","undefined","detachAndCloseSocket","currentSocket","url","param","Globals","microserviceWSQueryArgument","encodeURIComponent","includes","onopen","console","log","reset","start","sendAllSubscriptions","onclose","scheduled","schedule","onerror","error","onmessage","ev","handleMessage","data","sub","payload","send","JSON","stringify","rawData","parse","recordActivity","handleConnected","handleQueryResult","handlePong","warn","handleUnauthorized","isMessageForCurrentSubscription","supportsSubscriptionRevisions","result","isValid","QueryResult","unauthorized","has","isValidRevision","Number","isSafeInteger","MAX_SAFE_INTEGER","RangeError","latency","push","shift"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=with_server_validation_failing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_server_validation_failing.d.ts","sourceRoot":"","sources":["../../../../../queries/for_ObservableQueryFor/when_performing/with_server_validation_failing.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ import sinon from 'sinon';
2
+ import { an_observable_query_for } from '../given/an_observable_query_for.js';
3
+ import { given } from '../../../given.js';
4
+ import { createFetchHelper } from '../../../helpers/fetchHelper.js';
5
+ import { ValidationResult } from '../../../validation/ValidationResult.js';
6
+ describe('with server validation failing', given(an_observable_query_for, context => {
7
+ let result;
8
+ let fetchHelper;
9
+ beforeEach(async () => {
10
+ fetchHelper = createFetchHelper();
11
+ fetchHelper.stubFetch().resolves({
12
+ ok: false,
13
+ status: 400,
14
+ json: sinon.stub().resolves({
15
+ data: null,
16
+ isSuccess: false,
17
+ isAuthorized: true,
18
+ isValid: false,
19
+ hasExceptions: false,
20
+ validationResults: [{ severity: 2, message: 'Id is invalid.', members: ['id'], state: {} }],
21
+ exceptionMessages: [],
22
+ exceptionStackTrace: '',
23
+ paging: { page: 0, size: 0, totalItems: 0, totalPages: 0 }
24
+ })
25
+ });
26
+ context.query.setOrigin('https://example.com');
27
+ result = await context.query.perform({ id: 'invalid' });
28
+ });
29
+ afterEach(() => fetchHelper.restore());
30
+ it('should be invalid', () => result.isValid.should.be.false);
31
+ it('should not be successful', () => result.isSuccess.should.be.false);
32
+ it('should map the validation result', () => result.validationResults[0].should.be.instanceOf(ValidationResult));
33
+ it('should preserve the message', () => result.validationResults[0].message.should.equal('Id is invalid.'));
34
+ it('should preserve the members', () => result.validationResults[0].members.should.deep.equal(['id']));
35
+ }));
36
+ //# sourceMappingURL=with_server_validation_failing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_server_validation_failing.js","sourceRoot":"","sources":["../../../../../queries/for_ObservableQueryFor/when_performing/with_server_validation_failing.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAE3E,QAAQ,CAAC,gCAAgC,EAAE,KAAK,CAAC,uBAAuB,EAAE,OAAO,CAAC,EAAE;IAChF,IAAI,MAA2B,CAAC;IAChC,IAAI,WAAiD,CAAC;IAEtD,UAAU,CAAC,KAAK,IAAI,EAAE;QAClB,WAAW,GAAG,iBAAiB,EAAE,CAAC;QAClC,WAAW,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC;YAC7B,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC;gBACxB,IAAI,EAAE,IAAI;gBACV,SAAS,EAAE,KAAK;gBAChB,YAAY,EAAE,IAAI;gBAClB,OAAO,EAAE,KAAK;gBACd,aAAa,EAAE,KAAK;gBACpB,iBAAiB,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;gBAC3F,iBAAiB,EAAE,EAAE;gBACrB,mBAAmB,EAAE,EAAE;gBACvB,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;aAC7D,CAAC;SACkB,CAAC,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;QAC/C,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAEvC,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9D,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACvE,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACjH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC5G,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3G,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=with_server_validation_failing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_server_validation_failing.d.ts","sourceRoot":"","sources":["../../../../../queries/for_ObservableQueryFor/when_subscribing/with_server_validation_failing.ts"],"names":[],"mappings":""}
@@ -0,0 +1,110 @@
1
+ import sinon from 'sinon';
2
+ import { Globals } from '../../../Globals.js';
3
+ import { createFetchHelper } from '../../../helpers/fetchHelper.js';
4
+ import { QueryTransportMethod } from '../../QueryTransportMethod.js';
5
+ import { getSharedMultiplexer, resetSharedMultiplexer } from '../../ObservableQueryMultiplexer.js';
6
+ import { an_observable_query_for } from '../given/an_observable_query_for.js';
7
+ for (const direct of [true, false]) {
8
+ for (const transport of [QueryTransportMethod.WebSocket, QueryTransportMethod.ServerSentEvents]) {
9
+ describe(`with server validation failing over ${direct ? 'direct' : 'hub'} ${transport}`, () => {
10
+ let received;
11
+ let subscription;
12
+ let originalDirect;
13
+ let originalTransport;
14
+ let originalWebSocket;
15
+ let originalEventSource;
16
+ let originalEventSourceFactory;
17
+ let fetchHelper;
18
+ let stream;
19
+ const rejection = {
20
+ data: null,
21
+ isSuccess: false,
22
+ isAuthorized: true,
23
+ isValid: false,
24
+ hasExceptions: false,
25
+ validationResults: [{ severity: 2, message: 'Id is invalid.', members: ['id'], state: {} }],
26
+ exceptionMessages: [],
27
+ exceptionStackTrace: '',
28
+ paging: { page: 0, size: 0, totalItems: 0, totalPages: 0 }
29
+ };
30
+ const sendDirectRejection = () => {
31
+ stream.onmessage?.({ data: JSON.stringify(rejection) });
32
+ stream.onclose?.();
33
+ stream.onmessage?.({ data: JSON.stringify(rejection) });
34
+ };
35
+ const hubQueryId = (fetchStub) => {
36
+ if (transport === QueryTransportMethod.ServerSentEvents) {
37
+ stream.onmessage?.({ data: JSON.stringify({ type: 'Connected', payload: 'connection-1' }) });
38
+ return JSON.parse(fetchStub.firstCall.args[1].body).queryId;
39
+ }
40
+ return JSON.parse(stream.send.firstCall.args[0]).queryId;
41
+ };
42
+ const sendHubRejection = (fetchStub) => {
43
+ const queryId = hubQueryId(fetchStub);
44
+ stream.onmessage?.({ data: JSON.stringify({ type: 'QueryResult', queryId, payload: rejection }) });
45
+ stream.onmessage?.({ data: JSON.stringify({ type: 'QueryResult', queryId, payload: rejection }) });
46
+ };
47
+ beforeEach(() => {
48
+ originalDirect = Globals.queryDirectMode;
49
+ originalTransport = Globals.queryTransportMethod;
50
+ originalWebSocket = globalThis.WebSocket;
51
+ originalEventSource = globalThis.EventSource;
52
+ originalEventSourceFactory = Globals.eventSourceFactory;
53
+ resetSharedMultiplexer();
54
+ Globals.queryDirectMode = direct;
55
+ Globals.queryTransportMethod = transport;
56
+ received = [];
57
+ stream = {
58
+ readyState: 0,
59
+ onopen: null,
60
+ onclose: null,
61
+ onerror: null,
62
+ onmessage: null,
63
+ send: sinon.stub(),
64
+ close: sinon.stub()
65
+ };
66
+ const socketStub = sinon.stub().returns(stream);
67
+ Object.assign(socketStub, { CONNECTING: 0, OPEN: 1, CLOSING: 2, CLOSED: 3 });
68
+ globalThis['WebSocket'] = socketStub;
69
+ globalThis['EventSource'] = Object.assign(sinon.stub().returns(stream), { OPEN: 1 });
70
+ Globals.eventSourceFactory = () => stream;
71
+ fetchHelper = createFetchHelper();
72
+ const fetchStub = fetchHelper.stubFetch().resolves({ ok: true });
73
+ const query = new an_observable_query_for().query;
74
+ query.setOrigin('https://example.com');
75
+ subscription = query.subscribe(result => received.push(result), { id: 'invalid' });
76
+ stream.readyState = 1;
77
+ stream.onopen?.();
78
+ if (direct) {
79
+ sendDirectRejection();
80
+ }
81
+ else {
82
+ sendHubRejection(fetchStub);
83
+ }
84
+ });
85
+ afterEach(() => {
86
+ subscription?.unsubscribe();
87
+ resetSharedMultiplexer();
88
+ Globals.queryDirectMode = originalDirect;
89
+ Globals.queryTransportMethod = originalTransport;
90
+ Globals.eventSourceFactory = originalEventSourceFactory;
91
+ globalThis.WebSocket = originalWebSocket;
92
+ globalThis.EventSource = originalEventSource;
93
+ fetchHelper.restore();
94
+ });
95
+ it('should deliver one result to the subscriber', () => received.should.have.lengthOf(1));
96
+ it('should be invalid', () => received[0].isValid.should.be.false);
97
+ it('should not be successful', () => received[0].isSuccess.should.be.false);
98
+ it('should preserve the validation results', () => received[0].validationResults.should.deep.equal(rejection.validationResults));
99
+ it('should settle the rejected subscription', () => {
100
+ if (direct) {
101
+ stream.close.should.have.been.calledOnce;
102
+ }
103
+ else {
104
+ getSharedMultiplexer().getConnectionsSnapshot().every(connection => connection.queryCount === 0).should.be.true;
105
+ }
106
+ });
107
+ });
108
+ }
109
+ }
110
+ //# sourceMappingURL=with_server_validation_failing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_server_validation_failing.js","sourceRoot":"","sources":["../../../../../queries/for_ObservableQueryFor/when_subscribing/with_server_validation_failing.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAGrE,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AACnG,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE9E,KAAK,MAAM,MAAM,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;IACjC,KAAK,MAAM,SAAS,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,oBAAoB,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC9F,QAAQ,CAAC,uCAAuC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,SAAS,EAAE,EAAE,GAAG,EAAE;YAC3F,IAAI,QAA+B,CAAC;YACpC,IAAI,YAAiD,CAAC;YACtD,IAAI,cAAuB,CAAC;YAC5B,IAAI,iBAAuC,CAAC;YAC5C,IAAI,iBAAmC,CAAC;YACxC,IAAI,mBAAuC,CAAC;YAC5C,IAAI,0BAA6D,CAAC;YAClE,IAAI,WAAiD,CAAC;YACtD,IAAI,MAQH,CAAC;YACF,MAAM,SAAS,GAAG;gBACd,IAAI,EAAE,IAAI;gBACV,SAAS,EAAE,KAAK;gBAChB,YAAY,EAAE,IAAI;gBAClB,OAAO,EAAE,KAAK;gBACd,aAAa,EAAE,KAAK;gBACpB,iBAAiB,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;gBAC3F,iBAAiB,EAAE,EAAE;gBACrB,mBAAmB,EAAE,EAAE;gBACvB,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;aAC7D,CAAC;YAEF,MAAM,mBAAmB,GAAG,GAAG,EAAE;gBAC7B,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBAExD,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;gBACnB,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAC5D,CAAC,CAAC;YAEF,MAAM,UAAU,GAAG,CAAC,SAA0B,EAAU,EAAE;gBACtD,IAAI,SAAS,KAAK,oBAAoB,CAAC,gBAAgB,EAAE,CAAC;oBACtD,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC7F,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;gBAChE,CAAC;gBACD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7D,CAAC,CAAC;YAEF,MAAM,gBAAgB,GAAG,CAAC,SAA0B,EAAE,EAAE;gBACpD,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;gBACtC,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;gBAEnG,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;YACvG,CAAC,CAAC;YAEF,UAAU,CAAC,GAAG,EAAE;gBACZ,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;gBACzC,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC;gBACjD,iBAAiB,GAAG,UAAU,CAAC,SAAS,CAAC;gBACzC,mBAAmB,GAAG,UAAU,CAAC,WAAW,CAAC;gBAC7C,0BAA0B,GAAG,OAAO,CAAC,kBAAkB,CAAC;gBACxD,sBAAsB,EAAE,CAAC;gBACzB,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC;gBACjC,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;gBACzC,QAAQ,GAAG,EAAE,CAAC;gBACd,MAAM,GAAG;oBACL,UAAU,EAAE,CAAC;oBACb,MAAM,EAAE,IAAI;oBACZ,OAAO,EAAE,IAAI;oBACb,OAAO,EAAE,IAAI;oBACb,SAAS,EAAE,IAAI;oBACf,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;oBAClB,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE;iBACtB,CAAC;gBACF,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAChD,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC5E,UAAsC,CAAC,WAAW,CAAC,GAAG,UAAU,CAAC;gBACjE,UAAsC,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;gBAClH,OAAO,CAAC,kBAAkB,GAAG,GAAG,EAAE,CAAC,MAAgC,CAAC;gBACpE,WAAW,GAAG,iBAAiB,EAAE,CAAC;gBAClC,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,IAAI,EAAc,CAAC,CAAC;gBAC7E,MAAM,KAAK,GAAG,IAAI,uBAAuB,EAAE,CAAC,KAAK,CAAC;gBAClD,KAAK,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;gBACvC,YAAY,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;gBACnF,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC;gBACtB,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;gBAElB,IAAI,MAAM,EAAE,CAAC;oBACT,mBAAmB,EAAE,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACJ,gBAAgB,CAAC,SAAS,CAAC,CAAC;gBAChC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,SAAS,CAAC,GAAG,EAAE;gBACX,YAAY,EAAE,WAAW,EAAE,CAAC;gBAC5B,sBAAsB,EAAE,CAAC;gBACzB,OAAO,CAAC,eAAe,GAAG,cAAc,CAAC;gBACzC,OAAO,CAAC,oBAAoB,GAAG,iBAAiB,CAAC;gBACjD,OAAO,CAAC,kBAAkB,GAAG,0BAA0B,CAAC;gBACxD,UAAU,CAAC,SAAS,GAAG,iBAAiB,CAAC;gBACzC,UAAU,CAAC,WAAW,GAAG,mBAAmB,CAAC;gBAC7C,WAAW,CAAC,OAAO,EAAE,CAAC;YAC1B,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1F,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;YACnE,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;YAC5E,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC;YACjI,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;gBAC/C,IAAI,MAAM,EAAE,CAAC;oBACT,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;gBAC7C,CAAC;qBAAM,CAAC;oBACJ,oBAAoB,EAAG,CAAC,sBAAsB,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC;gBACrH,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=with_server_validation_failing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_server_validation_failing.d.ts","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_server_validation_failing.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ import sinon from 'sinon';
2
+ import { a_query_for } from '../given/a_query_for.js';
3
+ import { given } from '../../../given.js';
4
+ import { createFetchHelper } from '../../../helpers/fetchHelper.js';
5
+ import { ValidationResult } from '../../../validation/ValidationResult.js';
6
+ describe('with server validation failing', given(a_query_for, context => {
7
+ let result;
8
+ let fetchHelper;
9
+ beforeEach(async () => {
10
+ fetchHelper = createFetchHelper();
11
+ fetchHelper.stubFetch().resolves({
12
+ ok: false,
13
+ status: 400,
14
+ json: sinon.stub().resolves({
15
+ data: null,
16
+ isSuccess: false,
17
+ isAuthorized: true,
18
+ isValid: false,
19
+ hasExceptions: false,
20
+ validationResults: [{ severity: 2, message: 'Id is invalid.', members: ['id'], state: {} }],
21
+ exceptionMessages: [],
22
+ exceptionStackTrace: '',
23
+ paging: { page: 0, size: 0, totalItems: 0, totalPages: 0 }
24
+ })
25
+ });
26
+ context.query.setOrigin('https://example.com');
27
+ result = await context.query.perform({ id: 'invalid' });
28
+ });
29
+ afterEach(() => fetchHelper.restore());
30
+ it('should be invalid', () => result.isValid.should.be.false);
31
+ it('should not be successful', () => result.isSuccess.should.be.false);
32
+ it('should map the validation result', () => result.validationResults[0].should.be.instanceOf(ValidationResult));
33
+ it('should preserve the message', () => result.validationResults[0].message.should.equal('Id is invalid.'));
34
+ it('should preserve the members', () => result.validationResults[0].members.should.deep.equal(['id']));
35
+ }));
36
+ //# sourceMappingURL=with_server_validation_failing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with_server_validation_failing.js","sourceRoot":"","sources":["../../../../../queries/for_QueryFor/when_performing/with_server_validation_failing.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAE3E,QAAQ,CAAC,gCAAgC,EAAE,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE;IACpE,IAAI,MAA2B,CAAC;IAChC,IAAI,WAAiD,CAAC;IAEtD,UAAU,CAAC,KAAK,IAAI,EAAE;QAClB,WAAW,GAAG,iBAAiB,EAAE,CAAC;QAClC,WAAW,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC;YAC7B,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC;gBACxB,IAAI,EAAE,IAAI;gBACV,SAAS,EAAE,KAAK;gBAChB,YAAY,EAAE,IAAI;gBAClB,OAAO,EAAE,KAAK;gBACd,aAAa,EAAE,KAAK;gBACpB,iBAAiB,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;gBAC3F,iBAAiB,EAAE,EAAE;gBACrB,mBAAmB,EAAE,EAAE;gBACvB,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;aAC7D,CAAC;SACkB,CAAC,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;QAC/C,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IAEvC,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IAC9D,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;IACvE,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACjH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC5G,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3G,CAAC,CAAC,CAAC,CAAC"}