@cratis/chronicle 2.0.0 → 2.1.1

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 (102) hide show
  1. package/ChronicleClient.ts +69 -60
  2. package/connection/ChronicleConnection.ts +32 -9
  3. package/connection/ChronicleConnectionString.spec.ts +227 -0
  4. package/connection/ChronicleConnectionString.ts +290 -40
  5. package/connection/ChronicleServerAddressResolver.spec.ts +41 -0
  6. package/connection/ChronicleServerAddressResolver.ts +33 -0
  7. package/connection/ChronicleSrvResolutionError.ts +13 -0
  8. package/connection/ChronicleSrvResolver.spec.ts +103 -0
  9. package/connection/ChronicleSrvResolver.ts +57 -0
  10. package/connection/ConnectionLifecycle.spec.ts +109 -0
  11. package/connection/ILoadBalancerStrategy.ts +16 -0
  12. package/connection/KernelKeepAlive.spec.ts +175 -0
  13. package/connection/KernelKeepAlive.ts +161 -0
  14. package/connection/LeastConnectionsLoadBalancerStrategy.spec.ts +159 -0
  15. package/connection/LeastConnectionsLoadBalancerStrategy.ts +117 -0
  16. package/connection/LoadBalancerMode.ts +25 -0
  17. package/connection/LoadBalancerStrategyFactory.ts +28 -0
  18. package/connection/RandomLoadBalancerStrategy.spec.ts +50 -0
  19. package/connection/RandomLoadBalancerStrategy.ts +19 -0
  20. package/connection/RoundRobinLoadBalancerStrategy.spec.ts +61 -0
  21. package/connection/RoundRobinLoadBalancerStrategy.ts +29 -0
  22. package/connection/TokenProvider.spec.ts +159 -0
  23. package/connection/TokenProvider.ts +80 -68
  24. package/connection/fetchOAuthAccessToken.ts +86 -0
  25. package/connection/formatServerAddress.ts +16 -0
  26. package/dist/ChronicleClient.d.ts +8 -1
  27. package/dist/ChronicleClient.d.ts.map +1 -1
  28. package/dist/ChronicleClient.js +63 -56
  29. package/dist/ChronicleClient.js.map +1 -1
  30. package/dist/connection/ChronicleConnection.d.ts +4 -1
  31. package/dist/connection/ChronicleConnection.d.ts.map +1 -1
  32. package/dist/connection/ChronicleConnection.js +29 -9
  33. package/dist/connection/ChronicleConnection.js.map +1 -1
  34. package/dist/connection/ChronicleConnectionString.d.ts +77 -3
  35. package/dist/connection/ChronicleConnectionString.d.ts.map +1 -1
  36. package/dist/connection/ChronicleConnectionString.js +251 -37
  37. package/dist/connection/ChronicleConnectionString.js.map +1 -1
  38. package/dist/connection/ChronicleServerAddressResolver.d.ts +23 -0
  39. package/dist/connection/ChronicleServerAddressResolver.d.ts.map +1 -0
  40. package/dist/connection/ChronicleServerAddressResolver.js +32 -0
  41. package/dist/connection/ChronicleServerAddressResolver.js.map +1 -0
  42. package/dist/connection/ChronicleSrvResolutionError.d.ts +8 -0
  43. package/dist/connection/ChronicleSrvResolutionError.d.ts.map +1 -0
  44. package/dist/connection/ChronicleSrvResolutionError.js +13 -0
  45. package/dist/connection/ChronicleSrvResolutionError.js.map +1 -0
  46. package/dist/connection/ChronicleSrvResolver.d.ts +28 -0
  47. package/dist/connection/ChronicleSrvResolver.d.ts.map +1 -0
  48. package/dist/connection/ChronicleSrvResolver.js +51 -0
  49. package/dist/connection/ChronicleSrvResolver.js.map +1 -0
  50. package/dist/connection/ILoadBalancerStrategy.d.ts +13 -0
  51. package/dist/connection/ILoadBalancerStrategy.d.ts.map +1 -0
  52. package/dist/connection/ILoadBalancerStrategy.js +4 -0
  53. package/dist/connection/ILoadBalancerStrategy.js.map +1 -0
  54. package/dist/connection/KernelKeepAlive.d.ts +73 -0
  55. package/dist/connection/KernelKeepAlive.d.ts.map +1 -0
  56. package/dist/connection/KernelKeepAlive.js +115 -0
  57. package/dist/connection/KernelKeepAlive.js.map +1 -0
  58. package/dist/connection/LeastConnectionsLoadBalancerStrategy.d.ts +30 -0
  59. package/dist/connection/LeastConnectionsLoadBalancerStrategy.d.ts.map +1 -0
  60. package/dist/connection/LeastConnectionsLoadBalancerStrategy.js +95 -0
  61. package/dist/connection/LeastConnectionsLoadBalancerStrategy.js.map +1 -0
  62. package/dist/connection/LoadBalancerMode.d.ts +21 -0
  63. package/dist/connection/LoadBalancerMode.d.ts.map +1 -0
  64. package/dist/connection/LoadBalancerMode.js +24 -0
  65. package/dist/connection/LoadBalancerMode.js.map +1 -0
  66. package/dist/connection/LoadBalancerStrategyFactory.d.ts +11 -0
  67. package/dist/connection/LoadBalancerStrategyFactory.d.ts.map +1 -0
  68. package/dist/connection/LoadBalancerStrategyFactory.js +26 -0
  69. package/dist/connection/LoadBalancerStrategyFactory.js.map +1 -0
  70. package/dist/connection/RandomLoadBalancerStrategy.d.ts +9 -0
  71. package/dist/connection/RandomLoadBalancerStrategy.d.ts.map +1 -0
  72. package/dist/connection/RandomLoadBalancerStrategy.js +15 -0
  73. package/dist/connection/RandomLoadBalancerStrategy.js.map +1 -0
  74. package/dist/connection/RoundRobinLoadBalancerStrategy.d.ts +12 -0
  75. package/dist/connection/RoundRobinLoadBalancerStrategy.d.ts.map +1 -0
  76. package/dist/connection/RoundRobinLoadBalancerStrategy.js +22 -0
  77. package/dist/connection/RoundRobinLoadBalancerStrategy.js.map +1 -0
  78. package/dist/connection/TokenProvider.d.ts +32 -7
  79. package/dist/connection/TokenProvider.d.ts.map +1 -1
  80. package/dist/connection/TokenProvider.js +69 -61
  81. package/dist/connection/TokenProvider.js.map +1 -1
  82. package/dist/connection/fetchOAuthAccessToken.d.ts +18 -0
  83. package/dist/connection/fetchOAuthAccessToken.d.ts.map +1 -0
  84. package/dist/connection/fetchOAuthAccessToken.js +62 -0
  85. package/dist/connection/fetchOAuthAccessToken.js.map +1 -0
  86. package/dist/connection/formatServerAddress.d.ts +10 -0
  87. package/dist/connection/formatServerAddress.d.ts.map +1 -0
  88. package/dist/connection/formatServerAddress.js +14 -0
  89. package/dist/connection/formatServerAddress.js.map +1 -0
  90. package/dist/reactors/Reactors.d.ts +13 -0
  91. package/dist/reactors/Reactors.d.ts.map +1 -1
  92. package/dist/reactors/Reactors.js +42 -4
  93. package/dist/reactors/Reactors.js.map +1 -1
  94. package/dist/reducers/Reducers.d.ts +14 -0
  95. package/dist/reducers/Reducers.d.ts.map +1 -1
  96. package/dist/reducers/Reducers.js +43 -8
  97. package/dist/reducers/Reducers.js.map +1 -1
  98. package/dist/tsconfig.tsbuildinfo +1 -1
  99. package/package.json +8 -5
  100. package/reactors/Reactors.ts +53 -4
  101. package/reducers/Reducers.ts +55 -8
  102. package/vitest.config.ts +12 -0
