@private.me/xbind 3.0.2 → 3.0.3

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 (221) hide show
  1. package/README.md +2366 -204
  2. package/README.md.backup +2121 -0
  3. package/dist-standalone/_deps/mldsa-wasm/dist/mldsa.js +1 -1920
  4. package/dist-standalone/_deps/shared/cjs/errors.js +1 -729
  5. package/dist-standalone/_deps/shared/cjs/index.js +1 -463
  6. package/dist-standalone/_deps/shared/cjs/types.js +1 -315
  7. package/dist-standalone/_deps/shared/errors.js +1 -244
  8. package/dist-standalone/_deps/shared/index.js +1 -72
  9. package/dist-standalone/_deps/shared/types.js +1 -86
  10. package/dist-standalone/_deps/ux-helpers/cjs/errors.js +1 -1
  11. package/dist-standalone/_deps/ux-helpers/cjs/index.js +1 -1
  12. package/dist-standalone/_deps/ux-helpers/cjs/pagination.js +1 -1
  13. package/dist-standalone/_deps/ux-helpers/cjs/progress.js +1 -1
  14. package/dist-standalone/_deps/ux-helpers/cjs/search.js +1 -1
  15. package/dist-standalone/_deps/ux-helpers/cjs/types.js +1 -1
  16. package/dist-standalone/_deps/ux-helpers/errors.js +1 -1
  17. package/dist-standalone/_deps/ux-helpers/index.js +1 -1
  18. package/dist-standalone/_deps/ux-helpers/pagination.js +1 -1
  19. package/dist-standalone/_deps/ux-helpers/progress.js +1 -1
  20. package/dist-standalone/_deps/ux-helpers/search.js +1 -1
  21. package/dist-standalone/_deps/xchange/auto-accept.js +1 -1
  22. package/dist-standalone/_deps/xchange/cjs/auto-accept.js +1 -1
  23. package/dist-standalone/_deps/xchange/cjs/errors.js +1 -1
  24. package/dist-standalone/_deps/xchange/cjs/index.js +1 -1
  25. package/dist-standalone/_deps/xchange/cjs/invite-client.js +1 -1
  26. package/dist-standalone/_deps/xchange/cjs/lazy-init.js +1 -1
  27. package/dist-standalone/_deps/xchange/cjs/trust-integration.js +1 -1
  28. package/dist-standalone/_deps/xchange/cjs/xchange.js +1 -1
  29. package/dist-standalone/_deps/xchange/errors.js +1 -1
  30. package/dist-standalone/_deps/xchange/index.js +1 -1
  31. package/dist-standalone/_deps/xchange/invite-client.js +1 -1
  32. package/dist-standalone/_deps/xchange/lazy-init.js +1 -1
  33. package/dist-standalone/_deps/xchange/trust-integration.js +1 -1
  34. package/dist-standalone/_deps/xchange/xchange.js +1 -1
  35. package/dist-standalone/_deps/xregistry/cjs/discovery.js +1 -1
  36. package/dist-standalone/_deps/xregistry/cjs/errors.js +1 -1
  37. package/dist-standalone/_deps/xregistry/cjs/index.js +1 -1
  38. package/dist-standalone/_deps/xregistry/cjs/registry.js +1 -1
  39. package/dist-standalone/_deps/xregistry/cjs/schema.js +1 -1
  40. package/dist-standalone/_deps/xregistry/cjs/types.js +1 -1
  41. package/dist-standalone/_deps/xregistry/discovery.js +1 -1
  42. package/dist-standalone/_deps/xregistry/errors.js +1 -1
  43. package/dist-standalone/_deps/xregistry/index.js +1 -1
  44. package/dist-standalone/_deps/xregistry/registry.js +1 -1
  45. package/dist-standalone/_deps/xregistry/schema.js +1 -1
  46. package/dist-standalone/_deps/xregistry/types.js +1 -1
  47. package/dist-standalone/agent-call.d.ts +2 -2
  48. package/dist-standalone/agent-call.js +1 -659
  49. package/dist-standalone/agent-sdk.js +1 -328
  50. package/dist-standalone/agent.d.ts +2 -0
  51. package/dist-standalone/agent.js +1 -1800
  52. package/dist-standalone/approval.js +1 -193
  53. package/dist-standalone/async-iterators.d.ts +3 -3
  54. package/dist-standalone/async-iterators.js +1 -382
  55. package/dist-standalone/auth.js +1 -219
  56. package/dist-standalone/auto-accept.js +1 -229
  57. package/dist-standalone/backup-config.js +1 -201
  58. package/dist-standalone/backup.js +1 -326
  59. package/dist-standalone/batch-operations.js +1 -388
  60. package/dist-standalone/cancellation.js +1 -477
  61. package/dist-standalone/checkpoint.js +1 -186
  62. package/dist-standalone/circuit-breaker.js +1 -468
  63. package/dist-standalone/cjs/agent-call.js +1 -701
  64. package/dist-standalone/cjs/agent-sdk.js +1 -332
  65. package/dist-standalone/cjs/agent.js +1 -1837
  66. package/dist-standalone/cjs/approval.js +1 -199
  67. package/dist-standalone/cjs/async-iterators.js +1 -392
  68. package/dist-standalone/cjs/auth.js +1 -225
  69. package/dist-standalone/cjs/auto-accept.js +1 -233
  70. package/dist-standalone/cjs/backup-config.js +1 -207
  71. package/dist-standalone/cjs/backup.js +1 -330
  72. package/dist-standalone/cjs/batch-operations.js +1 -397
  73. package/dist-standalone/cjs/cancellation.js +1 -490
  74. package/dist-standalone/cjs/checkpoint.js +1 -193
  75. package/dist-standalone/cjs/circuit-breaker.js +1 -476
  76. package/dist-standalone/cjs/cli/init.js +1 -492
  77. package/dist-standalone/cjs/config-validation.js +1 -522
  78. package/dist-standalone/cjs/connect.js +1 -312
  79. package/dist-standalone/cjs/connection-pool.js +1 -506
  80. package/dist-standalone/cjs/correlation-id.js +1 -339
  81. package/dist-standalone/cjs/crypto-utils.js +1 -176
  82. package/dist-standalone/cjs/debug-mode.js +1 -534
  83. package/dist-standalone/cjs/did-document.js +1 -101
  84. package/dist-standalone/cjs/did-privateme.js +1 -130
  85. package/dist-standalone/cjs/did-web.js +1 -201
  86. package/dist-standalone/cjs/discovery.js +1 -462
  87. package/dist-standalone/cjs/dual-mode.js +1 -251
  88. package/dist-standalone/cjs/email-templates.js +1 -313
  89. package/dist-standalone/cjs/email-transport.js +1 -239
  90. package/dist-standalone/cjs/envelope.js +1 -538
  91. package/dist-standalone/cjs/errors.js +1 -913
  92. package/dist-standalone/cjs/event-emitter.js +1 -461
  93. package/dist-standalone/cjs/gateway-state.js +1 -55
  94. package/dist-standalone/cjs/gateway-transport.js +1 -120
  95. package/dist-standalone/cjs/graceful-degradation.js +1 -403
  96. package/dist-standalone/cjs/guardrails.js +1 -223
  97. package/dist-standalone/cjs/health-check.js +1 -336
  98. package/dist-standalone/cjs/http-compat.js +1 -272
  99. package/dist-standalone/cjs/http-status-map.js +1 -571
  100. package/dist-standalone/cjs/identity.js +1 -645
  101. package/dist-standalone/cjs/index.js +1 -406
  102. package/dist-standalone/cjs/invitation.js +1 -421
  103. package/dist-standalone/cjs/invite.js +1 -328
  104. package/dist-standalone/cjs/key-agreement.js +1 -335
  105. package/dist-standalone/cjs/lazy-init.js +1 -300
  106. package/dist-standalone/cjs/logger.js +1 -291
  107. package/dist-standalone/cjs/loopback-transport.js +1 -0
  108. package/dist-standalone/cjs/mdns-discovery.js +1 -202
  109. package/dist-standalone/cjs/nonce-store.js +1 -80
  110. package/dist-standalone/cjs/pairing-manager.js +1 -223
  111. package/dist-standalone/cjs/plugin-system.js +1 -264
  112. package/dist-standalone/cjs/plugins/logging.js +1 -168
  113. package/dist-standalone/cjs/plugins/metrics.js +1 -181
  114. package/dist-standalone/cjs/plugins/validation.js +1 -302
  115. package/dist-standalone/cjs/policy.js +1 -320
  116. package/dist-standalone/cjs/progress-callbacks.js +1 -583
  117. package/dist-standalone/cjs/redis-nonce-store.js +1 -76
  118. package/dist-standalone/cjs/registry-middleware.js +1 -50
  119. package/dist-standalone/cjs/retry-strategies.js +1 -544
  120. package/dist-standalone/cjs/retry-transport.js +1 -102
  121. package/dist-standalone/cjs/runtime/browser.js +1 -533
  122. package/dist-standalone/cjs/runtime/edge.js +1 -526
  123. package/dist-standalone/cjs/runtime/react-native.js +1 -394
  124. package/dist-standalone/cjs/security-policy.js +1 -245
  125. package/dist-standalone/cjs/serialization.js +1 -1040
  126. package/dist-standalone/cjs/split-channel.js +1 -225
  127. package/dist-standalone/cjs/subscription-proof.js +1 -230
  128. package/dist-standalone/cjs/succession.js +1 -148
  129. package/dist-standalone/cjs/timeouts.js +1 -412
  130. package/dist-standalone/cjs/trace-context.js +1 -424
  131. package/dist-standalone/cjs/trace-spans.js +1 -495
  132. package/dist-standalone/cjs/transport.js +1 -63
  133. package/dist-standalone/cjs/trust-registry.js +1 -991
  134. package/dist-standalone/cjs/types/error-response.js +1 -56
  135. package/dist-standalone/cjs/vault-auth.js +1 -178
  136. package/dist-standalone/cjs/vault-store-loader.js +1 -194
  137. package/dist-standalone/cjs/verify.js +1 -25
  138. package/dist-standalone/cjs/version-info.js +1 -543
  139. package/dist-standalone/cjs/xfetch.js +1 -340
  140. package/dist-standalone/cli/init.js +1 -455
  141. package/dist-standalone/cli/setup.js +1 -514
  142. package/dist-standalone/cli/types.js +1 -27
  143. package/dist-standalone/cli/xbind.js +1 -148
  144. package/dist-standalone/config-validation.js +1 -513
  145. package/dist-standalone/connect.js +1 -274
  146. package/dist-standalone/connection-pool.js +1 -500
  147. package/dist-standalone/correlation-id.js +1 -326
  148. package/dist-standalone/crypto-utils.d.ts +2 -7
  149. package/dist-standalone/crypto-utils.js +1 -157
  150. package/dist-standalone/debug-mode.js +1 -510
  151. package/dist-standalone/did-document.js +1 -96
  152. package/dist-standalone/did-privateme.js +1 -121
  153. package/dist-standalone/did-web.js +1 -196
  154. package/dist-standalone/discovery.js +1 -458
  155. package/dist-standalone/dual-mode.js +1 -247
  156. package/dist-standalone/email-templates.js +1 -309
  157. package/dist-standalone/email-transport.d.ts +2 -2
  158. package/dist-standalone/email-transport.js +1 -232
  159. package/dist-standalone/envelope.js +1 -525
  160. package/dist-standalone/errors.d.ts +13 -3
  161. package/dist-standalone/errors.js +1 -896
  162. package/dist-standalone/event-emitter.js +1 -456
  163. package/dist-standalone/gateway-state.d.ts +1 -1
  164. package/dist-standalone/gateway-state.js +1 -51
  165. package/dist-standalone/gateway-transport.js +1 -116
  166. package/dist-standalone/graceful-degradation.js +1 -396
  167. package/dist-standalone/guardrails.js +1 -216
  168. package/dist-standalone/health-check.d.ts +5 -1
  169. package/dist-standalone/health-check.js +1 -332
  170. package/dist-standalone/http-compat.d.ts +1 -1
  171. package/dist-standalone/http-compat.js +1 -267
  172. package/dist-standalone/http-status-map.js +1 -561
  173. package/dist-standalone/identity.js +1 -619
  174. package/dist-standalone/index.d.ts +15 -4
  175. package/dist-standalone/index.js +1 -78
  176. package/dist-standalone/invitation.js +1 -415
  177. package/dist-standalone/invite.js +1 -324
  178. package/dist-standalone/key-agreement.js +1 -325
  179. package/dist-standalone/lazy-init.d.ts +11 -6
  180. package/dist-standalone/lazy-init.js +1 -295
  181. package/dist-standalone/logger.js +1 -285
  182. package/dist-standalone/loopback-transport.d.ts +87 -0
  183. package/dist-standalone/loopback-transport.js +1 -0
  184. package/dist-standalone/mdns-discovery.js +1 -195
  185. package/dist-standalone/nonce-store.js +1 -76
  186. package/dist-standalone/pairing-manager.js +1 -219
  187. package/dist-standalone/plugin-system.js +1 -257
  188. package/dist-standalone/plugins/logging.js +1 -163
  189. package/dist-standalone/plugins/metrics.d.ts +4 -4
  190. package/dist-standalone/plugins/metrics.js +1 -176
  191. package/dist-standalone/plugins/validation.js +1 -297
  192. package/dist-standalone/policy.js +1 -315
  193. package/dist-standalone/progress-callbacks.js +1 -576
  194. package/dist-standalone/redis-nonce-store.js +1 -72
  195. package/dist-standalone/registry-middleware.js +1 -47
  196. package/dist-standalone/retry-strategies.js +1 -534
  197. package/dist-standalone/retry-transport.js +1 -98
  198. package/dist-standalone/runtime/browser.js +1 -516
  199. package/dist-standalone/runtime/edge.js +1 -511
  200. package/dist-standalone/runtime/react-native.d.ts +1 -1
  201. package/dist-standalone/runtime/react-native.js +1 -383
  202. package/dist-standalone/security-policy.js +1 -239
  203. package/dist-standalone/serialization.js +1 -1031
  204. package/dist-standalone/split-channel.js +1 -219
  205. package/dist-standalone/subscription-proof.js +1 -224
  206. package/dist-standalone/succession.js +1 -142
  207. package/dist-standalone/timeouts.js +1 -398
  208. package/dist-standalone/trace-context.js +1 -414
  209. package/dist-standalone/trace-spans.js +1 -488
  210. package/dist-standalone/transport.js +1 -59
  211. package/dist-standalone/trust-registry.d.ts +3 -3
  212. package/dist-standalone/trust-registry.js +1 -950
  213. package/dist-standalone/types/error-response.js +1 -52
  214. package/dist-standalone/vault-auth.js +1 -174
  215. package/dist-standalone/vault-store-loader.d.ts +9 -0
  216. package/dist-standalone/vault-store-loader.js +1 -187
  217. package/dist-standalone/verify.js +1 -16
  218. package/dist-standalone/version-info.js +1 -530
  219. package/dist-standalone/xfetch.js +1 -335
  220. package/package.json +1 -1
  221. package/share1.dat +0 -0
