@alter-ai/alter-sdk 0.3.1 → 0.5.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 +163 -33
- package/dist/index.cjs +767 -92
- package/dist/index.d.cts +298 -24
- package/dist/index.d.ts +298 -24
- package/dist/index.js +744 -88
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -24,24 +34,33 @@ __export(index_exports, {
|
|
|
24
34
|
ActorType: () => ActorType,
|
|
25
35
|
AlterSDKError: () => AlterSDKError,
|
|
26
36
|
AlterVault: () => AlterVault,
|
|
37
|
+
BackendError: () => BackendError,
|
|
38
|
+
ConnectConfigError: () => ConnectConfigError,
|
|
39
|
+
ConnectDeniedError: () => ConnectDeniedError,
|
|
40
|
+
ConnectFlowError: () => ConnectFlowError,
|
|
41
|
+
ConnectResult: () => ConnectResult,
|
|
27
42
|
ConnectSession: () => ConnectSession,
|
|
43
|
+
ConnectTimeoutError: () => ConnectTimeoutError,
|
|
44
|
+
ConnectionDeletedError: () => ConnectionDeletedError,
|
|
45
|
+
ConnectionExpiredError: () => ConnectionExpiredError,
|
|
28
46
|
ConnectionInfo: () => ConnectionInfo,
|
|
29
47
|
ConnectionListResult: () => ConnectionListResult,
|
|
30
48
|
ConnectionNotFoundError: () => ConnectionNotFoundError,
|
|
49
|
+
ConnectionRevokedError: () => ConnectionRevokedError,
|
|
31
50
|
HttpMethod: () => HttpMethod,
|
|
32
51
|
NetworkError: () => NetworkError,
|
|
33
52
|
PolicyViolationError: () => PolicyViolationError,
|
|
34
53
|
Provider: () => Provider,
|
|
35
54
|
ProviderAPIError: () => ProviderAPIError,
|
|
55
|
+
ReAuthRequiredError: () => ReAuthRequiredError,
|
|
56
|
+
ScopeReauthRequiredError: () => ScopeReauthRequiredError,
|
|
36
57
|
TimeoutError: () => TimeoutError,
|
|
37
|
-
|
|
38
|
-
TokenResponse: () => TokenResponse,
|
|
39
|
-
TokenRetrievalError: () => TokenRetrievalError
|
|
58
|
+
TokenResponse: () => TokenResponse
|
|
40
59
|
});
|
|
41
60
|
module.exports = __toCommonJS(index_exports);
|
|
42
61
|
|
|
43
62
|
// src/client.ts
|
|
44
|
-
var
|
|
63
|
+
var import_node_crypto2 = require("crypto");
|
|
45
64
|
|
|
46
65
|
// src/exceptions.ts
|
|
47
66
|
var AlterSDKError = class extends Error {
|
|
@@ -59,13 +78,45 @@ var AlterSDKError = class extends Error {
|
|
|
59
78
|
return this.message;
|
|
60
79
|
}
|
|
61
80
|
};
|
|
62
|
-
var
|
|
81
|
+
var BackendError = class extends AlterSDKError {
|
|
82
|
+
constructor(message, details) {
|
|
83
|
+
super(message, details);
|
|
84
|
+
this.name = "BackendError";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var ReAuthRequiredError = class extends BackendError {
|
|
88
|
+
constructor(message, details) {
|
|
89
|
+
super(message, details);
|
|
90
|
+
this.name = "ReAuthRequiredError";
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var ConnectionExpiredError = class extends ReAuthRequiredError {
|
|
94
|
+
constructor(message, details) {
|
|
95
|
+
super(message, details);
|
|
96
|
+
this.name = "ConnectionExpiredError";
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
var ConnectionRevokedError = class extends ReAuthRequiredError {
|
|
100
|
+
connectionId;
|
|
101
|
+
constructor(message, connectionId, details) {
|
|
102
|
+
super(message, details);
|
|
103
|
+
this.name = "ConnectionRevokedError";
|
|
104
|
+
this.connectionId = connectionId;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var ConnectionDeletedError = class extends ReAuthRequiredError {
|
|
108
|
+
constructor(message, details) {
|
|
109
|
+
super(message, details);
|
|
110
|
+
this.name = "ConnectionDeletedError";
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var ConnectionNotFoundError = class extends BackendError {
|
|
63
114
|
constructor(message, details) {
|
|
64
115
|
super(message, details);
|
|
65
|
-
this.name = "
|
|
116
|
+
this.name = "ConnectionNotFoundError";
|
|
66
117
|
}
|
|
67
118
|
};
|
|
68
|
-
var PolicyViolationError = class extends
|
|
119
|
+
var PolicyViolationError = class extends BackendError {
|
|
69
120
|
policyError;
|
|
70
121
|
constructor(message, policyError, details) {
|
|
71
122
|
super(message, details);
|
|
@@ -73,18 +124,28 @@ var PolicyViolationError = class extends TokenRetrievalError {
|
|
|
73
124
|
this.policyError = policyError;
|
|
74
125
|
}
|
|
75
126
|
};
|
|
76
|
-
var
|
|
127
|
+
var ConnectFlowError = class extends AlterSDKError {
|
|
77
128
|
constructor(message, details) {
|
|
78
129
|
super(message, details);
|
|
79
|
-
this.name = "
|
|
130
|
+
this.name = "ConnectFlowError";
|
|
80
131
|
}
|
|
81
132
|
};
|
|
82
|
-
var
|
|
83
|
-
|
|
84
|
-
constructor(message, connectionId, details) {
|
|
133
|
+
var ConnectDeniedError = class extends ConnectFlowError {
|
|
134
|
+
constructor(message, details) {
|
|
85
135
|
super(message, details);
|
|
86
|
-
this.name = "
|
|
87
|
-
|
|
136
|
+
this.name = "ConnectDeniedError";
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var ConnectConfigError = class extends ConnectFlowError {
|
|
140
|
+
constructor(message, details) {
|
|
141
|
+
super(message, details);
|
|
142
|
+
this.name = "ConnectConfigError";
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
var ConnectTimeoutError = class extends ConnectFlowError {
|
|
146
|
+
constructor(message, details) {
|
|
147
|
+
super(message, details);
|
|
148
|
+
this.name = "ConnectTimeoutError";
|
|
88
149
|
}
|
|
89
150
|
};
|
|
90
151
|
var ProviderAPIError = class extends AlterSDKError {
|
|
@@ -97,6 +158,16 @@ var ProviderAPIError = class extends AlterSDKError {
|
|
|
97
158
|
this.responseBody = responseBody;
|
|
98
159
|
}
|
|
99
160
|
};
|
|
161
|
+
var ScopeReauthRequiredError = class extends ProviderAPIError {
|
|
162
|
+
connectionId;
|
|
163
|
+
providerId;
|
|
164
|
+
constructor(message, connectionId, providerId, statusCode, responseBody, details) {
|
|
165
|
+
super(message, statusCode, responseBody, details);
|
|
166
|
+
this.name = "ScopeReauthRequiredError";
|
|
167
|
+
this.connectionId = connectionId;
|
|
168
|
+
this.providerId = providerId;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
100
171
|
var NetworkError = class extends AlterSDKError {
|
|
101
172
|
constructor(message, details) {
|
|
102
173
|
super(message, details);
|
|
@@ -134,6 +205,10 @@ var TokenResponse = class _TokenResponse {
|
|
|
134
205
|
injectionHeader;
|
|
135
206
|
/** Header value format with {token} placeholder (e.g., "Bearer {token}", "{token}") */
|
|
136
207
|
injectionFormat;
|
|
208
|
+
/** Extra credentials for multi-part auth (e.g. AWS SigV4 secret_key, region) */
|
|
209
|
+
additionalCredentials;
|
|
210
|
+
/** Additional injection rules for multi-header or query param auth */
|
|
211
|
+
additionalInjections;
|
|
137
212
|
constructor(data) {
|
|
138
213
|
this.tokenType = data.token_type ?? "Bearer";
|
|
139
214
|
this.expiresIn = data.expires_in ?? null;
|
|
@@ -143,6 +218,13 @@ var TokenResponse = class _TokenResponse {
|
|
|
143
218
|
this.providerId = data.provider_id ?? "";
|
|
144
219
|
this.injectionHeader = data.injection_header ?? "Authorization";
|
|
145
220
|
this.injectionFormat = data.injection_format ?? "Bearer {token}";
|
|
221
|
+
if (data.additional_credentials) {
|
|
222
|
+
const { secret_key: _, ...safeCredentials } = data.additional_credentials;
|
|
223
|
+
this.additionalCredentials = Object.keys(safeCredentials).length > 0 ? safeCredentials : null;
|
|
224
|
+
} else {
|
|
225
|
+
this.additionalCredentials = null;
|
|
226
|
+
}
|
|
227
|
+
this.additionalInjections = data.additional_injections ?? null;
|
|
146
228
|
Object.freeze(this);
|
|
147
229
|
}
|
|
148
230
|
/**
|
|
@@ -211,6 +293,7 @@ var ConnectionInfo = class {
|
|
|
211
293
|
accountIdentifier;
|
|
212
294
|
accountDisplayName;
|
|
213
295
|
status;
|
|
296
|
+
scopeMismatch;
|
|
214
297
|
expiresAt;
|
|
215
298
|
createdAt;
|
|
216
299
|
lastUsedAt;
|
|
@@ -221,6 +304,7 @@ var ConnectionInfo = class {
|
|
|
221
304
|
this.accountIdentifier = data.account_identifier ?? null;
|
|
222
305
|
this.accountDisplayName = data.account_display_name ?? null;
|
|
223
306
|
this.status = data.status;
|
|
307
|
+
this.scopeMismatch = data.scope_mismatch ?? false;
|
|
224
308
|
this.expiresAt = data.expires_at ?? null;
|
|
225
309
|
this.createdAt = data.created_at;
|
|
226
310
|
this.lastUsedAt = data.last_used_at ?? null;
|
|
@@ -234,6 +318,7 @@ var ConnectionInfo = class {
|
|
|
234
318
|
account_identifier: this.accountIdentifier,
|
|
235
319
|
account_display_name: this.accountDisplayName,
|
|
236
320
|
status: this.status,
|
|
321
|
+
scope_mismatch: this.scopeMismatch,
|
|
237
322
|
expires_at: this.expiresAt,
|
|
238
323
|
created_at: this.createdAt,
|
|
239
324
|
last_used_at: this.lastUsedAt
|
|
@@ -282,12 +367,41 @@ var ConnectionListResult = class {
|
|
|
282
367
|
Object.freeze(this);
|
|
283
368
|
}
|
|
284
369
|
};
|
|
370
|
+
var ConnectResult = class {
|
|
371
|
+
connectionId;
|
|
372
|
+
providerId;
|
|
373
|
+
accountIdentifier;
|
|
374
|
+
scopes;
|
|
375
|
+
connectionPolicy;
|
|
376
|
+
constructor(data) {
|
|
377
|
+
this.connectionId = data.connection_id;
|
|
378
|
+
this.providerId = data.provider_id;
|
|
379
|
+
this.accountIdentifier = data.account_identifier ?? null;
|
|
380
|
+
this.scopes = data.scopes ?? [];
|
|
381
|
+
this.connectionPolicy = data.connection_policy ?? null;
|
|
382
|
+
Object.freeze(this);
|
|
383
|
+
}
|
|
384
|
+
toJSON() {
|
|
385
|
+
return {
|
|
386
|
+
connection_id: this.connectionId,
|
|
387
|
+
provider_id: this.providerId,
|
|
388
|
+
account_identifier: this.accountIdentifier,
|
|
389
|
+
scopes: this.scopes,
|
|
390
|
+
connection_policy: this.connectionPolicy
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
toString() {
|
|
394
|
+
return `ConnectResult(connection_id=${this.connectionId}, provider=${this.providerId})`;
|
|
395
|
+
}
|
|
396
|
+
};
|
|
285
397
|
var SENSITIVE_HEADERS = /* @__PURE__ */ new Set([
|
|
286
398
|
"authorization",
|
|
287
399
|
"cookie",
|
|
288
400
|
"set-cookie",
|
|
289
401
|
"x-api-key",
|
|
290
|
-
"x-auth-token"
|
|
402
|
+
"x-auth-token",
|
|
403
|
+
"x-amz-date",
|
|
404
|
+
"x-amz-content-sha256"
|
|
291
405
|
]);
|
|
292
406
|
var APICallAuditLog = class {
|
|
293
407
|
connectionId;
|
|
@@ -361,11 +475,171 @@ var APICallAuditLog = class {
|
|
|
361
475
|
}
|
|
362
476
|
};
|
|
363
477
|
|
|
478
|
+
// src/aws-sig-v4.ts
|
|
479
|
+
var import_node_crypto = require("crypto");
|
|
480
|
+
var ALGORITHM = "AWS4-HMAC-SHA256";
|
|
481
|
+
var AWS_HOST_RE = /^(?<service>[a-z0-9-]+)\.(?<region>[a-z]{2}(?:-[a-z0-9]+)+-\d+)\.amazonaws\.com$/;
|
|
482
|
+
var S3_VIRTUAL_HOST_RE = /^[^.]+\.s3\.(?<region>[a-z]{2}(?:-[a-z0-9]+)+-\d+)\.amazonaws\.com$/;
|
|
483
|
+
function hmacSha256(key, message) {
|
|
484
|
+
return (0, import_node_crypto.createHmac)("sha256", key).update(message, "utf8").digest();
|
|
485
|
+
}
|
|
486
|
+
function sha256Hex(data) {
|
|
487
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
488
|
+
if (typeof data === "string") {
|
|
489
|
+
hash.update(data, "utf8");
|
|
490
|
+
} else {
|
|
491
|
+
hash.update(data);
|
|
492
|
+
}
|
|
493
|
+
return hash.digest("hex");
|
|
494
|
+
}
|
|
495
|
+
function detectServiceAndRegion(hostname) {
|
|
496
|
+
const lower = hostname.toLowerCase();
|
|
497
|
+
const m = AWS_HOST_RE.exec(lower);
|
|
498
|
+
if (m?.groups) {
|
|
499
|
+
return { service: m.groups.service, region: m.groups.region };
|
|
500
|
+
}
|
|
501
|
+
const s3m = S3_VIRTUAL_HOST_RE.exec(lower);
|
|
502
|
+
if (s3m?.groups) {
|
|
503
|
+
return { service: "s3", region: s3m.groups.region };
|
|
504
|
+
}
|
|
505
|
+
return { service: null, region: null };
|
|
506
|
+
}
|
|
507
|
+
function deriveSigningKey(secretKey, dateStamp, region, service) {
|
|
508
|
+
const kDate = hmacSha256(Buffer.from("AWS4" + secretKey, "utf8"), dateStamp);
|
|
509
|
+
const kRegion = hmacSha256(kDate, region);
|
|
510
|
+
const kService = hmacSha256(kRegion, service);
|
|
511
|
+
const kSigning = hmacSha256(kService, "aws4_request");
|
|
512
|
+
return kSigning;
|
|
513
|
+
}
|
|
514
|
+
function canonicalUri(path) {
|
|
515
|
+
if (!path) return "/";
|
|
516
|
+
if (!path.startsWith("/")) path = "/" + path;
|
|
517
|
+
const segments = path.split("/");
|
|
518
|
+
return segments.map(
|
|
519
|
+
(seg) => encodeURIComponent(seg).replace(
|
|
520
|
+
/[!'()*]/g,
|
|
521
|
+
(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
|
|
522
|
+
)
|
|
523
|
+
).join("/");
|
|
524
|
+
}
|
|
525
|
+
function canonicalQueryString(query) {
|
|
526
|
+
if (!query) return "";
|
|
527
|
+
const sorted = [];
|
|
528
|
+
for (const pair of query.split("&")) {
|
|
529
|
+
const eqIdx = pair.indexOf("=");
|
|
530
|
+
if (eqIdx === -1) {
|
|
531
|
+
sorted.push([decodeURIComponent(pair), ""]);
|
|
532
|
+
} else {
|
|
533
|
+
sorted.push([
|
|
534
|
+
decodeURIComponent(pair.slice(0, eqIdx)),
|
|
535
|
+
decodeURIComponent(pair.slice(eqIdx + 1))
|
|
536
|
+
]);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
sorted.sort((a, b) => {
|
|
540
|
+
if (a[0] < b[0]) return -1;
|
|
541
|
+
if (a[0] > b[0]) return 1;
|
|
542
|
+
if (a[1] < b[1]) return -1;
|
|
543
|
+
if (a[1] > b[1]) return 1;
|
|
544
|
+
return 0;
|
|
545
|
+
});
|
|
546
|
+
const sigv4Encode = (s) => encodeURIComponent(s).replace(
|
|
547
|
+
/[!'()*]/g,
|
|
548
|
+
(c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`
|
|
549
|
+
);
|
|
550
|
+
return sorted.map(([k, v]) => `${sigv4Encode(k)}=${sigv4Encode(v)}`).join("&");
|
|
551
|
+
}
|
|
552
|
+
function canonicalHeadersAndSigned(headers) {
|
|
553
|
+
const canonical = {};
|
|
554
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
555
|
+
const lowerName = name.toLowerCase().trim();
|
|
556
|
+
const trimmedValue = value.replace(/\s+/g, " ").trim();
|
|
557
|
+
canonical[lowerName] = trimmedValue;
|
|
558
|
+
}
|
|
559
|
+
const sortedNames = Object.keys(canonical).sort();
|
|
560
|
+
const canonicalStr = sortedNames.map((name) => `${name}:${canonical[name]}
|
|
561
|
+
`).join("");
|
|
562
|
+
const signedStr = sortedNames.join(";");
|
|
563
|
+
return { canonicalHeaders: canonicalStr, signedHeaders: signedStr };
|
|
564
|
+
}
|
|
565
|
+
function signAwsRequest(opts) {
|
|
566
|
+
const parsed = new URL(opts.url);
|
|
567
|
+
const hostname = parsed.hostname;
|
|
568
|
+
let { region, service } = opts;
|
|
569
|
+
if (region == null || service == null) {
|
|
570
|
+
const detected = detectServiceAndRegion(hostname);
|
|
571
|
+
if (region == null) region = detected.region;
|
|
572
|
+
if (service == null) service = detected.service;
|
|
573
|
+
}
|
|
574
|
+
if (!region) {
|
|
575
|
+
throw new Error(
|
|
576
|
+
`Cannot determine AWS region from URL '${opts.url}'. Pass region explicitly via additional_credentials.`
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
if (!service) {
|
|
580
|
+
throw new Error(
|
|
581
|
+
`Cannot determine AWS service from URL '${opts.url}'. Pass service explicitly via additional_credentials.`
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
const timestamp = opts.timestamp ?? /* @__PURE__ */ new Date();
|
|
585
|
+
const amzDate = timestamp.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
586
|
+
const dateStamp = amzDate.slice(0, 8);
|
|
587
|
+
const bodyBytes = opts.body != null ? typeof opts.body === "string" ? Buffer.from(opts.body, "utf8") : opts.body : Buffer.alloc(0);
|
|
588
|
+
const payloadHash = sha256Hex(bodyBytes);
|
|
589
|
+
const headersToSign = {};
|
|
590
|
+
const hasHost = Object.keys(opts.headers).some(
|
|
591
|
+
(k) => k.toLowerCase() === "host"
|
|
592
|
+
);
|
|
593
|
+
if (!hasHost) {
|
|
594
|
+
const port = parsed.port;
|
|
595
|
+
headersToSign["host"] = port && port !== "80" && port !== "443" ? `${hostname}:${port}` : hostname;
|
|
596
|
+
} else {
|
|
597
|
+
for (const [k, v] of Object.entries(opts.headers)) {
|
|
598
|
+
if (k.toLowerCase() === "host") {
|
|
599
|
+
headersToSign["host"] = v;
|
|
600
|
+
break;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
headersToSign["x-amz-date"] = amzDate;
|
|
605
|
+
headersToSign["x-amz-content-sha256"] = payloadHash;
|
|
606
|
+
const canonicalUriStr = canonicalUri(parsed.pathname);
|
|
607
|
+
const canonicalQs = canonicalQueryString(parsed.search.replace(/^\?/, ""));
|
|
608
|
+
const { canonicalHeaders, signedHeaders } = canonicalHeadersAndSigned(headersToSign);
|
|
609
|
+
const canonicalRequest = [
|
|
610
|
+
opts.method.toUpperCase(),
|
|
611
|
+
canonicalUriStr,
|
|
612
|
+
canonicalQs,
|
|
613
|
+
canonicalHeaders,
|
|
614
|
+
signedHeaders,
|
|
615
|
+
payloadHash
|
|
616
|
+
].join("\n");
|
|
617
|
+
const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
|
|
618
|
+
const stringToSign = [
|
|
619
|
+
ALGORITHM,
|
|
620
|
+
amzDate,
|
|
621
|
+
credentialScope,
|
|
622
|
+
sha256Hex(canonicalRequest)
|
|
623
|
+
].join("\n");
|
|
624
|
+
const signingKey = deriveSigningKey(opts.secretKey, dateStamp, region, service);
|
|
625
|
+
const signature = (0, import_node_crypto.createHmac)("sha256", signingKey).update(stringToSign, "utf8").digest("hex");
|
|
626
|
+
const authorization = `${ALGORITHM} Credential=${opts.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
627
|
+
return {
|
|
628
|
+
Authorization: authorization,
|
|
629
|
+
"x-amz-date": amzDate,
|
|
630
|
+
"x-amz-content-sha256": payloadHash
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
364
634
|
// src/client.ts
|
|
365
635
|
var _tokenStore = /* @__PURE__ */ new WeakMap();
|
|
636
|
+
var _additionalCredsStore = /* @__PURE__ */ new WeakMap();
|
|
366
637
|
function _storeAccessToken(token, accessToken) {
|
|
367
638
|
_tokenStore.set(token, accessToken);
|
|
368
639
|
}
|
|
640
|
+
function _storeAdditionalCredentials(token, creds) {
|
|
641
|
+
_additionalCredsStore.set(token, creds);
|
|
642
|
+
}
|
|
369
643
|
function _extractAccessToken(token) {
|
|
370
644
|
const value = _tokenStore.get(token);
|
|
371
645
|
if (value === void 0) {
|
|
@@ -375,11 +649,15 @@ function _extractAccessToken(token) {
|
|
|
375
649
|
}
|
|
376
650
|
return value;
|
|
377
651
|
}
|
|
652
|
+
function _extractAdditionalCredentials(token) {
|
|
653
|
+
return _additionalCredsStore.get(token);
|
|
654
|
+
}
|
|
378
655
|
var _fetch;
|
|
379
|
-
var SDK_VERSION = "0.
|
|
656
|
+
var SDK_VERSION = "0.5.0";
|
|
380
657
|
var SDK_USER_AGENT = `alter-sdk-node/${SDK_VERSION}`;
|
|
381
658
|
var HTTP_FORBIDDEN = 403;
|
|
382
659
|
var HTTP_NOT_FOUND = 404;
|
|
660
|
+
var HTTP_GONE = 410;
|
|
383
661
|
var HTTP_BAD_REQUEST = 400;
|
|
384
662
|
var HTTP_UNAUTHORIZED = 401;
|
|
385
663
|
var HTTP_BAD_GATEWAY = 502;
|
|
@@ -433,7 +711,12 @@ var HttpClient = class {
|
|
|
433
711
|
headers: mergedHeaders,
|
|
434
712
|
signal: controller.signal
|
|
435
713
|
};
|
|
436
|
-
if (options?.
|
|
714
|
+
if (options?.body !== void 0) {
|
|
715
|
+
init.body = options.body;
|
|
716
|
+
if (!mergedHeaders["Content-Type"]) {
|
|
717
|
+
mergedHeaders["Content-Type"] = "application/json";
|
|
718
|
+
}
|
|
719
|
+
} else if (options?.json !== void 0) {
|
|
437
720
|
init.body = JSON.stringify(options.json);
|
|
438
721
|
mergedHeaders["Content-Type"] = "application/json";
|
|
439
722
|
}
|
|
@@ -469,6 +752,8 @@ var AlterVault = class _AlterVault {
|
|
|
469
752
|
#closed = false;
|
|
470
753
|
/** Pending audit log promises (fire-and-forget) */
|
|
471
754
|
#auditPromises = /* @__PURE__ */ new Set();
|
|
755
|
+
/** JWT identity resolution: callable that returns user token */
|
|
756
|
+
#userTokenGetter = null;
|
|
472
757
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
473
758
|
// Public readonly properties (frozen by Object.freeze)
|
|
474
759
|
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -496,7 +781,7 @@ var AlterVault = class _AlterVault {
|
|
|
496
781
|
for (const [name, value] of actorStrings) {
|
|
497
782
|
_AlterVault.#validateActorString(value, name);
|
|
498
783
|
}
|
|
499
|
-
this.#hmacKey = (0,
|
|
784
|
+
this.#hmacKey = (0, import_node_crypto2.createHmac)("sha256", options.apiKey).update("alter-signing-v1").digest();
|
|
500
785
|
this.baseUrl = (process.env.ALTER_BASE_URL ?? "https://backend.alterai.dev").replace(/\/+$/, "");
|
|
501
786
|
const timeoutMs = options.timeout ?? 3e4;
|
|
502
787
|
this.#actorType = options.actorType;
|
|
@@ -504,6 +789,7 @@ var AlterVault = class _AlterVault {
|
|
|
504
789
|
this.#actorName = options.actorName;
|
|
505
790
|
this.#actorVersion = options.actorVersion;
|
|
506
791
|
this.#clientType = options.clientType;
|
|
792
|
+
this.#userTokenGetter = options.userTokenGetter ?? null;
|
|
507
793
|
this.#framework = options.framework;
|
|
508
794
|
if (!_fetch) {
|
|
509
795
|
_fetch = globalThis.fetch;
|
|
@@ -600,12 +886,12 @@ var AlterVault = class _AlterVault {
|
|
|
600
886
|
*/
|
|
601
887
|
#computeHmacHeaders(method, path, body) {
|
|
602
888
|
const timestamp = String(Math.floor(Date.now() / 1e3));
|
|
603
|
-
const contentHash = (0,
|
|
889
|
+
const contentHash = (0, import_node_crypto2.createHash)("sha256").update(body ?? "").digest("hex");
|
|
604
890
|
const stringToSign = `${method.toUpperCase()}
|
|
605
891
|
${path}
|
|
606
892
|
${timestamp}
|
|
607
893
|
${contentHash}`;
|
|
608
|
-
const signature = (0,
|
|
894
|
+
const signature = (0, import_node_crypto2.createHmac)("sha256", this.#hmacKey).update(stringToSign).digest("hex");
|
|
609
895
|
return {
|
|
610
896
|
"X-Alter-Timestamp": timestamp,
|
|
611
897
|
"X-Alter-Content-SHA256": contentHash,
|
|
@@ -678,6 +964,24 @@ ${contentHash}`;
|
|
|
678
964
|
}
|
|
679
965
|
return false;
|
|
680
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* Resolve a value_source to the actual value for injection.
|
|
969
|
+
*
|
|
970
|
+
* @param valueSource - "token" or "additional_credentials.<field>"
|
|
971
|
+
* @param accessToken - The main credential value
|
|
972
|
+
* @param additionalCreds - Additional credentials from vault
|
|
973
|
+
* @returns The resolved value, or null if not available
|
|
974
|
+
*/
|
|
975
|
+
static #resolveInjectionValue(valueSource, accessToken, additionalCreds) {
|
|
976
|
+
if (valueSource === "token") {
|
|
977
|
+
return accessToken;
|
|
978
|
+
}
|
|
979
|
+
if (valueSource.startsWith("additional_credentials.")) {
|
|
980
|
+
const field = valueSource.slice("additional_credentials.".length);
|
|
981
|
+
return additionalCreds?.[field] ?? null;
|
|
982
|
+
}
|
|
983
|
+
return null;
|
|
984
|
+
}
|
|
681
985
|
static async #safeParseJson(response) {
|
|
682
986
|
try {
|
|
683
987
|
return await response.clone().json();
|
|
@@ -699,12 +1003,25 @@ ${contentHash}`;
|
|
|
699
1003
|
}
|
|
700
1004
|
if (response.status === HTTP_FORBIDDEN) {
|
|
701
1005
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
1006
|
+
if (errorData.error === "connection_expired") {
|
|
1007
|
+
throw new ConnectionExpiredError(
|
|
1008
|
+
errorData.message ?? "Connection expired per TTL policy",
|
|
1009
|
+
errorData.details
|
|
1010
|
+
);
|
|
1011
|
+
}
|
|
702
1012
|
throw new PolicyViolationError(
|
|
703
1013
|
errorData.message ?? "Access denied by policy",
|
|
704
1014
|
errorData.error,
|
|
705
1015
|
errorData.details
|
|
706
1016
|
);
|
|
707
1017
|
}
|
|
1018
|
+
if (response.status === HTTP_GONE) {
|
|
1019
|
+
const errorData = await _AlterVault.#safeParseJson(response);
|
|
1020
|
+
throw new ConnectionDeletedError(
|
|
1021
|
+
errorData.message ?? "Connection has been deleted. A new connection_id will be issued on re-authorization.",
|
|
1022
|
+
errorData
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
708
1025
|
if (response.status === HTTP_NOT_FOUND) {
|
|
709
1026
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
710
1027
|
throw new ConnectionNotFoundError(
|
|
@@ -714,35 +1031,35 @@ ${contentHash}`;
|
|
|
714
1031
|
}
|
|
715
1032
|
if (response.status === HTTP_BAD_REQUEST || response.status === HTTP_BAD_GATEWAY) {
|
|
716
1033
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
717
|
-
if (
|
|
718
|
-
throw new
|
|
719
|
-
errorData.message ?? "
|
|
1034
|
+
if (errorData.error === "connection_revoked") {
|
|
1035
|
+
throw new ConnectionRevokedError(
|
|
1036
|
+
errorData.message ?? "Connection has been revoked. User must re-authorize.",
|
|
720
1037
|
errorData.connection_id,
|
|
721
1038
|
errorData
|
|
722
1039
|
);
|
|
723
1040
|
}
|
|
724
|
-
throw new
|
|
1041
|
+
throw new BackendError(
|
|
725
1042
|
errorData.message ?? `Backend error ${response.status}`,
|
|
726
1043
|
errorData
|
|
727
1044
|
);
|
|
728
1045
|
}
|
|
729
1046
|
if (response.status === HTTP_UNAUTHORIZED) {
|
|
730
1047
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
731
|
-
throw new
|
|
1048
|
+
throw new BackendError(
|
|
732
1049
|
errorData.message ?? "Unauthorized \u2014 check your API key",
|
|
733
1050
|
errorData
|
|
734
1051
|
);
|
|
735
1052
|
}
|
|
736
1053
|
if (response.status === HTTP_INTERNAL_SERVER_ERROR || response.status === HTTP_SERVICE_UNAVAILABLE) {
|
|
737
1054
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
738
|
-
throw new
|
|
1055
|
+
throw new BackendError(
|
|
739
1056
|
errorData.message ?? `Backend unavailable (HTTP ${response.status})`,
|
|
740
1057
|
errorData
|
|
741
1058
|
);
|
|
742
1059
|
}
|
|
743
1060
|
if (response.status >= HTTP_CLIENT_ERROR_START) {
|
|
744
1061
|
const errorData = await _AlterVault.#safeParseJson(response);
|
|
745
|
-
throw new
|
|
1062
|
+
throw new BackendError(
|
|
746
1063
|
errorData.message ?? `Unexpected backend error (HTTP ${response.status})`,
|
|
747
1064
|
errorData
|
|
748
1065
|
);
|
|
@@ -754,24 +1071,52 @@ ${contentHash}`;
|
|
|
754
1071
|
* This is a private method. Tokens are NEVER exposed to developers.
|
|
755
1072
|
* Use request() instead, which handles tokens internally.
|
|
756
1073
|
*/
|
|
757
|
-
async #
|
|
1074
|
+
async #getUserToken() {
|
|
1075
|
+
if (!this.#userTokenGetter) {
|
|
1076
|
+
throw new AlterSDKError(
|
|
1077
|
+
"userTokenGetter is required for provider-based resolution. Pass userTokenGetter to AlterVault constructor."
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
const result = this.#userTokenGetter();
|
|
1081
|
+
const token = result instanceof Promise ? await result : result;
|
|
1082
|
+
if (!token || typeof token !== "string") {
|
|
1083
|
+
throw new AlterSDKError("userTokenGetter must return a non-empty string");
|
|
1084
|
+
}
|
|
1085
|
+
return token;
|
|
1086
|
+
}
|
|
1087
|
+
async #getToken(connectionId, reason, requestMetadata, runId, threadId, toolCallId, provider, account) {
|
|
758
1088
|
const actorHeaders = this.#getActorRequestHeaders(
|
|
759
1089
|
runId,
|
|
760
1090
|
threadId,
|
|
761
1091
|
toolCallId
|
|
762
1092
|
);
|
|
763
1093
|
let response;
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
1094
|
+
let tokenBody;
|
|
1095
|
+
if (provider) {
|
|
1096
|
+
const userToken = await this.#getUserToken();
|
|
1097
|
+
tokenBody = {
|
|
1098
|
+
provider_id: provider,
|
|
1099
|
+
user_token: userToken,
|
|
1100
|
+
reason: reason ?? null,
|
|
1101
|
+
request: requestMetadata ?? null
|
|
1102
|
+
};
|
|
1103
|
+
if (account) {
|
|
1104
|
+
tokenBody.account = account;
|
|
1105
|
+
}
|
|
1106
|
+
} else {
|
|
1107
|
+
tokenBody = {
|
|
1108
|
+
connection_id: connectionId,
|
|
1109
|
+
reason: reason ?? null,
|
|
1110
|
+
request: requestMetadata ?? null
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
769
1113
|
const tokenPath = "/sdk/token";
|
|
770
|
-
const
|
|
1114
|
+
const tokenBodyStr = JSON.stringify(tokenBody);
|
|
1115
|
+
const hmacHeaders = this.#computeHmacHeaders("POST", tokenPath, tokenBodyStr);
|
|
771
1116
|
try {
|
|
772
1117
|
response = await this.#alterClient.post(tokenPath, {
|
|
773
|
-
|
|
774
|
-
headers: { ...actorHeaders, ...hmacHeaders }
|
|
1118
|
+
body: tokenBodyStr,
|
|
1119
|
+
headers: { ...actorHeaders, ...hmacHeaders, "Content-Type": "application/json" }
|
|
775
1120
|
});
|
|
776
1121
|
} catch (error) {
|
|
777
1122
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
@@ -786,7 +1131,7 @@ ${contentHash}`;
|
|
|
786
1131
|
{ base_url: this.baseUrl }
|
|
787
1132
|
);
|
|
788
1133
|
}
|
|
789
|
-
throw new
|
|
1134
|
+
throw new BackendError(
|
|
790
1135
|
`Failed to retrieve token: ${error instanceof Error ? error.message : String(error)}`,
|
|
791
1136
|
{ connection_id: connectionId, error: String(error) }
|
|
792
1137
|
);
|
|
@@ -795,21 +1140,25 @@ ${contentHash}`;
|
|
|
795
1140
|
await this.#handleErrorResponse(response);
|
|
796
1141
|
const tokenData = await response.json();
|
|
797
1142
|
const typedData = tokenData;
|
|
1143
|
+
const scopeMismatch = typedData.scope_mismatch ?? false;
|
|
798
1144
|
const tokenResponse = new TokenResponse(typedData);
|
|
799
1145
|
if (!/^[A-Za-z][A-Za-z0-9-]*$/.test(tokenResponse.injectionHeader)) {
|
|
800
|
-
throw new
|
|
1146
|
+
throw new BackendError(
|
|
801
1147
|
`Backend returned invalid injection_header: ${tokenResponse.injectionHeader}`,
|
|
802
1148
|
{ connectionId: String(connectionId) }
|
|
803
1149
|
);
|
|
804
1150
|
}
|
|
805
1151
|
if (/[\r\n\x00]/.test(tokenResponse.injectionFormat)) {
|
|
806
|
-
throw new
|
|
1152
|
+
throw new BackendError(
|
|
807
1153
|
`Backend returned invalid injection_format (contains control characters)`,
|
|
808
1154
|
{ connectionId: String(connectionId) }
|
|
809
1155
|
);
|
|
810
1156
|
}
|
|
811
1157
|
_storeAccessToken(tokenResponse, typedData.access_token);
|
|
812
|
-
|
|
1158
|
+
if (typedData.additional_credentials) {
|
|
1159
|
+
_storeAdditionalCredentials(tokenResponse, typedData.additional_credentials);
|
|
1160
|
+
}
|
|
1161
|
+
return { tokenResponse, scopeMismatch };
|
|
813
1162
|
}
|
|
814
1163
|
/**
|
|
815
1164
|
* Log an API call to the backend audit endpoint (INTERNAL).
|
|
@@ -839,10 +1188,11 @@ ${contentHash}`;
|
|
|
839
1188
|
const actorHeaders = this.#getActorRequestHeaders(params.runId);
|
|
840
1189
|
const auditPath = "/sdk/oauth/audit/api-call";
|
|
841
1190
|
const auditBody = sanitized;
|
|
842
|
-
const
|
|
1191
|
+
const auditBodyStr = JSON.stringify(auditBody);
|
|
1192
|
+
const auditHmac = this.#computeHmacHeaders("POST", auditPath, auditBodyStr);
|
|
843
1193
|
const response = await this.#alterClient.post(auditPath, {
|
|
844
|
-
|
|
845
|
-
headers: { ...actorHeaders, ...auditHmac }
|
|
1194
|
+
body: auditBodyStr,
|
|
1195
|
+
headers: { ...actorHeaders, ...auditHmac, "Content-Type": "application/json" }
|
|
846
1196
|
});
|
|
847
1197
|
this.#cacheActorIdFromResponse(response);
|
|
848
1198
|
if (!response.ok) {
|
|
@@ -914,12 +1264,22 @@ ${contentHash}`;
|
|
|
914
1264
|
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
915
1265
|
);
|
|
916
1266
|
}
|
|
917
|
-
const
|
|
1267
|
+
const provider = options?.provider;
|
|
1268
|
+
const account = options?.account;
|
|
1269
|
+
if (!connectionId && !provider) {
|
|
1270
|
+
throw new AlterSDKError("Provide connectionId or options.provider");
|
|
1271
|
+
}
|
|
1272
|
+
if (connectionId && provider) {
|
|
1273
|
+
throw new AlterSDKError("Cannot provide both connectionId and options.provider");
|
|
1274
|
+
}
|
|
1275
|
+
const effectiveConnectionId = connectionId ?? null;
|
|
1276
|
+
let currentUrl = url;
|
|
1277
|
+
const runId = options?.runId ?? (0, import_node_crypto2.randomUUID)();
|
|
918
1278
|
const methodStr = String(method).toUpperCase();
|
|
919
|
-
const urlLower =
|
|
1279
|
+
const urlLower = currentUrl.toLowerCase();
|
|
920
1280
|
if (!ALLOWED_URL_SCHEMES.some((scheme) => urlLower.startsWith(scheme))) {
|
|
921
1281
|
throw new AlterSDKError(
|
|
922
|
-
`URL must start with https:// or http://, got: ${
|
|
1282
|
+
`URL must start with https:// or http://, got: ${currentUrl.slice(0, 50)}`
|
|
923
1283
|
);
|
|
924
1284
|
}
|
|
925
1285
|
if (options?.pathParams && Object.keys(options.pathParams).length > 0) {
|
|
@@ -928,7 +1288,7 @@ ${contentHash}`;
|
|
|
928
1288
|
encodedParams[key] = encodeURIComponent(String(value));
|
|
929
1289
|
}
|
|
930
1290
|
try {
|
|
931
|
-
let resolvedUrl =
|
|
1291
|
+
let resolvedUrl = currentUrl;
|
|
932
1292
|
for (const [key, value] of Object.entries(encodedParams)) {
|
|
933
1293
|
const placeholder = `{${key}}`;
|
|
934
1294
|
if (!resolvedUrl.includes(placeholder)) {
|
|
@@ -939,74 +1299,142 @@ ${contentHash}`;
|
|
|
939
1299
|
const remaining = resolvedUrl.match(/\{(\w+)\}/);
|
|
940
1300
|
if (remaining) {
|
|
941
1301
|
throw new AlterSDKError(
|
|
942
|
-
`Invalid URL template or missing path_params: '${remaining[1]}'. URL: ${
|
|
1302
|
+
`Invalid URL template or missing path_params: '${remaining[1]}'. URL: ${currentUrl}, path_params: ${JSON.stringify(options.pathParams)}`
|
|
943
1303
|
);
|
|
944
1304
|
}
|
|
945
|
-
|
|
1305
|
+
currentUrl = resolvedUrl;
|
|
946
1306
|
} catch (error) {
|
|
947
1307
|
if (error instanceof AlterSDKError) {
|
|
948
1308
|
throw error;
|
|
949
1309
|
}
|
|
950
1310
|
throw new AlterSDKError(
|
|
951
|
-
`Invalid URL template or missing path_params: ${error instanceof Error ? error.message : String(error)}. URL: ${
|
|
1311
|
+
`Invalid URL template or missing path_params: ${error instanceof Error ? error.message : String(error)}. URL: ${currentUrl}, path_params: ${JSON.stringify(options.pathParams)}`
|
|
952
1312
|
);
|
|
953
1313
|
}
|
|
954
1314
|
}
|
|
955
|
-
const tokenResponse = await this.#getToken(
|
|
956
|
-
|
|
1315
|
+
const { tokenResponse, scopeMismatch } = await this.#getToken(
|
|
1316
|
+
effectiveConnectionId,
|
|
957
1317
|
options?.reason,
|
|
958
|
-
{ method: methodStr, url },
|
|
1318
|
+
{ method: methodStr, url: currentUrl },
|
|
959
1319
|
runId,
|
|
960
1320
|
options?.threadId,
|
|
961
|
-
options?.toolCallId
|
|
1321
|
+
options?.toolCallId,
|
|
1322
|
+
provider,
|
|
1323
|
+
account
|
|
962
1324
|
);
|
|
963
|
-
const injectionHeaderLower = tokenResponse.injectionHeader.toLowerCase();
|
|
964
|
-
if (options?.extraHeaders && Object.keys(options.extraHeaders).some(
|
|
965
|
-
(k) => k.toLowerCase() === injectionHeaderLower
|
|
966
|
-
)) {
|
|
967
|
-
console.warn(
|
|
968
|
-
`extraHeaders contains '${tokenResponse.injectionHeader}' which will be overwritten with the auto-injected credential`
|
|
969
|
-
);
|
|
970
|
-
}
|
|
971
1325
|
const requestHeaders = options?.extraHeaders ? { ...options.extraHeaders } : {};
|
|
972
1326
|
const accessToken = _extractAccessToken(tokenResponse);
|
|
973
|
-
|
|
1327
|
+
const injectionHeaderLower = tokenResponse.injectionHeader.toLowerCase();
|
|
1328
|
+
const additionalCreds = _extractAdditionalCredentials(tokenResponse);
|
|
1329
|
+
const isSigV4 = tokenResponse.injectionFormat.startsWith("AWS4-HMAC-SHA256") && additionalCreds != null;
|
|
1330
|
+
let sigv4BodyStr = null;
|
|
1331
|
+
if (isSigV4) {
|
|
1332
|
+
const accessKeyId = accessToken;
|
|
1333
|
+
if (options?.json != null) {
|
|
1334
|
+
sigv4BodyStr = JSON.stringify(options.json);
|
|
1335
|
+
if (!requestHeaders["Content-Type"]) {
|
|
1336
|
+
requestHeaders["Content-Type"] = "application/json";
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
if (!additionalCreds.secret_key) {
|
|
1340
|
+
throw new BackendError(
|
|
1341
|
+
"AWS SigV4 credential is missing secret_key in additional_credentials. Re-store the credential with both Access Key ID and Secret Access Key.",
|
|
1342
|
+
{ connection_id: effectiveConnectionId }
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
const awsHeaders = signAwsRequest({
|
|
1346
|
+
method: methodStr,
|
|
1347
|
+
url: currentUrl,
|
|
1348
|
+
headers: requestHeaders,
|
|
1349
|
+
body: sigv4BodyStr,
|
|
1350
|
+
accessKeyId,
|
|
1351
|
+
secretKey: additionalCreds.secret_key,
|
|
1352
|
+
region: additionalCreds.region ?? null,
|
|
1353
|
+
service: additionalCreds.service ?? null
|
|
1354
|
+
});
|
|
1355
|
+
Object.assign(requestHeaders, awsHeaders);
|
|
1356
|
+
} else {
|
|
1357
|
+
if (options?.extraHeaders && Object.keys(options.extraHeaders).some(
|
|
1358
|
+
(k) => k.toLowerCase() === injectionHeaderLower
|
|
1359
|
+
)) {
|
|
1360
|
+
console.warn(
|
|
1361
|
+
`extraHeaders contains '${tokenResponse.injectionHeader}' which will be overwritten with the auto-injected credential`
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
requestHeaders[tokenResponse.injectionHeader] = tokenResponse.injectionFormat.replace("{token}", accessToken);
|
|
1365
|
+
}
|
|
1366
|
+
const auditUrl = currentUrl;
|
|
1367
|
+
if (tokenResponse.additionalInjections && !isSigV4) {
|
|
1368
|
+
for (const rule of tokenResponse.additionalInjections) {
|
|
1369
|
+
const value = _AlterVault.#resolveInjectionValue(
|
|
1370
|
+
rule.value_source,
|
|
1371
|
+
accessToken,
|
|
1372
|
+
additionalCreds
|
|
1373
|
+
);
|
|
1374
|
+
if (!value) continue;
|
|
1375
|
+
if (!/^[A-Za-z][A-Za-z0-9\-_]*$/.test(rule.key)) continue;
|
|
1376
|
+
if (rule.target === "header") {
|
|
1377
|
+
requestHeaders[rule.key] = value;
|
|
1378
|
+
} else if (rule.target === "query_param") {
|
|
1379
|
+
const urlObj = new URL(currentUrl);
|
|
1380
|
+
urlObj.searchParams.set(rule.key, value);
|
|
1381
|
+
currentUrl = urlObj.toString();
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
974
1385
|
if (!requestHeaders["User-Agent"]) {
|
|
975
1386
|
requestHeaders["User-Agent"] = SDK_USER_AGENT;
|
|
976
1387
|
}
|
|
977
1388
|
const startTime = Date.now();
|
|
978
1389
|
let response;
|
|
979
1390
|
try {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1391
|
+
if (isSigV4 && sigv4BodyStr != null) {
|
|
1392
|
+
response = await this.#providerClient.request(methodStr, currentUrl, {
|
|
1393
|
+
body: sigv4BodyStr,
|
|
1394
|
+
headers: requestHeaders,
|
|
1395
|
+
params: options?.queryParams
|
|
1396
|
+
});
|
|
1397
|
+
} else {
|
|
1398
|
+
response = await this.#providerClient.request(methodStr, currentUrl, {
|
|
1399
|
+
json: options?.json,
|
|
1400
|
+
headers: requestHeaders,
|
|
1401
|
+
params: options?.queryParams
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
985
1404
|
} catch (error) {
|
|
986
1405
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
987
1406
|
throw new TimeoutError(
|
|
988
1407
|
`Provider API request timed out: ${error instanceof Error ? error.message : String(error)}`,
|
|
989
1408
|
{
|
|
990
|
-
connection_id:
|
|
1409
|
+
connection_id: effectiveConnectionId,
|
|
991
1410
|
method: methodStr,
|
|
992
|
-
url
|
|
1411
|
+
url: currentUrl
|
|
993
1412
|
}
|
|
994
1413
|
);
|
|
995
1414
|
}
|
|
996
1415
|
throw new NetworkError(
|
|
997
1416
|
`Failed to call provider API: ${error instanceof Error ? error.message : String(error)}`,
|
|
998
1417
|
{
|
|
999
|
-
connection_id:
|
|
1418
|
+
connection_id: effectiveConnectionId,
|
|
1000
1419
|
method: methodStr,
|
|
1001
|
-
url,
|
|
1420
|
+
url: currentUrl,
|
|
1002
1421
|
error: String(error)
|
|
1003
1422
|
}
|
|
1004
1423
|
);
|
|
1005
1424
|
}
|
|
1006
1425
|
const latencyMs = Date.now() - startTime;
|
|
1426
|
+
const sigv4Sensitive = /* @__PURE__ */ new Set(["authorization", "x-amz-date", "x-amz-content-sha256"]);
|
|
1427
|
+
const stripHeaders = isSigV4 ? sigv4Sensitive : /* @__PURE__ */ new Set([injectionHeaderLower]);
|
|
1428
|
+
if (tokenResponse.additionalInjections && !isSigV4) {
|
|
1429
|
+
for (const rule of tokenResponse.additionalInjections) {
|
|
1430
|
+
if (rule.target === "header") {
|
|
1431
|
+
stripHeaders.add(rule.key.toLowerCase());
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1007
1435
|
const auditHeaders = {};
|
|
1008
1436
|
for (const [key, value] of Object.entries(requestHeaders)) {
|
|
1009
|
-
if (key.toLowerCase()
|
|
1437
|
+
if (!stripHeaders.has(key.toLowerCase())) {
|
|
1010
1438
|
auditHeaders[key] = value;
|
|
1011
1439
|
}
|
|
1012
1440
|
}
|
|
@@ -1017,9 +1445,9 @@ ${contentHash}`;
|
|
|
1017
1445
|
});
|
|
1018
1446
|
this.#scheduleAuditLog({
|
|
1019
1447
|
connectionId: tokenResponse.connectionId,
|
|
1020
|
-
providerId: tokenResponse.providerId ||
|
|
1448
|
+
providerId: tokenResponse.providerId || effectiveConnectionId || "",
|
|
1021
1449
|
method: methodStr,
|
|
1022
|
-
url,
|
|
1450
|
+
url: auditUrl,
|
|
1023
1451
|
requestHeaders: auditHeaders,
|
|
1024
1452
|
requestBody: options?.json ?? null,
|
|
1025
1453
|
responseStatus: response.status,
|
|
@@ -1032,14 +1460,29 @@ ${contentHash}`;
|
|
|
1032
1460
|
toolCallId: options?.toolCallId ?? null
|
|
1033
1461
|
});
|
|
1034
1462
|
if (response.status >= HTTP_CLIENT_ERROR_START) {
|
|
1463
|
+
if (response.status === HTTP_FORBIDDEN && scopeMismatch) {
|
|
1464
|
+
throw new ScopeReauthRequiredError(
|
|
1465
|
+
"Provider API returned 403 and the connection's scopes don't match the provider config. The user needs to re-authorize to grant updated permissions.",
|
|
1466
|
+
tokenResponse.connectionId,
|
|
1467
|
+
tokenResponse.providerId,
|
|
1468
|
+
response.status,
|
|
1469
|
+
responseBody,
|
|
1470
|
+
{
|
|
1471
|
+
connection_id: tokenResponse.connectionId,
|
|
1472
|
+
provider_id: tokenResponse.providerId,
|
|
1473
|
+
method: methodStr,
|
|
1474
|
+
url: currentUrl
|
|
1475
|
+
}
|
|
1476
|
+
);
|
|
1477
|
+
}
|
|
1035
1478
|
throw new ProviderAPIError(
|
|
1036
1479
|
`Provider API returned error ${response.status}`,
|
|
1037
1480
|
response.status,
|
|
1038
1481
|
responseBody,
|
|
1039
1482
|
{
|
|
1040
|
-
connection_id:
|
|
1483
|
+
connection_id: effectiveConnectionId,
|
|
1041
1484
|
method: methodStr,
|
|
1042
|
-
url
|
|
1485
|
+
url: currentUrl
|
|
1043
1486
|
}
|
|
1044
1487
|
);
|
|
1045
1488
|
}
|
|
@@ -1064,12 +1507,23 @@ ${contentHash}`;
|
|
|
1064
1507
|
limit: options?.limit ?? 100,
|
|
1065
1508
|
offset: options?.offset ?? 0
|
|
1066
1509
|
};
|
|
1510
|
+
if (this.#userTokenGetter) {
|
|
1511
|
+
try {
|
|
1512
|
+
listBody.user_token = await this.#getUserToken();
|
|
1513
|
+
} catch (err) {
|
|
1514
|
+
console.warn(
|
|
1515
|
+
"user_token_getter failed in listConnections, falling back to un-scoped listing:",
|
|
1516
|
+
err instanceof Error ? err.message : String(err)
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1067
1520
|
const listPath = "/sdk/oauth/connections/list";
|
|
1068
|
-
const
|
|
1521
|
+
const listBodyStr = JSON.stringify(listBody);
|
|
1522
|
+
const listHmac = this.#computeHmacHeaders("POST", listPath, listBodyStr);
|
|
1069
1523
|
try {
|
|
1070
1524
|
response = await this.#alterClient.post(listPath, {
|
|
1071
|
-
|
|
1072
|
-
headers: { ...actorHeaders, ...listHmac }
|
|
1525
|
+
body: listBodyStr,
|
|
1526
|
+
headers: { ...actorHeaders, ...listHmac, "Content-Type": "application/json" }
|
|
1073
1527
|
});
|
|
1074
1528
|
} catch (error) {
|
|
1075
1529
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
@@ -1115,24 +1569,37 @@ ${contentHash}`;
|
|
|
1115
1569
|
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
1116
1570
|
);
|
|
1117
1571
|
}
|
|
1118
|
-
if (!options.endUser?.id) {
|
|
1119
|
-
throw new AlterSDKError("endUser.id is required");
|
|
1120
|
-
}
|
|
1121
1572
|
const actorHeaders = this.#getActorRequestHeaders();
|
|
1122
1573
|
let response;
|
|
1123
1574
|
const sessionBody = {
|
|
1124
|
-
end_user: options.endUser,
|
|
1125
1575
|
allowed_providers: options.allowedProviders ?? null,
|
|
1126
1576
|
return_url: options.returnUrl ?? null,
|
|
1127
1577
|
allowed_origin: options.allowedOrigin ?? null,
|
|
1128
1578
|
metadata: options.metadata ?? null
|
|
1129
1579
|
};
|
|
1580
|
+
if (options.connectionPolicy) {
|
|
1581
|
+
sessionBody.connection_policy = {
|
|
1582
|
+
max_ttl_seconds: options.connectionPolicy.maxTtlSeconds ?? null,
|
|
1583
|
+
default_ttl_seconds: options.connectionPolicy.defaultTtlSeconds ?? null
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
if (this.#userTokenGetter) {
|
|
1587
|
+
try {
|
|
1588
|
+
sessionBody.user_token = await this.#getUserToken();
|
|
1589
|
+
} catch (err) {
|
|
1590
|
+
console.warn(
|
|
1591
|
+
"userTokenGetter failed in createConnectSession, session will not have identity tagging:",
|
|
1592
|
+
err instanceof Error ? err.message : String(err)
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1130
1596
|
const sessionPath = "/sdk/oauth/connect/session";
|
|
1131
|
-
const
|
|
1597
|
+
const sessionBodyStr = JSON.stringify(sessionBody);
|
|
1598
|
+
const sessionHmac = this.#computeHmacHeaders("POST", sessionPath, sessionBodyStr);
|
|
1132
1599
|
try {
|
|
1133
1600
|
response = await this.#alterClient.post(sessionPath, {
|
|
1134
|
-
|
|
1135
|
-
headers: { ...actorHeaders, ...sessionHmac }
|
|
1601
|
+
body: sessionBodyStr,
|
|
1602
|
+
headers: { ...actorHeaders, ...sessionHmac, "Content-Type": "application/json" }
|
|
1136
1603
|
});
|
|
1137
1604
|
} catch (error) {
|
|
1138
1605
|
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
@@ -1156,6 +1623,143 @@ ${contentHash}`;
|
|
|
1156
1623
|
const data = await response.json();
|
|
1157
1624
|
return new ConnectSession(data);
|
|
1158
1625
|
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Open OAuth in the user's browser and wait for completion.
|
|
1628
|
+
*
|
|
1629
|
+
* This is the headless connect flow for CLI tools, scripts, and
|
|
1630
|
+
* server-side applications. It creates a Connect session, opens the
|
|
1631
|
+
* browser, and polls until the user completes OAuth.
|
|
1632
|
+
*
|
|
1633
|
+
* @param options - Connect options
|
|
1634
|
+
* @returns Array of ConnectResult objects (one per connected provider)
|
|
1635
|
+
* @throws ConnectTimeoutError if the user doesn't complete within timeout
|
|
1636
|
+
* @throws ConnectFlowError if the user denies or provider returns error
|
|
1637
|
+
* @throws AlterSDKError if SDK is closed or session creation fails
|
|
1638
|
+
*/
|
|
1639
|
+
async connect(options) {
|
|
1640
|
+
if (this.#closed) {
|
|
1641
|
+
throw new AlterSDKError(
|
|
1642
|
+
"SDK instance has been closed. Create a new AlterVault instance to make requests."
|
|
1643
|
+
);
|
|
1644
|
+
}
|
|
1645
|
+
const timeout = options.timeout ?? 300;
|
|
1646
|
+
const pollInterval = options.pollInterval ?? 2;
|
|
1647
|
+
const openBrowser = options.openBrowser ?? true;
|
|
1648
|
+
const session = await this.createConnectSession({
|
|
1649
|
+
allowedProviders: options.providers,
|
|
1650
|
+
connectionPolicy: options.connectionPolicy
|
|
1651
|
+
});
|
|
1652
|
+
if (openBrowser) {
|
|
1653
|
+
try {
|
|
1654
|
+
const openModule = await import("open");
|
|
1655
|
+
const openFn = openModule.default;
|
|
1656
|
+
if (openFn) {
|
|
1657
|
+
await openFn(session.connectUrl);
|
|
1658
|
+
} else {
|
|
1659
|
+
console.log(
|
|
1660
|
+
`Open this URL to authorize: ${session.connectUrl}`
|
|
1661
|
+
);
|
|
1662
|
+
}
|
|
1663
|
+
} catch {
|
|
1664
|
+
console.log(
|
|
1665
|
+
`Open this URL to authorize: ${session.connectUrl}`
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
} else {
|
|
1669
|
+
console.log(
|
|
1670
|
+
`Open this URL to authorize: ${session.connectUrl}`
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
const deadline = Date.now() + timeout * 1e3;
|
|
1674
|
+
while (Date.now() < deadline) {
|
|
1675
|
+
await new Promise(
|
|
1676
|
+
(resolve) => setTimeout(resolve, pollInterval * 1e3)
|
|
1677
|
+
);
|
|
1678
|
+
const pollResult = await this.#pollSession(session.sessionToken);
|
|
1679
|
+
const pollStatus = pollResult.status;
|
|
1680
|
+
if (pollStatus === "completed") {
|
|
1681
|
+
const connectionsData = pollResult.connections ?? [];
|
|
1682
|
+
return connectionsData.map(
|
|
1683
|
+
(conn) => new ConnectResult({
|
|
1684
|
+
connection_id: conn.connection_id ?? "",
|
|
1685
|
+
provider_id: conn.provider_id ?? "",
|
|
1686
|
+
account_identifier: conn.account_identifier ?? null,
|
|
1687
|
+
scopes: conn.scopes ?? [],
|
|
1688
|
+
connection_policy: conn.connection_policy ?? null
|
|
1689
|
+
})
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
if (pollStatus === "error") {
|
|
1693
|
+
const err = pollResult.error;
|
|
1694
|
+
const errorCode = err?.error_code ?? "unknown_error";
|
|
1695
|
+
const errorMessage = err?.error_message ?? "OAuth flow failed";
|
|
1696
|
+
const errorDetails = { error_code: errorCode };
|
|
1697
|
+
if (errorCode === "connect_denied") {
|
|
1698
|
+
throw new ConnectDeniedError(errorMessage, errorDetails);
|
|
1699
|
+
}
|
|
1700
|
+
if ([
|
|
1701
|
+
"connect_config_error",
|
|
1702
|
+
"invalid_redirect_uri",
|
|
1703
|
+
"invalid_client",
|
|
1704
|
+
"unauthorized_client"
|
|
1705
|
+
].includes(errorCode)) {
|
|
1706
|
+
throw new ConnectConfigError(errorMessage, errorDetails);
|
|
1707
|
+
}
|
|
1708
|
+
throw new ConnectFlowError(errorMessage, errorDetails);
|
|
1709
|
+
}
|
|
1710
|
+
if (pollStatus === "expired") {
|
|
1711
|
+
throw new ConnectFlowError(
|
|
1712
|
+
"Connect session expired before OAuth was completed"
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
throw new ConnectTimeoutError(
|
|
1717
|
+
`OAuth flow did not complete within ${timeout} seconds. The user may not have finished authorizing in the browser.`,
|
|
1718
|
+
{ timeout }
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Poll the Connect session for completion status (INTERNAL).
|
|
1723
|
+
*
|
|
1724
|
+
* Makes an HMAC-signed POST to the poll endpoint.
|
|
1725
|
+
*/
|
|
1726
|
+
async #pollSession(sessionToken) {
|
|
1727
|
+
const actorHeaders = this.#getActorRequestHeaders();
|
|
1728
|
+
const pollPath = "/sdk/oauth/connect/session/poll";
|
|
1729
|
+
const pollBody = { session_token: sessionToken };
|
|
1730
|
+
const pollBodyStr = JSON.stringify(pollBody);
|
|
1731
|
+
const pollHmac = this.#computeHmacHeaders(
|
|
1732
|
+
"POST",
|
|
1733
|
+
pollPath,
|
|
1734
|
+
pollBodyStr
|
|
1735
|
+
);
|
|
1736
|
+
let response;
|
|
1737
|
+
try {
|
|
1738
|
+
response = await this.#alterClient.post(pollPath, {
|
|
1739
|
+
body: pollBodyStr,
|
|
1740
|
+
headers: { ...actorHeaders, ...pollHmac, "Content-Type": "application/json" }
|
|
1741
|
+
});
|
|
1742
|
+
} catch (error) {
|
|
1743
|
+
if (_AlterVault.#isTimeoutOrAbortError(error)) {
|
|
1744
|
+
throw new TimeoutError(
|
|
1745
|
+
`Request to Alter Vault backend timed out: ${error instanceof Error ? error.message : String(error)}`,
|
|
1746
|
+
{ base_url: this.baseUrl }
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
if (error instanceof TypeError) {
|
|
1750
|
+
throw new NetworkError(
|
|
1751
|
+
`Failed to connect to Alter Vault backend: ${error.message}`,
|
|
1752
|
+
{ base_url: this.baseUrl }
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
throw new AlterSDKError(
|
|
1756
|
+
`Failed to poll connect session: ${error instanceof Error ? error.message : String(error)}`
|
|
1757
|
+
);
|
|
1758
|
+
}
|
|
1759
|
+
this.#cacheActorIdFromResponse(response);
|
|
1760
|
+
await this.#handleErrorResponse(response);
|
|
1761
|
+
return await response.json();
|
|
1762
|
+
}
|
|
1159
1763
|
/**
|
|
1160
1764
|
* Close HTTP clients and release resources.
|
|
1161
1765
|
* Waits for any pending audit tasks before closing.
|
|
@@ -1181,10 +1785,72 @@ Object.freeze(AlterVault.prototype);
|
|
|
1181
1785
|
|
|
1182
1786
|
// src/providers/enums.ts
|
|
1183
1787
|
var Provider = /* @__PURE__ */ ((Provider2) => {
|
|
1184
|
-
Provider2["
|
|
1788
|
+
Provider2["ACUITY_SCHEDULING"] = "acuity-scheduling";
|
|
1789
|
+
Provider2["ADOBE"] = "adobe";
|
|
1790
|
+
Provider2["AIRCALL"] = "aircall";
|
|
1791
|
+
Provider2["AIRTABLE"] = "airtable";
|
|
1792
|
+
Provider2["APOLLO"] = "apollo";
|
|
1793
|
+
Provider2["ASANA"] = "asana";
|
|
1794
|
+
Provider2["ATLASSIAN"] = "atlassian";
|
|
1795
|
+
Provider2["ATTIO"] = "attio";
|
|
1796
|
+
Provider2["AUTODESK"] = "autodesk";
|
|
1797
|
+
Provider2["BASECAMP"] = "basecamp";
|
|
1798
|
+
Provider2["BITBUCKET"] = "bitbucket";
|
|
1799
|
+
Provider2["BITLY"] = "bitly";
|
|
1800
|
+
Provider2["BOX"] = "box";
|
|
1801
|
+
Provider2["BREX"] = "brex";
|
|
1802
|
+
Provider2["CALENDLY"] = "calendly";
|
|
1803
|
+
Provider2["CAL_COM"] = "cal-com";
|
|
1804
|
+
Provider2["CANVA"] = "canva";
|
|
1805
|
+
Provider2["CLICKUP"] = "clickup";
|
|
1806
|
+
Provider2["CLOSE"] = "close";
|
|
1807
|
+
Provider2["CONSTANT_CONTACT"] = "constant-contact";
|
|
1808
|
+
Provider2["CONTENTFUL"] = "contentful";
|
|
1809
|
+
Provider2["DEEL"] = "deel";
|
|
1810
|
+
Provider2["DIALPAD"] = "dialpad";
|
|
1811
|
+
Provider2["DIGITALOCEAN"] = "digitalocean";
|
|
1812
|
+
Provider2["DISCORD"] = "discord";
|
|
1813
|
+
Provider2["DOCUSIGN"] = "docusign";
|
|
1814
|
+
Provider2["DROPBOX"] = "dropbox";
|
|
1815
|
+
Provider2["EBAY"] = "ebay";
|
|
1816
|
+
Provider2["EVENTBRITE"] = "eventbrite";
|
|
1817
|
+
Provider2["FACEBOOK"] = "facebook";
|
|
1818
|
+
Provider2["FIGMA"] = "figma";
|
|
1185
1819
|
Provider2["GITHUB"] = "github";
|
|
1186
|
-
Provider2["
|
|
1820
|
+
Provider2["GOOGLE"] = "google";
|
|
1821
|
+
Provider2["HUBSPOT"] = "hubspot";
|
|
1822
|
+
Provider2["INSTAGRAM"] = "instagram";
|
|
1823
|
+
Provider2["LINEAR"] = "linear";
|
|
1824
|
+
Provider2["LINKEDIN"] = "linkedin";
|
|
1825
|
+
Provider2["MAILCHIMP"] = "mailchimp";
|
|
1826
|
+
Provider2["MERCURY"] = "mercury";
|
|
1827
|
+
Provider2["MICROSOFT"] = "microsoft";
|
|
1828
|
+
Provider2["MIRO"] = "miro";
|
|
1829
|
+
Provider2["MONDAY"] = "monday";
|
|
1830
|
+
Provider2["NOTION"] = "notion";
|
|
1831
|
+
Provider2["OUTREACH"] = "outreach";
|
|
1832
|
+
Provider2["PAGERDUTY"] = "pagerduty";
|
|
1833
|
+
Provider2["PAYPAL"] = "paypal";
|
|
1834
|
+
Provider2["PINTEREST"] = "pinterest";
|
|
1835
|
+
Provider2["PIPEDRIVE"] = "pipedrive";
|
|
1836
|
+
Provider2["QUICKBOOKS"] = "quickbooks";
|
|
1837
|
+
Provider2["RAMP"] = "ramp";
|
|
1838
|
+
Provider2["REDDIT"] = "reddit";
|
|
1839
|
+
Provider2["RINGCENTRAL"] = "ringcentral";
|
|
1840
|
+
Provider2["SALESFORCE"] = "salesforce";
|
|
1187
1841
|
Provider2["SENTRY"] = "sentry";
|
|
1842
|
+
Provider2["SLACK"] = "slack";
|
|
1843
|
+
Provider2["SNAPCHAT"] = "snapchat";
|
|
1844
|
+
Provider2["SPOTIFY"] = "spotify";
|
|
1845
|
+
Provider2["SQUARE"] = "square";
|
|
1846
|
+
Provider2["SQUARESPACE"] = "squarespace";
|
|
1847
|
+
Provider2["STRIPE"] = "stripe";
|
|
1848
|
+
Provider2["TIKTOK"] = "tiktok";
|
|
1849
|
+
Provider2["TODOIST"] = "todoist";
|
|
1850
|
+
Provider2["TWITTER"] = "twitter";
|
|
1851
|
+
Provider2["TYPEFORM"] = "typeform";
|
|
1852
|
+
Provider2["WEBEX"] = "webex";
|
|
1853
|
+
Provider2["WEBFLOW"] = "webflow";
|
|
1188
1854
|
return Provider2;
|
|
1189
1855
|
})(Provider || {});
|
|
1190
1856
|
var HttpMethod = /* @__PURE__ */ ((HttpMethod2) => {
|
|
@@ -1203,17 +1869,26 @@ var HttpMethod = /* @__PURE__ */ ((HttpMethod2) => {
|
|
|
1203
1869
|
ActorType,
|
|
1204
1870
|
AlterSDKError,
|
|
1205
1871
|
AlterVault,
|
|
1872
|
+
BackendError,
|
|
1873
|
+
ConnectConfigError,
|
|
1874
|
+
ConnectDeniedError,
|
|
1875
|
+
ConnectFlowError,
|
|
1876
|
+
ConnectResult,
|
|
1206
1877
|
ConnectSession,
|
|
1878
|
+
ConnectTimeoutError,
|
|
1879
|
+
ConnectionDeletedError,
|
|
1880
|
+
ConnectionExpiredError,
|
|
1207
1881
|
ConnectionInfo,
|
|
1208
1882
|
ConnectionListResult,
|
|
1209
1883
|
ConnectionNotFoundError,
|
|
1884
|
+
ConnectionRevokedError,
|
|
1210
1885
|
HttpMethod,
|
|
1211
1886
|
NetworkError,
|
|
1212
1887
|
PolicyViolationError,
|
|
1213
1888
|
Provider,
|
|
1214
1889
|
ProviderAPIError,
|
|
1890
|
+
ReAuthRequiredError,
|
|
1891
|
+
ScopeReauthRequiredError,
|
|
1215
1892
|
TimeoutError,
|
|
1216
|
-
|
|
1217
|
-
TokenResponse,
|
|
1218
|
-
TokenRetrievalError
|
|
1893
|
+
TokenResponse
|
|
1219
1894
|
});
|