@@ -1,9 +1,14 @@
1
1
  // Copyright (c) Cratis. All rights reserved.
2
2
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
- import * as http from 'http';
4
- import * as https from 'https';
5
- const TOKEN_EXPIRY_BUFFER_SECONDS = 60;
3
+ import { diag } from '@opentelemetry/api';
4
+ import { fetchOAuthAccessToken } from './fetchOAuthAccessToken';
5
+ // Refresh once the token has less than this long left before it expires.
6
+ const TOKEN_REFRESH_MARGIN_MS = 60_000;
7
+ // Assumed lifetime when the token response carries no usable expires_in.
6
8
  const DEFAULT_TOKEN_EXPIRY_SECONDS = 3600;
9
+ // Minimum pause between failed fetch attempts, so an auth outage does not turn
10
+ // every RPC into a token request.
11
+ const FAILED_FETCH_RETRY_DELAY_MS = 5_000;
7
12
  /**
8
13
  * No-op token provider for when authentication is not required.
9
14
  */
@@ -16,28 +21,47 @@ export class NoOpTokenProvider {
16
21
  }
17
22
  }
18
23
  /**
19
- * OAuth token provider using client credentials flow.
24
+ * OAuth token provider using the client credentials flow.
25
+ *
26
+ * Owns the access token so it can be attached to every RPC individually instead of
27
+ * being baked into the channel at connect time: the token is fetched lazily on first
28
+ * use, cached, and refreshed once it enters the refresh margin ahead of expiry, so
29
+ * token expiry never invalidates the channel. A failed refresh falls back to the
30
+ * cached token while it is still actually valid — only the refresh margin has been
31
+ * crossed, not the expiry — and further attempts are throttled so an unreachable
32
+ * auth endpoint does not turn every RPC into a fetch attempt.
20
33
  */
