@private.me/xbind 1.3.5 → 2.3.4
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.
- package/LICENSES.md +212 -0
- package/README.md +388 -6
- package/dist-standalone/_deps/mldsa-wasm/dist/mldsa.js +1 -1920
- package/dist-standalone/_deps/shared/cjs/errors.js +1 -639
- package/dist-standalone/_deps/shared/cjs/index.js +1 -496
- package/dist-standalone/_deps/shared/cjs/types.js +1 -317
- package/dist-standalone/_deps/shared/errors.js +1 -255
- package/dist-standalone/_deps/shared/index.js +1 -74
- package/dist-standalone/_deps/shared/types.js +1 -90
- package/dist-standalone/_deps/ux-helpers/cjs/errors.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/index.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/progress.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/search.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/types.js +1 -1
- package/dist-standalone/_deps/ux-helpers/errors.js +1 -1
- package/dist-standalone/_deps/ux-helpers/index.js +1 -1
- package/dist-standalone/_deps/ux-helpers/pagination.js +1 -1
- package/dist-standalone/_deps/ux-helpers/progress.js +1 -1
- package/dist-standalone/_deps/ux-helpers/search.js +1 -1
- package/dist-standalone/_deps/xchange/auto-accept.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/auto-accept.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/errors.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/index.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/invite-client.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/lazy-init.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/trust-integration.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/xchange.js +1 -1
- package/dist-standalone/_deps/xchange/errors.js +1 -1
- package/dist-standalone/_deps/xchange/index.js +1 -1
- package/dist-standalone/_deps/xchange/invite-client.js +1 -1
- package/dist-standalone/_deps/xchange/lazy-init.js +1 -1
- package/dist-standalone/_deps/xchange/trust-integration.js +1 -1
- package/dist-standalone/_deps/xchange/xchange.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/discovery.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/errors.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/index.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/registry.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/schema.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/types.js +1 -1
- package/dist-standalone/_deps/xregistry/discovery.js +1 -1
- package/dist-standalone/_deps/xregistry/errors.js +1 -1
- package/dist-standalone/_deps/xregistry/index.js +1 -1
- package/dist-standalone/_deps/xregistry/registry.js +1 -1
- package/dist-standalone/_deps/xregistry/schema.js +1 -1
- package/dist-standalone/_deps/xregistry/types.js +1 -1
- package/dist-standalone/agent-call.js +1 -642
- package/dist-standalone/agent-sdk.js +1 -328
- package/dist-standalone/agent.d.ts +95 -5
- package/dist-standalone/agent.js +1 -1545
- package/dist-standalone/approval.js +1 -193
- package/dist-standalone/async-iterators.d.ts +275 -0
- package/dist-standalone/async-iterators.js +1 -0
- package/dist-standalone/auth.js +1 -219
- package/dist-standalone/auto-accept.js +1 -229
- package/dist-standalone/backup-config.js +1 -201
- package/dist-standalone/backup.d.ts +114 -0
- package/dist-standalone/backup.js +1 -0
- package/dist-standalone/batch-operations.d.ts +297 -0
- package/dist-standalone/batch-operations.js +1 -0
- package/dist-standalone/cancellation.d.ts +301 -0
- package/dist-standalone/cancellation.js +1 -0
- package/dist-standalone/checkpoint.js +1 -186
- package/dist-standalone/circuit-breaker.d.ts +351 -0
- package/dist-standalone/circuit-breaker.js +1 -0
- package/dist-standalone/cjs/agent-call.js +1 -651
- package/dist-standalone/cjs/agent-sdk.js +1 -332
- package/dist-standalone/cjs/agent.js +1 -1582
- package/dist-standalone/cjs/approval.js +1 -199
- package/dist-standalone/cjs/async-iterators.js +1 -0
- package/dist-standalone/cjs/auth.js +1 -225
- package/dist-standalone/cjs/auto-accept.js +1 -233
- package/dist-standalone/cjs/backup-config.js +1 -207
- package/dist-standalone/cjs/backup.js +1 -0
- package/dist-standalone/cjs/batch-operations.js +1 -0
- package/dist-standalone/cjs/cancellation.js +1 -0
- package/dist-standalone/cjs/checkpoint.js +1 -193
- package/dist-standalone/cjs/circuit-breaker.js +1 -0
- package/dist-standalone/cjs/cli/init.js +1 -486
- package/dist-standalone/cjs/config-validation.js +1 -0
- package/dist-standalone/cjs/connect.js +1 -312
- package/dist-standalone/cjs/connection-pool.js +1 -0
- package/dist-standalone/cjs/correlation-id.js +1 -339
- package/dist-standalone/cjs/crypto-utils.js +1 -0
- package/dist-standalone/cjs/debug-mode.js +1 -0
- package/dist-standalone/cjs/did-document.js +1 -101
- package/dist-standalone/cjs/did-privateme.js +1 -130
- package/dist-standalone/cjs/did-web.js +1 -201
- package/dist-standalone/cjs/discovery.js +1 -462
- package/dist-standalone/cjs/dual-mode.js +1 -251
- package/dist-standalone/cjs/email-templates.js +1 -313
- package/dist-standalone/cjs/email-transport.js +1 -239
- package/dist-standalone/cjs/envelope.js +1 -510
- package/dist-standalone/cjs/errors.js +1 -826
- package/dist-standalone/cjs/event-emitter.js +1 -0
- package/dist-standalone/cjs/gateway-state.js +1 -55
- package/dist-standalone/cjs/gateway-transport.js +1 -120
- package/dist-standalone/cjs/graceful-degradation.js +1 -0
- package/dist-standalone/cjs/guardrails.js +1 -223
- package/dist-standalone/cjs/health-check.js +1 -0
- package/dist-standalone/cjs/http-compat.js +1 -272
- package/dist-standalone/cjs/http-status-map.js +1 -571
- package/dist-standalone/cjs/identity.js +1 -540
- package/dist-standalone/cjs/index.js +1 -237
- package/dist-standalone/cjs/invitation.js +1 -421
- package/dist-standalone/cjs/invite.js +1 -328
- package/dist-standalone/cjs/key-agreement.js +1 -246
- package/dist-standalone/cjs/lazy-init.js +1 -300
- package/dist-standalone/cjs/logger.js +1 -0
- package/dist-standalone/cjs/mdns-discovery.js +1 -202
- package/dist-standalone/cjs/nonce-store.js +1 -66
- package/dist-standalone/cjs/pairing-manager.js +1 -223
- package/dist-standalone/cjs/plugin-system.js +1 -0
- package/dist-standalone/cjs/plugins/logging.js +1 -0
- package/dist-standalone/cjs/plugins/metrics.js +1 -0
- package/dist-standalone/cjs/plugins/validation.js +1 -0
- package/dist-standalone/cjs/policy.js +1 -320
- package/dist-standalone/cjs/progress-callbacks.js +1 -0
- package/dist-standalone/cjs/redis-nonce-store.js +1 -76
- package/dist-standalone/cjs/registry-middleware.js +1 -50
- package/dist-standalone/cjs/retry-strategies.js +1 -0
- package/dist-standalone/cjs/retry-transport.js +1 -102
- package/dist-standalone/cjs/runtime/browser.js +1 -0
- package/dist-standalone/cjs/runtime/edge.js +1 -0
- package/dist-standalone/cjs/runtime/react-native.js +1 -0
- package/dist-standalone/cjs/security-policy.js +1 -245
- package/dist-standalone/cjs/serialization.js +1 -0
- package/dist-standalone/cjs/split-channel.js +1 -177
- package/dist-standalone/cjs/subscription-proof.js +1 -230
- package/dist-standalone/cjs/succession.js +1 -148
- package/dist-standalone/cjs/timeouts.js +1 -0
- package/dist-standalone/cjs/trace-context.js +1 -0
- package/dist-standalone/cjs/trace-spans.js +1 -0
- package/dist-standalone/cjs/transport.js +1 -63
- package/dist-standalone/cjs/trust-registry.js +1 -742
- package/dist-standalone/cjs/types/error-response.js +1 -56
- package/dist-standalone/cjs/vault-auth.js +1 -0
- package/dist-standalone/cjs/vault-store-loader.js +1 -0
- package/dist-standalone/cjs/verify.js +1 -25
- package/dist-standalone/cjs/version-info.js +1 -0
- package/dist-standalone/cjs/xfetch.js +1 -252
- package/dist-standalone/cli/init.js +1 -449
- package/dist-standalone/cli/setup.js +1 -514
- package/dist-standalone/cli/types.js +1 -27
- package/dist-standalone/cli/xbind.js +1 -148
- package/dist-standalone/config-validation.d.ts +185 -0
- package/dist-standalone/config-validation.js +1 -0
- package/dist-standalone/connect.js +1 -274
- package/dist-standalone/connection-pool.d.ts +251 -0
- package/dist-standalone/connection-pool.js +1 -0
- package/dist-standalone/correlation-id.js +1 -326
- package/dist-standalone/crypto-utils.d.ts +60 -0
- package/dist-standalone/crypto-utils.js +1 -0
- package/dist-standalone/debug-mode.d.ts +286 -0
- package/dist-standalone/debug-mode.js +1 -0
- package/dist-standalone/did-document.js +1 -96
- package/dist-standalone/did-privateme.js +1 -121
- package/dist-standalone/did-web.js +1 -196
- package/dist-standalone/discovery.js +1 -458
- package/dist-standalone/dual-mode.js +1 -247
- package/dist-standalone/email-templates.js +1 -309
- package/dist-standalone/email-transport.js +1 -232
- package/dist-standalone/envelope.d.ts +29 -1
- package/dist-standalone/envelope.js +1 -497
- package/dist-standalone/errors.d.ts +10 -0
- package/dist-standalone/errors.js +1 -811
- package/dist-standalone/event-emitter.d.ts +395 -0
- package/dist-standalone/event-emitter.js +1 -0
- package/dist-standalone/gateway-state.js +1 -51
- package/dist-standalone/gateway-transport.js +1 -116
- package/dist-standalone/graceful-degradation.d.ts +246 -0
- package/dist-standalone/graceful-degradation.js +1 -0
- package/dist-standalone/guardrails.js +1 -216
- package/dist-standalone/health-check.d.ts +150 -0
- package/dist-standalone/health-check.js +1 -0
- package/dist-standalone/http-compat.js +1 -267
- package/dist-standalone/http-status-map.js +1 -561
- package/dist-standalone/identity.d.ts +64 -1
- package/dist-standalone/identity.js +1 -515
- package/dist-standalone/index.d.ts +45 -3
- package/dist-standalone/index.js +1 -52
- package/dist-standalone/invitation.js +1 -415
- package/dist-standalone/invite.js +1 -324
- package/dist-standalone/key-agreement.d.ts +61 -13
- package/dist-standalone/key-agreement.js +1 -236
- package/dist-standalone/lazy-init.js +1 -295
- package/dist-standalone/logger.d.ts +77 -0
- package/dist-standalone/logger.js +1 -0
- package/dist-standalone/mdns-discovery.js +1 -195
- package/dist-standalone/nonce-store.d.ts +16 -3
- package/dist-standalone/nonce-store.js +1 -62
- package/dist-standalone/package.json +0 -1
- package/dist-standalone/pairing-manager.js +1 -219
- package/dist-standalone/plugin-system.d.ts +145 -0
- package/dist-standalone/plugin-system.js +1 -0
- package/dist-standalone/policy.js +1 -315
- package/dist-standalone/progress-callbacks.d.ts +394 -0
- package/dist-standalone/progress-callbacks.js +1 -0
- package/dist-standalone/redis-nonce-store.js +1 -72
- package/dist-standalone/registry-middleware.js +1 -47
- package/dist-standalone/retry-strategies.d.ts +382 -0
- package/dist-standalone/retry-strategies.js +1 -0
- package/dist-standalone/retry-transport.js +1 -98
- package/dist-standalone/security-policy.js +1 -239
- package/dist-standalone/serialization.d.ts +244 -0
- package/dist-standalone/serialization.js +1 -0
- package/dist-standalone/split-channel.d.ts +49 -1
- package/dist-standalone/split-channel.js +1 -171
- package/dist-standalone/subscription-proof.js +1 -224
- package/dist-standalone/succession.js +1 -142
- package/dist-standalone/timeouts.d.ts +275 -0
- package/dist-standalone/timeouts.js +1 -0
- package/dist-standalone/trace-context.d.ts +252 -0
- package/dist-standalone/trace-context.js +1 -0
- package/dist-standalone/trace-spans.d.ts +360 -0
- package/dist-standalone/trace-spans.js +1 -0
- package/dist-standalone/transport.js +1 -59
- package/dist-standalone/trust-registry.d.ts +106 -5
- package/dist-standalone/trust-registry.js +1 -702
- package/dist-standalone/vault-auth.d.ts +91 -0
- package/dist-standalone/vault-auth.js +1 -0
- package/dist-standalone/vault-store-loader.d.ts +110 -0
- package/dist-standalone/vault-store-loader.js +1 -0
- package/dist-standalone/verify.js +1 -16
- package/dist-standalone/version-info.d.ts +259 -0
- package/dist-standalone/version-info.js +1 -0
- package/dist-standalone/xfetch.js +1 -247
- package/llms.txt +1 -0
- package/package.json +65 -5
- package/share1.dat +0 -0
- package/dist-standalone/_deps/crypto/base64.d.ts +0 -29
- package/dist-standalone/_deps/crypto/base64.js +0 -222
- package/dist-standalone/_deps/crypto/cjs/base64.js +0 -665
- package/dist-standalone/_deps/crypto/cjs/errors.js +0 -675
- package/dist-standalone/_deps/crypto/cjs/hmac.js +0 -473
- package/dist-standalone/_deps/crypto/cjs/index.js +0 -852
- package/dist-standalone/_deps/crypto/cjs/package.json +0 -1
- package/dist-standalone/_deps/crypto/cjs/padding.js +0 -511
- package/dist-standalone/_deps/crypto/cjs/share-header.js +0 -372
- package/dist-standalone/_deps/crypto/cjs/shares.js +0 -874
- package/dist-standalone/_deps/crypto/cjs/tlv.js +0 -1021
- package/dist-standalone/_deps/crypto/cjs/uuid.js +0 -443
- package/dist-standalone/_deps/crypto/cjs/verify.js +0 -414
- package/dist-standalone/_deps/crypto/cjs/xorida.js +0 -923
- package/dist-standalone/_deps/crypto/errors.d.ts +0 -51
- package/dist-standalone/_deps/crypto/errors.js +0 -199
- package/dist-standalone/_deps/crypto/hmac.d.ts +0 -39
- package/dist-standalone/_deps/crypto/hmac.js +0 -134
- package/dist-standalone/_deps/crypto/index.d.ts +0 -20
- package/dist-standalone/_deps/crypto/index.js +0 -145
- package/dist-standalone/_deps/crypto/padding.d.ts +0 -19
- package/dist-standalone/_deps/crypto/padding.js +0 -159
- package/dist-standalone/_deps/crypto/share-header.d.ts +0 -44
- package/dist-standalone/_deps/crypto/share-header.js +0 -92
- package/dist-standalone/_deps/crypto/shares.d.ts +0 -27
- package/dist-standalone/_deps/crypto/shares.js +0 -295
- package/dist-standalone/_deps/crypto/tlv.d.ts +0 -26
- package/dist-standalone/_deps/crypto/tlv.js +0 -364
- package/dist-standalone/_deps/crypto/uuid.d.ts +0 -22
- package/dist-standalone/_deps/crypto/uuid.js +0 -136
- package/dist-standalone/_deps/crypto/verify.d.ts +0 -15
- package/dist-standalone/_deps/crypto/verify.js +0 -71
- package/dist-standalone/_deps/crypto/xorida.d.ts +0 -44
- package/dist-standalone/_deps/crypto/xorida.js +0 -366
- package/dist-standalone/_deps/shared/errors.d.ts.map +0 -1
- package/dist-standalone/_deps/shared/errors.js.map +0 -1
- package/dist-standalone/_deps/shared/index.d.ts.map +0 -1
- package/dist-standalone/_deps/shared/index.js.map +0 -1
- package/dist-standalone/_deps/shared/types.d.ts.map +0 -1
- package/dist-standalone/_deps/shared/types.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/errors.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/errors.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/index.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/index.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/progress.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/progress.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/search.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/search.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/types.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/types.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/errors.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/errors.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/index.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/index.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/pagination.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/pagination.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/progress.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/progress.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/search.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/search.js.map +0 -1
- package/dist-standalone/_deps/ux-helpers/types.d.ts.map +0 -1
- package/dist-standalone/_deps/ux-helpers/types.js.map +0 -1
- package/dist-standalone/_deps/xregistry/discovery.d.ts.map +0 -1
- package/dist-standalone/_deps/xregistry/discovery.js.map +0 -1
- package/dist-standalone/_deps/xregistry/errors.d.ts.map +0 -1
- package/dist-standalone/_deps/xregistry/errors.js.map +0 -1
- package/dist-standalone/_deps/xregistry/index.d.ts.map +0 -1
- package/dist-standalone/_deps/xregistry/index.js.map +0 -1
- package/dist-standalone/_deps/xregistry/registry.d.ts.map +0 -1
- package/dist-standalone/_deps/xregistry/registry.js.map +0 -1
- package/dist-standalone/_deps/xregistry/schema.d.ts.map +0 -1
- package/dist-standalone/_deps/xregistry/schema.js.map +0 -1
- package/dist-standalone/_deps/xregistry/types.d.ts.map +0 -1
- package/dist-standalone/_deps/xregistry/types.js.map +0 -1
|
@@ -0,0 +1,251 @@
|
|
|
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 configuration options
|
|
21
|
+
*/
|
|
22
|
+
export interface ConnectionPoolOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Maximum number of connections per origin
|
|
25
|
+
* @default 10
|
|
26
|
+
*/
|
|
27
|
+
maxConnections?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Minimum number of idle connections to maintain
|
|
30
|
+
* @default 2
|
|
31
|
+
*/
|
|
32
|
+
minConnections?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Keep-alive timeout in milliseconds
|
|
35
|
+
* @default 30000 (30 seconds)
|
|
36
|
+
*/
|
|
37
|
+
keepAliveTimeout?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Maximum time a connection can be idle before cleanup
|
|
40
|
+
* @default 60000 (60 seconds)
|
|
41
|
+
*/
|
|
42
|
+
idleTimeout?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Request timeout in milliseconds
|
|
45
|
+
* @default 30000 (30 seconds)
|
|
46
|
+
*/
|
|
47
|
+
requestTimeout?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Enable connection pooling metrics
|
|
50
|
+
* @default true
|
|
51
|
+
*/
|
|
52
|
+
enableMetrics?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Retry failed connections
|
|
55
|
+
* @default true
|
|
56
|
+
*/
|
|
57
|
+
retryOnFailure?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Maximum retry attempts for failed requests
|
|
60
|
+
* @default 3
|
|
61
|
+
*/
|
|
62
|
+
maxRetries?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Connection pool metrics
|
|
66
|
+
*/
|
|
67
|
+
export interface ConnectionPoolMetrics {
|
|
68
|
+
/** Total number of connections */
|
|
69
|
+
totalConnections: number;
|
|
70
|
+
/** Number of active connections */
|
|
71
|
+
activeConnections: number;
|
|
72
|
+
/** Number of idle connections */
|
|
73
|
+
idleConnections: number;
|
|
74
|
+
/** Total requests served */
|
|
75
|
+
totalRequests: number;
|
|
76
|
+
/** Number of connection reuses */
|
|
77
|
+
reuseCount: number;
|
|
78
|
+
/** Number of failed requests */
|
|
79
|
+
failedRequests: number;
|
|
80
|
+
/** Average request duration in milliseconds */
|
|
81
|
+
avgRequestDuration: number;
|
|
82
|
+
/** Connection pool hit rate (0-1) */
|
|
83
|
+
hitRate: number;
|
|
84
|
+
/** Metrics by origin */
|
|
85
|
+
byOrigin: Map<string, {
|
|
86
|
+
connections: number;
|
|
87
|
+
requests: number;
|
|
88
|
+
avgDuration: number;
|
|
89
|
+
}>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Connection pool for HTTP requests
|
|
93
|
+
*
|
|
94
|
+
* Manages connection lifecycle, keep-alive, and automatic cleanup
|
|
95
|
+
* to optimize performance for frequent requests to the same origins.
|
|
96
|
+
*/
|
|
97
|
+
export declare class ConnectionPool {
|
|
98
|
+
private options;
|
|
99
|
+
private connections;
|
|
100
|
+
private metrics;
|
|
101
|
+
private cleanupInterval;
|
|
102
|
+
/**
|
|
103
|
+
* Create a new connection pool
|
|
104
|
+
*
|
|
105
|
+
* @param options - Pool configuration options
|
|
106
|
+
*/
|
|
107
|
+
constructor(options?: ConnectionPoolOptions);
|
|
108
|
+
/**
|
|
109
|
+
* Make an HTTP request using the connection pool
|
|
110
|
+
*
|
|
111
|
+
* @param url - Target URL
|
|
112
|
+
* @param init - Fetch options
|
|
113
|
+
* @returns Response promise
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const response = await pool.fetch('https://api.example.com/data', {
|
|
118
|
+
* method: 'POST',
|
|
119
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
120
|
+
* body: JSON.stringify({ key: 'value' }),
|
|
121
|
+
* });
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
fetch(url: string, init?: RequestInit): Promise<Response>;
|
|
125
|
+
/**
|
|
126
|
+
* Retry a failed request with exponential backoff
|
|
127
|
+
*/
|
|
128
|
+
private retryRequest;
|
|
129
|
+
/**
|
|
130
|
+
* Acquire a connection from the pool or create a new one
|
|
131
|
+
*/
|
|
132
|
+
private acquireConnection;
|
|
133
|
+
/**
|
|
134
|
+
* Wait for a connection to become available
|
|
135
|
+
*/
|
|
136
|
+
private waitForConnection;
|
|
137
|
+
/**
|
|
138
|
+
* Create a new connection
|
|
139
|
+
*/
|
|
140
|
+
private createConnection;
|
|
141
|
+
/**
|
|
142
|
+
* Get origin from URL
|
|
143
|
+
*/
|
|
144
|
+
private getOrigin;
|
|
145
|
+
/**
|
|
146
|
+
* Record request metrics
|
|
147
|
+
*/
|
|
148
|
+
private recordMetrics;
|
|
149
|
+
/**
|
|
150
|
+
* Get connection pool metrics
|
|
151
|
+
*
|
|
152
|
+
* @returns Current metrics snapshot
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const metrics = pool.getMetrics();
|
|
157
|
+
* console.log(`Hit rate: ${(metrics.hitRate * 100).toFixed(1)}%`);
|
|
158
|
+
* console.log(`Avg duration: ${metrics.avgRequestDuration}ms`);
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
getMetrics(): ConnectionPoolMetrics;
|
|
162
|
+
/**
|
|
163
|
+
* Reset metrics counters
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* pool.resetMetrics();
|
|
168
|
+
* // Start fresh measurements
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
resetMetrics(): void;
|
|
172
|
+
/**
|
|
173
|
+
* Start automatic connection cleanup
|
|
174
|
+
*/
|
|
175
|
+
private startCleanup;
|
|
176
|
+
/**
|
|
177
|
+
* Clean up idle and expired connections
|
|
178
|
+
*/
|
|
179
|
+
private cleanup;
|
|
180
|
+
/**
|
|
181
|
+
* Manually trigger connection cleanup
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* // Force cleanup of idle connections
|
|
186
|
+
* pool.cleanupNow();
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
cleanupNow(): void;
|
|
190
|
+
/**
|
|
191
|
+
* Close all connections and shutdown the pool
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* // Cleanup on application shutdown
|
|
196
|
+
* await pool.close();
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
close(): Promise<void>;
|
|
200
|
+
/**
|
|
201
|
+
* Get the number of connections for a specific origin
|
|
202
|
+
*
|
|
203
|
+
* @param origin - Target origin (e.g., "https://api.example.com")
|
|
204
|
+
* @returns Number of connections
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const count = pool.getConnectionCount('https://api.example.com');
|
|
209
|
+
* console.log(`Active connections: ${count}`);
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
getConnectionCount(origin: string): number;
|
|
213
|
+
/**
|
|
214
|
+
* Get all origins with active connections
|
|
215
|
+
*
|
|
216
|
+
* @returns Array of origins
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* const origins = pool.getOrigins();
|
|
221
|
+
* console.log(`Connected to ${origins.length} origins`);
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
getOrigins(): string[];
|
|
225
|
+
/**
|
|
226
|
+
* Check if the pool is healthy
|
|
227
|
+
*
|
|
228
|
+
* @returns True if pool is operating normally
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```typescript
|
|
232
|
+
* if (!pool.isHealthy()) {
|
|
233
|
+
* console.warn('Connection pool degraded');
|
|
234
|
+
* }
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
isHealthy(): boolean;
|
|
238
|
+
}
|
|
239
|
+
export declare function getGlobalPool(options?: ConnectionPoolOptions): ConnectionPool;
|
|
240
|
+
/**
|
|
241
|
+
* Reset the global connection pool
|
|
242
|
+
*
|
|
243
|
+
* Closes the current pool and allows a new one to be created.
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* await resetGlobalPool();
|
|
248
|
+
* // Next getGlobalPool() call will create a fresh instance
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
export declare function resetGlobalPool(): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
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(n){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(e){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)}
|
|
@@ -1,326 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @module correlation-id
|
|
3
|
-
* Client-side correlation ID utilities for request tracking
|
|
4
|
-
*
|
|
5
|
-
* Correlation IDs enable distributed tracing across xBind agent operations,
|
|
6
|
-
* making it easier to debug issues, track requests across microservices,
|
|
7
|
-
* and correlate logs between client and server.
|
|
8
|
-
*
|
|
9
|
-
* Format: `req_{timestamp}_{random}`
|
|
10
|
-
* Example: `req_1716234567890_a3f5c9d2`
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* ```typescript
|
|
14
|
-
* import { generateCorrelationId, attachCorrelationId } from '@private.me/xbind';
|
|
15
|
-
*
|
|
16
|
-
* // Generate a new correlation ID
|
|
17
|
-
* const id = generateCorrelationId();
|
|
18
|
-
*
|
|
19
|
-
* // Attach to request headers
|
|
20
|
-
* const headers = attachCorrelationId(new Headers(), id);
|
|
21
|
-
*
|
|
22
|
-
* // Validate format
|
|
23
|
-
* if (validateCorrelationId(id)) {
|
|
24
|
-
* console.log('Valid correlation ID');
|
|
25
|
-
* }
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
/**
|
|
29
|
-
* Standard header name for correlation ID
|
|
30
|
-
*/
|
|
31
|
-
export const CORRELATION_ID_HEADER = 'X-Correlation-ID';
|
|
32
|
-
/**
|
|
33
|
-
* Alternative header names for compatibility
|
|
34
|
-
*/
|
|
35
|
-
export const CORRELATION_ID_ALIASES = [
|
|
36
|
-
'X-Request-ID',
|
|
37
|
-
'X-Trace-ID',
|
|
38
|
-
'X-Transaction-ID',
|
|
39
|
-
];
|
|
40
|
-
/**
|
|
41
|
-
* Regular expression for validating correlation ID format
|
|
42
|
-
*/
|
|
43
|
-
const CORRELATION_ID_PATTERN = /^req_\d{13}_[a-f0-9]{8}$/;
|
|
44
|
-
/**
|
|
45
|
-
* Generate a new correlation ID
|
|
46
|
-
*
|
|
47
|
-
* Format: `req_{timestamp}_{random}`
|
|
48
|
-
* - `req`: Static prefix for identification
|
|
49
|
-
* - `timestamp`: Unix timestamp in milliseconds (13 digits)
|
|
50
|
-
* - `random`: 8-character hex string for uniqueness
|
|
51
|
-
*
|
|
52
|
-
* @returns New correlation ID string
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```typescript
|
|
56
|
-
* const id = generateCorrelationId();
|
|
57
|
-
* // => "req_1716234567890_a3f5c9d2"
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
export function generateCorrelationId() {
|
|
61
|
-
const timestamp = Date.now();
|
|
62
|
-
const random = generateRandomHex(8);
|
|
63
|
-
return `req_${timestamp}_${random}`;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Validate correlation ID format
|
|
67
|
-
*
|
|
68
|
-
* Checks if the provided string matches the expected correlation ID format.
|
|
69
|
-
*
|
|
70
|
-
* @param id - String to validate
|
|
71
|
-
* @returns True if valid, false otherwise
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* ```typescript
|
|
75
|
-
* validateCorrelationId('req_1716234567890_a3f5c9d2'); // => true
|
|
76
|
-
* validateCorrelationId('invalid'); // => false
|
|
77
|
-
* validateCorrelationId('req_123_abc'); // => false (wrong lengths)
|
|
78
|
-
* ```
|
|
79
|
-
*/
|
|
80
|
-
export function validateCorrelationId(id) {
|
|
81
|
-
if (typeof id !== 'string')
|
|
82
|
-
return false;
|
|
83
|
-
return CORRELATION_ID_PATTERN.test(id);
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Parse correlation ID into components
|
|
87
|
-
*
|
|
88
|
-
* Extracts the timestamp and random components from a correlation ID.
|
|
89
|
-
*
|
|
90
|
-
* @param id - Correlation ID to parse
|
|
91
|
-
* @returns Parsed components or null if invalid
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```typescript
|
|
95
|
-
* const spec = parseCorrelationId('req_1716234567890_a3f5c9d2');
|
|
96
|
-
* // => { prefix: 'req', timestamp: 1716234567890, random: 'a3f5c9d2' }
|
|
97
|
-
* ```
|
|
98
|
-
*/
|
|
99
|
-
export function parseCorrelationId(id) {
|
|
100
|
-
if (!validateCorrelationId(id))
|
|
101
|
-
return null;
|
|
102
|
-
const parts = id.split('_');
|
|
103
|
-
return {
|
|
104
|
-
prefix: parts[0] ?? 'req',
|
|
105
|
-
timestamp: parseInt(parts[1] ?? '0', 10),
|
|
106
|
-
random: parts[2] ?? '',
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Attach correlation ID to request headers
|
|
111
|
-
*
|
|
112
|
-
* Adds the correlation ID to the X-Correlation-ID header.
|
|
113
|
-
* If no ID is provided, generates a new one.
|
|
114
|
-
* Compatible with both Headers API and plain objects.
|
|
115
|
-
*
|
|
116
|
-
* @param headers - Headers object or plain object
|
|
117
|
-
* @param id - Correlation ID (generates new if not provided)
|
|
118
|
-
* @returns Updated headers object
|
|
119
|
-
*
|
|
120
|
-
* @example
|
|
121
|
-
* ```typescript
|
|
122
|
-
* // With Headers API
|
|
123
|
-
* const headers = new Headers();
|
|
124
|
-
* attachCorrelationId(headers);
|
|
125
|
-
*
|
|
126
|
-
* // With plain object
|
|
127
|
-
* const headers = { 'Content-Type': 'application/json' };
|
|
128
|
-
* attachCorrelationId(headers, 'req_1716234567890_a3f5c9d2');
|
|
129
|
-
*
|
|
130
|
-
* // With existing correlation ID
|
|
131
|
-
* const id = generateCorrelationId();
|
|
132
|
-
* attachCorrelationId(headers, id);
|
|
133
|
-
* ```
|
|
134
|
-
*/
|
|
135
|
-
export function attachCorrelationId(headers, id) {
|
|
136
|
-
const correlationId = id ?? generateCorrelationId();
|
|
137
|
-
if (!validateCorrelationId(correlationId)) {
|
|
138
|
-
throw new Error(`Invalid correlation ID format: ${correlationId}. Expected format: req_{timestamp}_{random}`);
|
|
139
|
-
}
|
|
140
|
-
if (headers instanceof Headers) {
|
|
141
|
-
headers.set(CORRELATION_ID_HEADER, correlationId);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
headers[CORRELATION_ID_HEADER] = correlationId;
|
|
145
|
-
}
|
|
146
|
-
return headers;
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Extract correlation ID from request headers
|
|
150
|
-
*
|
|
151
|
-
* Checks the standard header and common aliases.
|
|
152
|
-
*
|
|
153
|
-
* @param headers - Headers object or plain object
|
|
154
|
-
* @returns Correlation ID if found, undefined otherwise
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* ```typescript
|
|
158
|
-
* const headers = new Headers({
|
|
159
|
-
* 'X-Correlation-ID': 'req_1716234567890_a3f5c9d2'
|
|
160
|
-
* });
|
|
161
|
-
* const id = extractCorrelationId(headers);
|
|
162
|
-
* // => 'req_1716234567890_a3f5c9d2'
|
|
163
|
-
* ```
|
|
164
|
-
*/
|
|
165
|
-
export function extractCorrelationId(headers) {
|
|
166
|
-
// Check primary header
|
|
167
|
-
const primary = headers instanceof Headers
|
|
168
|
-
? headers.get(CORRELATION_ID_HEADER)
|
|
169
|
-
: headers[CORRELATION_ID_HEADER];
|
|
170
|
-
if (primary && validateCorrelationId(primary)) {
|
|
171
|
-
return primary;
|
|
172
|
-
}
|
|
173
|
-
// Check aliases
|
|
174
|
-
for (const alias of CORRELATION_ID_ALIASES) {
|
|
175
|
-
const value = headers instanceof Headers ? headers.get(alias) : headers[alias];
|
|
176
|
-
if (value && validateCorrelationId(value)) {
|
|
177
|
-
return value;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return undefined;
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Get or create correlation ID from headers
|
|
184
|
-
*
|
|
185
|
-
* Returns existing correlation ID from headers, or generates a new one if not found.
|
|
186
|
-
* Does NOT modify the input headers.
|
|
187
|
-
*
|
|
188
|
-
* @param headers - Headers to check
|
|
189
|
-
* @returns Existing or new correlation ID
|
|
190
|
-
*
|
|
191
|
-
* @example
|
|
192
|
-
* ```typescript
|
|
193
|
-
* const headers = new Headers();
|
|
194
|
-
* const id = getOrCreateCorrelationId(headers);
|
|
195
|
-
* // => Generates new ID if not found in headers
|
|
196
|
-
* ```
|
|
197
|
-
*/
|
|
198
|
-
export function getOrCreateCorrelationId(headers) {
|
|
199
|
-
if (!headers)
|
|
200
|
-
return generateCorrelationId();
|
|
201
|
-
const existing = extractCorrelationId(headers);
|
|
202
|
-
return existing ?? generateCorrelationId();
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Create a correlation ID from a timestamp
|
|
206
|
-
*
|
|
207
|
-
* Useful for testing or when you need deterministic IDs.
|
|
208
|
-
*
|
|
209
|
-
* @param timestamp - Unix timestamp in milliseconds
|
|
210
|
-
* @param random - Optional random component (generates if not provided)
|
|
211
|
-
* @returns Correlation ID
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* ```typescript
|
|
215
|
-
* const id = createCorrelationIdFromTimestamp(1716234567890);
|
|
216
|
-
* // => 'req_1716234567890_a3f5c9d2'
|
|
217
|
-
*
|
|
218
|
-
* const deterministicId = createCorrelationIdFromTimestamp(1716234567890, 'aaaaaaaa');
|
|
219
|
-
* // => 'req_1716234567890_aaaaaaaa'
|
|
220
|
-
* ```
|
|
221
|
-
*/
|
|
222
|
-
export function createCorrelationIdFromTimestamp(timestamp, random) {
|
|
223
|
-
const randomComponent = random ?? generateRandomHex(8);
|
|
224
|
-
if (!/^[a-f0-9]{8}$/.test(randomComponent)) {
|
|
225
|
-
throw new Error(`Invalid random component: ${randomComponent}. Expected 8 hex characters`);
|
|
226
|
-
}
|
|
227
|
-
return `req_${timestamp}_${randomComponent}`;
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* Calculate age of correlation ID in milliseconds
|
|
231
|
-
*
|
|
232
|
-
* @param id - Correlation ID
|
|
233
|
-
* @returns Age in milliseconds, or null if invalid
|
|
234
|
-
*
|
|
235
|
-
* @example
|
|
236
|
-
* ```typescript
|
|
237
|
-
* const id = generateCorrelationId();
|
|
238
|
-
* setTimeout(() => {
|
|
239
|
-
* const age = getCorrelationIdAge(id);
|
|
240
|
-
* console.log(`Request age: ${age}ms`);
|
|
241
|
-
* }, 1000);
|
|
242
|
-
* ```
|
|
243
|
-
*/
|
|
244
|
-
export function getCorrelationIdAge(id) {
|
|
245
|
-
const spec = parseCorrelationId(id);
|
|
246
|
-
if (!spec)
|
|
247
|
-
return null;
|
|
248
|
-
const now = Date.now();
|
|
249
|
-
return now - spec.timestamp;
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Check if correlation ID is expired
|
|
253
|
-
*
|
|
254
|
-
* @param id - Correlation ID
|
|
255
|
-
* @param maxAgeMs - Maximum age in milliseconds (default: 5 minutes)
|
|
256
|
-
* @returns True if expired, false otherwise
|
|
257
|
-
*
|
|
258
|
-
* @example
|
|
259
|
-
* ```typescript
|
|
260
|
-
* const id = generateCorrelationId();
|
|
261
|
-
* if (isCorrelationIdExpired(id, 60000)) {
|
|
262
|
-
* console.log('Request older than 1 minute');
|
|
263
|
-
* }
|
|
264
|
-
* ```
|
|
265
|
-
*/
|
|
266
|
-
export function isCorrelationIdExpired(id, maxAgeMs = 5 * 60 * 1000) {
|
|
267
|
-
const age = getCorrelationIdAge(id);
|
|
268
|
-
return age !== null && age > maxAgeMs;
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Generate random hex string
|
|
272
|
-
*
|
|
273
|
-
* Uses Web Crypto API in browser, Node.js crypto in Node.
|
|
274
|
-
* Falls back to Math.random() if neither available (NOT cryptographically secure).
|
|
275
|
-
*
|
|
276
|
-
* @param length - Number of hex characters to generate
|
|
277
|
-
* @returns Random hex string
|
|
278
|
-
*
|
|
279
|
-
* @internal
|
|
280
|
-
*/
|
|
281
|
-
function generateRandomHex(length) {
|
|
282
|
-
const bytes = Math.ceil(length / 2);
|
|
283
|
-
// Try Web Crypto API (browser)
|
|
284
|
-
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
|
285
|
-
const buffer = new Uint8Array(bytes);
|
|
286
|
-
crypto.getRandomValues(buffer);
|
|
287
|
-
return Array.from(buffer)
|
|
288
|
-
.map((b) => b.toString(16).padStart(2, '0'))
|
|
289
|
-
.join('')
|
|
290
|
-
.substring(0, length);
|
|
291
|
-
}
|
|
292
|
-
// Try Node.js crypto
|
|
293
|
-
try {
|
|
294
|
-
const nodeCrypto = require('node:crypto');
|
|
295
|
-
return nodeCrypto.randomBytes(bytes).toString('hex').substring(0, length);
|
|
296
|
-
}
|
|
297
|
-
catch {
|
|
298
|
-
// SECURITY: Never fall back to Math.random() in production (OWASP violation)
|
|
299
|
-
// Correlation IDs must be cryptographically random to prevent enumeration attacks
|
|
300
|
-
throw new Error('Cryptographic random generation unavailable. ' +
|
|
301
|
-
'Install crypto polyfill or use environment with crypto support.');
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Middleware helper for Express/Koa-style frameworks
|
|
306
|
-
*
|
|
307
|
-
* Automatically attaches correlation ID to incoming requests.
|
|
308
|
-
*
|
|
309
|
-
* @example
|
|
310
|
-
* ```typescript
|
|
311
|
-
* import express from 'express';
|
|
312
|
-
* import { correlationIdMiddleware } from '@private.me/xbind';
|
|
313
|
-
*
|
|
314
|
-
* const app = express();
|
|
315
|
-
* app.use(correlationIdMiddleware());
|
|
316
|
-
* ```
|
|
317
|
-
*/
|
|
318
|
-
export function correlationIdMiddleware() {
|
|
319
|
-
return (req, res, next) => {
|
|
320
|
-
const id = getOrCreateCorrelationId(req.headers);
|
|
321
|
-
req.correlationId = id;
|
|
322
|
-
res.setHeader(CORRELATION_ID_HEADER, id);
|
|
323
|
-
if (typeof next === 'function')
|
|
324
|
-
next();
|
|
325
|
-
};
|
|
326
|
-
}
|
|
1
|
+
export const CORRELATION_ID_HEADER="X-Correlation-ID";export const CORRELATION_ID_ALIASES=["X-Request-ID","X-Trace-ID","X-Transaction-ID"];const CORRELATION_ID_PATTERN=/^req_\d{13}_[a-f0-9]{8}$/;export function generateCorrelationId(){return`req_${Date.now()}_${generateRandomHex(8)}`}export function validateCorrelationId(r){return"string"==typeof r&&CORRELATION_ID_PATTERN.test(r)}export function parseCorrelationId(r){if(!validateCorrelationId(r))return null;const e=r.split("_");return{prefix:e[0]??"req",timestamp:parseInt(e[1]??"0",10),random:e[2]??""}}export function attachCorrelationId(r,e){const t=e??generateCorrelationId();if(!validateCorrelationId(t))throw new Error(`Invalid correlation ID format: ${t}. Expected format: req_{timestamp}_{random}`);return r instanceof Headers?r.set("X-Correlation-ID",t):r["X-Correlation-ID"]=t,r}export function extractCorrelationId(r){const e=r instanceof Headers?r.get("X-Correlation-ID"):r["X-Correlation-ID"];if(e&&validateCorrelationId(e))return e;for(const e of CORRELATION_ID_ALIASES){const t=r instanceof Headers?r.get(e):r[e];if(t&&validateCorrelationId(t))return t}}export function getOrCreateCorrelationId(r){if(!r)return generateCorrelationId();return extractCorrelationId(r)??generateCorrelationId()}export function createCorrelationIdFromTimestamp(r,e){const t=e??generateRandomHex(8);if(!/^[a-f0-9]{8}$/.test(t))throw new Error(`Invalid random component: ${t}. Expected 8 hex characters`);return`req_${r}_${t}`}export function getCorrelationIdAge(r){const e=parseCorrelationId(r);if(!e)return null;return Date.now()-e.timestamp}export function isCorrelationIdExpired(r,e=3e5){const t=getCorrelationIdAge(r);return null!==t&&t>e}function generateRandomHex(r){const e=Math.ceil(r/2);if("undefined"!=typeof crypto&&crypto.getRandomValues){const t=new Uint8Array(e);return crypto.getRandomValues(t),Array.from(t).map(r=>r.toString(16).padStart(2,"0")).join("").substring(0,r)}try{return require("node:crypto").randomBytes(e).toString("hex").substring(0,r)}catch{throw new Error("Cryptographic random generation unavailable. Install crypto polyfill or use environment with crypto support.")}}export function correlationIdMiddleware(){return(r,e,t)=>{const o=getOrCreateCorrelationId(r.headers);r.correlationId=o,e.setHeader("X-Correlation-ID",o),"function"==typeof t&&t()}}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module crypto-utils
|
|
3
|
+
* Local crypto utilities (non-IP, safe for npm distribution).
|
|
4
|
+
*
|
|
5
|
+
* These are NOT proprietary - just standard Web Crypto API wrappers.
|
|
6
|
+
* The proprietary XorIDA algorithm is vault-gated via vault-store-loader.ts.
|
|
7
|
+
*/
|
|
8
|
+
/** Convert Uint8Array to Base64 string */
|
|
9
|
+
export declare function toBase64(data: Uint8Array): string;
|
|
10
|
+
/** Convert Base64 string to Uint8Array */
|
|
11
|
+
export declare function fromBase64(base64: string): Uint8Array;
|
|
12
|
+
/** Convert Uint8Array to Base64URL string (URL-safe) */
|
|
13
|
+
export declare function toBase64Url(data: Uint8Array): string;
|
|
14
|
+
/** Convert Base64URL string to Uint8Array */
|
|
15
|
+
export declare function fromBase64Url(base64url: string): Uint8Array;
|
|
16
|
+
/** Generate a UUID v4 (random) */
|
|
17
|
+
export declare function generateUUID(): string;
|
|
18
|
+
/**
|
|
19
|
+
* Wrap share data with branded IDA5 copyright header.
|
|
20
|
+
* @param data - Base64-encoded share data
|
|
21
|
+
* @returns Branded string with copyright header
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatShareHeader(data: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Extract share data from branded IDA5 header.
|
|
26
|
+
* @param input - Branded share string or legacy raw data
|
|
27
|
+
* @returns Extracted share data
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseShareHeader(input: string): string;
|
|
30
|
+
/** Check if string has branded IDA5 share header */
|
|
31
|
+
export declare function hasShareHeader(input: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Vault-gated XorIDA functions (loaded dynamically from payment-gated Vault Store).
|
|
34
|
+
* These are re-exported from vault-store-loader for convenience.
|
|
35
|
+
*/
|
|
36
|
+
import { getCrypto, loadCryptoPackage, isCryptoLoaded } from './vault-store-loader.js';
|
|
37
|
+
/** Split data using XorIDA (vault-gated, requires payment) */
|
|
38
|
+
export declare function splitXorIDA(data: Uint8Array, totalShares: number, requiredShares: number): Uint8Array[];
|
|
39
|
+
/** Reconstruct data from XorIDA shares (vault-gated, requires payment) */
|
|
40
|
+
export declare function reconstructXorIDA(shares: Uint8Array[], indices: number[], requiredShares: number, totalShares: number): Uint8Array;
|
|
41
|
+
/** Get next odd prime >= n (vault-gated utility) */
|
|
42
|
+
export declare function nextOddPrime(n: number): number;
|
|
43
|
+
/** PKCS7 padding (vault-gated utility) */
|
|
44
|
+
export declare function pkcs7Pad(data: Uint8Array, blockSize: number): Uint8Array;
|
|
45
|
+
/** PKCS7 unpadding (vault-gated utility) */
|
|
46
|
+
export declare function pkcs7Unpad(data: Uint8Array, blockSize: number): {
|
|
47
|
+
ok: true;
|
|
48
|
+
value: Uint8Array;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
error: unknown;
|
|
52
|
+
};
|
|
53
|
+
/** Generate HMAC-SHA256 (vault-gated utility) */
|
|
54
|
+
export declare function generateHMAC(data: Uint8Array): Promise<{
|
|
55
|
+
key: Uint8Array;
|
|
56
|
+
signature: Uint8Array;
|
|
57
|
+
}>;
|
|
58
|
+
/** Verify HMAC-SHA256 (vault-gated utility) */
|
|
59
|
+
export declare function verifyHMAC(key: Uint8Array, data: Uint8Array, expectedHmac: Uint8Array): Promise<boolean>;
|
|
60
|
+
export { loadCryptoPackage, getCrypto, isCryptoLoaded };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function toBase64(r){if("undefined"!=typeof Buffer)return Buffer.from(r).toString("base64");const t=String.fromCharCode(...r);return btoa(t)}export function fromBase64(r){if("undefined"!=typeof Buffer)return new Uint8Array(Buffer.from(r,"base64"));const t=atob(r),e=new Uint8Array(t.length);for(let r=0;r<t.length;r++)e[r]=t.charCodeAt(r);return e}export function toBase64Url(r){return toBase64(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}export function fromBase64Url(r){let t=r.replace(/-/g,"+").replace(/_/g,"/");for(;t.length%4;)t+="=";return fromBase64(t)}export function generateUUID(){if("undefined"!=typeof crypto&&crypto.randomUUID)return crypto.randomUUID();const r=new Uint8Array(16);crypto.getRandomValues(r),r[6]=15&r[6]|64,r[8]=63&r[8]|128;const t=Array.from(r).map(r=>r.toString(16).padStart(2,"0")).join("");return`${t.substring(0,8)}-${t.substring(8,12)}-${t.substring(12,16)}-${t.substring(16,20)}-${t.substring(20)}`}const START_MARKER="Encrypted://",END_MARKER="=> Generated by Xecret (TM)",BRAND_PREFIX="Xecret (TM) -> PRIVATE .ME (R) -> IDA5 -> ";export function formatShareHeader(r){return`${BRAND_PREFIX}${START_MARKER} ${r} ${END_MARKER}`}export function parseShareHeader(r){const t=r.indexOf(START_MARKER);if(t<0)return r.trim();const e=t+12,o=r.indexOf(END_MARKER,e);return o<0?r.trim():r.substring(e,o).trim()}export function hasShareHeader(r){return r.includes(START_MARKER)&&r.includes(END_MARKER)}import{getCrypto,loadCryptoPackage,isCryptoLoaded}from"./vault-store-loader.js";export function splitXorIDA(r,t,e){const o=getCrypto();if(!o)throw new Error("Crypto package not loaded. Call loadCryptoPackage() first.");return o.splitXorIDA(r,t,e)}export function reconstructXorIDA(r,t,e,o){const n=getCrypto();if(!n)throw new Error("Crypto package not loaded. Call loadCryptoPackage() first.");return n.reconstructXorIDA(r,t,e,o)}export function nextOddPrime(r){const t=getCrypto();if(!t)throw new Error("Crypto package not loaded. Call loadCryptoPackage() first.");return t.nextOddPrime(r)}export function pkcs7Pad(r,t){const e=getCrypto();if(!e)throw new Error("Crypto package not loaded. Call loadCryptoPackage() first.");return e.pkcs7Pad(r,t)}export function pkcs7Unpad(r,t){const e=getCrypto();if(!e)throw new Error("Crypto package not loaded. Call loadCryptoPackage() first.");return e.pkcs7Unpad(r,t)}export async function generateHMAC(r){const t=getCrypto();if(!t)throw new Error("Crypto package not loaded. Call loadCryptoPackage() first.");return t.generateHMAC(r)}export async function verifyHMAC(r,t,e){const o=getCrypto();if(!o)throw new Error("Crypto package not loaded. Call loadCryptoPackage() first.");return o.verifyHMAC(r,t,e)}export{loadCryptoPackage,getCrypto,isCryptoLoaded};
|