@alter-ai/alter-sdk 0.2.1 → 0.3.1
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 +145 -51
- package/dist/index.cjs +315 -53
- package/dist/index.d.cts +262 -137
- package/dist/index.d.ts +262 -137
- package/dist/index.js +311 -53
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -21,8 +21,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
APICallAuditLog: () => APICallAuditLog,
|
|
24
|
+
ActorType: () => ActorType,
|
|
24
25
|
AlterSDKError: () => AlterSDKError,
|
|
25
26
|
AlterVault: () => AlterVault,
|
|
27
|
+
ConnectSession: () => ConnectSession,
|
|
28
|
+
ConnectionInfo: () => ConnectionInfo,
|
|
29
|
+
ConnectionListResult: () => ConnectionListResult,
|
|
26
30
|
ConnectionNotFoundError: () => ConnectionNotFoundError,
|
|
27
31
|
HttpMethod: () => HttpMethod,
|
|
28
32
|
NetworkError: () => NetworkError,
|
|
@@ -36,6 +40,9 @@ __export(index_exports, {
|
|
|
36
40
|
});
|
|
37
41
|
module.exports = __toCommonJS(index_exports);
|
|
38
42
|
|
|
43
|
+
// src/client.ts
|
|
44
|
+
var import_node_crypto = require("crypto");
|
|
45
|
+
|
|
39
46
|
// src/exceptions.ts
|
|
40
47
|
var AlterSDKError = class extends Error {
|
|
41
48
|
details;
|
|
@@ -104,6 +111,12 @@ var TimeoutError = class extends NetworkError {
|
|
|
104
111
|
};
|
|
105
112
|
|
|
106
113
|
// src/models.ts
|
|
114
|
+
var ActorType = /* @__PURE__ */ ((ActorType2) => {
|
|
115
|
+
ActorType2["BACKEND_SERVICE"] = "backend_service";
|
|
116
|
+
ActorType2["AI_AGENT"] = "ai_agent";
|
|
117
|
+
ActorType2["MCP_SERVER"] = "mcp_server";
|
|
118
|
+
return ActorType2;
|
|
119
|
+
})(ActorType || {});
|
|
107
120
|
var TokenResponse = class _TokenResponse {
|
|
108
121
|
/** Token type (usually "Bearer") */
|
|
109
122
|
tokenType;
|
|
@@ -115,12 +128,21 @@ var TokenResponse = class _TokenResponse {
|
|
|
115
128
|
scopes;
|
|
116
129
|
/** Connection ID that provided this token */
|
|
117
130
|
connectionId;
|
|
131
|
+
/** Provider ID (google, github, etc.) */
|
|
132
|
+
providerId;
|
|
133
|
+
/** HTTP header name for credential injection (e.g., "Authorization", "X-API-Key") */
|
|
134
|
+
injectionHeader;
|
|
135
|
+
/** Header value format with {token} placeholder (e.g., "Bearer {token}", "{token}") */
|
|
136
|
+
injectionFormat;
|
|
118
137
|
constructor(data) {
|
|
119
138
|
this.tokenType = data.token_type ?? "Bearer";
|
|
120
139
|
this.expiresIn = data.expires_in ?? null;
|
|
121
140
|
this.expiresAt = data.expires_at ? _TokenResponse.parseExpiresAt(data.expires_at) : null;
|
|
122
141
|
this.scopes = data.scopes ?? [];
|
|
123
142
|
this.connectionId = data.connection_id;
|
|
143
|
+
this.providerId = data.provider_id ?? "";
|
|
144
|
+
this.injectionHeader = data.injection_header ?? "Authorization";
|
|
145
|
+
this.injectionFormat = data.injection_format ?? "Bearer {token}";
|
|
124
146
|
Object.freeze(this);
|
|
125
147
|
}
|
|
126
148
|
/**
|
|
@@ -182,6 +204,84 @@ var TokenResponse = class _TokenResponse {
|
|
|
182
204
|
return this.toString();
|
|
183
205
|
}
|
|
184
206
|
};
|
|
207
|
+
var ConnectionInfo = class {
|
|
208
|
+
id;
|
|
209
|
+
providerId;
|
|
210
|
+
scopes;
|
|
211
|
+
accountIdentifier;
|
|
212
|
+
accountDisplayName;
|
|
213
|
+
status;
|
|
214
|
+
expiresAt;
|
|
215
|
+
createdAt;
|
|
216
|
+
lastUsedAt;
|
|
217
|
+
constructor(data) {
|
|
218
|
+
this.id = data.id;
|
|
219
|
+
this.providerId = data.provider_id;
|
|
220
|
+
this.scopes = data.scopes ?? [];
|
|
221
|
+
this.accountIdentifier = data.account_identifier ?? null;
|
|
222
|
+
this.accountDisplayName = data.account_display_name ?? null;
|
|
223
|
+
this.status = data.status;
|
|
224
|
+
this.expiresAt = data.expires_at ?? null;
|
|
225
|
+
this.createdAt = data.created_at;
|
|
226
|
+
this.lastUsedAt = data.last_used_at ?? null;
|
|
227
|
+
Object.freeze(this);
|
|
228
|
+
}
|
|
229
|
+
toJSON() {
|
|
230
|
+
return {
|
|
231
|
+
id: this.id,
|
|
232
|
+
provider_id: this.providerId,
|
|
233
|
+
scopes: this.scopes,
|
|
234
|
+
account_identifier: this.accountIdentifier,
|
|
235
|
+
account_display_name: this.accountDisplayName,
|
|
236
|
+
status: this.status,
|
|
237
|
+
expires_at: this.expiresAt,
|
|
238
|
+
created_at: this.createdAt,
|
|
239
|
+
last_used_at: this.lastUsedAt
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
toString() {
|
|
243
|
+
return `ConnectionInfo(id=${this.id}, provider=${this.providerId}, status=${this.status})`;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
var ConnectSession = class {
|
|
247
|
+
sessionToken;
|
|
248
|
+
connectUrl;
|
|
249
|
+
expiresIn;
|
|
250
|
+
expiresAt;
|
|
251
|
+
constructor(data) {
|
|
252
|
+
this.sessionToken = data.session_token;
|
|
253
|
+
this.connectUrl = data.connect_url;
|
|
254
|
+
this.expiresIn = data.expires_in;
|
|
255
|
+
this.expiresAt = data.expires_at;
|
|
256
|
+
Object.freeze(this);
|
|
257
|
+
}
|
|
258
|
+
toJSON() {
|
|
259
|
+
return {
|
|
260
|
+
session_token: this.sessionToken,
|
|
261
|
+
connect_url: this.connectUrl,
|
|
262
|
+
expires_in: this.expiresIn,
|
|
263
|
+
expires_at: this.expiresAt
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
toString() {
|
|
267
|
+
return `ConnectSession(url=${this.connectUrl}, expires_in=${this.expiresIn})`;
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
var ConnectionListResult = class {
|
|
271
|
+
connections;
|
|
272
|
+
total;
|
|
273
|
+
limit;
|
|
274
|
+
offset;
|
|
275
|
+
hasMore;
|
|
276
|
+
constructor(data) {
|
|
277
|
+
this.connections = data.connections;
|
|
278
|
+
this.total = data.total;
|
|
279
|
+
this.limit = data.limit;
|
|
280
|
+
this.offset = data.offset;
|
|
281
|
+
this.hasMore = data.has_more;
|
|
282
|
+
Object.freeze(this);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
185
285
|
var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
|
|
186
286
|
"authorization",
|
|
187
287
|
"cookie",
|
|
@@ -276,9 +376,8 @@ function _extractAccessToken(token) {
|
|
|
276
376
|
return value;
|
|
277
377
|
}
|
|
278
378
|
var _fetch;
|
|
279
|
-
var SDK_VERSION = "0.
|
|
379
|
+
var SDK_VERSION = "0.3.0";
|
|
280
380
|
var SDK_USER_AGENT = `alter-sdk-node/${SDK_VERSION}`;
|
|
281
|
-
var VALID_ACTOR_TYPES = ["ai_agent", "mcp_server"];
|
|
282
381
|
var HTTP_FORBIDDEN = 403;
|
|
283
382
|
var HTTP_NOT_FOUND = 404;
|
|
284
383
|
var HTTP_BAD_REQUEST = 400;
|
|
@@ -358,6 +457,8 @@ var AlterVault = class _AlterVault {
|
|
|
358
457
|
// SECURITY LAYER 4: ES2022 private fields — truly private at runtime.
|
|
359
458
|
// These are NOT accessible via (obj as any), Object.keys(), or prototype.
|
|
360
459
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
460
|
+
/** HMAC signing key (derived from API key using AWS SigV4 pattern, raw bytes) */
|
|
461
|
+
#hmacKey;
|
|
361
462
|
/** HTTP Client for Alter Backend (has x-api-key) */
|
|
362
463
|
#alterClient;
|
|
363
464
|
/** HTTP Client for External Provider APIs (NO x-api-key) */
|
|
@@ -395,10 +496,8 @@ var AlterVault = class _AlterVault {
|
|
|
395
496
|
for (const [name, value] of actorStrings) {
|
|
396
497
|
_AlterVault.#validateActorString(value, name);
|
|
397
498
|
}
|
|
398
|
-
this
|
|
399
|
-
|
|
400
|
-
""
|
|
401
|
-
);
|
|
499
|
+
this.#hmacKey = (0, import_node_crypto.createHmac)("sha256", options.apiKey).update("alter-signing-v1").digest();
|
|
500
|
+
this.baseUrl = (process.env.ALTER_BASE_URL ?? "https://backend.alterai.dev").replace(/\/+$/, "");
|
|
402
501
|
const timeoutMs = options.timeout ?? 3e4;
|
|
403
502
|
this.#actorType = options.actorType;
|
|
404
503
|
this.#actorIdentifier = options.actorIdentifier;
|
|
@@ -451,14 +550,20 @@ var AlterVault = class _AlterVault {
|
|
|
451
550
|
if (!apiKey.startsWith("alter_key_")) {
|
|
452
551
|
throw new AlterSDKError("api_key must start with 'alter_key_'");
|
|
453
552
|
}
|
|
454
|
-
if (
|
|
455
|
-
throw new AlterSDKError(
|
|
553
|
+
if (!actorType) {
|
|
554
|
+
throw new AlterSDKError(
|
|
555
|
+
"actor_type is required (use ActorType.AI_AGENT, ActorType.MCP_SERVER, or ActorType.BACKEND_SERVICE)"
|
|
556
|
+
);
|
|
456
557
|
}
|
|
457
|
-
|
|
558
|
+
const validValues = Object.values(ActorType);
|
|
559
|
+
if (!validValues.includes(String(actorType))) {
|
|
458
560
|
throw new AlterSDKError(
|
|
459
|
-
|
|
561
|
+
`actor_type must be one of ${JSON.stringify(validValues.sort())}, got '${String(actorType)}'`
|
|
460
562
|
);
|
|
461
563
|
}
|
|
564
|
+
if (!actorIdentifier) {
|
|
565
|
+
throw new AlterSDKError("actor_identifier is required");
|
|
566
|
+
}
|
|
462
567
|
}
|
|
463
568
|
/**
|
|
464
569
|
* Build default headers for the Alter backend HTTP client.
|
|
@@ -485,6 +590,28 @@ var AlterVault = class _AlterVault {
|
|
|
485
590
|
}
|
|
486
591
|
return headers;
|
|
487
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* Compute HMAC-SHA256 signature headers for an Alter backend request.
|
|
595
|
+
*
|
|
596
|
+
* String-to-sign format: METHOD\nPATH_WITH_SORTED_QUERY\nTIMESTAMP\nCONTENT_HASH
|
|
597
|
+
*
|
|
598
|
+
* The path should include sorted query parameters if present (e.g. "/sdk/endpoint?a=1&b=2").
|
|
599
|
+
* Currently all SDK→backend calls are POSTs without query params, so the path is clean.
|
|
600
|
+
*/
|
|
601
|
+
#computeHmacHeaders(method, path, body) {
|
|
602
|
+
const timestamp = String(Math.floor(Date.now() / 1e3));
|
|
603
|
+
const contentHash = (0, import_node_crypto.createHash)("sha256").update(body ?? "").digest("hex");
|
|
604
|
+
const stringToSign = `${method.toUpperCase()}
|
|
605
|
+
${path}
|
|
606
|
+
${timestamp}
|
|
607
|
+
${contentHash}`;
|
|
608
|
+
const signature = (0, import_node_crypto.createHmac)("sha256", this.#hmacKey).update(stringToSign).digest("hex");
|
|
609
|
+
return {
|
|
610
|
+
"X-Alter-Timestamp": timestamp,
|
|
611
|
+
"X-Alter-Content-SHA256": contentHash,
|
|
612
|
+
"X-Alter-Signature": signature
|
|
613
|
+
};
|
|
614
|
+
}
|
|
488
615
|
/**
|
|
489
616
|
* Build per-request actor headers for instance tracking.
|
|
490
617
|
*/
|
|
@@ -581,7 +708,7 @@ var AlterVault = class _AlterVault {
|
|
|
581
708
|
if (response.status === HTTP_NOT_FOUND) {
|
|
582
709
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
583
710
|
throw new ConnectionNotFoundError(
|
|
584
|
-
errorData.message ?? "OAuth connection not found for
|
|
711
|
+
errorData.message ?? "OAuth connection not found for the given connection_id",
|
|
585
712
|
errorData
|
|
586
713
|
);
|
|
587
714
|
}
|
|
@@ -627,21 +754,24 @@ var AlterVault = class _AlterVault {
|
|
|
627
754
|
* This is a private method. Tokens are NEVER exposed to developers.
|
|
628
755
|
* Use request() instead, which handles tokens internally.
|
|
629
756
|
*/
|
|
630
|
-
async #getToken(
|
|
757
|
+
async #getToken(connectionId, reason, requestMetadata, runId, threadId, toolCallId) {
|
|
631
758
|
const actorHeaders = this.#getActorRequestHeaders(
|
|
632
759
|
runId,
|
|
633
760
|
threadId,
|
|
634
761
|
toolCallId
|
|
635
762
|
);
|
|
636
763
|
let response;
|
|
764
|
+
const tokenBody = {
|
|
765
|
+
connection_id: connectionId,
|
|
766
|
+
reason: reason ?? null,
|
|
767
|
+
request: requestMetadata ?? null
|
|
768
|
+
};
|
|
769
|
+
const tokenPath = "/sdk/token";
|
|
770
|
+
const hmacHeaders = this.#computeHmacHeaders("POST", tokenPath, JSON.stringify(tokenBody));
|
|
637
771
|
try {
|
|
638
|
-
response = await this.#alterClient.post(
|
|
639
|
-
json:
|
|
640
|
-
|
|
641
|
-
attributes,
|
|
642
|
-
reason: reason ?? null
|
|
643
|
-
},
|
|
644
|
-
headers: actorHeaders
|
|
772
|
+
response = await this.#alterClient.post(tokenPath, {
|
|
773
|
+
json: tokenBody,
|
|
774
|
+
headers: { ...actorHeaders, ...hmacHeaders }
|
|
645
775
|
});
|
|
646
776
|
} catch (error) {
|
|
647
777
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
@@ -658,7 +788,7 @@ var AlterVault = class _AlterVault {
|
|
|
658
788
|
}
|
|
659
789
|
throw new TokenRetrievalError(
|
|
660
790
|
`Failed to retrieve token: ${error instanceof Error ? error.message : String(error)}`,
|
|
661
|
-
{
|
|
791
|
+
{ connection_id: connectionId, error: String(error) }
|
|
662
792
|
);
|
|
663
793
|
}
|
|
664
794
|
this.#cacheActorIdFromResponse(response);
|
|
@@ -666,6 +796,18 @@ var AlterVault = class _AlterVault {
|
|
|
666
796
|
const tokenData = await response.json();
|
|
667
797
|
const typedData = tokenData;
|
|
668
798
|
const tokenResponse = new TokenResponse(typedData);
|
|
799
|
+
if (!/^[A-Za-z][A-Za-z0-9-]*$/.test(tokenResponse.injectionHeader)) {
|
|
800
|
+
throw new TokenRetrievalError(
|
|
801
|
+
`Backend returned invalid injection_header: ${tokenResponse.injectionHeader}`,
|
|
802
|
+
{ connectionId: String(connectionId) }
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
if (/[\r\n\x00]/.test(tokenResponse.injectionFormat)) {
|
|
806
|
+
throw new TokenRetrievalError(
|
|
807
|
+
`Backend returned invalid injection_format (contains control characters)`,
|
|
808
|
+
{ connectionId: String(connectionId) }
|
|
809
|
+
);
|
|
810
|
+
}
|
|
669
811
|
_storeAccessToken(tokenResponse, typedData.access_token);
|
|
670
812
|
return tokenResponse;
|
|
671
813
|
}
|
|
@@ -694,10 +836,13 @@ var AlterVault = class _AlterVault {
|
|
|
694
836
|
toolCallId: params.toolCallId
|
|
695
837
|
});
|
|
696
838
|
const sanitized = auditLog.sanitize();
|
|
697
|
-
const actorHeaders = this.#getActorRequestHeaders();
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
839
|
+
const actorHeaders = this.#getActorRequestHeaders(params.runId);
|
|
840
|
+
const auditPath = "/sdk/oauth/audit/api-call";
|
|
841
|
+
const auditBody = sanitized;
|
|
842
|
+
const auditHmac = this.#computeHmacHeaders("POST", auditPath, JSON.stringify(auditBody));
|
|
843
|
+
const response = await this.#alterClient.post(auditPath, {
|
|
844
|
+
json: auditBody,
|
|
845
|
+
headers: { ...actorHeaders, ...auditHmac }
|
|
701
846
|
});
|
|
702
847
|
this.#cacheActorIdFromResponse(response);
|
|
703
848
|
if (!response.ok) {
|
|
@@ -763,13 +908,13 @@ var AlterVault = class _AlterVault {
|
|
|
763
908
|
* 4. Logs the call for audit (fire-and-forget)
|
|
764
909
|
* 5. Returns the raw response
|
|
765
910
|
*/
|
|
766
|
-
async request(
|
|
911
|
+
async request(connectionId, method, url, options) {
|
|
767
912
|
if (this.#closed) {
|
|
768
913
|
throw new AlterSDKError(
|
|
769
914
|
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
770
915
|
);
|
|
771
916
|
}
|
|
772
|
-
const
|
|
917
|
+
const runId = options?.runId ?? (0, import_node_crypto.randomUUID)();
|
|
773
918
|
const methodStr = String(method).toUpperCase();
|
|
774
919
|
const urlLower = url.toLowerCase();
|
|
775
920
|
if (!ALLOWED_URL_SCHEMES.some((scheme) => urlLower.startsWith(scheme))) {
|
|
@@ -777,7 +922,7 @@ var AlterVault = class _AlterVault {
|
|
|
777
922
|
`URL must start with https:// or http://, got: ${url.slice(0, 50)}`
|
|
778
923
|
);
|
|
779
924
|
}
|
|
780
|
-
if (options
|
|
925
|
+
if (options?.pathParams && Object.keys(options.pathParams).length > 0) {
|
|
781
926
|
const encodedParams = {};
|
|
782
927
|
for (const [key, value] of Object.entries(options.pathParams)) {
|
|
783
928
|
encodedParams[key] = encodeURIComponent(String(value));
|
|
@@ -807,21 +952,25 @@ var AlterVault = class _AlterVault {
|
|
|
807
952
|
);
|
|
808
953
|
}
|
|
809
954
|
}
|
|
810
|
-
|
|
955
|
+
const tokenResponse = await this.#getToken(
|
|
956
|
+
connectionId,
|
|
957
|
+
options?.reason,
|
|
958
|
+
{ method: methodStr, url },
|
|
959
|
+
runId,
|
|
960
|
+
options?.threadId,
|
|
961
|
+
options?.toolCallId
|
|
962
|
+
);
|
|
963
|
+
const injectionHeaderLower = tokenResponse.injectionHeader.toLowerCase();
|
|
964
|
+
if (options?.extraHeaders && Object.keys(options.extraHeaders).some(
|
|
965
|
+
(k) => k.toLowerCase() === injectionHeaderLower
|
|
966
|
+
)) {
|
|
811
967
|
console.warn(
|
|
812
|
-
|
|
968
|
+
`extraHeaders contains '${tokenResponse.injectionHeader}' which will be overwritten with the auto-injected credential`
|
|
813
969
|
);
|
|
814
970
|
}
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
options.reason,
|
|
819
|
-
options.runId,
|
|
820
|
-
options.threadId,
|
|
821
|
-
options.toolCallId
|
|
822
|
-
);
|
|
823
|
-
const requestHeaders = options.extraHeaders ? { ...options.extraHeaders } : {};
|
|
824
|
-
requestHeaders["Authorization"] = `Bearer ${_extractAccessToken(tokenResponse)}`;
|
|
971
|
+
const requestHeaders = options?.extraHeaders ? { ...options.extraHeaders } : {};
|
|
972
|
+
const accessToken = _extractAccessToken(tokenResponse);
|
|
973
|
+
requestHeaders[tokenResponse.injectionHeader] = tokenResponse.injectionFormat.replace("{token}", accessToken);
|
|
825
974
|
if (!requestHeaders["User-Agent"]) {
|
|
826
975
|
requestHeaders["User-Agent"] = SDK_USER_AGENT;
|
|
827
976
|
}
|
|
@@ -829,16 +978,16 @@ var AlterVault = class _AlterVault {
|
|
|
829
978
|
let response;
|
|
830
979
|
try {
|
|
831
980
|
response = await this.#providerClient.request(methodStr, url, {
|
|
832
|
-
json: options
|
|
981
|
+
json: options?.json,
|
|
833
982
|
headers: requestHeaders,
|
|
834
|
-
params: options
|
|
983
|
+
params: options?.queryParams
|
|
835
984
|
});
|
|
836
985
|
} catch (error) {
|
|
837
986
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
838
987
|
throw new TimeoutError(
|
|
839
988
|
`Provider API request timed out: ${error instanceof Error ? error.message : String(error)}`,
|
|
840
989
|
{
|
|
841
|
-
|
|
990
|
+
connection_id: connectionId,
|
|
842
991
|
method: methodStr,
|
|
843
992
|
url
|
|
844
993
|
}
|
|
@@ -847,7 +996,7 @@ var AlterVault = class _AlterVault {
|
|
|
847
996
|
throw new NetworkError(
|
|
848
997
|
`Failed to call provider API: ${error instanceof Error ? error.message : String(error)}`,
|
|
849
998
|
{
|
|
850
|
-
|
|
999
|
+
connection_id: connectionId,
|
|
851
1000
|
method: methodStr,
|
|
852
1001
|
url,
|
|
853
1002
|
error: String(error)
|
|
@@ -857,7 +1006,7 @@ var AlterVault = class _AlterVault {
|
|
|
857
1006
|
const latencyMs = Date.now() - startTime;
|
|
858
1007
|
const auditHeaders = {};
|
|
859
1008
|
for (const [key, value] of Object.entries(requestHeaders)) {
|
|
860
|
-
if (key.toLowerCase() !==
|
|
1009
|
+
if (key.toLowerCase() !== injectionHeaderLower) {
|
|
861
1010
|
auditHeaders[key] = value;
|
|
862
1011
|
}
|
|
863
1012
|
}
|
|
@@ -868,19 +1017,19 @@ var AlterVault = class _AlterVault {
|
|
|
868
1017
|
});
|
|
869
1018
|
this.#scheduleAuditLog({
|
|
870
1019
|
connectionId: tokenResponse.connectionId,
|
|
871
|
-
providerId:
|
|
1020
|
+
providerId: tokenResponse.providerId || connectionId,
|
|
872
1021
|
method: methodStr,
|
|
873
1022
|
url,
|
|
874
1023
|
requestHeaders: auditHeaders,
|
|
875
|
-
requestBody: options
|
|
1024
|
+
requestBody: options?.json ?? null,
|
|
876
1025
|
responseStatus: response.status,
|
|
877
1026
|
responseHeaders,
|
|
878
1027
|
responseBody,
|
|
879
1028
|
latencyMs,
|
|
880
|
-
reason: options
|
|
881
|
-
runId
|
|
882
|
-
threadId: options
|
|
883
|
-
toolCallId: options
|
|
1029
|
+
reason: options?.reason ?? null,
|
|
1030
|
+
runId,
|
|
1031
|
+
threadId: options?.threadId ?? null,
|
|
1032
|
+
toolCallId: options?.toolCallId ?? null
|
|
884
1033
|
});
|
|
885
1034
|
if (response.status >= HTTP_CLIENT_ERROR_START) {
|
|
886
1035
|
throw new ProviderAPIError(
|
|
@@ -888,7 +1037,7 @@ var AlterVault = class _AlterVault {
|
|
|
888
1037
|
response.status,
|
|
889
1038
|
responseBody,
|
|
890
1039
|
{
|
|
891
|
-
|
|
1040
|
+
connection_id: connectionId,
|
|
892
1041
|
method: methodStr,
|
|
893
1042
|
url
|
|
894
1043
|
}
|
|
@@ -896,6 +1045,117 @@ var AlterVault = class _AlterVault {
|
|
|
896
1045
|
}
|
|
897
1046
|
return response;
|
|
898
1047
|
}
|
|
1048
|
+
/**
|
|
1049
|
+
* List OAuth connections for this app.
|
|
1050
|
+
*
|
|
1051
|
+
* Returns paginated connection metadata (no tokens).
|
|
1052
|
+
* Useful for discovering which services a user has connected.
|
|
1053
|
+
*/
|
|
1054
|
+
async listConnections(options) {
|
|
1055
|
+
if (this.#closed) {
|
|
1056
|
+
throw new AlterSDKError(
|
|
1057
|
+
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
const actorHeaders = this.#getActorRequestHeaders();
|
|
1061
|
+
let response;
|
|
1062
|
+
const listBody = {
|
|
1063
|
+
provider_id: options?.providerId ?? null,
|
|
1064
|
+
limit: options?.limit ?? 100,
|
|
1065
|
+
offset: options?.offset ?? 0
|
|
1066
|
+
};
|
|
1067
|
+
const listPath = "/sdk/oauth/connections/list";
|
|
1068
|
+
const listHmac = this.#computeHmacHeaders("POST", listPath, JSON.stringify(listBody));
|
|
1069
|
+
try {
|
|
1070
|
+
response = await this.#alterClient.post(listPath, {
|
|
1071
|
+
json: listBody,
|
|
1072
|
+
headers: { ...actorHeaders, ...listHmac }
|
|
1073
|
+
});
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
1076
|
+
throw new TimeoutError(
|
|
1077
|
+
`Request to Alter Vault backend timed out: ${error instanceof Error ? error.message : String(error)}`,
|
|
1078
|
+
{ base_url: this.baseUrl }
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
if (error instanceof TypeError) {
|
|
1082
|
+
throw new NetworkError(
|
|
1083
|
+
`Failed to connect to Alter Vault backend: ${error.message}`,
|
|
1084
|
+
{ base_url: this.baseUrl }
|
|
1085
|
+
);
|
|
1086
|
+
}
|
|
1087
|
+
throw new AlterSDKError(
|
|
1088
|
+
`Failed to list connections: ${error instanceof Error ? error.message : String(error)}`
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
this.#cacheActorIdFromResponse(response);
|
|
1092
|
+
await this.#handleErrorResponse(response);
|
|
1093
|
+
const data = await response.json();
|
|
1094
|
+
const connections = data.connections.map(
|
|
1095
|
+
(c) => new ConnectionInfo(
|
|
1096
|
+
c
|
|
1097
|
+
)
|
|
1098
|
+
);
|
|
1099
|
+
return new ConnectionListResult({
|
|
1100
|
+
connections,
|
|
1101
|
+
total: data.total,
|
|
1102
|
+
limit: data.limit,
|
|
1103
|
+
offset: data.offset,
|
|
1104
|
+
has_more: data.has_more
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Create a Connect session for initiating OAuth flows.
|
|
1109
|
+
*
|
|
1110
|
+
* Returns a URL the user can open in their browser to authorize access.
|
|
1111
|
+
*/
|
|
1112
|
+
async createConnectSession(options) {
|
|
1113
|
+
if (this.#closed) {
|
|
1114
|
+
throw new AlterSDKError(
|
|
1115
|
+
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
if (!options.endUser?.id) {
|
|
1119
|
+
throw new AlterSDKError("endUser.id is required");
|
|
1120
|
+
}
|
|
1121
|
+
const actorHeaders = this.#getActorRequestHeaders();
|
|
1122
|
+
let response;
|
|
1123
|
+
const sessionBody = {
|
|
1124
|
+
end_user: options.endUser,
|
|
1125
|
+
allowed_providers: options.allowedProviders ?? null,
|
|
1126
|
+
return_url: options.returnUrl ?? null,
|
|
1127
|
+
allowed_origin: options.allowedOrigin ?? null,
|
|
1128
|
+
metadata: options.metadata ?? null
|
|
1129
|
+
};
|
|
1130
|
+
const sessionPath = "/sdk/oauth/connect/session";
|
|
1131
|
+
const sessionHmac = this.#computeHmacHeaders("POST", sessionPath, JSON.stringify(sessionBody));
|
|
1132
|
+
try {
|
|
1133
|
+
response = await this.#alterClient.post(sessionPath, {
|
|
1134
|
+
json: sessionBody,
|
|
1135
|
+
headers: { ...actorHeaders, ...sessionHmac }
|
|
1136
|
+
});
|
|
1137
|
+
} catch (error) {
|
|
1138
|
+
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
1139
|
+
throw new TimeoutError(
|
|
1140
|
+
`Request to Alter Vault backend timed out: ${error instanceof Error ? error.message : String(error)}`,
|
|
1141
|
+
{ base_url: this.baseUrl }
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
if (error instanceof TypeError) {
|
|
1145
|
+
throw new NetworkError(
|
|
1146
|
+
`Failed to connect to Alter Vault backend: ${error.message}`,
|
|
1147
|
+
{ base_url: this.baseUrl }
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
throw new AlterSDKError(
|
|
1151
|
+
`Failed to create connect session: ${error instanceof Error ? error.message : String(error)}`
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
this.#cacheActorIdFromResponse(response);
|
|
1155
|
+
await this.#handleErrorResponse(response);
|
|
1156
|
+
const data = await response.json();
|
|
1157
|
+
return new ConnectSession(data);
|
|
1158
|
+
}
|
|
899
1159
|
/**
|
|
900
1160
|
* Close HTTP clients and release resources.
|
|
901
1161
|
* Waits for any pending audit tasks before closing.
|
|
@@ -924,8 +1184,6 @@ var Provider = /* @__PURE__ */ ((Provider2) => {
|
|
|
924
1184
|
Provider2["GOOGLE"] = "google";
|
|
925
1185
|
Provider2["GITHUB"] = "github";
|
|
926
1186
|
Provider2["SLACK"] = "slack";
|
|
927
|
-
Provider2["MICROSOFT"] = "microsoft";
|
|
928
|
-
Provider2["SALESFORCE"] = "salesforce";
|
|
929
1187
|
Provider2["SENTRY"] = "sentry";
|
|
930
1188
|
return Provider2;
|
|
931
1189
|
})(Provider || {});
|
|
@@ -942,8 +1200,12 @@ var HttpMethod = /* @__PURE__ */ ((HttpMethod2) => {
|
|
|
942
1200
|
// Annotate the CommonJS export names for ESM import in node:
|
|
943
1201
|
0 && (module.exports = {
|
|
944
1202
|
APICallAuditLog,
|
|
1203
|
+
ActorType,
|
|
945
1204
|
AlterSDKError,
|
|
946
1205
|
AlterVault,
|
|
1206
|
+
ConnectSession,
|
|
1207
|
+
ConnectionInfo,
|
|
1208
|
+
ConnectionListResult,
|
|
947
1209
|
ConnectionNotFoundError,
|
|
948
1210
|
HttpMethod,
|
|
949
1211
|
NetworkError,
|