21
34
  export class OAuthTokenProvider {
22
- _tokenEndpoint;
23
- _clientId;
24
- _clientSecret;
35
+ _fetchToken;
36
+ _logger = diag.createComponentLogger({
37
+ namespace: '@cratis/chronicle/OAuthTokenProvider'
38
+ });
25
39
  _accessToken;
26
- _tokenExpiry = new Date(0);
40
+ _expiresAt = 0;
41
+ _lastFailedFetch;
27
42
  _refreshPromise;
28
- constructor(_tokenEndpoint, _clientId, _clientSecret) {
29
- this._tokenEndpoint = _tokenEndpoint;
30
- this._clientId = _clientId;
31
- this._clientSecret = _clientSecret;
43
+ /**
44
+ * Creates a new {@link OAuthTokenProvider}.
45
+ * @param tokenEndpoint - The OAuth2 token endpoint to request tokens from.
46
+ * @param clientId - The client identifier.
47
+ * @param clientSecret - The client secret.
48
+ * @param skipTlsValidation - Whether to skip TLS certificate chain validation.
49
+ * @param _fetchToken - Test-only seam replacing the OAuth2 token request.
50
+ */
51
+ constructor(tokenEndpoint, clientId, clientSecret, skipTlsValidation = true, _fetchToken = () => fetchOAuthAccessToken(tokenEndpoint, clientId, clientSecret, skipTlsValidation)) {
52
+ this._fetchToken = _fetchToken;
32
53
  }
33
54
  async getAccessToken() {
34
- if (this._accessToken && new Date() < this._tokenExpiry) {
55
+ if (this.hasFreshToken()) {
35
56
  return this._accessToken;
36
57
  }
37
58
  if (this._refreshPromise) {
38
59
  return this._refreshPromise;
39
60
  }
40
- this._refreshPromise = this.fetchAccessToken();
61
+ if (this.isThrottled()) {
62
+ return this.cachedTokenWhileValid();
63
+ }
64
+ this._refreshPromise = this.fetchAndCacheAccessToken();
41
65
  try {
42
66
  return await this._refreshPromise;
43
67
  }
@@ -47,56 +71,40 @@ export class OAuthTokenProvider {
47
71
  }
48
72
  async refresh() {
49
73
  this._accessToken = undefined;
50
- this._tokenExpiry = new Date(0);
74
+ this._expiresAt = 0;
75
+ this._lastFailedFetch = undefined;
51
76
  return this.getAccessToken();
52
77
  }
53
- async fetchAccessToken() {
54
- const params = new URLSearchParams();
55
- params.append('grant_type', 'client_credentials');
56
- params.append('client_id', this._clientId);
57
- params.append('client_secret', this._clientSecret);
58
- const body = params.toString();
59
- return new Promise((resolve, reject) => {
60
- const url = new URL(this._tokenEndpoint);
61
- const isHttps = url.protocol === 'https:';
62
- const httpModule = isHttps ? https : http;
63
- const req = httpModule.request(url, {
64
- method: 'POST',
65
- headers: {
66
- 'Content-Type': 'application/x-www-form-urlencoded',
67
- 'Content-Length': Buffer.byteLength(body)
68
- },
69
- // Chronicle generates a self-signed certificate in development, so chain
70
- // validation is skipped, matching the gRPC channel's credentials.
71
- ...(isHttps ? { rejectUnauthorized: false } : {})
72
- }, response => {
73
- let data = '';
74
- response.on('data', chunk => {
75
- data += chunk;
76
- });
77
- response.on('end', () => {
78
- if (response.statusCode !== 200) {
79
- reject(new Error(`Token request failed with status ${response.statusCode}: ${data}`));
80
- return;
81
- }
82
- try {
83
- const tokenResponse = JSON.parse(data);
84
- this._accessToken = tokenResponse.access_token;
85
- const expiresInSeconds = tokenResponse.expires_in || DEFAULT_TOKEN_EXPIRY_SECONDS;
86
- this._tokenExpiry = new Date(Date.now() + (expiresInSeconds - TOKEN_EXPIRY_BUFFER_SECONDS) * 1000);
87
- resolve(this._accessToken);
88
- }
89
- catch (error) {
90
- reject(new Error(`Failed to parse token response: ${error instanceof Error ? error.message : String(error)}`));
91
- }
92
- });
93
- });
94
- req.on('error', error => {
95
- reject(new Error(`Token request failed: ${error.message}`));
78
+ hasFreshToken() {
79
+ return !!this._accessToken && this._expiresAt - Date.now() > TOKEN_REFRESH_MARGIN_MS;
80
+ }
81
+ isThrottled() {
82
+ return this._lastFailedFetch !== undefined && Date.now() - this._lastFailedFetch < FAILED_FETCH_RETRY_DELAY_MS;
83
+ }
84
+ cachedTokenWhileValid() {
85
+ return this._accessToken && Date.now() < this._expiresAt ? this._accessToken : undefined;
86
+ }
87
+ async fetchAndCacheAccessToken() {
88
+ try {
89
+ const response = await this._fetchToken();
90
+ this._accessToken = response.access_token;
91
+ this._expiresAt = Date.now() + this.lifetimeSecondsFrom(response) * 1000;
92
+ this._lastFailedFetch = undefined;
93
+ return this._accessToken;
94
+ }
95
+ catch (error) {
96
+ this._logger.warn('Failed to fetch OAuth2 token', {
97
+ error: error instanceof Error ? error.message : String(error)
96
98
  });
97
- req.write(body);
98
- req.end();
99
- });
99
+ this._lastFailedFetch = Date.now();
100
+ return this.cachedTokenWhileValid();
101
+ }
102
+ }
103
+ // expires_in is RECOMMENDED but not required by OAuth2, and some servers send it
104
+ // as a string.
105
+ lifetimeSecondsFrom(response) {
106
+ const seconds = Number(response.expires_in);
107
+ return Number.isFinite(seconds) && seconds > 0 ? seconds : DEFAULT_TOKEN_EXPIRY_SECONDS;
100
108
  }
101
109
  }
102
110
  //# sourceMappingURL=TokenProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TokenProvider.js","sourceRoot":"","sources":["../../connection/TokenProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TokenProvider.js","sourceRoot":"","sources":["../../connection/TokenProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The shape of a successful OAuth2 token response.
3
+ */
4
+ export interface OAuthTokenResponse {
5
+ access_token: string;
6
+ /** RECOMMENDED but not required by OAuth2, and some servers send it as a string. */
7
+ expires_in?: number | string;
8
+ }
9
+ /**
10
+ * Requests an access token from an OAuth2 token endpoint using the client credentials flow.
11
+ * @param tokenEndpoint - The token endpoint URL.
12
+ * @param clientId - The client identifier.
13
+ * @param clientSecret - The client secret.
14
+ * @param skipTlsValidation - Whether to skip TLS certificate chain validation.
15
+ * @returns The parsed token response; rejects when the request fails or the response is not a valid token.
16
+ */
17
+ export declare function fetchOAuthAccessToken(tokenEndpoint: string, clientId: string, clientSecret: string, skipTlsValidation: boolean): Promise<OAuthTokenResponse>;
18
+ //# sourceMappingURL=fetchOAuthAccessToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchOAuthAccessToken.d.ts","sourceRoot":"","sources":["../../connection/fetchOAuthAccessToken.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,MAAM,CAAC;IAErB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACjC,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,OAAO,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAwD7B"}
@@ -0,0 +1,62 @@
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
+ import * as http from 'http';
4
+ import * as https from 'https';
5
+ /**
6
+ * Requests an access token from an OAuth2 token endpoint using the client credentials flow.
7
+ * @param tokenEndpoint - The token endpoint URL.
8
+ * @param clientId - The client identifier.
9
+ * @param clientSecret - The client secret.
10
+ * @param skipTlsValidation - Whether to skip TLS certificate chain validation.
11
+ * @returns The parsed token response; rejects when the request fails or the response is not a valid token.
12
+ */
13
+ export function fetchOAuthAccessToken(tokenEndpoint, clientId, clientSecret, skipTlsValidation) {
14
+ const params = new URLSearchParams();
15
+ params.append('grant_type', 'client_credentials');
16
+ params.append('client_id', clientId);
17
+ params.append('client_secret', clientSecret);
18
+ const body = params.toString();
19
+ return new Promise((resolve, reject) => {
20
+ const url = new URL(tokenEndpoint);
21
+ const isHttps = url.protocol === 'https:';
22
+ const httpModule = isHttps ? https : http;
23
+ const request = httpModule.request(url, {
24
+ method: 'POST',
25
+ headers: {
26
+ 'Content-Type': 'application/x-www-form-urlencoded',
27
+ 'Content-Length': Buffer.byteLength(body)
28
+ },
29
+ // Chain validation is skipped only when skipTlsValidation is explicitly set,
30
+ // matching the gRPC channel's credentials for the same connection string.
31
+ ...(isHttps && skipTlsValidation ? { rejectUnauthorized: false } : {})
32
+ }, response => {
33
+ let data = '';
34
+ response.on('data', chunk => {
35
+ data += chunk;
36
+ });
37
+ response.on('end', () => {
38
+ if (response.statusCode !== 200) {
39
+ reject(new Error(`Token request failed with status ${response.statusCode}: ${data}`));
40
+ return;
41
+ }
42
+ try {
43
+ const tokenResponse = JSON.parse(data);
44
+ if (!tokenResponse.access_token) {
45
+ reject(new Error('Token response did not contain an access_token'));
46
+ return;
47
+ }
48
+ resolve(tokenResponse);
49
+ }
50
+ catch (error) {
51
+ reject(new Error(`Failed to parse token response: ${error instanceof Error ? error.message : String(error)}`));
52
+ }
53
+ });
54
+ });
55
+ request.on('error', error => {
56
+ reject(new Error(`Token request failed: ${error.message}`));
57
+ });
58
+ request.write(body);
59
+ request.end();
60
+ });
61
+ }
62
+ //# sourceMappingURL=fetchOAuthAccessToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetchOAuthAccessToken.js","sourceRoot":"","sources":["../../connection/fetchOAuthAccessToken.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,qGAAqG;AAErG,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAY/B;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACjC,aAAqB,EACrB,QAAgB,EAChB,YAAoB,EACpB,iBAA0B;IAE1B,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;IACrC,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;IAClD,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;IAE7C,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IAE/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;QAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAE1C,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,mCAAmC;gBACnD,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;aAC5C;YACD,6EAA6E;YAC7E,0EAA0E;YAC1E,GAAG,CAAC,OAAO,IAAI,iBAAiB,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzE,EAAE,QAAQ,CAAC,EAAE;YACV,IAAI,IAAI,GAAG,EAAE,CAAC;YAEd,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;gBACxB,IAAI,IAAI,KAAK,CAAC;YAClB,CAAC,CAAC,CAAC;YAEH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBACpB,IAAI,QAAQ,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;oBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,QAAQ,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;oBACtF,OAAO;gBACX,CAAC;gBAED,IAAI,CAAC;oBACD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAuB,CAAC;oBAC7D,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC;wBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC,CAAC;wBACpE,OAAO;oBACX,CAAC;oBAED,OAAO,CAAC,aAAa,CAAC,CAAC;gBAC3B,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACb,MAAM,CAAC,IAAI,KAAK,CAAC,mCAAmC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;gBACnH,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;YACxB,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpB,OAAO,CAAC,GAAG,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ChronicleServerAddress } from './ChronicleConnectionString';
2
+ /**
3
+ * Formats a {@link ChronicleServerAddress} as a `host:port` string, wrapping IPv6 host
4
+ * literals in bracket notation (e.g. `[::1]:35000`) as required by both the connection
5
+ * string grammar and gRPC target grammar.
6
+ * @param address - The address to format.
7
+ * @returns The formatted `host:port` string.
8
+ */
9
+ export declare function formatServerAddress(address: ChronicleServerAddress): string;
10
+ //# sourceMappingURL=formatServerAddress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatServerAddress.d.ts","sourceRoot":"","sources":["../../connection/formatServerAddress.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE1E;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAG3E"}
@@ -0,0 +1,14 @@
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
+ * Formats a {@link ChronicleServerAddress} as a `host:port` string, wrapping IPv6 host
5
+ * literals in bracket notation (e.g. `[::1]:35000`) as required by both the connection
6
+ * string grammar and gRPC target grammar.
7
+ * @param address - The address to format.
8
+ * @returns The formatted `host:port` string.
9
+ */
10
+ export function formatServerAddress(address) {
11
+ const host = address.host.includes(':') ? `[${address.host}]` : address.host;
12
+ return `${host}:${address.port}`;
13
+ }
14
+ //# sourceMappingURL=formatServerAddress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatServerAddress.js","sourceRoot":"","sources":["../../connection/formatServerAddress.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,qGAAqG;AAIrG;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA+B;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAC7E,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;AACrC,CAAC"}
@@ -12,6 +12,8 @@ export declare class Reactors implements IReactors {
12
12
  private readonly _connection;
13
13
  private readonly _eventStoreName;
14
14
  private readonly _namespace;
15
+ /** How long to wait before re-establishing an observation whose stream ended. */
16
+ private static readonly _reobserveDelayMs;
15
17
  private readonly _logger;
16
18
  private readonly _lifecycle;
17
19
  private readonly _reactors;
@@ -31,6 +33,17 @@ export declare class Reactors implements IReactors {
31
33
  /** @inheritdoc */
32
34
  register(): Promise<void>;
33
35
  private startObservation;
36
+ private runObservation;
37
+ /**
38
+ * Re-establishes an observation whose stream ended.
39
+ *
40
+ * The stream ending without an error is not proof that all is well — the kernel
41
+ * closes a cross-store (inbox) reactor's stream rather than tailing it forever,
42
+ * so a reactor that does not re-subscribe there silently stops observing until
43
+ * the whole client reconnects. Both endings are therefore retried, and the delay
44
+ * keeps a stream that keeps ending from becoming a hot loop.
45
+ */
46
+ private scheduleReobserve;
34
47
  private observeReactor;
35
48
  private getEventTypesFor;
36
49
  private disconnectAll;
@@ -1 +1 @@
1
- {"version":3,"file":"Reactors.d.ts","sourceRoot":"","sources":["../../reactors/Reactors.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAC;AAI1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAMxE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAyExC;;;GAGG;AACH,qBAAa,QAAS,YAAW,SAAS;IAgBlC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAlB/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiD;IACzE,OAAO,CAAC,WAAW,CAAS;IAE5B;;;;;;;OAOG;gBAEkB,gBAAgB,EAAE,wBAAwB,EAC1C,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EACnC,SAAS,EAAE,mBAAmB;IAUlC,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAW/B,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB/B,OAAO,CAAC,gBAAgB;YAiBV,cAAc;IA0H5B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,aAAa;CAMxB"}
1
+ {"version":3,"file":"Reactors.d.ts","sourceRoot":"","sources":["../../reactors/Reactors.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAC;AAI1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAMxE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAyExC;;;GAGG;AACH,qBAAa,QAAS,YAAW,SAAS;IAmBlC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;IArB/B,iFAAiF;IACjF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAEjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiD;IACzE,OAAO,CAAC,WAAW,CAAS;IAE5B;;;;;;;OAOG;gBAEkB,gBAAgB,EAAE,wBAAwB,EAC1C,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EACnC,SAAS,EAAE,mBAAmB;IAUlC,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAW/B,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB/B,OAAO,CAAC,gBAAgB;YAeV,cAAc;IAe5B;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;YAmBX,cAAc;IA+H5B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,aAAa;CAMxB"}
@@ -77,6 +77,8 @@ export class Reactors {
77
77
  _connection;
78
78
  _eventStoreName;
79
79
  _namespace;
80
+ /** How long to wait before re-establishing an observation whose stream ended. */
81
+ static _reobserveDelayMs = 2000;
80
82
  _logger = diag.createComponentLogger({ namespace: '@cratis/chronicle/reactors' });
81
83
  _lifecycle;
82
84
  _reactors = new Map();
@@ -137,9 +139,40 @@ export class Reactors {
137
139
  handlerCount: eventTypes.length,
138
140
  handlers: eventTypes.map(e => e.methodName)
139
141
  });
140
- this.observeReactor(id, reactorType, eventSequenceId, eventTypes).catch(err => {
141
- this._logger.error('Reactor observation loop exited with error', { reactorId: id, error: String(err) });
142
- });
142
+ void this.runObservation(id, reactorType, eventSequenceId, eventTypes);
143
+ }
144
+ async runObservation(id, reactorType, eventSequenceId, eventTypes) {
145
+ try {
146
+ await this.observeReactor(id, reactorType, eventSequenceId, eventTypes);
147
+ }
148
+ catch (error) {
149
+ this._logger.error('Reactor observation loop exited with error', { reactorId: id, error: String(error) });
150
+ }
151
+ this.scheduleReobserve(id, reactorType);
152
+ }
153
+ /**
154
+ * Re-establishes an observation whose stream ended.
155
+ *
156
+ * The stream ending without an error is not proof that all is well — the kernel
157
+ * closes a cross-store (inbox) reactor's stream rather than tailing it forever,
158
+ * so a reactor that does not re-subscribe there silently stops observing until
159
+ * the whole client reconnects. Both endings are therefore retried, and the delay
160
+ * keeps a stream that keeps ending from becoming a hot loop.
161
+ */
162
+ scheduleReobserve(id, reactorType) {
163
+ // A disconnect clears the registration; the reconnect re-registers every
164
+ // reactor from scratch, so retrying here as well would double up.
165
+ if (!this._registered) {
166
+ return;
167
+ }
168
+ const handle = setTimeout(() => {
169
+ if (!this._registered) {
170
+ return;
171
+ }
172
+ this._logger.info('Re-establishing reactor observation', { reactorId: id });
173
+ this.startObservation(id, reactorType);
174
+ }, Reactors._reobserveDelayMs);
175
+ handle.unref?.();
143
176
  }
144
177
  async observeReactor(id, reactorType, eventSequenceId, eventTypes) {
145
178
  const queue = new AsyncQueue();
@@ -248,7 +281,12 @@ export class Reactors {
248
281
  }
249
282
  }
250
283
  finally {
251
- this._queues.delete(id);
284
+ // Only retire our own queue: a reconnect can already have replaced it,
285
+ // and deleting the new one would leave that observation untracked and
286
+ // leak a duplicate stream on every reconnect.
287
+ if (this._queues.get(id) === queue) {
288
+ this._queues.delete(id);
289
+ }
252
290
  }
253
291
  }
254
292
  getEventTypesFor(reactorType) {
@@ -1 +1 @@
1
- {"version":3,"file":"Reactors.js","sourceRoot":"","sources":["../../reactors/Reactors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Reactors.js","sourceRoot":"","sources":["../../reactors/Reactors.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,8 @@ export declare class Reducers implements IReducers {
13
13
  private readonly _eventStoreName;
14
14
  private readonly _namespace;
15
15
  private readonly _defaultSinkTypeId;
16
+ /** How long to wait before re-establishing an observation whose stream ended. */
17
+ private static readonly _reobserveDelayMs;
16
18
  private readonly _logger;
17
19
  private readonly _lifecycle;
18
20
  private readonly _reducers;
@@ -35,6 +37,18 @@ export declare class Reducers implements IReducers {
35
37
  private registerReadModels;
36
38
  private getReducerSchema;
37
39
  private startObservation;
40
+ private runObservation;
41
+ /**
42
+ * Re-establishes an observation whose stream ended.
43
+ *
44
+ * The stream ending without an error is not proof that all is well — the kernel
45
+ * closes a cross-store (inbox) observation's stream rather than tailing it
46
+ * forever, so a reducer that does not re-subscribe there silently stops
47
+ * observing until the whole client reconnects. Both endings are therefore
48
+ * retried, and the delay keeps a stream that keeps ending from becoming a hot
49
+ * loop.
50
+ */
51
+ private scheduleReobserve;
38
52
  private getReducerReadModelIdentifier;
39
53
  private observeReducer;
40
54
  private getEventTypesFor;
@@ -1 +1 @@
1
- {"version":3,"file":"Reducers.d.ts","sourceRoot":"","sources":["../../reducers/Reducers.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAC;AAI1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA2ExC;;;GAGG;AACH,qBAAa,QAAS,YAAW,SAAS;IAiBlC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAE3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IArBvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiD;IACzE,OAAO,CAAC,WAAW,CAAS;IAE5B;;;;;;;;OAQG;gBAEkB,gBAAgB,EAAE,wBAAwB,EAC1C,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EACnC,SAAS,EAAE,mBAAmB,EACb,kBAAkB,EAAE,MAAM;IAU/C,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAW/B,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAmBjB,kBAAkB;IAoChC,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,6BAA6B;YASvB,cAAc;IA+H5B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,aAAa;CAMxB"}
1
+ {"version":3,"file":"Reducers.d.ts","sourceRoot":"","sources":["../../reducers/Reducers.ts"],"names":[],"mappings":"AAGA,OAAO,kBAAkB,CAAC;AAI1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAGxE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AA2ExC;;;GAGG;AACH,qBAAa,QAAS,YAAW,SAAS;IAoBlC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAE3B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAxBvC,iFAAiF;IACjF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAEjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiD;IACzE,OAAO,CAAC,WAAW,CAAS;IAE5B;;;;;;;;OAQG;gBAEkB,gBAAgB,EAAE,wBAAwB,EAC1C,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EACnC,SAAS,EAAE,mBAAmB,EACb,kBAAkB,EAAE,MAAM;IAU/C,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAW/B,kBAAkB;IACZ,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAmBjB,kBAAkB;IAoChC,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,gBAAgB;YAiBV,cAAc;IAgB5B;;;;;;;;;OASG;IACH,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,6BAA6B;YASvB,cAAc;IAgI5B,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,aAAa;CAMxB"}
@@ -80,6 +80,8 @@ export class Reducers {
80
80
  _eventStoreName;
81
81
  _namespace;
82
82
  _defaultSinkTypeId;
83
+ /** How long to wait before re-establishing an observation whose stream ended. */
84
+ static _reobserveDelayMs = 2000;
83
85
  _logger = diag.createComponentLogger({ namespace: '@cratis/chronicle/reducers' });
84
86
  _lifecycle;
85
87
  _reducers = new Map();
@@ -195,9 +197,41 @@ export class Reducers {
195
197
  handlerCount: eventTypes.length,
196
198
  handlers: eventTypes.map(e => e.methodName)
197
199
  });
198
- this.observeReducer(id, reducerType, eventSequenceId, eventTypes, readModelName).catch(err => {
199
- this._logger.error('Reducer observation loop exited with error', { reducerId: id, error: String(err) });
200
- });
200
+ void this.runObservation(id, reducerType, eventSequenceId, eventTypes, readModelName);
201
+ }
202
+ async runObservation(id, reducerType, eventSequenceId, eventTypes, readModelName) {
203
+ try {
204
+ await this.observeReducer(id, reducerType, eventSequenceId, eventTypes, readModelName);
205
+ }
206
+ catch (error) {
207
+ this._logger.error('Reducer observation loop exited with error', { reducerId: id, error: String(error) });
208
+ }
209
+ this.scheduleReobserve(id, reducerType);
210
+ }
211
+ /**
212
+ * Re-establishes an observation whose stream ended.
213
+ *
214
+ * The stream ending without an error is not proof that all is well — the kernel
215
+ * closes a cross-store (inbox) observation's stream rather than tailing it
216
+ * forever, so a reducer that does not re-subscribe there silently stops
217
+ * observing until the whole client reconnects. Both endings are therefore
218
+ * retried, and the delay keeps a stream that keeps ending from becoming a hot
219
+ * loop.
220
+ */
221
+ scheduleReobserve(id, reducerType) {
222
+ // A disconnect clears the registration; the reconnect re-registers every
223
+ // reducer from scratch, so retrying here as well would double up.
224
+ if (!this._registered) {
225
+ return;
226
+ }
227
+ const handle = setTimeout(() => {
228
+ if (!this._registered) {
229
+ return;
230
+ }
231
+ this._logger.info('Re-establishing reducer observation', { reducerId: id });
232
+ this.startObservation(id, reducerType);
233
+ }, Reducers._reobserveDelayMs);
234
+ handle.unref?.();
201
235
  }
202
236
  getReducerReadModelIdentifier(reducerType) {
203
237
  const metadata = getReducerMetadata(reducerType);
@@ -224,10 +258,6 @@ export class Reducers {
224
258
  })),
225
259
  ReadModel: readModelName,
226
260
  IsActive: true,
227
- Sink: {
228
- TypeId: this._defaultSinkTypeId,
229
- ConfigurationId: toContractsGuid(Guid.empty)
230
- },
231
261
  Tags: [],
232
262
  Filters: {
233
263
  FilterTags: [],
@@ -315,7 +345,12 @@ export class Reducers {
315
345
  }
316
346
  }
317
347
  finally {
318
- this._queues.delete(id);
348
+ // Only retire our own queue: a reconnect can already have replaced it,
349
+ // and deleting the new one would leave that observation untracked and
350
+ // leak a duplicate stream on every reconnect.
351
+ if (this._queues.get(id) === queue) {
352
+ this._queues.delete(id);
353
+ }
319
354
  }
320
355
  }
321
356
  getEventTypesFor(reducerType) {