@@ -1,500 +1 @@
1
- /**
2
- * @module connection-pool
3
- * HTTP connection pooling for xBind registry/gateway requests
4
- *
5
- * Provides connection reuse, keep-alive support, and automatic cleanup
6
- * to enhance performance for applications making frequent requests.
7
- *
8
- * @example
9
- * ```typescript
10
- * const pool = new ConnectionPool({
11
- * maxConnections: 50,
12
- * keepAliveTimeout: 30000,
13
- * });
14
- *
15
- * const response = await pool.fetch('https://api.example.com/data');
16
- * const data = await response.json();
17
- * ```
18
- */
19
- /**
20
- * Connection pool for HTTP requests
21
- *
22
- * Manages connection lifecycle, keep-alive, and automatic cleanup
23
- * to optimize performance for frequent requests to the same origins.
24
- */
25
- export class ConnectionPool {
26
- options;
27
- connections = new Map();
28
- metrics;
29
- cleanupInterval = null;
30
- /**
31
- * Create a new connection pool
32
- *
33
- * @param options - Pool configuration options
34
- */
35
- constructor(options = {}) {
36
- this.options = {
37
- maxConnections: options.maxConnections ?? 10,
38
- minConnections: options.minConnections ?? 2,
39
- keepAliveTimeout: options.keepAliveTimeout ?? 30000,
40
- idleTimeout: options.idleTimeout ?? 60000,
41
- requestTimeout: options.requestTimeout ?? 30000,
42
- enableMetrics: options.enableMetrics ?? true,
43
- retryOnFailure: options.retryOnFailure ?? true,
44
- maxRetries: options.maxRetries ?? 3,
45
- };
46
- this.metrics = {
47
- totalRequests: 0,
48
- reuseCount: 0,
49
- failedRequests: 0,
50
- requestDurations: [],
51
- byOrigin: new Map(),
52
- };
53
- // Start automatic cleanup
54
- this.startCleanup();
55
- }
56
- /**
57
- * Make an HTTP request using the connection pool
58
- *
59
- * @param url - Target URL
60
- * @param init - Fetch options
61
- * @returns Response promise
62
- *
63
- * @example
64
- * ```typescript
65
- * const response = await pool.fetch('https://api.example.com/data', {
66
- * method: 'POST',
67
- * headers: { 'Content-Type': 'application/json' },
68
- * body: JSON.stringify({ key: 'value' }),
69
- * });
70
- * ```
71
- */
72
- async fetch(url, init) {
73
- const startTime = Date.now();
74
- const origin = this.getOrigin(url);
75
- try {
76
- // Get or create connection
77
- const connection = await this.acquireConnection(origin);
78
- // Update metrics
79
- if (this.options.enableMetrics) {
80
- this.metrics.totalRequests++;
81
- if (connection.requestCount > 0) {
82
- this.metrics.reuseCount++;
83
- }
84
- }
85
- // Make request with keep-alive
86
- const requestInit = {
87
- ...init,
88
- signal: init?.signal ?? connection.controller.signal,
89
- // @ts-ignore - keepalive is a valid fetch option
90
- keepalive: true,
91
- };
92
- const response = await fetch(url, requestInit);
93
- // Update connection state
94
- connection.requestCount++;
95
- connection.lastUsedAt = Date.now();
96
- connection.state = 'idle';
97
- // Record metrics
98
- if (this.options.enableMetrics) {
99
- const duration = Date.now() - startTime;
100
- this.recordMetrics(origin, duration);
101
- }
102
- return response;
103
- }
104
- catch (error) {
105
- // Record failure
106
- if (this.options.enableMetrics) {
107
- this.metrics.failedRequests++;
108
- }
109
- // Retry if enabled
110
- if (this.options.retryOnFailure && init?.signal?.aborted !== true) {
111
- return this.retryRequest(url, init, 1);
112
- }
113
- throw error;
114
- }
115
- }
116
- /**
117
- * Retry a failed request with exponential backoff
118
- */
119
- async retryRequest(url, init, attempt) {
120
- if (attempt > this.options.maxRetries) {
121
- throw new Error(`Request failed after ${this.options.maxRetries} retries: ${url}`);
122
- }
123
- // Exponential backoff: 100ms, 200ms, 400ms...
124
- const delay = 100 * Math.pow(2, attempt - 1);
125
- await new Promise(resolve => setTimeout(resolve, delay));
126
- const origin = this.getOrigin(url);
127
- try {
128
- // Get or create connection
129
- const connection = await this.acquireConnection(origin);
130
- // Make request with keep-alive
131
- const requestInit = {
132
- ...init,
133
- signal: init?.signal ?? connection.controller.signal,
134
- // @ts-ignore - keepalive is a valid fetch option
135
- keepalive: true,
136
- };
137
- const response = await fetch(url, requestInit);
138
- // Update connection state
139
- connection.requestCount++;
140
- connection.lastUsedAt = Date.now();
141
- connection.state = 'idle';
142
- return response;
143
- }
144
- catch (error) {
145
- if (attempt >= this.options.maxRetries) {
146
- throw new Error(`Request failed after ${this.options.maxRetries} retries: ${url}`);
147
- }
148
- return this.retryRequest(url, init, attempt + 1);
149
- }
150
- }
151
- /**
152
- * Acquire a connection from the pool or create a new one
153
- */
154
- async acquireConnection(origin) {
155
- let pool = this.connections.get(origin);
156
- if (!pool) {
157
- pool = [];
158
- this.connections.set(origin, pool);
159
- }
160
- // Find idle connection
161
- const idleConnection = pool.find(conn => conn.state === 'idle');
162
- if (idleConnection) {
163
- idleConnection.state = 'active';
164
- return idleConnection;
165
- }
166
- // Check if we can create a new connection
167
- if (pool.length < this.options.maxConnections) {
168
- const connection = this.createConnection(origin);
169
- pool.push(connection);
170
- return connection;
171
- }
172
- // Wait for an available connection
173
- return this.waitForConnection(origin);
174
- }
175
- /**
176
- * Wait for a connection to become available
177
- */
178
- async waitForConnection(origin) {
179
- const startTime = Date.now();
180
- const timeout = this.options.requestTimeout;
181
- while (Date.now() - startTime < timeout) {
182
- const pool = this.connections.get(origin);
183
- if (!pool) {
184
- throw new Error(`Connection pool for ${origin} disappeared`);
185
- }
186
- const idleConnection = pool.find(conn => conn.state === 'idle');
187
- if (idleConnection) {
188
- idleConnection.state = 'active';
189
- return idleConnection;
190
- }
191
- // Wait a bit before checking again
192
- await new Promise(resolve => setTimeout(resolve, 10));
193
- }
194
- throw new Error(`Timeout waiting for connection to ${origin} after ${timeout}ms`);
195
- }
196
- /**
197
- * Create a new connection
198
- */
199
- createConnection(origin) {
200
- const randomBytes = new Uint8Array(8);
201
- crypto.getRandomValues(randomBytes);
202
- const id = Array.from(randomBytes)
203
- .map(b => b.toString(16).padStart(2, '0'))
204
- .join('');
205
- return {
206
- id: `conn_${id}`,
207
- origin,
208
- createdAt: Date.now(),
209
- lastUsedAt: Date.now(),
210
- requestCount: 0,
211
- state: 'active',
212
- controller: new AbortController(),
213
- };
214
- }
215
- /**
216
- * Get origin from URL
217
- */
218
- getOrigin(url) {
219
- try {
220
- const parsed = new URL(url);
221
- return `${parsed.protocol}//${parsed.host}`;
222
- }
223
- catch (error) {
224
- throw new Error(`Invalid URL: ${url}`);
225
- }
226
- }
227
- /**
228
- * Record request metrics
229
- */
230
- recordMetrics(origin, duration) {
231
- this.metrics.requestDurations.push(duration);
232
- // Limit stored durations to last 1000 requests
233
- if (this.metrics.requestDurations.length > 1000) {
234
- this.metrics.requestDurations.shift();
235
- }
236
- // Record origin-specific metrics
237
- let originMetrics = this.metrics.byOrigin.get(origin);
238
- if (!originMetrics) {
239
- originMetrics = { requests: 0, durations: [] };
240
- this.metrics.byOrigin.set(origin, originMetrics);
241
- }
242
- originMetrics.requests++;
243
- originMetrics.durations.push(duration);
244
- // Limit origin durations
245
- if (originMetrics.durations.length > 100) {
246
- originMetrics.durations.shift();
247
- }
248
- }
249
- /**
250
- * Get connection pool metrics
251
- *
252
- * @returns Current metrics snapshot
253
- *
254
- * @example
255
- * ```typescript
256
- * const metrics = pool.getMetrics();
257
- * console.log(`Hit rate: ${(metrics.hitRate * 100).toFixed(1)}%`);
258
- * console.log(`Avg duration: ${metrics.avgRequestDuration}ms`);
259
- * ```
260
- */
261
- getMetrics() {
262
- let totalConnections = 0;
263
- let activeConnections = 0;
264
- let idleConnections = 0;
265
- const byOrigin = new Map();
266
- for (const [origin, pool] of this.connections.entries()) {
267
- totalConnections += pool.length;
268
- activeConnections += pool.filter(c => c.state === 'active').length;
269
- idleConnections += pool.filter(c => c.state === 'idle').length;
270
- const originMetrics = this.metrics.byOrigin.get(origin);
271
- if (originMetrics) {
272
- const avgDuration = originMetrics.durations.length > 0
273
- ? originMetrics.durations.reduce((a, b) => a + b, 0) /
274
- originMetrics.durations.length
275
- : 0;
276
- byOrigin.set(origin, {
277
- connections: pool.length,
278
- requests: originMetrics.requests,
279
- avgDuration: Math.round(avgDuration),
280
- });
281
- }
282
- }
283
- const avgRequestDuration = this.metrics.requestDurations.length > 0
284
- ? Math.round(this.metrics.requestDurations.reduce((a, b) => a + b, 0) /
285
- this.metrics.requestDurations.length)
286
- : 0;
287
- const hitRate = this.metrics.totalRequests > 0
288
- ? this.metrics.reuseCount / this.metrics.totalRequests
289
- : 0;
290
- return {
291
- totalConnections,
292
- activeConnections,
293
- idleConnections,
294
- totalRequests: this.metrics.totalRequests,
295
- reuseCount: this.metrics.reuseCount,
296
- failedRequests: this.metrics.failedRequests,
297
- avgRequestDuration,
298
- hitRate,
299
- byOrigin,
300
- };
301
- }
302
- /**
303
- * Reset metrics counters
304
- *
305
- * @example
306
- * ```typescript
307
- * pool.resetMetrics();
308
- * // Start fresh measurements
309
- * ```
310
- */
311
- resetMetrics() {
312
- this.metrics = {
313
- totalRequests: 0,
314
- reuseCount: 0,
315
- failedRequests: 0,
316
- requestDurations: [],
317
- byOrigin: new Map(),
318
- };
319
- }
320
- /**
321
- * Start automatic connection cleanup
322
- */
323
- startCleanup() {
324
- // Run cleanup every 10 seconds
325
- this.cleanupInterval = setInterval(() => {
326
- this.cleanup();
327
- }, 10000);
328
- }
329
- /**
330
- * Clean up idle and expired connections
331
- */
332
- cleanup() {
333
- const now = Date.now();
334
- for (const [origin, pool] of this.connections.entries()) {
335
- // Remove expired connections
336
- const activePool = pool.filter(conn => {
337
- const isExpired = now - conn.lastUsedAt > this.options.idleTimeout &&
338
- conn.state === 'idle';
339
- if (isExpired) {
340
- conn.controller.abort();
341
- conn.state = 'closed';
342
- return false;
343
- }
344
- return conn.state !== 'closed';
345
- });
346
- // Ensure minimum connections are maintained
347
- while (activePool.length < this.options.minConnections &&
348
- activePool.length < this.options.maxConnections) {
349
- const conn = this.createConnection(origin);
350
- conn.state = 'idle';
351
- activePool.push(conn);
352
- }
353
- if (activePool.length > 0) {
354
- this.connections.set(origin, activePool);
355
- }
356
- else {
357
- this.connections.delete(origin);
358
- }
359
- }
360
- }
361
- /**
362
- * Manually trigger connection cleanup
363
- *
364
- * @example
365
- * ```typescript
366
- * // Force cleanup of idle connections
367
- * pool.cleanupNow();
368
- * ```
369
- */
370
- cleanupNow() {
371
- this.cleanup();
372
- }
373
- /**
374
- * Close all connections and shutdown the pool
375
- *
376
- * @example
377
- * ```typescript
378
- * // Cleanup on application shutdown
379
- * await pool.close();
380
- * ```
381
- */
382
- async close() {
383
- // Stop cleanup interval
384
- if (this.cleanupInterval) {
385
- clearInterval(this.cleanupInterval);
386
- this.cleanupInterval = null;
387
- }
388
- // Close all connections
389
- for (const [_origin, pool] of this.connections.entries()) {
390
- for (const conn of pool) {
391
- conn.controller.abort();
392
- conn.state = 'closed';
393
- }
394
- }
395
- this.connections.clear();
396
- }
397
- /**
398
- * Get the number of connections for a specific origin
399
- *
400
- * @param origin - Target origin (e.g., "https://api.example.com")
401
- * @returns Number of connections
402
- *
403
- * @example
404
- * ```typescript
405
- * const count = pool.getConnectionCount('https://api.example.com');
406
- * console.log(`Active connections: ${count}`);
407
- * ```
408
- */
409
- getConnectionCount(origin) {
410
- const pool = this.connections.get(origin);
411
- return pool ? pool.length : 0;
412
- }
413
- /**
414
- * Get all origins with active connections
415
- *
416
- * @returns Array of origins
417
- *
418
- * @example
419
- * ```typescript
420
- * const origins = pool.getOrigins();
421
- * console.log(`Connected to ${origins.length} origins`);
422
- * ```
423
- */
424
- getOrigins() {
425
- return Array.from(this.connections.keys());
426
- }
427
- /**
428
- * Check if the pool is healthy
429
- *
430
- * @returns True if pool is operating normally
431
- *
432
- * @example
433
- * ```typescript
434
- * if (!pool.isHealthy()) {
435
- * console.warn('Connection pool degraded');
436
- * }
437
- * ```
438
- */
439
- isHealthy() {
440
- const metrics = this.getMetrics();
441
- // Check if failure rate is too high
442
- const failureRate = metrics.totalRequests > 0
443
- ? metrics.failedRequests / metrics.totalRequests
444
- : 0;
445
- if (failureRate > 0.1) {
446
- // More than 10% failure rate
447
- return false;
448
- }
449
- // Check if we have reasonable response times
450
- if (metrics.avgRequestDuration > 5000) {
451
- // Average over 5 seconds
452
- return false;
453
- }
454
- return true;
455
- }
456
- }
457
- /**
458
- * Create a global connection pool instance
459
- *
460
- * Useful for sharing a single pool across your application.
461
- *
462
- * @param options - Pool configuration
463
- * @returns Singleton connection pool instance
464
- *
465
- * @example
466
- * ```typescript
467
- * import { getGlobalPool } from '@private.me/xbind/connection-pool';
468
- *
469
- * const pool = getGlobalPool({
470
- * maxConnections: 50,
471
- * keepAliveTimeout: 30000,
472
- * });
473
- *
474
- * const response = await pool.fetch('https://api.example.com/data');
475
- * ```
476
- */
477
- let globalPool = null;
478
- export function getGlobalPool(options) {
479
- if (!globalPool) {
480
- globalPool = new ConnectionPool(options);
481
- }
482
- return globalPool;
483
- }
484
- /**
485
- * Reset the global connection pool
486
- *
487
- * Closes the current pool and allows a new one to be created.
488
- *
489
- * @example
490
- * ```typescript
491
- * await resetGlobalPool();
492
- * // Next getGlobalPool() call will create a fresh instance
493
- * ```
494
- */
495
- export async function resetGlobalPool() {
496
- if (globalPool) {
497
- await globalPool.close();
498
- globalPool = null;
499
- }
500
- }
1
+ export class ConnectionPool{options;connections=new Map;metrics;cleanupInterval=null;constructor(t={}){this.options={maxConnections:t.maxConnections??10,minConnections:t.minConnections??2,keepAliveTimeout:t.keepAliveTimeout??3e4,idleTimeout:t.idleTimeout??6e4,requestTimeout:t.requestTimeout??3e4,enableMetrics:t.enableMetrics??!0,retryOnFailure:t.retryOnFailure??!0,maxRetries:t.maxRetries??3},this.metrics={totalRequests:0,reuseCount:0,failedRequests:0,requestDurations:[],byOrigin:new Map},this.startCleanup()}async fetch(t,e){const s=Date.now(),n=this.getOrigin(t);try{const o=await this.acquireConnection(n);this.options.enableMetrics&&(this.metrics.totalRequests++,o.requestCount>0&&this.metrics.reuseCount++);const i={...e,signal:e?.signal??o.controller.signal,keepalive:!0},r=await fetch(t,i);if(o.requestCount++,o.lastUsedAt=Date.now(),o.state="idle",this.options.enableMetrics){const t=Date.now()-s;this.recordMetrics(n,t)}return r}catch(s){if(this.options.enableMetrics&&this.metrics.failedRequests++,this.options.retryOnFailure&&!0!==e?.signal?.aborted)return this.retryRequest(t,e,1);throw s}}async retryRequest(t,e,s){if(s>this.options.maxRetries)throw new Error(`Request failed after ${this.options.maxRetries} retries: ${t}`);const n=100*Math.pow(2,s-1);await new Promise(t=>setTimeout(t,n));const o=this.getOrigin(t);try{const s=await this.acquireConnection(o),n={...e,signal:e?.signal??s.controller.signal,keepalive:!0},i=await fetch(t,n);return s.requestCount++,s.lastUsedAt=Date.now(),s.state="idle",i}catch{if(s>=this.options.maxRetries)throw new Error(`Request failed after ${this.options.maxRetries} retries: ${t}`);return this.retryRequest(t,e,s+1)}}async acquireConnection(t){let e=this.connections.get(t);e||(e=[],this.connections.set(t,e));const s=e.find(t=>"idle"===t.state);if(s)return s.state="active",s;if(e.length<this.options.maxConnections){const s=this.createConnection(t);return e.push(s),s}return this.waitForConnection(t)}async waitForConnection(t){const e=Date.now(),s=this.options.requestTimeout;for(;Date.now()-e<s;){const e=this.connections.get(t);if(!e)throw new Error(`Connection pool for ${t} disappeared`);const s=e.find(t=>"idle"===t.state);if(s)return s.state="active",s;await new Promise(t=>setTimeout(t,10))}throw new Error(`Timeout waiting for connection to ${t} after ${s}ms`)}createConnection(t){const e=new Uint8Array(8);crypto.getRandomValues(e);return{id:`conn_${Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}`,origin:t,createdAt:Date.now(),lastUsedAt:Date.now(),requestCount:0,state:"active",controller:new AbortController}}getOrigin(t){try{const e=new URL(t);return`${e.protocol}//${e.host}`}catch{throw new Error(`Invalid URL: ${t}`)}}recordMetrics(t,e){this.metrics.requestDurations.push(e),this.metrics.requestDurations.length>1e3&&this.metrics.requestDurations.shift();let s=this.metrics.byOrigin.get(t);s||(s={requests:0,durations:[]},this.metrics.byOrigin.set(t,s)),s.requests++,s.durations.push(e),s.durations.length>100&&s.durations.shift()}getMetrics(){let t=0,e=0,s=0;const n=new Map;for(const[o,i]of this.connections.entries()){t+=i.length,e+=i.filter(t=>"active"===t.state).length,s+=i.filter(t=>"idle"===t.state).length;const r=this.metrics.byOrigin.get(o);if(r){const t=r.durations.length>0?r.durations.reduce((t,e)=>t+e,0)/r.durations.length:0;n.set(o,{connections:i.length,requests:r.requests,avgDuration:Math.round(t)})}}const o=this.metrics.requestDurations.length>0?Math.round(this.metrics.requestDurations.reduce((t,e)=>t+e,0)/this.metrics.requestDurations.length):0,i=this.metrics.totalRequests>0?this.metrics.reuseCount/this.metrics.totalRequests:0;return{totalConnections:t,activeConnections:e,idleConnections:s,totalRequests:this.metrics.totalRequests,reuseCount:this.metrics.reuseCount,failedRequests:this.metrics.failedRequests,avgRequestDuration:o,hitRate:i,byOrigin:n}}resetMetrics(){this.metrics={totalRequests:0,reuseCount:0,failedRequests:0,requestDurations:[],byOrigin:new Map}}startCleanup(){this.cleanupInterval=setInterval(()=>{this.cleanup()},1e4)}cleanup(){const t=Date.now();for(const[e,s]of this.connections.entries()){const n=s.filter(e=>t-e.lastUsedAt>this.options.idleTimeout&&"idle"===e.state?(e.controller.abort(),e.state="closed",!1):"closed"!==e.state);for(;n.length<this.options.minConnections&&n.length<this.options.maxConnections;){const t=this.createConnection(e);t.state="idle",n.push(t)}n.length>0?this.connections.set(e,n):this.connections.delete(e)}}cleanupNow(){this.cleanup()}async close(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null);for(const[t,e]of this.connections.entries())for(const t of e)t.controller.abort(),t.state="closed";this.connections.clear()}getConnectionCount(t){const e=this.connections.get(t);return e?e.length:0}getOrigins(){return Array.from(this.connections.keys())}isHealthy(){const t=this.getMetrics();return!((t.totalRequests>0?t.failedRequests/t.totalRequests:0)>.1)&&!(t.avgRequestDuration>5e3)}}let globalPool=null;export function getGlobalPool(t){return globalPool||(globalPool=new ConnectionPool(t)),globalPool}export async function resetGlobalPool(){globalPool&&(await globalPool.close(),globalPool=null)}