blockintel-gate-sdk 0.3.5 → 0.3.6
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 +0 -24
- package/dist/index.cjs +162 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -17
- package/dist/index.d.ts +29 -17
- package/dist/index.js +161 -144
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { createHash, createHmac } from 'crypto';
|
|
2
1
|
import { v4 } from 'uuid';
|
|
3
2
|
import { SignCommand } from '@aws-sdk/client-kms';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
4
4
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
7
13
|
var __esm = (fn, res) => function __init() {
|
|
8
14
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
9
15
|
};
|
|
@@ -40,24 +46,56 @@ function canonicalizeJson(obj) {
|
|
|
40
46
|
return JSON.stringify(sorted);
|
|
41
47
|
}
|
|
42
48
|
async function sha256Hex(input) {
|
|
43
|
-
|
|
49
|
+
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
50
|
+
const encoder = new TextEncoder();
|
|
51
|
+
const data = encoder.encode(input);
|
|
52
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
53
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
54
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
55
|
+
}
|
|
56
|
+
if (typeof __require !== "undefined") {
|
|
57
|
+
const crypto2 = __require("crypto");
|
|
58
|
+
return crypto2.createHash("sha256").update(input, "utf8").digest("hex");
|
|
59
|
+
}
|
|
60
|
+
throw new Error("SHA-256 not available in this environment");
|
|
44
61
|
}
|
|
45
62
|
var init_canonicalJson = __esm({
|
|
46
63
|
"src/utils/canonicalJson.ts"() {
|
|
47
64
|
}
|
|
48
65
|
});
|
|
66
|
+
|
|
67
|
+
// src/utils/crypto.ts
|
|
49
68
|
async function hmacSha256(secret, message) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
if (typeof __require !== "undefined") {
|
|
70
|
+
const crypto2 = __require("crypto");
|
|
71
|
+
const hmac = crypto2.createHmac("sha256", secret);
|
|
72
|
+
hmac.update(message, "utf8");
|
|
73
|
+
const signatureHex = hmac.digest("hex");
|
|
74
|
+
console.error("[HMAC CRYPTO DEBUG] Signature computation:", JSON.stringify({
|
|
75
|
+
secretLength: secret.length,
|
|
76
|
+
messageLength: message.length,
|
|
77
|
+
messagePreview: message.substring(0, 200) + "...",
|
|
78
|
+
signatureLength: signatureHex.length,
|
|
79
|
+
signaturePreview: signatureHex.substring(0, 16) + "..."
|
|
80
|
+
}, null, 2));
|
|
81
|
+
return signatureHex;
|
|
82
|
+
}
|
|
83
|
+
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
84
|
+
const encoder = new TextEncoder();
|
|
85
|
+
const keyData = encoder.encode(secret);
|
|
86
|
+
const messageData = encoder.encode(message);
|
|
87
|
+
const key = await crypto.subtle.importKey(
|
|
88
|
+
"raw",
|
|
89
|
+
keyData,
|
|
90
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
91
|
+
false,
|
|
92
|
+
["sign"]
|
|
93
|
+
);
|
|
94
|
+
const signature = await crypto.subtle.sign("HMAC", key, messageData);
|
|
95
|
+
const hashArray = Array.from(new Uint8Array(signature));
|
|
96
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
97
|
+
}
|
|
98
|
+
throw new Error("HMAC-SHA256 not available in this environment");
|
|
61
99
|
}
|
|
62
100
|
|
|
63
101
|
// src/auth/HmacSigner.ts
|
|
@@ -90,7 +128,26 @@ var HmacSigner = class {
|
|
|
90
128
|
// Used as nonce in canonical string
|
|
91
129
|
bodyHash
|
|
92
130
|
].join("\n");
|
|
131
|
+
console.error("[HMAC SIGNER DEBUG] Canonical request string:", JSON.stringify({
|
|
132
|
+
method: method.toUpperCase(),
|
|
133
|
+
path,
|
|
134
|
+
tenantId,
|
|
135
|
+
keyId: this.keyId,
|
|
136
|
+
timestampMs: String(timestampMs),
|
|
137
|
+
requestId,
|
|
138
|
+
bodyHash,
|
|
139
|
+
signingStringLength: signingString.length,
|
|
140
|
+
signingStringPreview: signingString.substring(0, 200) + "...",
|
|
141
|
+
bodyJsonLength: bodyJson.length,
|
|
142
|
+
bodyJsonPreview: bodyJson.substring(0, 200) + "..."
|
|
143
|
+
}, null, 2));
|
|
93
144
|
const signature = await hmacSha256(this.secret, signingString);
|
|
145
|
+
console.error("[HMAC SIGNER DEBUG] Signature computed:", JSON.stringify({
|
|
146
|
+
signatureLength: signature.length,
|
|
147
|
+
signaturePreview: signature.substring(0, 16) + "...",
|
|
148
|
+
secretLength: this.secret.length,
|
|
149
|
+
secretPreview: this.secret.substring(0, 4) + "..." + this.secret.substring(this.secret.length - 4)
|
|
150
|
+
}, null, 2));
|
|
94
151
|
return {
|
|
95
152
|
"X-GATE-TENANT-ID": tenantId,
|
|
96
153
|
"X-GATE-KEY-ID": this.keyId,
|
|
@@ -289,10 +346,6 @@ async function retryWithBackoff(fn, options = {}) {
|
|
|
289
346
|
if (!isRetryable) {
|
|
290
347
|
throw error;
|
|
291
348
|
}
|
|
292
|
-
const status = error instanceof Response && error.status || error && typeof error === "object" && "status" in error && error.status || error && typeof error === "object" && "statusCode" in error && error.statusCode;
|
|
293
|
-
const errName = error instanceof Error ? error.name : error && typeof error === "object" && "code" in error ? error.code : "Unknown";
|
|
294
|
-
const extra = ` attempt=${attempt}/${opts.maxAttempts} status=${status ?? "n/a"} err=${errName}`;
|
|
295
|
-
console.warn("[GATE SDK] X-BlockIntel-Degraded: true (reason=retry)" + extra);
|
|
296
349
|
const delay = calculateBackoffDelay(attempt, opts);
|
|
297
350
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
298
351
|
}
|
|
@@ -300,73 +353,17 @@ async function retryWithBackoff(fn, options = {}) {
|
|
|
300
353
|
throw lastError;
|
|
301
354
|
}
|
|
302
355
|
|
|
303
|
-
// src/utils/sanitize.ts
|
|
304
|
-
var SENSITIVE_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
305
|
-
"authorization",
|
|
306
|
-
"x-api-key",
|
|
307
|
-
"x-gate-heartbeat-key",
|
|
308
|
-
"x-gate-signature",
|
|
309
|
-
"cookie"
|
|
310
|
-
]);
|
|
311
|
-
var MAX_STRING_LENGTH = 80;
|
|
312
|
-
function sanitizeHeaders(headers) {
|
|
313
|
-
const out = {};
|
|
314
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
315
|
-
const lower = key.toLowerCase();
|
|
316
|
-
if (SENSITIVE_HEADER_NAMES.has(lower) || lower.includes("signature") || lower.includes("secret") || lower.includes("token")) {
|
|
317
|
-
out[key] = value ? "[REDACTED]" : "[empty]";
|
|
318
|
-
} else {
|
|
319
|
-
out[key] = truncate(String(value), MAX_STRING_LENGTH);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return out;
|
|
323
|
-
}
|
|
324
|
-
function sanitizeBodyShape(body) {
|
|
325
|
-
if (body === null || body === void 0) {
|
|
326
|
-
return {};
|
|
327
|
-
}
|
|
328
|
-
if (typeof body !== "object") {
|
|
329
|
-
return { _: typeof body };
|
|
330
|
-
}
|
|
331
|
-
if (Array.isArray(body)) {
|
|
332
|
-
return { _: "array", length: String(body.length) };
|
|
333
|
-
}
|
|
334
|
-
const out = {};
|
|
335
|
-
for (const key of Object.keys(body).sort()) {
|
|
336
|
-
const val = body[key];
|
|
337
|
-
if (val !== null && typeof val === "object" && !Array.isArray(val)) {
|
|
338
|
-
out[key] = "object";
|
|
339
|
-
} else if (Array.isArray(val)) {
|
|
340
|
-
out[key] = "array";
|
|
341
|
-
} else {
|
|
342
|
-
out[key] = typeof val;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
return out;
|
|
346
|
-
}
|
|
347
|
-
function truncate(s, max) {
|
|
348
|
-
if (s.length <= max) return s;
|
|
349
|
-
return s.slice(0, max) + "...";
|
|
350
|
-
}
|
|
351
|
-
function isDebugEnabled(debugOption) {
|
|
352
|
-
if (debugOption === true) return true;
|
|
353
|
-
if (typeof process !== "undefined" && process.env.GATE_SDK_DEBUG === "1") return true;
|
|
354
|
-
return false;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
356
|
// src/http/HttpClient.ts
|
|
358
357
|
var HttpClient = class {
|
|
359
358
|
baseUrl;
|
|
360
359
|
timeoutMs;
|
|
361
360
|
userAgent;
|
|
362
361
|
retryOptions;
|
|
363
|
-
debug;
|
|
364
362
|
constructor(config) {
|
|
365
363
|
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
366
364
|
this.timeoutMs = config.timeoutMs ?? 15e3;
|
|
367
365
|
this.userAgent = config.userAgent ?? "blockintel-gate-sdk/0.1.0";
|
|
368
366
|
this.retryOptions = config.retryOptions;
|
|
369
|
-
this.debug = isDebugEnabled(config.debug);
|
|
370
367
|
if (!this.baseUrl) {
|
|
371
368
|
throw new Error("baseUrl is required");
|
|
372
369
|
}
|
|
@@ -385,6 +382,7 @@ var HttpClient = class {
|
|
|
385
382
|
const controller = new AbortController();
|
|
386
383
|
const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
387
384
|
let requestDetailsForLogging = null;
|
|
385
|
+
let requestDetailsSet = false;
|
|
388
386
|
try {
|
|
389
387
|
const response = await retryWithBackoff(
|
|
390
388
|
async () => {
|
|
@@ -407,22 +405,31 @@ var HttpClient = class {
|
|
|
407
405
|
fetchOptions.body = JSON.stringify(body);
|
|
408
406
|
}
|
|
409
407
|
}
|
|
408
|
+
const logHeaders = {};
|
|
409
|
+
if (fetchOptions.headers) {
|
|
410
|
+
Object.entries(fetchOptions.headers).forEach(([key, value]) => {
|
|
411
|
+
if (key.toLowerCase().includes("signature") || key.toLowerCase().includes("secret")) {
|
|
412
|
+
logHeaders[key] = String(value).substring(0, 8) + "...";
|
|
413
|
+
} else {
|
|
414
|
+
logHeaders[key] = String(value);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
410
418
|
const bodyStr = typeof fetchOptions.body === "string" ? fetchOptions.body : null;
|
|
411
|
-
|
|
412
|
-
headers:
|
|
413
|
-
bodyLength: bodyStr ? bodyStr.length : 0
|
|
419
|
+
const details = {
|
|
420
|
+
headers: logHeaders,
|
|
421
|
+
bodyLength: bodyStr ? bodyStr.length : 0,
|
|
422
|
+
bodyPreview: bodyStr ? bodyStr.substring(0, 300) : null
|
|
414
423
|
};
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
}, null, 2));
|
|
425
|
-
}
|
|
424
|
+
requestDetailsForLogging = details;
|
|
425
|
+
requestDetailsSet = true;
|
|
426
|
+
console.error("[HTTP CLIENT DEBUG] Sending request:", JSON.stringify({
|
|
427
|
+
url,
|
|
428
|
+
method,
|
|
429
|
+
headers: logHeaders,
|
|
430
|
+
bodyLength: requestDetailsForLogging.bodyLength,
|
|
431
|
+
bodyPreview: requestDetailsForLogging.bodyPreview
|
|
432
|
+
}, null, 2));
|
|
426
433
|
const res = await fetch(url, fetchOptions);
|
|
427
434
|
if (!res.ok && isRetryableStatus(res.status)) {
|
|
428
435
|
throw res;
|
|
@@ -440,24 +447,26 @@ var HttpClient = class {
|
|
|
440
447
|
clearTimeout(timeoutId);
|
|
441
448
|
let data;
|
|
442
449
|
const contentType = response.headers.get("content-type");
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
+
console.error("[HTTP CLIENT DEBUG] Response received:", JSON.stringify({
|
|
451
|
+
status: response.status,
|
|
452
|
+
ok: response.ok,
|
|
453
|
+
statusText: response.statusText,
|
|
454
|
+
contentType,
|
|
455
|
+
url: response.url
|
|
456
|
+
}, null, 2));
|
|
450
457
|
if (contentType && contentType.includes("application/json")) {
|
|
451
458
|
try {
|
|
452
459
|
const jsonText = await response.text();
|
|
460
|
+
console.error("[HTTP CLIENT DEBUG] Response body (first 500 chars):", jsonText.substring(0, 500));
|
|
453
461
|
data = JSON.parse(jsonText);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
462
|
+
console.error("[HTTP CLIENT DEBUG] Parsed JSON:", JSON.stringify({
|
|
463
|
+
hasSuccess: typeof data?.success !== "undefined",
|
|
464
|
+
success: data?.success,
|
|
465
|
+
hasData: typeof data?.data !== "undefined",
|
|
466
|
+
hasError: typeof data?.error !== "undefined"
|
|
467
|
+
}, null, 2));
|
|
457
468
|
} catch (parseError) {
|
|
458
|
-
|
|
459
|
-
console.error("[GATE SDK] JSON parse error:", parseError instanceof Error ? parseError.message : String(parseError));
|
|
460
|
-
}
|
|
469
|
+
console.error("[HTTP CLIENT DEBUG] JSON parse error:", parseError);
|
|
461
470
|
throw new GateError(
|
|
462
471
|
"INVALID_RESPONSE" /* INVALID_RESPONSE */,
|
|
463
472
|
"Failed to parse JSON response",
|
|
@@ -485,12 +494,26 @@ var HttpClient = class {
|
|
|
485
494
|
response.headers.forEach((value, key) => {
|
|
486
495
|
responseHeaders[key] = value;
|
|
487
496
|
});
|
|
488
|
-
if (
|
|
489
|
-
console.error("[
|
|
497
|
+
if (response.status === 401) {
|
|
498
|
+
console.error("[HTTP CLIENT DEBUG] 401 UNAUTHORIZED - Full request details:", JSON.stringify({
|
|
490
499
|
status: response.status,
|
|
500
|
+
statusText: response.statusText,
|
|
491
501
|
url: response.url,
|
|
502
|
+
requestMethod: method,
|
|
492
503
|
requestPath: path,
|
|
493
|
-
|
|
504
|
+
requestHeaders: requestDetailsForLogging ? requestDetailsForLogging.headers : {},
|
|
505
|
+
responseHeaders,
|
|
506
|
+
responseData: data,
|
|
507
|
+
bodyLength: requestDetailsForLogging ? requestDetailsForLogging.bodyLength : 0,
|
|
508
|
+
bodyPreview: requestDetailsForLogging ? requestDetailsForLogging.bodyPreview : null
|
|
509
|
+
}, null, 2));
|
|
510
|
+
} else {
|
|
511
|
+
console.error("[HTTP CLIENT DEBUG] Response not OK:", JSON.stringify({
|
|
512
|
+
status: response.status,
|
|
513
|
+
statusText: response.statusText,
|
|
514
|
+
url: response.url,
|
|
515
|
+
headers: responseHeaders,
|
|
516
|
+
data
|
|
494
517
|
}, null, 2));
|
|
495
518
|
}
|
|
496
519
|
const errorCode = this.statusToErrorCode(response.status);
|
|
@@ -502,6 +525,7 @@ var HttpClient = class {
|
|
|
502
525
|
details: data
|
|
503
526
|
});
|
|
504
527
|
}
|
|
528
|
+
console.error("[HTTP CLIENT DEBUG] Response OK, returning data");
|
|
505
529
|
return data;
|
|
506
530
|
} catch (error) {
|
|
507
531
|
clearTimeout(timeoutId);
|
|
@@ -1060,8 +1084,6 @@ var HeartbeatManager = class {
|
|
|
1060
1084
|
// Unique per process
|
|
1061
1085
|
sdkVersion;
|
|
1062
1086
|
// SDK version for tracking
|
|
1063
|
-
apiKey;
|
|
1064
|
-
// x-gate-heartbeat-key for Control Plane auth
|
|
1065
1087
|
currentToken = null;
|
|
1066
1088
|
refreshTimer = null;
|
|
1067
1089
|
started = false;
|
|
@@ -1074,22 +1096,19 @@ var HeartbeatManager = class {
|
|
|
1074
1096
|
this.signerId = options.signerId;
|
|
1075
1097
|
this.environment = options.environment ?? "prod";
|
|
1076
1098
|
this.baseRefreshIntervalSeconds = options.refreshIntervalSeconds ?? 10;
|
|
1077
|
-
this.apiKey = options.apiKey;
|
|
1078
1099
|
this.clientInstanceId = options.clientInstanceId || v4();
|
|
1079
1100
|
this.sdkVersion = options.sdkVersion || "1.0.0";
|
|
1080
|
-
this.apiKey = options.apiKey;
|
|
1081
1101
|
}
|
|
1082
1102
|
/**
|
|
1083
|
-
* Start background heartbeat refresher
|
|
1084
|
-
* Optionally wait for initial token (first evaluate() will otherwise wait up to 2s for token).
|
|
1103
|
+
* Start background heartbeat refresher
|
|
1085
1104
|
*/
|
|
1086
|
-
start(
|
|
1105
|
+
start() {
|
|
1087
1106
|
if (this.started) {
|
|
1088
1107
|
return;
|
|
1089
1108
|
}
|
|
1090
1109
|
this.started = true;
|
|
1091
1110
|
this.acquireHeartbeat().catch((error) => {
|
|
1092
|
-
console.error("[HEARTBEAT] Failed to acquire initial heartbeat:", error
|
|
1111
|
+
console.error("[HEARTBEAT] Failed to acquire initial heartbeat:", error);
|
|
1093
1112
|
});
|
|
1094
1113
|
this.scheduleNextRefresh();
|
|
1095
1114
|
}
|
|
@@ -1172,23 +1191,12 @@ var HeartbeatManager = class {
|
|
|
1172
1191
|
/**
|
|
1173
1192
|
* Acquire a new heartbeat token from Control Plane
|
|
1174
1193
|
* NEVER logs token value (security)
|
|
1175
|
-
* Requires x-gate-heartbeat-key header (apiKey) for authentication.
|
|
1176
1194
|
*/
|
|
1177
1195
|
async acquireHeartbeat() {
|
|
1178
|
-
if (!this.apiKey || this.apiKey.length === 0) {
|
|
1179
|
-
throw new GateError(
|
|
1180
|
-
"UNAUTHORIZED" /* UNAUTHORIZED */,
|
|
1181
|
-
"Heartbeat API key is required. Set GATE_HEARTBEAT_KEY in environment or pass heartbeatApiKey in GateClientConfig.",
|
|
1182
|
-
{}
|
|
1183
|
-
);
|
|
1184
|
-
}
|
|
1185
1196
|
try {
|
|
1186
1197
|
const response = await this.httpClient.request({
|
|
1187
1198
|
method: "POST",
|
|
1188
1199
|
path: "/api/v1/gate/heartbeat",
|
|
1189
|
-
headers: {
|
|
1190
|
-
"x-gate-heartbeat-key": this.apiKey
|
|
1191
|
-
},
|
|
1192
1200
|
body: {
|
|
1193
1201
|
tenantId: this.tenantId,
|
|
1194
1202
|
signerId: this.signerId,
|
|
@@ -1516,8 +1524,7 @@ var GateClient = class {
|
|
|
1516
1524
|
this.httpClient = new HttpClient({
|
|
1517
1525
|
baseUrl: config.baseUrl,
|
|
1518
1526
|
timeoutMs: config.timeoutMs,
|
|
1519
|
-
userAgent: config.userAgent
|
|
1520
|
-
debug: config.debug
|
|
1527
|
+
userAgent: config.userAgent
|
|
1521
1528
|
});
|
|
1522
1529
|
if (config.enableStepUp) {
|
|
1523
1530
|
this.stepUpPoller = new StepUpPoller({
|
|
@@ -1538,12 +1545,6 @@ var GateClient = class {
|
|
|
1538
1545
|
console.warn("[GATE CLIENT] LOCAL MODE ENABLED - Auth, heartbeat, and break-glass are disabled");
|
|
1539
1546
|
this.heartbeatManager = null;
|
|
1540
1547
|
} else {
|
|
1541
|
-
const heartbeatApiKey = config.heartbeatApiKey ?? (typeof process !== "undefined" ? process.env.GATE_HEARTBEAT_KEY : void 0);
|
|
1542
|
-
if (!heartbeatApiKey || heartbeatApiKey.length === 0) {
|
|
1543
|
-
throw new Error(
|
|
1544
|
-
"GATE_HEARTBEAT_KEY environment variable or heartbeatApiKey in config is required for heartbeat authentication. Set GATE_HEARTBEAT_KEY in your environment or pass heartbeatApiKey in GateClientConfig."
|
|
1545
|
-
);
|
|
1546
|
-
}
|
|
1547
1548
|
let controlPlaneUrl = config.baseUrl;
|
|
1548
1549
|
if (controlPlaneUrl.includes("/defense")) {
|
|
1549
1550
|
controlPlaneUrl = controlPlaneUrl.split("/defense")[0];
|
|
@@ -1563,8 +1564,7 @@ var GateClient = class {
|
|
|
1563
1564
|
tenantId: config.tenantId,
|
|
1564
1565
|
signerId: initialSignerId,
|
|
1565
1566
|
environment: config.environment ?? "prod",
|
|
1566
|
-
refreshIntervalSeconds: config.heartbeatRefreshIntervalSeconds ?? 10
|
|
1567
|
-
apiKey: heartbeatApiKey
|
|
1567
|
+
refreshIntervalSeconds: config.heartbeatRefreshIntervalSeconds ?? 10
|
|
1568
1568
|
});
|
|
1569
1569
|
this.heartbeatManager.start();
|
|
1570
1570
|
}
|
|
@@ -1653,9 +1653,7 @@ var GateClient = class {
|
|
|
1653
1653
|
delete txIntent.from;
|
|
1654
1654
|
}
|
|
1655
1655
|
const signingContext = {
|
|
1656
|
-
...req.signingContext
|
|
1657
|
-
actorPrincipal: req.signingContext?.actorPrincipal ?? req.signingContext?.signerId ?? "gate-sdk-client",
|
|
1658
|
-
signerId: req.signingContext?.signerId ?? req.signingContext?.actorPrincipal ?? "gate-sdk-client"
|
|
1656
|
+
...req.signingContext
|
|
1659
1657
|
};
|
|
1660
1658
|
if (heartbeatToken) {
|
|
1661
1659
|
signingContext.heartbeatToken = heartbeatToken;
|
|
@@ -1671,16 +1669,17 @@ var GateClient = class {
|
|
|
1671
1669
|
};
|
|
1672
1670
|
}
|
|
1673
1671
|
let body = {
|
|
1674
|
-
tenantId: this.config.tenantId,
|
|
1675
1672
|
requestId,
|
|
1676
1673
|
timestampMs,
|
|
1677
1674
|
txIntent,
|
|
1678
1675
|
signingContext,
|
|
1679
1676
|
// Add SDK info (required by Hot Path validation)
|
|
1677
|
+
// Note: Must match Python SDK name for consistent canonical JSON
|
|
1680
1678
|
sdk: {
|
|
1681
1679
|
name: "gate-sdk",
|
|
1682
1680
|
version: "0.1.0"
|
|
1683
1681
|
},
|
|
1682
|
+
// Add mode and connection failure strategy
|
|
1684
1683
|
mode: requestMode,
|
|
1685
1684
|
onConnectionFailure: this.onConnectionFailure
|
|
1686
1685
|
};
|
|
@@ -1710,6 +1709,15 @@ var GateClient = class {
|
|
|
1710
1709
|
});
|
|
1711
1710
|
headers = { ...hmacHeaders };
|
|
1712
1711
|
body.__canonicalJson = canonicalBodyJson;
|
|
1712
|
+
const debugHeaders = {};
|
|
1713
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
1714
|
+
if (key.toLowerCase().includes("signature")) {
|
|
1715
|
+
debugHeaders[key] = value.substring(0, 8) + "...";
|
|
1716
|
+
} else {
|
|
1717
|
+
debugHeaders[key] = value;
|
|
1718
|
+
}
|
|
1719
|
+
});
|
|
1720
|
+
console.error("[GATE CLIENT DEBUG] HMAC headers prepared:", JSON.stringify(debugHeaders, null, 2));
|
|
1713
1721
|
} else if (this.apiKeyAuth) {
|
|
1714
1722
|
const apiKeyHeaders = this.apiKeyAuth.createHeaders({
|
|
1715
1723
|
tenantId: this.config.tenantId,
|
|
@@ -1717,6 +1725,7 @@ var GateClient = class {
|
|
|
1717
1725
|
requestId
|
|
1718
1726
|
});
|
|
1719
1727
|
headers = { ...apiKeyHeaders };
|
|
1728
|
+
console.error("[GATE CLIENT DEBUG] API key headers prepared:", JSON.stringify(headers, null, 2));
|
|
1720
1729
|
} else {
|
|
1721
1730
|
throw new Error("No authentication configured");
|
|
1722
1731
|
}
|
|
@@ -1850,7 +1859,6 @@ var GateClient = class {
|
|
|
1850
1859
|
tenantId: this.config.tenantId,
|
|
1851
1860
|
mode: requestMode
|
|
1852
1861
|
});
|
|
1853
|
-
console.warn("[GATE SDK] X-BlockIntel-Degraded: true (reason: fail_open)");
|
|
1854
1862
|
this.metrics.recordRequest("FAIL_OPEN", Date.now() - startTime);
|
|
1855
1863
|
return {
|
|
1856
1864
|
decision: "ALLOW",
|
|
@@ -1882,10 +1890,6 @@ var GateClient = class {
|
|
|
1882
1890
|
}
|
|
1883
1891
|
throw error;
|
|
1884
1892
|
}
|
|
1885
|
-
if (error instanceof GateError && error.code === "RATE_LIMITED" /* RATE_LIMITED */) {
|
|
1886
|
-
console.warn("[GATE SDK] X-BlockIntel-Degraded: true (reason: 429)");
|
|
1887
|
-
throw error;
|
|
1888
|
-
}
|
|
1889
1893
|
if (error instanceof BlockIntelBlockedError || error instanceof BlockIntelStepUpRequiredError) {
|
|
1890
1894
|
throw error;
|
|
1891
1895
|
}
|
|
@@ -1898,7 +1902,6 @@ var GateClient = class {
|
|
|
1898
1902
|
*/
|
|
1899
1903
|
handleFailSafe(mode, error, requestId) {
|
|
1900
1904
|
if (mode === "ALLOW_ON_TIMEOUT") {
|
|
1901
|
-
console.warn("[GATE SDK] X-BlockIntel-Degraded: true (reason: fail_safe_allow)");
|
|
1902
1905
|
return {
|
|
1903
1906
|
decision: "ALLOW",
|
|
1904
1907
|
reasonCodes: ["FAIL_SAFE_ALLOW"],
|
|
@@ -1909,7 +1912,6 @@ var GateClient = class {
|
|
|
1909
1912
|
return null;
|
|
1910
1913
|
}
|
|
1911
1914
|
if (mode === "BLOCK_ON_ANOMALY") {
|
|
1912
|
-
console.warn("[GATE SDK] X-BlockIntel-Degraded: true (reason: fail_safe_allow)");
|
|
1913
1915
|
return {
|
|
1914
1916
|
decision: "ALLOW",
|
|
1915
1917
|
reasonCodes: ["FAIL_SAFE_ALLOW"],
|
|
@@ -1984,6 +1986,21 @@ function createGateClient(config) {
|
|
|
1984
1986
|
return new GateClient(config);
|
|
1985
1987
|
}
|
|
1986
1988
|
|
|
1987
|
-
|
|
1989
|
+
// src/client/Gate.ts
|
|
1990
|
+
var Gate = class {
|
|
1991
|
+
apiKey;
|
|
1992
|
+
constructor(opts) {
|
|
1993
|
+
this.apiKey = opts?.apiKey ?? process.env.BLOCKINTEL_API_KEY;
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Guard a signing operation. In passthrough mode, executes the callback.
|
|
1997
|
+
* For full Gate integration, use GateClient with evaluate() before sending.
|
|
1998
|
+
*/
|
|
1999
|
+
async guard(_ctx, cb) {
|
|
2000
|
+
return cb();
|
|
2001
|
+
}
|
|
2002
|
+
};
|
|
2003
|
+
|
|
2004
|
+
export { BlockIntelAuthError, BlockIntelBlockedError, BlockIntelStepUpRequiredError, BlockIntelUnavailableError, Gate, GateClient, GateError, GateErrorCode, HeartbeatManager, ProvenanceProvider, StepUpNotConfiguredError, createGateClient, GateClient as default, wrapKmsClient };
|
|
1988
2005
|
//# sourceMappingURL=index.js.map
|
|
1989
2006
|
//# sourceMappingURL=index.js.map
|