blockintel-gate-sdk 0.3.10 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -408,11 +408,27 @@ The SDK includes a **Heartbeat Manager** that automatically acquires and refresh
408
408
 
409
409
  ### How It Works
410
410
 
411
- 1. **Automatic Token Acquisition**: The SDK automatically starts a background heartbeat refresher when the `GateClient` is initialized. This continuously sends heartbeats to the Control Plane, keeping the signer status active in the UI.
412
- 2. **Token Refresh**: Heartbeat tokens are refreshed every 10 seconds (configurable via `heartbeatRefreshIntervalSeconds`) to maintain a valid token
413
- 3. **Signing Enforcement**: Before any `evaluate()` call, the SDK checks for a valid heartbeat token. If missing or expired, it throws `HEARTBEAT_MISSING` error
414
- 4. **Token Inclusion**: The heartbeat token is automatically included in the `signingContext` of every evaluation request
415
- 5. **No Manual Scripts Needed**: The SDK handles all heartbeat management automatically - no need for separate heartbeat scripts
411
+ 1. **Per-Signer Token Cache**: The heartbeat manager maintains a `Map<signerId, SignerHeartbeatEntry>` so each signer gets its own cached token, refresh timer, and backoff state. Switching between signers never invalidates other signers' tokens.
412
+ 2. **Automatic Token Acquisition**: When `getTokenForSigner(signerId)` is called, the manager returns the cached token immediately if valid, or acquires a new one on demand. The initial default signer is pre-warmed on `start()`.
413
+ 3. **Per-Signer Refresh**: Each signer entry has its own background `setTimeout` timer that refreshes the token before expiry (default every 10 seconds + jitter + backoff on failure).
414
+ 4. **LRU Eviction**: When the number of concurrent signer entries exceeds `maxSigners` (default: 20), the least-recently-used entry is evicted.
415
+ 5. **Idle TTL Eviction**: A background timer (every 60s) evicts signer entries not used within `signerIdleTtlMs` (default: 5 minutes).
416
+ 6. **Local Rate Limiting**: Per-signer guard prevents re-requesting within `localRateLimitMs` (default: 2.1s) to avoid hammering the Control Plane.
417
+ 7. **Token Inclusion**: The heartbeat token is automatically included in the `signingContext` of every evaluation request.
418
+
419
+ ### Multi-Signer Support
420
+
421
+ Trading desks running 3+ bot profiles no longer experience `HEARTBEAT_MISSING` errors when switching signers. Each signer's token is cached independently:
422
+
423
+ ```typescript
424
+ // KMS wrapper automatically uses the correct signer from KeyId
425
+ const protectedKms = gate.wrapKmsClient(kmsClient);
426
+
427
+ // These calls use independent heartbeat tokens — no cross-invalidation
428
+ await protectedKms.sign({ KeyId: 'alias/bot-1', Message: tx1, ... });
429
+ await protectedKms.sign({ KeyId: 'alias/bot-2', Message: tx2, ... });
430
+ await protectedKms.sign({ KeyId: 'alias/bot-1', Message: tx3, ... }); // cache hit
431
+ ```
416
432
 
417
433
  ### Configuration
418
434
 
@@ -426,8 +442,11 @@ const gate = new GateClient({
426
442
  // Heartbeat manager uses baseUrl to infer Control Plane URL
427
443
  // Or explicitly set controlPlaneUrl if different
428
444
  controlPlaneUrl: 'https://control-plane.blockintelai.com', // Optional
429
- signerId: 'my-signer-id', // Optional: signerId for heartbeat (if known upfront)
445
+ signerId: 'my-signer-id', // Optional: default signerId for heartbeat (if known upfront)
430
446
  heartbeatRefreshIntervalSeconds: 10, // Optional: heartbeat refresh interval (default: 10s)
447
+ maxSigners: 20, // Optional: max concurrent signer entries (default: 20)
448
+ signerIdleTtlMs: 300000, // Optional: evict idle signers after this many ms (default: 5 min)
449
+ localRateLimitMs: 2100, // Optional: min ms between acquire attempts per signer (default: 2.1s)
431
450
  });
432
451
  ```
433
452
 
@@ -458,23 +477,17 @@ try {
458
477
 
459
478
  ### Heartbeat Manager API
460
479
 
461
- The heartbeat manager is internal to the SDK, but you can access it if needed:
480
+ The primary API is `getTokenForSigner()`, which handles cache lookup, on-demand acquisition, and waiting:
462
481
 
463
482
  ```typescript
464
- // Check if heartbeat is valid
465
- const isValid = gate.heartbeatManager.isValid();
466
-
467
- // Get current heartbeat token (if valid)
468
- const token = gate.heartbeatManager.getToken();
469
-
470
- // Update signer ID (called automatically when signer is known)
471
- gate.heartbeatManager.updateSignerId('new-signer-id');
483
+ // Get token for a specific signer
484
+ const token = await gate.heartbeatManager.getTokenForSigner('my-signer-id', 2000);
472
485
 
473
- // Stop heartbeat refresher (e.g., on shutdown)
486
+ // Stop heartbeat manager and clean up all timers (e.g., on shutdown)
474
487
  gate.heartbeatManager.stop();
475
488
  ```
476
489
 
477
- **Note**: The heartbeat manager automatically updates the `signerId` when using the KMS wrapper, so manual updates are typically not needed.
490
+ **Note**: The KMS wrapper automatically calls `getTokenForSigner()` with the correct signer ID extracted from `KeyId`, so manual token management is typically not needed.
478
491
 
479
492
  ## Secret Rotation
480
493
 
@@ -169,6 +169,18 @@ interface DefenseEvaluateResponseV2 {
169
169
  * Gate mode used for this evaluation
170
170
  */
171
171
  mode?: GateMode;
172
+ /**
173
+ * Gate receipt (when HARD_KMS_GATEWAY (or HARD_KMS_ATTESTED, deprecated) or receipt requested). Required for KMS signing in receipt-required mode.
174
+ */
175
+ receipt?: Record<string, unknown>;
176
+ /**
177
+ * Decision hash from receipt (SHA256 of canonical receipt payload). Used for receipt-required KMS flow.
178
+ */
179
+ decisionHash?: string;
180
+ /**
181
+ * Receipt signature (HS256:base64). Used for receipt-required KMS flow.
182
+ */
183
+ receiptSignature?: string;
172
184
  /**
173
185
  * Metadata (evaluation latency, simulation, policy hash for pinning)
174
186
  */
@@ -169,6 +169,18 @@ interface DefenseEvaluateResponseV2 {
169
169
  * Gate mode used for this evaluation
170
170
  */
171
171
  mode?: GateMode;
172
+ /**
173
+ * Gate receipt (when HARD_KMS_GATEWAY (or HARD_KMS_ATTESTED, deprecated) or receipt requested). Required for KMS signing in receipt-required mode.
174
+ */
175
+ receipt?: Record<string, unknown>;
176
+ /**
177
+ * Decision hash from receipt (SHA256 of canonical receipt payload). Used for receipt-required KMS flow.
178
+ */
179
+ decisionHash?: string;
180
+ /**
181
+ * Receipt signature (HS256:base64). Used for receipt-required KMS flow.
182
+ */
183
+ receiptSignature?: string;
172
184
  /**
173
185
  * Metadata (evaluation latency, simulation, policy hash for pinning)
174
186
  */