@alter-ai/alter-sdk 0.2.2 → 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 +132 -51
- package/dist/index.cjs +543 -80
- package/dist/index.d.cts +100 -18
- package/dist/index.d.ts +100 -18
- package/dist/index.js +529 -80
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import { createHash as createHash2, createHmac as createHmac2, randomUUID } from "crypto";
|
|
3
|
+
|
|
1
4
|
// src/exceptions.ts
|
|
2
5
|
var AlterSDKError = class extends Error {
|
|
3
6
|
details;
|
|
@@ -42,6 +45,18 @@ var TokenExpiredError = class extends TokenRetrievalError {
|
|
|
42
45
|
this.connectionId = connectionId;
|
|
43
46
|
}
|
|
44
47
|
};
|
|
48
|
+
var ConnectFlowError = class extends AlterSDKError {
|
|
49
|
+
constructor(message, details) {
|
|
50
|
+
super(message, details);
|
|
51
|
+
this.name = "ConnectFlowError";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var ConnectTimeoutError = class extends ConnectFlowError {
|
|
55
|
+
constructor(message, details) {
|
|
56
|
+
super(message, details);
|
|
57
|
+
this.name = "ConnectTimeoutError";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
45
60
|
var ProviderAPIError = class extends AlterSDKError {
|
|
46
61
|
statusCode;
|
|
47
62
|
responseBody;
|
|
@@ -66,6 +81,12 @@ var TimeoutError = class extends NetworkError {
|
|
|
66
81
|
};
|
|
67
82
|
|
|
68
83
|
// src/models.ts
|
|
84
|
+
var ActorType = /* @__PURE__ */ ((ActorType2) => {
|
|
85
|
+
ActorType2["BACKEND_SERVICE"] = "backend_service";
|
|
86
|
+
ActorType2["AI_AGENT"] = "ai_agent";
|
|
87
|
+
ActorType2["MCP_SERVER"] = "mcp_server";
|
|
88
|
+
return ActorType2;
|
|
89
|
+
})(ActorType || {});
|
|
69
90
|
var TokenResponse = class _TokenResponse {
|
|
70
91
|
/** Token type (usually "Bearer") */
|
|
71
92
|
tokenType;
|
|
@@ -77,12 +98,29 @@ var TokenResponse = class _TokenResponse {
|
|
|
77
98
|
scopes;
|
|
78
99
|
/** Connection ID that provided this token */
|
|
79
100
|
connectionId;
|
|
101
|
+
/** Provider ID (google, github, etc.) */
|
|
102
|
+
providerId;
|
|
103
|
+
/** HTTP header name for credential injection (e.g., "Authorization", "X-API-Key") */
|
|
104
|
+
injectionHeader;
|
|
105
|
+
/** Header value format with {token} placeholder (e.g., "Bearer {token}", "{token}") */
|
|
106
|
+
injectionFormat;
|
|
107
|
+
/** Extra credentials for multi-part auth (e.g. AWS SigV4 secret_key, region) */
|
|
108
|
+
additionalCredentials;
|
|
80
109
|
constructor(data) {
|
|
81
110
|
this.tokenType = data.token_type ?? "Bearer";
|
|
82
111
|
this.expiresIn = data.expires_in ?? null;
|
|
83
112
|
this.expiresAt = data.expires_at ? _TokenResponse.parseExpiresAt(data.expires_at) : null;
|
|
84
113
|
this.scopes = data.scopes ?? [];
|
|
85
114
|
this.connectionId = data.connection_id;
|
|
115
|
+
this.providerId = data.provider_id ?? "";
|
|
116
|
+
this.injectionHeader = data.injection_header ?? "Authorization";
|
|
117
|
+
this.injectionFormat = data.injection_format ?? "Bearer {token}";
|
|
118
|
+
if (data.additional_credentials) {
|
|
119
|
+
const { secret_key: _, ...safeCredentials } = data.additional_credentials;
|
|
120
|
+
this.additionalCredentials = Object.keys(safeCredentials).length > 0 ? safeCredentials : null;
|
|
121
|
+
} else {
|
|
122
|
+
this.additionalCredentials = null;
|
|
123
|
+
}
|
|
86
124
|
Object.freeze(this);
|
|
87
125
|
}
|
|
88
126
|
/**
|
|
@@ -147,7 +185,6 @@ var TokenResponse = class _TokenResponse {
|
|
|
147
185
|
var ConnectionInfo = class {
|
|
148
186
|
id;
|
|
149
187
|
providerId;
|
|
150
|
-
attributes;
|
|
151
188
|
scopes;
|
|
152
189
|
accountIdentifier;
|
|
153
190
|
accountDisplayName;
|
|
@@ -158,7 +195,6 @@ var ConnectionInfo = class {
|
|
|
158
195
|
constructor(data) {
|
|
159
196
|
this.id = data.id;
|
|
160
197
|
this.providerId = data.provider_id;
|
|
161
|
-
this.attributes = data.attributes ?? {};
|
|
162
198
|
this.scopes = data.scopes ?? [];
|
|
163
199
|
this.accountIdentifier = data.account_identifier ?? null;
|
|
164
200
|
this.accountDisplayName = data.account_display_name ?? null;
|
|
@@ -172,7 +208,6 @@ var ConnectionInfo = class {
|
|
|
172
208
|
return {
|
|
173
209
|
id: this.id,
|
|
174
210
|
provider_id: this.providerId,
|
|
175
|
-
attributes: this.attributes,
|
|
176
211
|
scopes: this.scopes,
|
|
177
212
|
account_identifier: this.accountIdentifier,
|
|
178
213
|
account_display_name: this.accountDisplayName,
|
|
@@ -225,12 +260,38 @@ var ConnectionListResult = class {
|
|
|
225
260
|
Object.freeze(this);
|
|
226
261
|
}
|
|
227
262
|
};
|
|
263
|
+
var ConnectResult = class {
|
|
264
|
+
connectionId;
|
|
265
|
+
providerId;
|
|
266
|
+
accountIdentifier;
|
|
267
|
+
scopes;
|
|
268
|
+
constructor(data) {
|
|
269
|
+
this.connectionId = data.connection_id;
|
|
270
|
+
this.providerId = data.provider_id;
|
|
271
|
+
this.accountIdentifier = data.account_identifier ?? null;
|
|
272
|
+
this.scopes = data.scopes ?? [];
|
|
273
|
+
Object.freeze(this);
|
|
274
|
+
}
|
|
275
|
+
toJSON() {
|
|
276
|
+
return {
|
|
277
|
+
connection_id: this.connectionId,
|
|
278
|
+
provider_id: this.providerId,
|
|
279
|
+
account_identifier: this.accountIdentifier,
|
|
280
|
+
scopes: this.scopes
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
toString() {
|
|
284
|
+
return `ConnectResult(connection_id=${this.connectionId}, provider=${this.providerId})`;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
228
287
|
var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
|
|
229
288
|
"authorization",
|
|
230
289
|
"cookie",
|
|
231
290
|
"set-cookie",
|
|
232
291
|
"x-api-key",
|
|
233
|
-
"x-auth-token"
|
|
292
|
+
"x-auth-token",
|
|
293
|
+
"x-amz-date",
|
|
294
|
+
"x-amz-content-sha256"
|
|
234
295
|
]);
|
|
235
296
|
var APICallAuditLog = class {
|
|
236
297
|
connectionId;
|
|
@@ -304,11 +365,171 @@ var APICallAuditLog = class {
|
|
|
304
365
|
}
|
|
305
366
|
};
|
|
306
367
|
|
|
368
|
+
// src/aws-sig-v4.ts
|
|
369
|
+
import { createHash, createHmac } from "crypto";
|
|
370
|
+
var ALGORITHM = "AWS4-HMAC-SHA256";
|
|
371
|
+
var AWS_HOST_RE = /^(?<service>[a-z0-9-]+)\.(?<region>[a-z]{2}(?:-[a-z0-9]+)+-\d+)\.amazonaws\.com$/;
|
|
372
|
+
var S3_VIRTUAL_HOST_RE = /^[^.]+\.s3\.(?<region>[a-z]{2}(?:-[a-z0-9]+)+-\d+)\.amazonaws\.com$/;
|
|
373
|
+
function hmacSha256(key, message) {
|
|
374
|
+
return createHmac("sha256", key).update(message, "utf8").digest();
|
|
375
|
+
}
|
|
376
|
+
function sha256Hex(data) {
|
|
377
|
+
const hash = createHash("sha256");
|
|
378
|
+
if (typeof data === "string") {
|
|
379
|
+
hash.update(data, "utf8");
|
|
380
|
+
} else {
|
|
381
|
+
hash.update(data);
|
|
382
|
+
}
|
|
383
|
+
return hash.digest("hex");
|
|
384
|
+
}
|
|
385
|
+
function detectServiceAndRegion(hostname) {
|
|
386
|
+
const lower = hostname.toLowerCase();
|
|
387
|
+
const m = AWS_HOST_RE.exec(lower);
|
|
388
|
+
if (m?.groups) {
|
|
389
|
+
return { service: m.groups.service, region: m.groups.region };
|
|
390
|
+
}
|
|
391
|
+
const s3m = S3_VIRTUAL_HOST_RE.exec(lower);
|
|
392
|
+
if (s3m?.groups) {
|
|
393
|
+
return { service: "s3", region: s3m.groups.region };
|
|
394
|
+
}
|
|
395
|
+
return { service: null, region: null };
|
|
396
|
+
}
|
|
397
|
+
function deriveSigningKey(secretKey, dateStamp, region, service) {
|
|
398
|
+
const kDate = hmacSha256(Buffer.from("AWS4" + secretKey, "utf8"), dateStamp);
|
|
399
|
+
const kRegion = hmacSha256(kDate, region);
|
|
400
|
+
const kService = hmacSha256(kRegion, service);
|
|
401
|
+
const kSigning = hmacSha256(kService, "aws4_request");
|
|
402
|
+
return kSigning;
|
|
403
|
+
}
|
|
404
|
+
function canonicalUri(path) {
|
|
405
|
+
if (!path) return "/";
|
|
406
|
+
if (!path.startsWith("/")) path = "/" + path;
|
|
407
|
+
const segments = path.split("/");
|
|
408
|
+
return segments.map(
|
|
409
|
+
(seg) => encodeURIComponent(seg).replace(
|
|
410
|
+
/[!'()*]/g,
|
|
411
|
+
(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
|
|
412
|
+
)
|
|
413
|
+
).join("/");
|
|
414
|
+
}
|
|
415
|
+
function canonicalQueryString(query) {
|
|
416
|
+
if (!query) return "";
|
|
417
|
+
const sorted = [];
|
|
418
|
+
for (const pair of query.split("&")) {
|
|
419
|
+
const eqIdx = pair.indexOf("=");
|
|
420
|
+
if (eqIdx === -1) {
|
|
421
|
+
sorted.push([decodeURIComponent(pair), ""]);
|
|
422
|
+
} else {
|
|
423
|
+
sorted.push([
|
|
424
|
+
decodeURIComponent(pair.slice(0, eqIdx)),
|
|
425
|
+
decodeURIComponent(pair.slice(eqIdx + 1))
|
|
426
|
+
]);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
sorted.sort((a, b) => {
|
|
430
|
+
if (a[0] < b[0]) return -1;
|
|
431
|
+
if (a[0] > b[0]) return 1;
|
|
432
|
+
if (a[1] < b[1]) return -1;
|
|
433
|
+
if (a[1] > b[1]) return 1;
|
|
434
|
+
return 0;
|
|
435
|
+
});
|
|
436
|
+
const sigv4Encode = (s) => encodeURIComponent(s).replace(
|
|
437
|
+
/[!'()*]/g,
|
|
438
|
+
(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
|
|
439
|
+
);
|
|
440
|
+
return sorted.map(([k, v]) => `${sigv4Encode(k)}=${sigv4Encode(v)}`).join("&");
|
|
441
|
+
}
|
|
442
|
+
function canonicalHeadersAndSigned(headers) {
|
|
443
|
+
const canonical = {};
|
|
444
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
445
|
+
const lowerName = name.toLowerCase().trim();
|
|
446
|
+
const trimmedValue = value.replace(/\s+/g, " ").trim();
|
|
447
|
+
canonical[lowerName] = trimmedValue;
|
|
448
|
+
}
|
|
449
|
+
const sortedNames = Object.keys(canonical).sort();
|
|
450
|
+
const canonicalStr = sortedNames.map((name) => `${name}:${canonical[name]}
|
|
451
|
+
`).join("");
|
|
452
|
+
const signedStr = sortedNames.join(";");
|
|
453
|
+
return { canonicalHeaders: canonicalStr, signedHeaders: signedStr };
|
|
454
|
+
}
|
|
455
|
+
function signAwsRequest(opts) {
|
|
456
|
+
const parsed = new URL(opts.url);
|
|
457
|
+
const hostname = parsed.hostname;
|
|
458
|
+
let { region, service } = opts;
|
|
459
|
+
if (region == null || service == null) {
|
|
460
|
+
const detected = detectServiceAndRegion(hostname);
|
|
461
|
+
if (region == null) region = detected.region;
|
|
462
|
+
if (service == null) service = detected.service;
|
|
463
|
+
}
|
|
464
|
+
if (!region) {
|
|
465
|
+
throw new Error(
|
|
466
|
+
`Cannot determine AWS region from URL '${opts.url}'. Pass region explicitly via additional_credentials.`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
if (!service) {
|
|
470
|
+
throw new Error(
|
|
471
|
+
`Cannot determine AWS service from URL '${opts.url}'. Pass service explicitly via additional_credentials.`
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
const timestamp = opts.timestamp ?? /* @__PURE__ */ new Date();
|
|
475
|
+
const amzDate = timestamp.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
476
|
+
const dateStamp = amzDate.slice(0, 8);
|
|
477
|
+
const bodyBytes = opts.body != null ? typeof opts.body === "string" ? Buffer.from(opts.body, "utf8") : opts.body : Buffer.alloc(0);
|
|
478
|
+
const payloadHash = sha256Hex(bodyBytes);
|
|
479
|
+
const headersToSign = {};
|
|
480
|
+
const hasHost = Object.keys(opts.headers).some(
|
|
481
|
+
(k) => k.toLowerCase() === "host"
|
|
482
|
+
);
|
|
483
|
+
if (!hasHost) {
|
|
484
|
+
const port = parsed.port;
|
|
485
|
+
headersToSign["host"] = port && port !== "80" && port !== "443" ? `${hostname}:${port}` : hostname;
|
|
486
|
+
} else {
|
|
487
|
+
for (const [k, v] of Object.entries(opts.headers)) {
|
|
488
|
+
if (k.toLowerCase() === "host") {
|
|
489
|
+
headersToSign["host"] = v;
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
headersToSign["x-amz-date"] = amzDate;
|
|
495
|
+
headersToSign["x-amz-content-sha256"] = payloadHash;
|
|
496
|
+
const canonicalUriStr = canonicalUri(parsed.pathname);
|
|
497
|
+
const canonicalQs = canonicalQueryString(parsed.search.replace(/^\?/, ""));
|
|
498
|
+
const { canonicalHeaders, signedHeaders } = canonicalHeadersAndSigned(headersToSign);
|
|
499
|
+
const canonicalRequest = [
|
|
500
|
+
opts.method.toUpperCase(),
|
|
501
|
+
canonicalUriStr,
|
|
502
|
+
canonicalQs,
|
|
503
|
+
canonicalHeaders,
|
|
504
|
+
signedHeaders,
|
|
505
|
+
payloadHash
|
|
506
|
+
].join("\n");
|
|
507
|
+
const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
|
|
508
|
+
const stringToSign = [
|
|
509
|
+
ALGORITHM,
|
|
510
|
+
amzDate,
|
|
511
|
+
credentialScope,
|
|
512
|
+
sha256Hex(canonicalRequest)
|
|
513
|
+
].join("\n");
|
|
514
|
+
const signingKey = deriveSigningKey(opts.secretKey, dateStamp, region, service);
|
|
515
|
+
const signature = createHmac("sha256", signingKey).update(stringToSign, "utf8").digest("hex");
|
|
516
|
+
const authorization = `${ALGORITHM} Credential=${opts.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
517
|
+
return {
|
|
518
|
+
Authorization: authorization,
|
|
519
|
+
"x-amz-date": amzDate,
|
|
520
|
+
"x-amz-content-sha256": payloadHash
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
307
524
|
// src/client.ts
|
|
308
525
|
var _tokenStore = /* @__PURE__ */ new WeakMap();
|
|
526
|
+
var _additionalCredsStore = /* @__PURE__ */ new WeakMap();
|
|
309
527
|
function _storeAccessToken(token, accessToken) {
|
|
310
528
|
_tokenStore.set(token, accessToken);
|
|
311
529
|
}
|
|
530
|
+
function _storeAdditionalCredentials(token, creds) {
|
|
531
|
+
_additionalCredsStore.set(token, creds);
|
|
532
|
+
}
|
|
312
533
|
function _extractAccessToken(token) {
|
|
313
534
|
const value = _tokenStore.get(token);
|
|
314
535
|
if (value === void 0) {
|
|
@@ -318,10 +539,12 @@ function _extractAccessToken(token) {
|
|
|
318
539
|
}
|
|
319
540
|
return value;
|
|
320
541
|
}
|
|
542
|
+
function _extractAdditionalCredentials(token) {
|
|
543
|
+
return _additionalCredsStore.get(token);
|
|
544
|
+
}
|
|
321
545
|
var _fetch;
|
|
322
|
-
var SDK_VERSION = "0.
|
|
546
|
+
var SDK_VERSION = "0.4.0";
|
|
323
547
|
var SDK_USER_AGENT = `alter-sdk-node/${SDK_VERSION}`;
|
|
324
|
-
var VALID_ACTOR_TYPES = ["ai_agent", "mcp_server"];
|
|
325
548
|
var HTTP_FORBIDDEN = 403;
|
|
326
549
|
var HTTP_NOT_FOUND = 404;
|
|
327
550
|
var HTTP_BAD_REQUEST = 400;
|
|
@@ -377,7 +600,9 @@ var HttpClient = class {
|
|
|
377
600
|
headers: mergedHeaders,
|
|
378
601
|
signal: controller.signal
|
|
379
602
|
};
|
|
380
|
-
if (options?.
|
|
603
|
+
if (options?.body !== void 0) {
|
|
604
|
+
init.body = options.body;
|
|
605
|
+
} else if (options?.json !== void 0) {
|
|
381
606
|
init.body = JSON.stringify(options.json);
|
|
382
607
|
mergedHeaders["Content-Type"] = "application/json";
|
|
383
608
|
}
|
|
@@ -401,6 +626,8 @@ var AlterVault = class _AlterVault {
|
|
|
401
626
|
// SECURITY LAYER 4: ES2022 private fields — truly private at runtime.
|
|
402
627
|
// These are NOT accessible via (obj as any), Object.keys(), or prototype.
|
|
403
628
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
629
|
+
/** HMAC signing key (derived from API key using AWS SigV4 pattern, raw bytes) */
|
|
630
|
+
#hmacKey;
|
|
404
631
|
/** HTTP Client for Alter Backend (has x-api-key) */
|
|
405
632
|
#alterClient;
|
|
406
633
|
/** HTTP Client for External Provider APIs (NO x-api-key) */
|
|
@@ -438,10 +665,8 @@ var AlterVault = class _AlterVault {
|
|
|
438
665
|
for (const [name, value] of actorStrings) {
|
|
439
666
|
_AlterVault.#validateActorString(value, name);
|
|
440
667
|
}
|
|
441
|
-
this
|
|
442
|
-
|
|
443
|
-
""
|
|
444
|
-
);
|
|
668
|
+
this.#hmacKey = createHmac2("sha256", options.apiKey).update("alter-signing-v1").digest();
|
|
669
|
+
this.baseUrl = (process.env.ALTER_BASE_URL ?? "https://backend.alterai.dev").replace(/\/+$/, "");
|
|
445
670
|
const timeoutMs = options.timeout ?? 3e4;
|
|
446
671
|
this.#actorType = options.actorType;
|
|
447
672
|
this.#actorIdentifier = options.actorIdentifier;
|
|
@@ -494,14 +719,20 @@ var AlterVault = class _AlterVault {
|
|
|
494
719
|
if (!apiKey.startsWith("alter_key_")) {
|
|
495
720
|
throw new AlterSDKError("api_key must start with 'alter_key_'");
|
|
496
721
|
}
|
|
497
|
-
if (
|
|
498
|
-
throw new AlterSDKError(
|
|
722
|
+
if (!actorType) {
|
|
723
|
+
throw new AlterSDKError(
|
|
724
|
+
"actor_type is required (use ActorType.AI_AGENT, ActorType.MCP_SERVER, or ActorType.BACKEND_SERVICE)"
|
|
725
|
+
);
|
|
499
726
|
}
|
|
500
|
-
|
|
727
|
+
const validValues = Object.values(ActorType);
|
|
728
|
+
if (!validValues.includes(String(actorType))) {
|
|
501
729
|
throw new AlterSDKError(
|
|
502
|
-
|
|
730
|
+
`actor_type must be one of ${JSON.stringify(validValues.sort())}, got '${String(actorType)}'`
|
|
503
731
|
);
|
|
504
732
|
}
|
|
733
|
+
if (!actorIdentifier) {
|
|
734
|
+
throw new AlterSDKError("actor_identifier is required");
|
|
735
|
+
}
|
|
505
736
|
}
|
|
506
737
|
/**
|
|
507
738
|
* Build default headers for the Alter backend HTTP client.
|
|
@@ -528,6 +759,28 @@ var AlterVault = class _AlterVault {
|
|
|
528
759
|
}
|
|
529
760
|
return headers;
|
|
530
761
|
}
|
|
762
|
+
/**
|
|
763
|
+
* Compute HMAC-SHA256 signature headers for an Alter backend request.
|
|
764
|
+
*
|
|
765
|
+
* String-to-sign format: METHOD\nPATH_WITH_SORTED_QUERY\nTIMESTAMP\nCONTENT_HASH
|
|
766
|
+
*
|
|
767
|
+
* The path should include sorted query parameters if present (e.g. "/sdk/endpoint?a=1&b=2").
|
|
768
|
+
* Currently all SDK→backend calls are POSTs without query params, so the path is clean.
|
|
769
|
+
*/
|
|
770
|
+
#computeHmacHeaders(method, path, body) {
|
|
771
|
+
const timestamp = String(Math.floor(Date.now() / 1e3));
|
|
772
|
+
const contentHash = createHash2("sha256").update(body ?? "").digest("hex");
|
|
773
|
+
const stringToSign = `${method.toUpperCase()}
|
|
774
|
+
${path}
|
|
775
|
+
${timestamp}
|
|
776
|
+
${contentHash}`;
|
|
777
|
+
const signature = createHmac2("sha256", this.#hmacKey).update(stringToSign).digest("hex");
|
|
778
|
+
return {
|
|
779
|
+
"X-Alter-Timestamp": timestamp,
|
|
780
|
+
"X-Alter-Content-SHA256": contentHash,
|
|
781
|
+
"X-Alter-Signature": signature
|
|
782
|
+
};
|
|
783
|
+
}
|
|
531
784
|
/**
|
|
532
785
|
* Build per-request actor headers for instance tracking.
|
|
533
786
|
*/
|
|
@@ -624,7 +877,7 @@ var AlterVault = class _AlterVault {
|
|
|
624
877
|
if (response.status === HTTP_NOT_FOUND) {
|
|
625
878
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
626
879
|
throw new ConnectionNotFoundError(
|
|
627
|
-
errorData.message ?? "OAuth connection not found for
|
|
880
|
+
errorData.message ?? "OAuth connection not found for the given connection_id",
|
|
628
881
|
errorData
|
|
629
882
|
);
|
|
630
883
|
}
|
|
@@ -670,22 +923,24 @@ var AlterVault = class _AlterVault {
|
|
|
670
923
|
* This is a private method. Tokens are NEVER exposed to developers.
|
|
671
924
|
* Use request() instead, which handles tokens internally.
|
|
672
925
|
*/
|
|
673
|
-
async #getToken(
|
|
926
|
+
async #getToken(connectionId, reason, requestMetadata, runId, threadId, toolCallId) {
|
|
674
927
|
const actorHeaders = this.#getActorRequestHeaders(
|
|
675
928
|
runId,
|
|
676
929
|
threadId,
|
|
677
930
|
toolCallId
|
|
678
931
|
);
|
|
679
932
|
let response;
|
|
933
|
+
const tokenBody = {
|
|
934
|
+
connection_id: connectionId,
|
|
935
|
+
reason: reason ?? null,
|
|
936
|
+
request: requestMetadata ?? null
|
|
937
|
+
};
|
|
938
|
+
const tokenPath = "/sdk/token";
|
|
939
|
+
const hmacHeaders = this.#computeHmacHeaders("POST", tokenPath, JSON.stringify(tokenBody));
|
|
680
940
|
try {
|
|
681
|
-
response = await this.#alterClient.post(
|
|
682
|
-
json:
|
|
683
|
-
|
|
684
|
-
attributes,
|
|
685
|
-
reason: reason ?? null,
|
|
686
|
-
request: requestMetadata ?? null
|
|
687
|
-
},
|
|
688
|
-
headers: actorHeaders
|
|
941
|
+
response = await this.#alterClient.post(tokenPath, {
|
|
942
|
+
json: tokenBody,
|
|
943
|
+
headers: { ...actorHeaders, ...hmacHeaders }
|
|
689
944
|
});
|
|
690
945
|
} catch (error) {
|
|
691
946
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
@@ -702,7 +957,7 @@ var AlterVault = class _AlterVault {
|
|
|
702
957
|
}
|
|
703
958
|
throw new TokenRetrievalError(
|
|
704
959
|
`Failed to retrieve token: ${error instanceof Error ? error.message : String(error)}`,
|
|
705
|
-
{
|
|
960
|
+
{ connection_id: connectionId, error: String(error) }
|
|
706
961
|
);
|
|
707
962
|
}
|
|
708
963
|
this.#cacheActorIdFromResponse(response);
|
|
@@ -710,7 +965,22 @@ var AlterVault = class _AlterVault {
|
|
|
710
965
|
const tokenData = await response.json();
|
|
711
966
|
const typedData = tokenData;
|
|
712
967
|
const tokenResponse = new TokenResponse(typedData);
|
|
968
|
+
if (!/^[A-Za-z][A-Za-z0-9-]*$/.test(tokenResponse.injectionHeader)) {
|
|
969
|
+
throw new TokenRetrievalError(
|
|
970
|
+
`Backend returned invalid injection_header: ${tokenResponse.injectionHeader}`,
|
|
971
|
+
{ connectionId: String(connectionId) }
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
if (/[\r\n\x00]/.test(tokenResponse.injectionFormat)) {
|
|
975
|
+
throw new TokenRetrievalError(
|
|
976
|
+
`Backend returned invalid injection_format (contains control characters)`,
|
|
977
|
+
{ connectionId: String(connectionId) }
|
|
978
|
+
);
|
|
979
|
+
}
|
|
713
980
|
_storeAccessToken(tokenResponse, typedData.access_token);
|
|
981
|
+
if (typedData.additional_credentials) {
|
|
982
|
+
_storeAdditionalCredentials(tokenResponse, typedData.additional_credentials);
|
|
983
|
+
}
|
|
714
984
|
return tokenResponse;
|
|
715
985
|
}
|
|
716
986
|
/**
|
|
@@ -738,10 +1008,13 @@ var AlterVault = class _AlterVault {
|
|
|
738
1008
|
toolCallId: params.toolCallId
|
|
739
1009
|
});
|
|
740
1010
|
const sanitized = auditLog.sanitize();
|
|
741
|
-
const actorHeaders = this.#getActorRequestHeaders();
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
|
|
1011
|
+
const actorHeaders = this.#getActorRequestHeaders(params.runId);
|
|
1012
|
+
const auditPath = "/sdk/oauth/audit/api-call";
|
|
1013
|
+
const auditBody = sanitized;
|
|
1014
|
+
const auditHmac = this.#computeHmacHeaders("POST", auditPath, JSON.stringify(auditBody));
|
|
1015
|
+
const response = await this.#alterClient.post(auditPath, {
|
|
1016
|
+
json: auditBody,
|
|
1017
|
+
headers: { ...actorHeaders, ...auditHmac }
|
|
745
1018
|
});
|
|
746
1019
|
this.#cacheActorIdFromResponse(response);
|
|
747
1020
|
if (!response.ok) {
|
|
@@ -807,13 +1080,13 @@ var AlterVault = class _AlterVault {
|
|
|
807
1080
|
* 4. Logs the call for audit (fire-and-forget)
|
|
808
1081
|
* 5. Returns the raw response
|
|
809
1082
|
*/
|
|
810
|
-
async request(
|
|
1083
|
+
async request(connectionId, method, url, options) {
|
|
811
1084
|
if (this.#closed) {
|
|
812
1085
|
throw new AlterSDKError(
|
|
813
1086
|
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
814
1087
|
);
|
|
815
1088
|
}
|
|
816
|
-
const
|
|
1089
|
+
const runId = options?.runId ?? randomUUID();
|
|
817
1090
|
const methodStr = String(method).toUpperCase();
|
|
818
1091
|
const urlLower = url.toLowerCase();
|
|
819
1092
|
if (!ALLOWED_URL_SCHEMES.some((scheme) => urlLower.startsWith(scheme))) {
|
|
@@ -821,7 +1094,7 @@ var AlterVault = class _AlterVault {
|
|
|
821
1094
|
`URL must start with https:// or http://, got: ${url.slice(0, 50)}`
|
|
822
1095
|
);
|
|
823
1096
|
}
|
|
824
|
-
if (options
|
|
1097
|
+
if (options?.pathParams && Object.keys(options.pathParams).length > 0) {
|
|
825
1098
|
const encodedParams = {};
|
|
826
1099
|
for (const [key, value] of Object.entries(options.pathParams)) {
|
|
827
1100
|
encodedParams[key] = encodeURIComponent(String(value));
|
|
@@ -851,39 +1124,80 @@ var AlterVault = class _AlterVault {
|
|
|
851
1124
|
);
|
|
852
1125
|
}
|
|
853
1126
|
}
|
|
854
|
-
if (options.extraHeaders && "Authorization" in options.extraHeaders) {
|
|
855
|
-
console.warn(
|
|
856
|
-
"extraHeaders contains 'Authorization' which will be overwritten with the auto-injected Bearer token"
|
|
857
|
-
);
|
|
858
|
-
}
|
|
859
1127
|
const tokenResponse = await this.#getToken(
|
|
860
|
-
|
|
861
|
-
options
|
|
862
|
-
options.reason,
|
|
1128
|
+
connectionId,
|
|
1129
|
+
options?.reason,
|
|
863
1130
|
{ method: methodStr, url },
|
|
864
|
-
|
|
865
|
-
options
|
|
866
|
-
options
|
|
1131
|
+
runId,
|
|
1132
|
+
options?.threadId,
|
|
1133
|
+
options?.toolCallId
|
|
867
1134
|
);
|
|
868
|
-
const requestHeaders = options
|
|
869
|
-
|
|
1135
|
+
const requestHeaders = options?.extraHeaders ? { ...options.extraHeaders } : {};
|
|
1136
|
+
const accessToken = _extractAccessToken(tokenResponse);
|
|
1137
|
+
const injectionHeaderLower = tokenResponse.injectionHeader.toLowerCase();
|
|
1138
|
+
const additionalCreds = _extractAdditionalCredentials(tokenResponse);
|
|
1139
|
+
const isSigV4 = tokenResponse.injectionFormat.startsWith("AWS4-HMAC-SHA256") && additionalCreds != null;
|
|
1140
|
+
let sigv4BodyStr = null;
|
|
1141
|
+
if (isSigV4) {
|
|
1142
|
+
const accessKeyId = accessToken;
|
|
1143
|
+
if (options?.json != null) {
|
|
1144
|
+
sigv4BodyStr = JSON.stringify(options.json);
|
|
1145
|
+
if (!requestHeaders["Content-Type"]) {
|
|
1146
|
+
requestHeaders["Content-Type"] = "application/json";
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (!additionalCreds.secret_key) {
|
|
1150
|
+
throw new TokenRetrievalError(
|
|
1151
|
+
"AWS SigV4 credential is missing secret_key in additional_credentials. Re-store the credential with both Access Key ID and Secret Access Key.",
|
|
1152
|
+
{ connection_id: connectionId }
|
|
1153
|
+
);
|
|
1154
|
+
}
|
|
1155
|
+
const awsHeaders = signAwsRequest({
|
|
1156
|
+
method: methodStr,
|
|
1157
|
+
url,
|
|
1158
|
+
headers: requestHeaders,
|
|
1159
|
+
body: sigv4BodyStr,
|
|
1160
|
+
accessKeyId,
|
|
1161
|
+
secretKey: additionalCreds.secret_key,
|
|
1162
|
+
region: additionalCreds.region ?? null,
|
|
1163
|
+
service: additionalCreds.service ?? null
|
|
1164
|
+
});
|
|
1165
|
+
Object.assign(requestHeaders, awsHeaders);
|
|
1166
|
+
} else {
|
|
1167
|
+
if (options?.extraHeaders && Object.keys(options.extraHeaders).some(
|
|
1168
|
+
(k) => k.toLowerCase() === injectionHeaderLower
|
|
1169
|
+
)) {
|
|
1170
|
+
console.warn(
|
|
1171
|
+
`extraHeaders contains '${tokenResponse.injectionHeader}' which will be overwritten with the auto-injected credential`
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
requestHeaders[tokenResponse.injectionHeader] = tokenResponse.injectionFormat.replace("{token}", accessToken);
|
|
1175
|
+
}
|
|
870
1176
|
if (!requestHeaders["User-Agent"]) {
|
|
871
1177
|
requestHeaders["User-Agent"] = SDK_USER_AGENT;
|
|
872
1178
|
}
|
|
873
1179
|
const startTime = Date.now();
|
|
874
1180
|
let response;
|
|
875
1181
|
try {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
1182
|
+
if (isSigV4 && sigv4BodyStr != null) {
|
|
1183
|
+
response = await this.#providerClient.request(methodStr, url, {
|
|
1184
|
+
body: sigv4BodyStr,
|
|
1185
|
+
headers: requestHeaders,
|
|
1186
|
+
params: options?.queryParams
|
|
1187
|
+
});
|
|
1188
|
+
} else {
|
|
1189
|
+
response = await this.#providerClient.request(methodStr, url, {
|
|
1190
|
+
json: options?.json,
|
|
1191
|
+
headers: requestHeaders,
|
|
1192
|
+
params: options?.queryParams
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
881
1195
|
} catch (error) {
|
|
882
1196
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
883
1197
|
throw new TimeoutError(
|
|
884
1198
|
`Provider API request timed out: ${error instanceof Error ? error.message : String(error)}`,
|
|
885
1199
|
{
|
|
886
|
-
|
|
1200
|
+
connection_id: connectionId,
|
|
887
1201
|
method: methodStr,
|
|
888
1202
|
url
|
|
889
1203
|
}
|
|
@@ -892,7 +1206,7 @@ var AlterVault = class _AlterVault {
|
|
|
892
1206
|
throw new NetworkError(
|
|
893
1207
|
`Failed to call provider API: ${error instanceof Error ? error.message : String(error)}`,
|
|
894
1208
|
{
|
|
895
|
-
|
|
1209
|
+
connection_id: connectionId,
|
|
896
1210
|
method: methodStr,
|
|
897
1211
|
url,
|
|
898
1212
|
error: String(error)
|
|
@@ -900,9 +1214,11 @@ var AlterVault = class _AlterVault {
|
|
|
900
1214
|
);
|
|
901
1215
|
}
|
|
902
1216
|
const latencyMs = Date.now() - startTime;
|
|
1217
|
+
const sigv4Sensitive = /* @__PURE__ */ new Set(["authorization", "x-amz-date", "x-amz-content-sha256"]);
|
|
1218
|
+
const stripHeaders = isSigV4 ? sigv4Sensitive : /* @__PURE__ */ new Set([injectionHeaderLower]);
|
|
903
1219
|
const auditHeaders = {};
|
|
904
1220
|
for (const [key, value] of Object.entries(requestHeaders)) {
|
|
905
|
-
if (key.toLowerCase()
|
|
1221
|
+
if (!stripHeaders.has(key.toLowerCase())) {
|
|
906
1222
|
auditHeaders[key] = value;
|
|
907
1223
|
}
|
|
908
1224
|
}
|
|
@@ -913,19 +1229,19 @@ var AlterVault = class _AlterVault {
|
|
|
913
1229
|
});
|
|
914
1230
|
this.#scheduleAuditLog({
|
|
915
1231
|
connectionId: tokenResponse.connectionId,
|
|
916
|
-
providerId:
|
|
1232
|
+
providerId: tokenResponse.providerId || connectionId,
|
|
917
1233
|
method: methodStr,
|
|
918
1234
|
url,
|
|
919
1235
|
requestHeaders: auditHeaders,
|
|
920
|
-
requestBody: options
|
|
1236
|
+
requestBody: options?.json ?? null,
|
|
921
1237
|
responseStatus: response.status,
|
|
922
1238
|
responseHeaders,
|
|
923
1239
|
responseBody,
|
|
924
1240
|
latencyMs,
|
|
925
|
-
reason: options
|
|
926
|
-
runId
|
|
927
|
-
threadId: options
|
|
928
|
-
toolCallId: options
|
|
1241
|
+
reason: options?.reason ?? null,
|
|
1242
|
+
runId,
|
|
1243
|
+
threadId: options?.threadId ?? null,
|
|
1244
|
+
toolCallId: options?.toolCallId ?? null
|
|
929
1245
|
});
|
|
930
1246
|
if (response.status >= HTTP_CLIENT_ERROR_START) {
|
|
931
1247
|
throw new ProviderAPIError(
|
|
@@ -933,7 +1249,7 @@ var AlterVault = class _AlterVault {
|
|
|
933
1249
|
response.status,
|
|
934
1250
|
responseBody,
|
|
935
1251
|
{
|
|
936
|
-
|
|
1252
|
+
connection_id: connectionId,
|
|
937
1253
|
method: methodStr,
|
|
938
1254
|
url
|
|
939
1255
|
}
|
|
@@ -955,14 +1271,17 @@ var AlterVault = class _AlterVault {
|
|
|
955
1271
|
}
|
|
956
1272
|
const actorHeaders = this.#getActorRequestHeaders();
|
|
957
1273
|
let response;
|
|
1274
|
+
const listBody = {
|
|
1275
|
+
provider_id: options?.providerId ?? null,
|
|
1276
|
+
limit: options?.limit ?? 100,
|
|
1277
|
+
offset: options?.offset ?? 0
|
|
1278
|
+
};
|
|
1279
|
+
const listPath = "/sdk/oauth/connections/list";
|
|
1280
|
+
const listHmac = this.#computeHmacHeaders("POST", listPath, JSON.stringify(listBody));
|
|
958
1281
|
try {
|
|
959
|
-
response = await this.#alterClient.post(
|
|
960
|
-
json:
|
|
961
|
-
|
|
962
|
-
limit: options?.limit ?? 100,
|
|
963
|
-
offset: options?.offset ?? 0
|
|
964
|
-
},
|
|
965
|
-
headers: actorHeaders
|
|
1282
|
+
response = await this.#alterClient.post(listPath, {
|
|
1283
|
+
json: listBody,
|
|
1284
|
+
headers: { ...actorHeaders, ...listHmac }
|
|
966
1285
|
});
|
|
967
1286
|
} catch (error) {
|
|
968
1287
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
@@ -1013,17 +1332,19 @@ var AlterVault = class _AlterVault {
|
|
|
1013
1332
|
}
|
|
1014
1333
|
const actorHeaders = this.#getActorRequestHeaders();
|
|
1015
1334
|
let response;
|
|
1335
|
+
const sessionBody = {
|
|
1336
|
+
end_user: options.endUser,
|
|
1337
|
+
allowed_providers: options.allowedProviders ?? null,
|
|
1338
|
+
return_url: options.returnUrl ?? null,
|
|
1339
|
+
allowed_origin: options.allowedOrigin ?? null,
|
|
1340
|
+
metadata: options.metadata ?? null
|
|
1341
|
+
};
|
|
1342
|
+
const sessionPath = "/sdk/oauth/connect/session";
|
|
1343
|
+
const sessionHmac = this.#computeHmacHeaders("POST", sessionPath, JSON.stringify(sessionBody));
|
|
1016
1344
|
try {
|
|
1017
|
-
response = await this.#alterClient.post(
|
|
1018
|
-
json:
|
|
1019
|
-
|
|
1020
|
-
attributes: options.attributes ?? null,
|
|
1021
|
-
allowed_providers: options.allowedProviders ?? null,
|
|
1022
|
-
return_url: options.returnUrl ?? null,
|
|
1023
|
-
allowed_origin: options.allowedOrigin ?? null,
|
|
1024
|
-
metadata: options.metadata ?? null
|
|
1025
|
-
},
|
|
1026
|
-
headers: actorHeaders
|
|
1345
|
+
response = await this.#alterClient.post(sessionPath, {
|
|
1346
|
+
json: sessionBody,
|
|
1347
|
+
headers: { ...actorHeaders, ...sessionHmac }
|
|
1027
1348
|
});
|
|
1028
1349
|
} catch (error) {
|
|
1029
1350
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
@@ -1047,6 +1368,132 @@ var AlterVault = class _AlterVault {
|
|
|
1047
1368
|
const data = await response.json();
|
|
1048
1369
|
return new ConnectSession(data);
|
|
1049
1370
|
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Open OAuth in the user's browser and wait for completion.
|
|
1373
|
+
*
|
|
1374
|
+
* This is the headless connect flow for CLI tools, scripts, and
|
|
1375
|
+
* server-side applications. It creates a Connect session, opens the
|
|
1376
|
+
* browser, and polls until the user completes OAuth.
|
|
1377
|
+
*
|
|
1378
|
+
* @param options - Connect options (endUser is required)
|
|
1379
|
+
* @returns Array of ConnectResult objects (one per connected provider)
|
|
1380
|
+
* @throws ConnectTimeoutError if the user doesn't complete within timeout
|
|
1381
|
+
* @throws ConnectFlowError if the user denies or provider returns error
|
|
1382
|
+
* @throws AlterSDKError if SDK is closed or session creation fails
|
|
1383
|
+
*/
|
|
1384
|
+
async connect(options) {
|
|
1385
|
+
if (this.#closed) {
|
|
1386
|
+
throw new AlterSDKError(
|
|
1387
|
+
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
const timeout = options.timeout ?? 300;
|
|
1391
|
+
const pollInterval = options.pollInterval ?? 2;
|
|
1392
|
+
const openBrowser = options.openBrowser ?? true;
|
|
1393
|
+
const session = await this.createConnectSession({
|
|
1394
|
+
endUser: options.endUser,
|
|
1395
|
+
allowedProviders: options.providers
|
|
1396
|
+
});
|
|
1397
|
+
if (openBrowser) {
|
|
1398
|
+
try {
|
|
1399
|
+
const openModule = await import("open");
|
|
1400
|
+
const openFn = openModule.default;
|
|
1401
|
+
if (openFn) {
|
|
1402
|
+
await openFn(session.connectUrl);
|
|
1403
|
+
} else {
|
|
1404
|
+
console.log(
|
|
1405
|
+
`Open this URL to authorize: ${session.connectUrl}`
|
|
1406
|
+
);
|
|
1407
|
+
}
|
|
1408
|
+
} catch {
|
|
1409
|
+
console.log(
|
|
1410
|
+
`Open this URL to authorize: ${session.connectUrl}`
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
} else {
|
|
1414
|
+
console.log(
|
|
1415
|
+
`Open this URL to authorize: ${session.connectUrl}`
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
const deadline = Date.now() + timeout * 1e3;
|
|
1419
|
+
while (Date.now() < deadline) {
|
|
1420
|
+
await new Promise(
|
|
1421
|
+
(resolve) => setTimeout(resolve, pollInterval * 1e3)
|
|
1422
|
+
);
|
|
1423
|
+
const pollResult = await this.#pollSession(session.sessionToken);
|
|
1424
|
+
const pollStatus = pollResult.status;
|
|
1425
|
+
if (pollStatus === "completed") {
|
|
1426
|
+
const connectionsData = pollResult.connections ?? [];
|
|
1427
|
+
return connectionsData.map(
|
|
1428
|
+
(conn) => new ConnectResult({
|
|
1429
|
+
connection_id: conn.connection_id ?? "",
|
|
1430
|
+
provider_id: conn.provider_id ?? "",
|
|
1431
|
+
account_identifier: conn.account_identifier ?? null,
|
|
1432
|
+
scopes: conn.scopes ?? []
|
|
1433
|
+
})
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
if (pollStatus === "error") {
|
|
1437
|
+
const err = pollResult.error;
|
|
1438
|
+
throw new ConnectFlowError(
|
|
1439
|
+
err?.error_message ?? "OAuth flow failed",
|
|
1440
|
+
{
|
|
1441
|
+
error_code: err?.error_code ?? "unknown_error"
|
|
1442
|
+
}
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
if (pollStatus === "expired") {
|
|
1446
|
+
throw new ConnectFlowError(
|
|
1447
|
+
"Connect session expired before OAuth was completed"
|
|
1448
|
+
);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
throw new ConnectTimeoutError(
|
|
1452
|
+
`OAuth flow did not complete within ${timeout} seconds. The user may not have finished authorizing in the browser.`,
|
|
1453
|
+
{ timeout }
|
|
1454
|
+
);
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* Poll the Connect session for completion status (INTERNAL).
|
|
1458
|
+
*
|
|
1459
|
+
* Makes an HMAC-signed POST to the poll endpoint.
|
|
1460
|
+
*/
|
|
1461
|
+
async #pollSession(sessionToken) {
|
|
1462
|
+
const actorHeaders = this.#getActorRequestHeaders();
|
|
1463
|
+
const pollPath = "/sdk/oauth/connect/session/poll";
|
|
1464
|
+
const pollBody = { session_token: sessionToken };
|
|
1465
|
+
const pollHmac = this.#computeHmacHeaders(
|
|
1466
|
+
"POST",
|
|
1467
|
+
pollPath,
|
|
1468
|
+
JSON.stringify(pollBody)
|
|
1469
|
+
);
|
|
1470
|
+
let response;
|
|
1471
|
+
try {
|
|
1472
|
+
response = await this.#alterClient.post(pollPath, {
|
|
1473
|
+
json: pollBody,
|
|
1474
|
+
headers: { ...actorHeaders, ...pollHmac }
|
|
1475
|
+
});
|
|
1476
|
+
} catch (error) {
|
|
1477
|
+
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
1478
|
+
throw new TimeoutError(
|
|
1479
|
+
`Request to Alter Vault backend timed out: ${error instanceof Error ? error.message : String(error)}`,
|
|
1480
|
+
{ base_url: this.baseUrl }
|
|
1481
|
+
);
|
|
1482
|
+
}
|
|
1483
|
+
if (error instanceof TypeError) {
|
|
1484
|
+
throw new NetworkError(
|
|
1485
|
+
`Failed to connect to Alter Vault backend: ${error.message}`,
|
|
1486
|
+
{ base_url: this.baseUrl }
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
throw new AlterSDKError(
|
|
1490
|
+
`Failed to poll connect session: ${error instanceof Error ? error.message : String(error)}`
|
|
1491
|
+
);
|
|
1492
|
+
}
|
|
1493
|
+
this.#cacheActorIdFromResponse(response);
|
|
1494
|
+
await this.#handleErrorResponse(response);
|
|
1495
|
+
return await response.json();
|
|
1496
|
+
}
|
|
1050
1497
|
/**
|
|
1051
1498
|
* Close HTTP clients and release resources.
|
|
1052
1499
|
* Waits for any pending audit tasks before closing.
|
|
@@ -1075,8 +1522,6 @@ var Provider = /* @__PURE__ */ ((Provider2) => {
|
|
|
1075
1522
|
Provider2["GOOGLE"] = "google";
|
|
1076
1523
|
Provider2["GITHUB"] = "github";
|
|
1077
1524
|
Provider2["SLACK"] = "slack";
|
|
1078
|
-
Provider2["MICROSOFT"] = "microsoft";
|
|
1079
|
-
Provider2["SALESFORCE"] = "salesforce";
|
|
1080
1525
|
Provider2["SENTRY"] = "sentry";
|
|
1081
1526
|
return Provider2;
|
|
1082
1527
|
})(Provider || {});
|
|
@@ -1092,9 +1537,13 @@ var HttpMethod = /* @__PURE__ */ ((HttpMethod2) => {
|
|
|
1092
1537
|
})(HttpMethod || {});
|
|
1093
1538
|
export {
|
|
1094
1539
|
APICallAuditLog,
|
|
1540
|
+
ActorType,
|
|
1095
1541
|
AlterSDKError,
|
|
1096
1542
|
AlterVault,
|
|
1543
|
+
ConnectFlowError,
|
|
1544
|
+
ConnectResult,
|
|
1097
1545
|
ConnectSession,
|
|
1546
|
+
ConnectTimeoutError,
|
|
1098
1547
|
ConnectionInfo,
|
|
1099
1548
|
ConnectionListResult,
|
|
1100
1549
|
ConnectionNotFoundError,
|