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.
- package/LICENSE +22 -0
- package/README.md +386 -0
- package/dist/index.cjs +1193 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +492 -0
- package/dist/index.d.ts +492 -0
- package/dist/index.js +1179 -0
- package/dist/index.js.map +1 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 BlockIntel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# BlockIntel Gate SDK
|
|
2
|
+
|
|
3
|
+
Production-grade TypeScript/Node.js SDK for [BlockIntel Gate](https://blockintel.ai) Hot Path API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @blockintel/gate-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
- Node.js >= 18.0.0 (uses global `fetch` API)
|
|
14
|
+
- TypeScript >= 5.0.0 (optional, for type definitions)
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### HMAC Authentication
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { GateClient } from '@blockintel/gate-sdk';
|
|
22
|
+
|
|
23
|
+
const gate = new GateClient({
|
|
24
|
+
baseUrl: process.env.GATE_BASE_URL!,
|
|
25
|
+
tenantId: process.env.GATE_TENANT_ID!,
|
|
26
|
+
auth: {
|
|
27
|
+
mode: 'hmac',
|
|
28
|
+
keyId: process.env.GATE_KEY_ID!,
|
|
29
|
+
secret: process.env.GATE_HMAC_SECRET!,
|
|
30
|
+
},
|
|
31
|
+
enableStepUp: true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Evaluate a transaction
|
|
35
|
+
const response = await gate.evaluate({
|
|
36
|
+
txIntent: {
|
|
37
|
+
from: '0x1234567890123456789012345678901234567890',
|
|
38
|
+
to: '0x0987654321098765432109876543210987654321',
|
|
39
|
+
value: '1000000000000000000', // 1 ETH in wei
|
|
40
|
+
data: '0x...',
|
|
41
|
+
nonce: 42,
|
|
42
|
+
gasPrice: '20000000000',
|
|
43
|
+
gasLimit: '21000',
|
|
44
|
+
chainId: 1,
|
|
45
|
+
},
|
|
46
|
+
signingContext: {
|
|
47
|
+
signerId: 'my-signer-id',
|
|
48
|
+
source: {
|
|
49
|
+
repo: 'myorg/myrepo',
|
|
50
|
+
workflow: 'deploy-production',
|
|
51
|
+
environment: 'production',
|
|
52
|
+
},
|
|
53
|
+
wallet: {
|
|
54
|
+
address: '0x1234...',
|
|
55
|
+
type: 'hardware',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (response.decision === 'ALLOW') {
|
|
61
|
+
// Proceed with transaction
|
|
62
|
+
console.log('Transaction approved:', response.correlationId);
|
|
63
|
+
} else if (response.decision === 'REQUIRE_STEP_UP') {
|
|
64
|
+
// Poll for step-up decision
|
|
65
|
+
const final = await gate.awaitStepUpDecision({
|
|
66
|
+
requestId: response.stepUp!.requestId,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (final.status === 'APPROVED') {
|
|
70
|
+
// Proceed with transaction
|
|
71
|
+
console.log('Step-up approved:', final.correlationId);
|
|
72
|
+
} else {
|
|
73
|
+
// Block transaction
|
|
74
|
+
console.log('Step-up denied or expired:', final.status);
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
// BLOCK
|
|
78
|
+
console.log('Transaction blocked:', response.reasonCodes);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### API Key Authentication
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { GateClient } from '@blockintel/gate-sdk';
|
|
86
|
+
|
|
87
|
+
const gate = new GateClient({
|
|
88
|
+
baseUrl: process.env.GATE_BASE_URL!,
|
|
89
|
+
tenantId: process.env.GATE_TENANT_ID!,
|
|
90
|
+
auth: {
|
|
91
|
+
mode: 'apiKey',
|
|
92
|
+
apiKey: process.env.GATE_API_KEY!,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const response = await gate.evaluate({
|
|
97
|
+
txIntent: {
|
|
98
|
+
from: '0x123...',
|
|
99
|
+
to: '0x456...',
|
|
100
|
+
value: '1000000000000000000',
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Step-Up Polling
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Manual polling
|
|
109
|
+
const status = await gate.getStepUpStatus({
|
|
110
|
+
requestId: 'stepup-request-id',
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
console.log('Status:', status.status); // PENDING | APPROVED | DENIED | EXPIRED
|
|
114
|
+
|
|
115
|
+
// Automatic polling with timeout
|
|
116
|
+
const result = await gate.awaitStepUpDecision({
|
|
117
|
+
requestId: 'stepup-request-id',
|
|
118
|
+
maxWaitMs: 15000, // 15 seconds
|
|
119
|
+
intervalMs: 250, // Poll every 250ms
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
console.log('Final status:', result.status);
|
|
123
|
+
console.log('Elapsed time:', result.elapsedMs, 'ms');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Polling behavior:**
|
|
127
|
+
- `404 NOT_FOUND` → request ID does not exist OR does not belong to the tenant
|
|
128
|
+
- `EXPIRED` → TTL exceeded (deterministic), even if DynamoDB TTL has not deleted the item yet
|
|
129
|
+
- `PENDING` → waiting for external approval
|
|
130
|
+
- `APPROVED | DENIED` → terminal states
|
|
131
|
+
|
|
132
|
+
## Configuration
|
|
133
|
+
|
|
134
|
+
### `GateClientConfig`
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
interface GateClientConfig {
|
|
138
|
+
baseUrl: string; // Gate Hot Path API base URL
|
|
139
|
+
tenantId: string; // Your tenant ID
|
|
140
|
+
auth: // Authentication
|
|
141
|
+
| { mode: 'hmac'; keyId: string; secret: string }
|
|
142
|
+
| { mode: 'apiKey'; apiKey: string };
|
|
143
|
+
timeoutMs?: number; // Request timeout (default: 15000ms)
|
|
144
|
+
userAgent?: string; // User agent (default: '@blockintel/gate-sdk/<version>')
|
|
145
|
+
clockSkewMs?: number; // Clock skew tolerance (default: 120000ms)
|
|
146
|
+
enableStepUp?: boolean; // Enable step-up support (default: false)
|
|
147
|
+
stepUp?: {
|
|
148
|
+
pollingIntervalMs?: number; // Polling interval (default: 250ms)
|
|
149
|
+
maxWaitMs?: number; // Max wait time (default: 15000ms)
|
|
150
|
+
treatRequireStepUpAsBlockWhenDisabled?: boolean; // Transform REQUIRE_STEP_UP to BLOCK (default: true)
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
When step-up is disabled, the SDK treats `REQUIRE_STEP_UP` as `BLOCK` by default to preserve Gate-only safety, unless the caller explicitly overrides this behavior.
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Environment Variables
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Required
|
|
162
|
+
GATE_BASE_URL=https://gate.blockintelai.net
|
|
163
|
+
GATE_TENANT_ID=your-tenant-id
|
|
164
|
+
|
|
165
|
+
# HMAC Authentication
|
|
166
|
+
GATE_KEY_ID=your-key-id
|
|
167
|
+
GATE_HMAC_SECRET=your-secret
|
|
168
|
+
|
|
169
|
+
# OR API Key Authentication
|
|
170
|
+
GATE_API_KEY=your-api-key
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## API Reference
|
|
174
|
+
|
|
175
|
+
### `GateClient.evaluate(req, opts?)`
|
|
176
|
+
|
|
177
|
+
Evaluate a transaction defense request.
|
|
178
|
+
|
|
179
|
+
**Parameters:**
|
|
180
|
+
- `req: DefenseEvaluateRequestV2` - Transaction and signing context
|
|
181
|
+
- `opts?: { requestId?: string }` - Optional request ID (auto-generated if not provided)
|
|
182
|
+
|
|
183
|
+
**Returns:** `Promise<DefenseEvaluateResponseV2>`
|
|
184
|
+
|
|
185
|
+
**Response:**
|
|
186
|
+
```typescript
|
|
187
|
+
{
|
|
188
|
+
decision: 'ALLOW' | 'BLOCK' | 'REQUIRE_STEP_UP';
|
|
189
|
+
reasonCodes: string[];
|
|
190
|
+
policyVersion?: string;
|
|
191
|
+
correlationId?: string;
|
|
192
|
+
stepUp?: {
|
|
193
|
+
requestId: string;
|
|
194
|
+
ttlSeconds?: number;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### `GateClient.getStepUpStatus(args)`
|
|
200
|
+
|
|
201
|
+
Get current step-up status.
|
|
202
|
+
|
|
203
|
+
**Parameters:**
|
|
204
|
+
- `args: { requestId: string; tenantId?: string }`
|
|
205
|
+
|
|
206
|
+
**Returns:** `Promise<StepUpStatusResponse>`
|
|
207
|
+
|
|
208
|
+
**Status Types:**
|
|
209
|
+
- `PENDING` - Waiting for decision
|
|
210
|
+
- `APPROVED` - Step-up approved
|
|
211
|
+
- `DENIED` - Step-up denied
|
|
212
|
+
- `EXPIRED` - Step-up expired (TTL exceeded)
|
|
213
|
+
|
|
214
|
+
**Polling behavior:**
|
|
215
|
+
- Returns `404 NOT_FOUND` if request ID does not exist OR does not belong to the tenant
|
|
216
|
+
- Returns `EXPIRED` deterministically if TTL exceeded, even if DynamoDB TTL has not deleted the item yet
|
|
217
|
+
|
|
218
|
+
### `GateClient.awaitStepUpDecision(args)`
|
|
219
|
+
|
|
220
|
+
Poll step-up status until decision is reached or timeout.
|
|
221
|
+
|
|
222
|
+
**Parameters:**
|
|
223
|
+
- `args: { requestId: string; maxWaitMs?: number; intervalMs?: number }`
|
|
224
|
+
|
|
225
|
+
**Returns:** `Promise<StepUpFinalResult>`
|
|
226
|
+
|
|
227
|
+
## Error Handling
|
|
228
|
+
|
|
229
|
+
The SDK uses custom error types:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import { GateError, GateErrorCode, StepUpNotConfiguredError } from '@blockintel/gate-sdk';
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
const response = await gate.evaluate({ ... });
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (error instanceof GateError) {
|
|
238
|
+
console.error('Error code:', error.code);
|
|
239
|
+
console.error('Status:', error.status);
|
|
240
|
+
console.error('Request ID:', error.requestId);
|
|
241
|
+
console.error('Correlation ID:', error.correlationId);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Error Codes:**
|
|
247
|
+
- `NETWORK_ERROR` - Network connection failed
|
|
248
|
+
- `TIMEOUT` - Request timeout
|
|
249
|
+
- `NOT_FOUND` - Resource not found (404)
|
|
250
|
+
- `UNAUTHORIZED` - Authentication failed (401)
|
|
251
|
+
- `FORBIDDEN` - Access denied (403)
|
|
252
|
+
- `RATE_LIMITED` - Rate limit exceeded (429)
|
|
253
|
+
- `SERVER_ERROR` - Server error (5xx)
|
|
254
|
+
- `INVALID_RESPONSE` - Invalid response format
|
|
255
|
+
- `STEP_UP_NOT_CONFIGURED` - Step-up required but not enabled
|
|
256
|
+
- `STEP_UP_TIMEOUT` - Step-up polling timeout
|
|
257
|
+
|
|
258
|
+
## Authentication
|
|
259
|
+
|
|
260
|
+
### HMAC v1 Signing
|
|
261
|
+
|
|
262
|
+
The SDK implements HMAC v1 signing for secure authentication:
|
|
263
|
+
|
|
264
|
+
**Signing String:**
|
|
265
|
+
```
|
|
266
|
+
<HTTP_METHOD>\n
|
|
267
|
+
<PATH>\n
|
|
268
|
+
<TENANT_ID>\n
|
|
269
|
+
<TIMESTAMP_MS>\n
|
|
270
|
+
<REQUEST_ID>\n
|
|
271
|
+
<SHA256_HEX_OF_BODY>\n
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Signature:**
|
|
275
|
+
```
|
|
276
|
+
HMAC-SHA256(secret, signingString) as hex
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Headers:**
|
|
280
|
+
- `X-GATE-TENANT-ID`
|
|
281
|
+
- `X-GATE-KEY-ID`
|
|
282
|
+
- `X-GATE-TIMESTAMP-MS`
|
|
283
|
+
- `X-GATE-REQUEST-ID`
|
|
284
|
+
- `X-GATE-SIGNATURE`
|
|
285
|
+
|
|
286
|
+
### API Key
|
|
287
|
+
|
|
288
|
+
For simpler onboarding, use API key authentication:
|
|
289
|
+
|
|
290
|
+
**Headers:**
|
|
291
|
+
- `X-API-KEY`
|
|
292
|
+
- `X-GATE-TENANT-ID`
|
|
293
|
+
- `X-GATE-REQUEST-ID`
|
|
294
|
+
- `X-GATE-TIMESTAMP-MS`
|
|
295
|
+
|
|
296
|
+
## Step-Up Flow
|
|
297
|
+
|
|
298
|
+
Step-up is a feature-flagged capability that allows Gate to defer decisions to an external approval system.
|
|
299
|
+
|
|
300
|
+
**Flow:**
|
|
301
|
+
1. SDK calls `evaluate()` → Gate returns `REQUIRE_STEP_UP`
|
|
302
|
+
2. SDK polls `/defense/stepup/status` until decision is reached
|
|
303
|
+
3. External system (Control Plane) approves/denies via separate API
|
|
304
|
+
4. SDK receives final decision: `APPROVED`, `DENIED`, or `EXPIRED`
|
|
305
|
+
|
|
306
|
+
**Important:**
|
|
307
|
+
- Hot Path **never** approves/denies step-up
|
|
308
|
+
- Approve/deny happens **only** on Control Plane
|
|
309
|
+
- SDK only polls status from Hot Path
|
|
310
|
+
- **The SDK never performs approve/deny actions. Step-up resolution is handled exclusively by the Control Plane.**
|
|
311
|
+
|
|
312
|
+
Gate-only deployments should leave step-up disabled; the SDK will never "wait" unless step-up is enabled.
|
|
313
|
+
|
|
314
|
+
**TTL Guardrails:**
|
|
315
|
+
- Default: 600 seconds
|
|
316
|
+
- Min: 300 seconds
|
|
317
|
+
- Max: 900 seconds
|
|
318
|
+
|
|
319
|
+
## Retry Logic
|
|
320
|
+
|
|
321
|
+
The SDK automatically retries failed requests:
|
|
322
|
+
|
|
323
|
+
- **Max Attempts:** 3
|
|
324
|
+
- **Retry On:** Network errors, timeouts, 429, 5xx
|
|
325
|
+
- **Never Retry On:** 4xx (except 429)
|
|
326
|
+
- **Backoff:** Exponential with jitter (100ms base, 2x factor, 800ms max)
|
|
327
|
+
|
|
328
|
+
**Request ID Stability:**
|
|
329
|
+
- Same `requestId` is used across all retries
|
|
330
|
+
- Ensures idempotency on Gate server
|
|
331
|
+
|
|
332
|
+
## Secret Rotation
|
|
333
|
+
|
|
334
|
+
For HMAC authentication, secret rotation is the customer's responsibility:
|
|
335
|
+
|
|
336
|
+
1. Update environment variable with new secret
|
|
337
|
+
2. SDK reads from config at runtime (no caching)
|
|
338
|
+
3. Restart application to use new secret
|
|
339
|
+
|
|
340
|
+
The SDK does not cache secrets across process restarts unless the user explicitly does so.
|
|
341
|
+
|
|
342
|
+
## Security
|
|
343
|
+
|
|
344
|
+
- **HTTPS Required:** SDK validates HTTPS in production (localhost exception)
|
|
345
|
+
- **Secret Protection:** Never logs secrets or API keys
|
|
346
|
+
- **Clock Skew:** Configurable tolerance for timestamp validation
|
|
347
|
+
- **Replay Protection:** Request ID + timestamp prevent replay attacks
|
|
348
|
+
|
|
349
|
+
## TypeScript Support
|
|
350
|
+
|
|
351
|
+
Full TypeScript definitions are included:
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
import type {
|
|
355
|
+
DefenseEvaluateRequestV2,
|
|
356
|
+
DefenseEvaluateResponseV2,
|
|
357
|
+
GateDecision,
|
|
358
|
+
StepUpStatusResponse,
|
|
359
|
+
GateStepUpStatus,
|
|
360
|
+
StepUpFinalResult,
|
|
361
|
+
} from '@blockintel/gate-sdk';
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Examples
|
|
365
|
+
|
|
366
|
+
See [examples](./examples) directory for complete examples:
|
|
367
|
+
- [HMAC Authentication](./examples/hmac-auth.ts)
|
|
368
|
+
- [API Key Authentication](./examples/api-key-auth.ts)
|
|
369
|
+
- [Step-Up Flow](./examples/step-up-flow.ts)
|
|
370
|
+
|
|
371
|
+
## Publishing
|
|
372
|
+
|
|
373
|
+
- Package versions are immutable once published (NPM does not allow overwriting a released version). Always bump the version before tagging a release.
|
|
374
|
+
|
|
375
|
+
See [PUBLISHING.md](./PUBLISHING.md) for detailed publishing instructions.
|
|
376
|
+
|
|
377
|
+
## License
|
|
378
|
+
|
|
379
|
+
MIT License - see [LICENSE](./LICENSE) file.
|
|
380
|
+
|
|
381
|
+
## Support
|
|
382
|
+
|
|
383
|
+
- **Documentation:** https://docs.blockintel.ai
|
|
384
|
+
- **Issues:** https://github.com/4KInc/blockintel-ai/issues
|
|
385
|
+
- **Email:** support@blockintel.ai
|
|
386
|
+
|