blockintel-gate-sdk 0.1.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.
@@ -0,0 +1,492 @@
1
+ import * as _aws_sdk_client_kms from '@aws-sdk/client-kms';
2
+ import { SignCommandInput, KMSClient } from '@aws-sdk/client-kms';
3
+
4
+ /**
5
+ * Metrics Collector for SDK
6
+ *
7
+ * Collects counters and latency metrics for observability.
8
+ */
9
+ interface Metrics {
10
+ requestsTotal: number;
11
+ allowedTotal: number;
12
+ blockedTotal: number;
13
+ stepupTotal: number;
14
+ timeoutsTotal: number;
15
+ errorsTotal: number;
16
+ circuitBreakerOpenTotal: number;
17
+ latencyMs: number[];
18
+ }
19
+ type MetricsHook = (metrics: Metrics) => void | Promise<void>;
20
+ /**
21
+ * Metrics Collector
22
+ */
23
+ declare class MetricsCollector {
24
+ private requestsTotal;
25
+ private allowedTotal;
26
+ private blockedTotal;
27
+ private stepupTotal;
28
+ private timeoutsTotal;
29
+ private errorsTotal;
30
+ private circuitBreakerOpenTotal;
31
+ private latencyMs;
32
+ private readonly maxSamples;
33
+ private readonly hooks;
34
+ /**
35
+ * Record a request
36
+ */
37
+ recordRequest(decision: 'ALLOW' | 'BLOCK' | 'REQUIRE_STEP_UP', latencyMs: number): void;
38
+ /**
39
+ * Record a timeout
40
+ */
41
+ recordTimeout(): void;
42
+ /**
43
+ * Record an error
44
+ */
45
+ recordError(): void;
46
+ /**
47
+ * Record circuit breaker open
48
+ */
49
+ recordCircuitBreakerOpen(): void;
50
+ /**
51
+ * Get current metrics snapshot
52
+ */
53
+ getMetrics(): Metrics;
54
+ /**
55
+ * Register a metrics hook (e.g., for Prometheus/OpenTelemetry export)
56
+ */
57
+ registerHook(hook: MetricsHook): void;
58
+ /**
59
+ * Emit metrics to all registered hooks
60
+ */
61
+ private emitMetrics;
62
+ /**
63
+ * Reset all metrics
64
+ */
65
+ reset(): void;
66
+ }
67
+
68
+ /**
69
+ * BlockIntel Gate SDK - Type Contracts
70
+ *
71
+ * Type definitions for Gate Hot Path API v2 contracts.
72
+ * Internal SDK uses camelCase; mapping to/from API snake_case is handled internally.
73
+ */
74
+ /**
75
+ * Transaction intent structure for evaluate request
76
+ */
77
+ interface TransactionIntentV2 {
78
+ from: string;
79
+ to: string;
80
+ value?: string;
81
+ data?: string;
82
+ nonce?: number | string;
83
+ gasPrice?: string;
84
+ gasLimit?: string;
85
+ chainId?: number | string;
86
+ [key: string]: unknown;
87
+ }
88
+ /**
89
+ * Signing context metadata
90
+ */
91
+ interface SigningContext {
92
+ signerId?: string;
93
+ source?: {
94
+ repo?: string;
95
+ workflow?: string;
96
+ environment?: string;
97
+ [key: string]: unknown;
98
+ };
99
+ wallet?: {
100
+ address: string;
101
+ type?: string;
102
+ [key: string]: unknown;
103
+ };
104
+ [key: string]: unknown;
105
+ }
106
+ /**
107
+ * Defense evaluate request (v2)
108
+ */
109
+ interface DefenseEvaluateRequestV2 {
110
+ txIntent: TransactionIntentV2;
111
+ signingContext?: SigningContext;
112
+ requestId?: string;
113
+ timestampMs?: number;
114
+ }
115
+ /**
116
+ * Gate decision types
117
+ */
118
+ type GateDecision = 'ALLOW' | 'BLOCK' | 'REQUIRE_STEP_UP';
119
+ /**
120
+ * Step-up metadata in evaluate response
121
+ */
122
+ interface StepUpMetadata {
123
+ requestId: string;
124
+ ttlSeconds?: number;
125
+ }
126
+ /**
127
+ * Defense evaluate response (v2)
128
+ */
129
+ interface DefenseEvaluateResponseV2 {
130
+ decision: GateDecision;
131
+ reasonCodes: string[];
132
+ policyVersion?: string;
133
+ correlationId?: string;
134
+ stepUp?: StepUpMetadata;
135
+ }
136
+ /**
137
+ * Step-up status types
138
+ */
139
+ type GateStepUpStatus = 'PENDING' | 'APPROVED' | 'DENIED' | 'EXPIRED';
140
+ /**
141
+ * Step-up status response
142
+ */
143
+ interface StepUpStatusResponse {
144
+ status: GateStepUpStatus;
145
+ tenantId: string;
146
+ requestId: string;
147
+ decision?: string;
148
+ reasonCodes?: string[];
149
+ correlationId?: string;
150
+ expiresAtMs?: number;
151
+ ttl?: number;
152
+ }
153
+ /**
154
+ * Final result from awaitStepUpDecision
155
+ */
156
+ interface StepUpFinalResult {
157
+ status: GateStepUpStatus;
158
+ requestId: string;
159
+ elapsedMs: number;
160
+ decision?: string;
161
+ reasonCodes?: string[];
162
+ correlationId?: string;
163
+ }
164
+ /**
165
+ * Fail-safe mode for SDK
166
+ */
167
+ type FailSafeMode = 'ALLOW_ON_TIMEOUT' | 'BLOCK_ON_TIMEOUT' | 'BLOCK_ON_ANOMALY';
168
+ /**
169
+ * Circuit breaker configuration
170
+ */
171
+ interface CircuitBreakerConfig$1 {
172
+ tripAfterConsecutiveFailures?: number;
173
+ coolDownMs?: number;
174
+ }
175
+ /**
176
+ * SDK client configuration
177
+ */
178
+ interface GateClientConfig {
179
+ baseUrl: string;
180
+ tenantId: string;
181
+ auth: {
182
+ mode: 'hmac';
183
+ keyId: string;
184
+ secret: string;
185
+ } | {
186
+ mode: 'apiKey';
187
+ apiKey: string;
188
+ };
189
+ timeoutMs?: number;
190
+ userAgent?: string;
191
+ clockSkewMs?: number;
192
+ retries?: number;
193
+ failSafeMode?: FailSafeMode;
194
+ circuitBreaker?: CircuitBreakerConfig$1;
195
+ enableStepUp?: boolean;
196
+ stepUp?: {
197
+ pollingIntervalMs?: number;
198
+ maxWaitMs?: number;
199
+ treatRequireStepUpAsBlockWhenDisabled?: boolean;
200
+ };
201
+ onMetrics?: (metrics: Metrics) => void | Promise<void>;
202
+ }
203
+
204
+ /**
205
+ * Circuit Breaker for SDK
206
+ *
207
+ * Prevents cascading failures by opening the circuit after consecutive failures.
208
+ */
209
+ type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
210
+ interface CircuitBreakerConfig {
211
+ tripAfterConsecutiveFailures?: number;
212
+ coolDownMs?: number;
213
+ }
214
+ interface CircuitBreakerMetrics {
215
+ failures: number;
216
+ successes: number;
217
+ state: CircuitState;
218
+ lastFailureTime?: number;
219
+ lastSuccessTime?: number;
220
+ tripsToOpen: number;
221
+ }
222
+ /**
223
+ * Circuit Breaker implementation
224
+ */
225
+ declare class CircuitBreaker {
226
+ private state;
227
+ private failures;
228
+ private successes;
229
+ private lastFailureTime?;
230
+ private lastSuccessTime?;
231
+ private tripsToOpen;
232
+ private readonly tripThreshold;
233
+ private readonly coolDownMs;
234
+ constructor(config?: CircuitBreakerConfig);
235
+ /**
236
+ * Execute function with circuit breaker protection
237
+ */
238
+ execute<T>(fn: () => Promise<T>): Promise<T>;
239
+ private onSuccess;
240
+ private onFailure;
241
+ /**
242
+ * Get current metrics
243
+ */
244
+ getMetrics(): CircuitBreakerMetrics;
245
+ /**
246
+ * Reset circuit breaker to CLOSED state
247
+ */
248
+ reset(): void;
249
+ }
250
+
251
+ /**
252
+ * BlockIntel Gate SDK - AWS SDK v3 KMS Wrapper
253
+ *
254
+ * Wraps AWS SDK v3 KMSClient to intercept SignCommand calls and enforce Gate policies.
255
+ */
256
+
257
+ /**
258
+ * KMS wrapper options
259
+ */
260
+ interface WrapKmsClientOptions {
261
+ /**
262
+ * Wrapper mode
263
+ * - "enforce": Block if Gate denies, require step-up approval
264
+ * - "dry-run": Evaluate but always allow KMS call (for testing)
265
+ */
266
+ mode?: 'enforce' | 'dry-run';
267
+ /**
268
+ * Callback invoked when a decision is made
269
+ */
270
+ onDecision?: (decision: 'ALLOW' | 'BLOCK' | 'REQUIRE_STEP_UP', details: any) => void;
271
+ /**
272
+ * Custom hook to extract transaction intent from SignCommand
273
+ * If not provided, uses default extraction (minimal txIntent from message hash)
274
+ */
275
+ extractTxIntent?: (command: SignCommandInput) => {
276
+ toAddress?: string;
277
+ networkFamily?: 'EVM' | 'BTC' | 'SOL' | 'OTHER';
278
+ chainId?: number;
279
+ [key: string]: any;
280
+ };
281
+ }
282
+ /**
283
+ * Wrapped KMS client type (proxy that intercepts send calls)
284
+ */
285
+ interface WrappedKmsClient extends KMSClient {
286
+ /**
287
+ * Intercepted send method (overrides KMSClient.send)
288
+ */
289
+ send<T>(command: T): Promise<any>;
290
+ /**
291
+ * Original KMS client (for fallback or direct access)
292
+ */
293
+ _originalClient: KMSClient;
294
+ /**
295
+ * Gate client used for evaluation
296
+ */
297
+ _gateClient: GateClient;
298
+ /**
299
+ * Wrapper options
300
+ */
301
+ _wrapperOptions: Required<WrapKmsClientOptions>;
302
+ }
303
+ /**
304
+ * Wrap AWS SDK v3 KMS client to intercept SignCommand calls
305
+ *
306
+ * @param kmsClient - AWS SDK v3 KMSClient instance
307
+ * @param gateClient - Gate client for evaluation
308
+ * @param options - Wrapper options
309
+ * @returns Proxy object that intercepts send() calls
310
+ *
311
+ * @example
312
+ * ```typescript
313
+ * import { KMSClient } from '@aws-sdk/client-kms';
314
+ * import { GateClient, wrapKmsClient } from 'blockintel-gate-sdk';
315
+ *
316
+ * const kms = new KMSClient({});
317
+ * const gate = new GateClient({
318
+ * baseUrl: process.env.GATE_BASE_URL!,
319
+ * tenantId: process.env.GATE_TENANT_ID!,
320
+ * auth: { mode: 'hmac', keyId: process.env.GATE_KEY_ID!, secret: process.env.GATE_HMAC_SECRET! },
321
+ * });
322
+ *
323
+ * const protectedKms = wrapKmsClient(kms, gate);
324
+ *
325
+ * // Now calls to protectedKms.send(new SignCommand(...)) will be intercepted
326
+ * const result = await protectedKms.send(new SignCommand({
327
+ * KeyId: 'alias/my-key',
328
+ * Message: Buffer.from('...'),
329
+ * MessageType: 'RAW',
330
+ * SigningAlgorithm: 'ECDSA_SHA_256',
331
+ * }));
332
+ * ```
333
+ */
334
+ declare function wrapKmsClient(kmsClient: KMSClient, gateClient: GateClient, options?: WrapKmsClientOptions): WrappedKmsClient;
335
+
336
+ /**
337
+ * Gate Client for Hot Path API
338
+ */
339
+ declare class GateClient {
340
+ private readonly config;
341
+ private readonly httpClient;
342
+ private readonly hmacSigner?;
343
+ private readonly apiKeyAuth?;
344
+ private readonly stepUpPoller?;
345
+ private readonly circuitBreaker?;
346
+ private readonly metrics;
347
+ constructor(config: GateClientConfig);
348
+ /**
349
+ * Evaluate a transaction defense request
350
+ *
351
+ * Implements:
352
+ * - Circuit breaker protection
353
+ * - Fail-safe modes (ALLOW_ON_TIMEOUT, BLOCK_ON_TIMEOUT, BLOCK_ON_ANOMALY)
354
+ * - Metrics collection
355
+ * - Error handling (BLOCK → BlockIntelBlockedError, REQUIRE_STEP_UP → BlockIntelStepUpRequiredError)
356
+ */
357
+ evaluate(req: DefenseEvaluateRequestV2, opts?: {
358
+ requestId?: string;
359
+ }): Promise<DefenseEvaluateResponseV2>;
360
+ /**
361
+ * Handle fail-safe modes for timeouts/errors
362
+ */
363
+ private handleFailSafe;
364
+ /**
365
+ * Get current metrics
366
+ */
367
+ getMetrics(): ReturnType<MetricsCollector['getMetrics']>;
368
+ /**
369
+ * Get circuit breaker metrics (if enabled)
370
+ */
371
+ getCircuitBreakerMetrics(): ReturnType<CircuitBreaker['getMetrics']> | null;
372
+ /**
373
+ * Get step-up status
374
+ */
375
+ getStepUpStatus(args: {
376
+ requestId: string;
377
+ tenantId?: string;
378
+ }): Promise<StepUpStatusResponse>;
379
+ /**
380
+ * Wait for step-up decision with polling
381
+ */
382
+ awaitStepUpDecision(args: {
383
+ requestId: string;
384
+ maxWaitMs?: number;
385
+ intervalMs?: number;
386
+ }): Promise<StepUpFinalResult>;
387
+ /**
388
+ * Wrap AWS SDK v3 KMS client to intercept SignCommand calls
389
+ *
390
+ * @param kmsClient - AWS SDK v3 KMSClient instance
391
+ * @param options - Wrapper options
392
+ * @returns Wrapped KMS client that enforces Gate policies
393
+ *
394
+ * @example
395
+ * ```typescript
396
+ * import { KMSClient } from '@aws-sdk/client-kms';
397
+ *
398
+ * const kms = new KMSClient({});
399
+ * const protectedKms = gateClient.wrapKmsClient(kms);
400
+ *
401
+ * // Now SignCommand calls will be intercepted and evaluated by Gate
402
+ * const result = await protectedKms.send(new SignCommand({ ... }));
403
+ * ```
404
+ */
405
+ wrapKmsClient<T extends typeof _aws_sdk_client_kms.KMSClient>(kmsClient: InstanceType<T>, options?: WrapKmsClientOptions): WrappedKmsClient;
406
+ }
407
+ /**
408
+ * Create a Gate client instance
409
+ */
410
+ declare function createGateClient(config: GateClientConfig): GateClient;
411
+
412
+ /**
413
+ * BlockIntel Gate SDK - Error Types
414
+ */
415
+ /**
416
+ * Gate error codes
417
+ */
418
+ declare enum GateErrorCode {
419
+ NETWORK_ERROR = "NETWORK_ERROR",
420
+ TIMEOUT = "TIMEOUT",
421
+ NOT_FOUND = "NOT_FOUND",
422
+ UNAUTHORIZED = "UNAUTHORIZED",
423
+ FORBIDDEN = "FORBIDDEN",
424
+ RATE_LIMITED = "RATE_LIMITED",
425
+ SERVER_ERROR = "SERVER_ERROR",
426
+ INVALID_RESPONSE = "INVALID_RESPONSE",
427
+ STEP_UP_NOT_CONFIGURED = "STEP_UP_NOT_CONFIGURED",
428
+ STEP_UP_TIMEOUT = "STEP_UP_TIMEOUT",
429
+ BLOCKED = "BLOCKED",
430
+ SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
431
+ AUTH_ERROR = "AUTH_ERROR"
432
+ }
433
+ /**
434
+ * Base Gate error class
435
+ */
436
+ declare class GateError extends Error {
437
+ readonly code: GateErrorCode;
438
+ readonly status?: number;
439
+ readonly details?: Record<string, unknown>;
440
+ readonly requestId?: string;
441
+ readonly correlationId?: string;
442
+ constructor(code: GateErrorCode, message: string, options?: {
443
+ status?: number;
444
+ details?: Record<string, unknown>;
445
+ requestId?: string;
446
+ correlationId?: string;
447
+ cause?: Error;
448
+ });
449
+ toJSON(): Record<string, unknown>;
450
+ }
451
+ /**
452
+ * Step-up not configured error
453
+ * Thrown when REQUIRE_STEP_UP is returned but SDK is not configured for step-up
454
+ */
455
+ declare class StepUpNotConfiguredError extends GateError {
456
+ constructor(requestId?: string);
457
+ }
458
+ /**
459
+ * Blocked error
460
+ * Thrown when transaction is BLOCKED by Gate
461
+ */
462
+ declare class BlockIntelBlockedError extends GateError {
463
+ readonly receiptId?: string;
464
+ readonly reasonCode: string;
465
+ constructor(reasonCode: string, receiptId?: string, correlationId?: string, requestId?: string);
466
+ }
467
+ /**
468
+ * Service unavailable error
469
+ * Thrown when fail-safe mode is BLOCK_ON_TIMEOUT and service is unavailable
470
+ */
471
+ declare class BlockIntelUnavailableError extends GateError {
472
+ constructor(message: string, requestId?: string);
473
+ }
474
+ /**
475
+ * Auth error
476
+ * Thrown on 401/403 - always fails CLOSED (never silently allows)
477
+ */
478
+ declare class BlockIntelAuthError extends GateError {
479
+ constructor(message: string, status: number, requestId?: string);
480
+ }
481
+ /**
482
+ * Step-up required error
483
+ * Thrown when REQUIRE_STEP_UP is returned and step-up is enabled
484
+ */
485
+ declare class BlockIntelStepUpRequiredError extends GateError {
486
+ readonly stepUpRequestId: string;
487
+ readonly statusUrl?: string;
488
+ readonly expiresAtMs?: number;
489
+ constructor(stepUpRequestId: string, statusUrl?: string, expiresAtMs?: number, requestId?: string);
490
+ }
491
+
492
+ export { BlockIntelAuthError, BlockIntelBlockedError, BlockIntelStepUpRequiredError, BlockIntelUnavailableError, type DefenseEvaluateRequestV2, type DefenseEvaluateResponseV2, GateClient, type GateClientConfig, type GateDecision, GateError, GateErrorCode, type GateStepUpStatus, type SigningContext, type StepUpFinalResult, type StepUpMetadata, StepUpNotConfiguredError, type StepUpStatusResponse, type TransactionIntentV2, type WrapKmsClientOptions, type WrappedKmsClient, createGateClient, GateClient as default, wrapKmsClient };