@tangle-network/agent-integrations 0.53.48 → 0.53.50
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/dist/catalog.d.ts +2 -2
- package/dist/catalog.js +8 -8
- package/dist/{chunk-HNEEIMQC.js → chunk-2JRYKWYX.js} +696 -270
- package/dist/{chunk-HNEEIMQC.js.map → chunk-2JRYKWYX.js.map} +1 -1
- package/dist/{chunk-PXOM5AVK.js → chunk-EP6EDAPV.js} +4 -3
- package/dist/{chunk-PXOM5AVK.js.map → chunk-EP6EDAPV.js.map} +1 -1
- package/dist/{chunk-EZR72HCQ.js → chunk-KBYYTHXQ.js} +2 -2
- package/dist/{chunk-CBWD2IOL.js → chunk-QE4WFYSK.js} +2 -2
- package/dist/{chunk-GY4PFAWA.js → chunk-T3WH6MMA.js} +28 -28
- package/dist/chunk-T3WH6MMA.js.map +1 -0
- package/dist/{chunk-I5EF5KIT.js → chunk-UI3U62H6.js} +2 -2
- package/dist/{chunk-RRSNINEV.js → chunk-W72KPXXX.js} +9 -1
- package/dist/chunk-W72KPXXX.js.map +1 -0
- package/dist/{chunk-Q7TDHVRZ.js → chunk-ZZA4HOBE.js} +2 -2
- package/dist/connect/index.d.ts +2 -2
- package/dist/connect/index.js +2 -2
- package/dist/connectors/adapters/index.d.ts +16 -19
- package/dist/connectors/adapters/index.js +4 -2
- package/dist/connectors/index.d.ts +17 -5
- package/dist/connectors/index.js +15 -3
- package/dist/{consumer-BcFIDgMD.d.ts → consumer-DrLnbqYt.d.ts} +1 -1
- package/dist/consumer.d.ts +3 -3
- package/dist/consumer.js +2 -2
- package/dist/{core-types-CE1oMiuI.d.ts → core-types-D26cY5tD.d.ts} +1 -1
- package/dist/coverage-catalog.d.ts +2 -2
- package/dist/{importers-CHOC-2Y8.d.ts → importers-CQKts3pm.d.ts} +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +20 -8
- package/dist/mcp.d.ts +3 -3
- package/dist/mcp.js +8 -8
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.js +2 -2
- package/dist/registry.d.ts +2 -2
- package/dist/registry.js +8 -8
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +8 -8
- package/dist/specs.d.ts +2 -2
- package/dist/specs.js +4 -4
- package/dist/{tangle-id-BL_JQwKA.d.ts → tangle-id-BCOVbWrP.d.ts} +1 -1
- package/dist/{types-EXGqQYoU.d.ts → types-DpKn0frG.d.ts} +4 -0
- package/package.json +1 -1
- package/dist/chunk-GY4PFAWA.js.map +0 -1
- package/dist/chunk-RRSNINEV.js.map +0 -1
- /package/dist/{chunk-EZR72HCQ.js.map → chunk-KBYYTHXQ.js.map} +0 -0
- /package/dist/{chunk-CBWD2IOL.js.map → chunk-QE4WFYSK.js.map} +0 -0
- /package/dist/{chunk-I5EF5KIT.js.map → chunk-UI3U62H6.js.map} +0 -0
- /package/dist/{chunk-Q7TDHVRZ.js.map → chunk-ZZA4HOBE.js.map} +0 -0
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
TangleIdentityUnreachableError,
|
|
15
15
|
createTangleIdentityClient,
|
|
16
16
|
tangleIdentity
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-W72KPXXX.js";
|
|
18
18
|
import {
|
|
19
19
|
__export
|
|
20
20
|
} from "./chunk-PZ5AY32C.js";
|
|
@@ -530,6 +530,7 @@ __export(adapters_exports, {
|
|
|
530
530
|
reachinboxConnector: () => reachinboxConnector,
|
|
531
531
|
recallAiConnector: () => recallAiConnector,
|
|
532
532
|
recurlyConnector: () => recurlyConnector,
|
|
533
|
+
reddit: () => reddit,
|
|
533
534
|
redditConnector: () => redditConnector,
|
|
534
535
|
redisConnector: () => redisConnector,
|
|
535
536
|
redshiftConnector: () => redshiftConnector,
|
|
@@ -978,8 +979,9 @@ async function executeRestRequest(spec, request4, inv, requiredArgs) {
|
|
|
978
979
|
if (hostOverride) url.host = hostOverride.replace(/\{region\}/g, awsRegion);
|
|
979
980
|
if (inv.expectedEtag) headers["if-match"] = inv.expectedEtag;
|
|
980
981
|
const sendsBody = request4.method !== "GET" && (request4.method !== "DELETE" || request4.body !== void 0);
|
|
982
|
+
const bodyEncoding = request4.bodyEncoding ?? "json";
|
|
981
983
|
if (sendsBody && getHeaderCI(headers, "content-type") === void 0) {
|
|
982
|
-
headers["content-type"] = "application/json";
|
|
984
|
+
headers["content-type"] = bodyEncoding === "form" ? "application/x-www-form-urlencoded" : "application/json";
|
|
983
985
|
}
|
|
984
986
|
let resolvedBody = sendsBody ? resolveBody(request4.body, inv.args, scope, requiredArgs) : void 0;
|
|
985
987
|
if (placement.kind === "structured-json-body") {
|
|
@@ -996,7 +998,7 @@ async function executeRestRequest(spec, request4, inv, requiredArgs) {
|
|
|
996
998
|
)
|
|
997
999
|
};
|
|
998
1000
|
}
|
|
999
|
-
const bodyString = sendsBody ?
|
|
1001
|
+
const bodyString = sendsBody ? serializeRequestBody(spec.kind, bodyEncoding, resolvedBody) : void 0;
|
|
1000
1002
|
if (placement.kind === "aws-sigv4") {
|
|
1001
1003
|
signAwsRequest(headers, url, {
|
|
1002
1004
|
method: request4.method,
|
|
@@ -1072,6 +1074,21 @@ async function executeRestRequest(spec, request4, inv, requiredArgs) {
|
|
|
1072
1074
|
}
|
|
1073
1075
|
return { data: data4, etag: res.headers.get("etag") ?? void 0 };
|
|
1074
1076
|
}
|
|
1077
|
+
function serializeRequestBody(connectorKind, encoding, body) {
|
|
1078
|
+
if (encoding === "json") return JSON.stringify(body);
|
|
1079
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
1080
|
+
throw new Error(`${connectorKind}: form request bodies require a flat object`);
|
|
1081
|
+
}
|
|
1082
|
+
const form2 = new URLSearchParams();
|
|
1083
|
+
for (const [key, value] of Object.entries(body)) {
|
|
1084
|
+
if (value === void 0 || value === null) continue;
|
|
1085
|
+
if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
|
|
1086
|
+
throw new Error(`${connectorKind}: form field ${key} must be a scalar value`);
|
|
1087
|
+
}
|
|
1088
|
+
form2.set(key, String(value));
|
|
1089
|
+
}
|
|
1090
|
+
return form2.toString();
|
|
1091
|
+
}
|
|
1075
1092
|
function resolveBaseUrl(baseUrl4, metadata, allowedBaseUrls, allowedBaseUrlSuffixes, requirePublicHttpsBaseUrl) {
|
|
1076
1093
|
let resolved;
|
|
1077
1094
|
if (typeof baseUrl4 === "string") {
|
|
@@ -1628,7 +1645,325 @@ function membershipCapability(name, method, description) {
|
|
|
1628
1645
|
}
|
|
1629
1646
|
|
|
1630
1647
|
// src/connectors/adapters/client-credentials-rest.ts
|
|
1631
|
-
import { createHash as
|
|
1648
|
+
import { createHash as createHash3 } from "crypto";
|
|
1649
|
+
|
|
1650
|
+
// src/connectors/oauth.ts
|
|
1651
|
+
import { createHash as createHash2, randomBytes } from "crypto";
|
|
1652
|
+
var PENDING_TTL_MS = 10 * 60 * 1e3;
|
|
1653
|
+
var InMemoryOAuthFlowStore = class {
|
|
1654
|
+
pendingFlows = /* @__PURE__ */ new Map();
|
|
1655
|
+
put(state, flow) {
|
|
1656
|
+
this.pendingFlows.set(state, flow);
|
|
1657
|
+
}
|
|
1658
|
+
consume(state) {
|
|
1659
|
+
const flow = this.pendingFlows.get(state);
|
|
1660
|
+
this.pendingFlows.delete(state);
|
|
1661
|
+
if (!flow || flow.expiresAt <= Date.now()) return void 0;
|
|
1662
|
+
return flow;
|
|
1663
|
+
}
|
|
1664
|
+
sweep(now) {
|
|
1665
|
+
for (const [k, v] of this.pendingFlows) {
|
|
1666
|
+
if (v.expiresAt <= now) this.pendingFlows.delete(k);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
clear() {
|
|
1670
|
+
this.pendingFlows.clear();
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
var defaultFlowStore = new InMemoryOAuthFlowStore();
|
|
1674
|
+
function startOAuthFlow(input) {
|
|
1675
|
+
const store = input.store ?? defaultFlowStore;
|
|
1676
|
+
const now = input.now ?? Date.now();
|
|
1677
|
+
store.sweep?.(now);
|
|
1678
|
+
const usePkce = (input.pkce ?? "required") !== "unsupported";
|
|
1679
|
+
const codeVerifier = usePkce ? base64Url(randomBytes(48)) : void 0;
|
|
1680
|
+
const codeChallenge = codeVerifier ? base64Url(createHash2("sha256").update(codeVerifier).digest()) : void 0;
|
|
1681
|
+
const state = base64Url(randomBytes(24));
|
|
1682
|
+
store.put(state, {
|
|
1683
|
+
codeVerifier,
|
|
1684
|
+
state,
|
|
1685
|
+
projectId: input.projectId,
|
|
1686
|
+
kind: input.kind,
|
|
1687
|
+
label: input.label,
|
|
1688
|
+
redirectUri: input.redirectUri,
|
|
1689
|
+
expiresAt: now + PENDING_TTL_MS
|
|
1690
|
+
});
|
|
1691
|
+
const url = new URL(input.authorizationUrl);
|
|
1692
|
+
url.searchParams.set("response_type", "code");
|
|
1693
|
+
url.searchParams.set(
|
|
1694
|
+
oauthParameterName(input.authorizationClientIdParam, "client_id"),
|
|
1695
|
+
input.clientId
|
|
1696
|
+
);
|
|
1697
|
+
url.searchParams.set("redirect_uri", input.redirectUri);
|
|
1698
|
+
url.searchParams.set("scope", input.scopes.join(input.scopeSeparator ?? " "));
|
|
1699
|
+
url.searchParams.set("state", state);
|
|
1700
|
+
if (input.extraAuthParams) {
|
|
1701
|
+
for (const [k, v] of Object.entries(input.extraAuthParams)) {
|
|
1702
|
+
url.searchParams.set(k, v);
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
if (codeChallenge) {
|
|
1706
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
1707
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
1708
|
+
} else {
|
|
1709
|
+
url.searchParams.delete("code_challenge");
|
|
1710
|
+
url.searchParams.delete("code_challenge_method");
|
|
1711
|
+
}
|
|
1712
|
+
return { authorizationUrl: url.toString(), state };
|
|
1713
|
+
}
|
|
1714
|
+
async function consumePendingFlow(state, store = defaultFlowStore) {
|
|
1715
|
+
await store.sweep?.(Date.now());
|
|
1716
|
+
const flow = await store.consume(state);
|
|
1717
|
+
if (!flow) {
|
|
1718
|
+
throw new Error("Unknown or expired OAuth state: possible CSRF, replay, or stale flow");
|
|
1719
|
+
}
|
|
1720
|
+
return flow;
|
|
1721
|
+
}
|
|
1722
|
+
async function exchangeAuthorizationCode(input) {
|
|
1723
|
+
const usePkce = (input.pkce ?? "required") !== "unsupported";
|
|
1724
|
+
if (usePkce && !input.codeVerifier) {
|
|
1725
|
+
throw new Error("OAuth token exchange requires a PKCE code_verifier");
|
|
1726
|
+
}
|
|
1727
|
+
const body = new URLSearchParams({
|
|
1728
|
+
grant_type: "authorization_code",
|
|
1729
|
+
code: input.code,
|
|
1730
|
+
redirect_uri: input.redirectUri
|
|
1731
|
+
});
|
|
1732
|
+
if (usePkce) body.set("code_verifier", input.codeVerifier);
|
|
1733
|
+
const headers = createOAuthTokenRequestHeaders(input.tokenRequestHeaders);
|
|
1734
|
+
applyTokenClientAuthentication(input, body, headers);
|
|
1735
|
+
const redactionValues = [
|
|
1736
|
+
input.code,
|
|
1737
|
+
...input.codeVerifier ? [input.codeVerifier] : [],
|
|
1738
|
+
...oauthClientCredentialRedactionValues(
|
|
1739
|
+
input.clientId,
|
|
1740
|
+
input.clientSecret,
|
|
1741
|
+
headers.authorization
|
|
1742
|
+
)
|
|
1743
|
+
];
|
|
1744
|
+
let res;
|
|
1745
|
+
try {
|
|
1746
|
+
res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
|
|
1747
|
+
method: "POST",
|
|
1748
|
+
headers,
|
|
1749
|
+
body,
|
|
1750
|
+
signal: input.signal
|
|
1751
|
+
});
|
|
1752
|
+
} catch (cause) {
|
|
1753
|
+
const detail = redactOAuthSensitiveText(
|
|
1754
|
+
cause?.message ?? "unknown",
|
|
1755
|
+
redactionValues
|
|
1756
|
+
);
|
|
1757
|
+
throw new Error(`OAuth token exchange transport error: ${detail}`);
|
|
1758
|
+
}
|
|
1759
|
+
if (!res.ok) {
|
|
1760
|
+
const text = await res.text().catch(() => "");
|
|
1761
|
+
const statusText = redactOAuthSensitiveText(res.statusText, redactionValues);
|
|
1762
|
+
const detail = redactOAuthSensitiveText(text, redactionValues).slice(0, 200);
|
|
1763
|
+
throw new Error(
|
|
1764
|
+
`OAuth token exchange failed: ${res.status} ${statusText} \u2014 ${detail}`
|
|
1765
|
+
);
|
|
1766
|
+
}
|
|
1767
|
+
let json;
|
|
1768
|
+
try {
|
|
1769
|
+
json = await res.json();
|
|
1770
|
+
} catch {
|
|
1771
|
+
throw new Error("OAuth token exchange returned invalid JSON");
|
|
1772
|
+
}
|
|
1773
|
+
return {
|
|
1774
|
+
accessToken: json.access_token,
|
|
1775
|
+
refreshToken: json.refresh_token,
|
|
1776
|
+
expiresIn: json.expires_in,
|
|
1777
|
+
scope: json.scope,
|
|
1778
|
+
tokenType: json.token_type,
|
|
1779
|
+
idToken: json.id_token
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
async function refreshAccessToken(input) {
|
|
1783
|
+
const body = new URLSearchParams({
|
|
1784
|
+
grant_type: "refresh_token",
|
|
1785
|
+
refresh_token: input.refreshToken
|
|
1786
|
+
});
|
|
1787
|
+
const headers = createOAuthTokenRequestHeaders(input.tokenRequestHeaders);
|
|
1788
|
+
applyTokenClientAuthentication(input, body, headers);
|
|
1789
|
+
const redactionValues = [
|
|
1790
|
+
input.refreshToken,
|
|
1791
|
+
...oauthClientCredentialRedactionValues(
|
|
1792
|
+
input.clientId,
|
|
1793
|
+
input.clientSecret,
|
|
1794
|
+
headers.authorization
|
|
1795
|
+
)
|
|
1796
|
+
];
|
|
1797
|
+
let res;
|
|
1798
|
+
try {
|
|
1799
|
+
res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
|
|
1800
|
+
method: "POST",
|
|
1801
|
+
headers,
|
|
1802
|
+
body,
|
|
1803
|
+
signal: input.signal
|
|
1804
|
+
});
|
|
1805
|
+
} catch (cause) {
|
|
1806
|
+
const detail = redactOAuthSensitiveText(
|
|
1807
|
+
cause?.message ?? "unknown",
|
|
1808
|
+
redactionValues
|
|
1809
|
+
);
|
|
1810
|
+
throw new Error(`OAuth refresh transport error: ${detail}`);
|
|
1811
|
+
}
|
|
1812
|
+
if (!res.ok) {
|
|
1813
|
+
const text = await res.text().catch(() => "");
|
|
1814
|
+
const statusText = redactOAuthSensitiveText(res.statusText, redactionValues);
|
|
1815
|
+
const detail = redactOAuthSensitiveText(text, redactionValues).slice(0, 200);
|
|
1816
|
+
throw new Error(`OAuth refresh failed: ${res.status} ${statusText} \u2014 ${detail}`);
|
|
1817
|
+
}
|
|
1818
|
+
let json;
|
|
1819
|
+
try {
|
|
1820
|
+
json = await res.json();
|
|
1821
|
+
} catch {
|
|
1822
|
+
throw new Error("OAuth refresh returned invalid JSON");
|
|
1823
|
+
}
|
|
1824
|
+
return {
|
|
1825
|
+
accessToken: json.access_token,
|
|
1826
|
+
// Some providers omit refresh_token on refresh — keep the previous one
|
|
1827
|
+
// in that case (caller passes through if undefined).
|
|
1828
|
+
refreshToken: json.refresh_token,
|
|
1829
|
+
expiresIn: json.expires_in,
|
|
1830
|
+
scope: json.scope,
|
|
1831
|
+
tokenType: json.token_type,
|
|
1832
|
+
idToken: json.id_token
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
function createOAuthTokenRequestHeaders(additional) {
|
|
1836
|
+
const headers = new Headers(additional);
|
|
1837
|
+
headers.set("content-type", "application/x-www-form-urlencoded");
|
|
1838
|
+
headers.set("accept", "application/json");
|
|
1839
|
+
headers.delete("authorization");
|
|
1840
|
+
return Object.fromEntries(headers.entries());
|
|
1841
|
+
}
|
|
1842
|
+
function formEncodeOAuthClientCredential(value) {
|
|
1843
|
+
return new URLSearchParams({ value }).toString().slice("value=".length);
|
|
1844
|
+
}
|
|
1845
|
+
function createOAuthBasicAuthorizationHeader(clientId, clientSecret, encodeBase64 = defaultOAuthBase64Encode) {
|
|
1846
|
+
const encodedClientId = formEncodeOAuthClientCredential(clientId);
|
|
1847
|
+
const encodedClientSecret = formEncodeOAuthClientCredential(clientSecret);
|
|
1848
|
+
return `Basic ${encodeBase64(`${encodedClientId}:${encodedClientSecret}`)}`;
|
|
1849
|
+
}
|
|
1850
|
+
function defaultOAuthBase64Encode(value) {
|
|
1851
|
+
const encode = globalThis.btoa;
|
|
1852
|
+
if (typeof encode !== "function") {
|
|
1853
|
+
throw new Error(
|
|
1854
|
+
"OAuth client_secret_basic requires a base64 encoder in this runtime."
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
return encode(value);
|
|
1858
|
+
}
|
|
1859
|
+
function oauthClientCredentialRedactionValues(clientId, clientSecret, authorization) {
|
|
1860
|
+
return [
|
|
1861
|
+
clientId,
|
|
1862
|
+
...clientSecret ? [clientSecret] : [],
|
|
1863
|
+
...authorization ? [
|
|
1864
|
+
authorization,
|
|
1865
|
+
...authorization.startsWith("Basic ") ? [authorization.slice("Basic ".length)] : []
|
|
1866
|
+
] : []
|
|
1867
|
+
];
|
|
1868
|
+
}
|
|
1869
|
+
function redactOAuthSensitiveText(text, secrets) {
|
|
1870
|
+
const matchers = /* @__PURE__ */ new Map();
|
|
1871
|
+
for (const secret of new Set(secrets)) {
|
|
1872
|
+
if (secret.length === 0) continue;
|
|
1873
|
+
addOAuthRedactionMatcher(matchers, escapeRegExp(secret), secret.length);
|
|
1874
|
+
const jsonEscaped = JSON.stringify(secret).slice(1, -1);
|
|
1875
|
+
addOAuthRedactionMatcher(
|
|
1876
|
+
matchers,
|
|
1877
|
+
escapeRegExp(jsonEscaped),
|
|
1878
|
+
jsonEscaped.length
|
|
1879
|
+
);
|
|
1880
|
+
const formEncoded = formEncodeOAuthClientCredential(secret);
|
|
1881
|
+
addOAuthRedactionMatcher(
|
|
1882
|
+
matchers,
|
|
1883
|
+
formEncodedRedactionPattern(formEncoded),
|
|
1884
|
+
Math.max(formEncoded.length, formEncoded.replaceAll("+", "%20").length)
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
return [...matchers.values()].sort((left, right) => right.representedLength - left.representedLength).reduce(
|
|
1888
|
+
(redacted, matcher) => redacted.replace(matcher.pattern, "[REDACTED]"),
|
|
1889
|
+
text
|
|
1890
|
+
);
|
|
1891
|
+
}
|
|
1892
|
+
function addOAuthRedactionMatcher(matchers, source, representedLength) {
|
|
1893
|
+
const existing = matchers.get(source);
|
|
1894
|
+
if (existing && existing.representedLength >= representedLength) return;
|
|
1895
|
+
matchers.set(source, {
|
|
1896
|
+
pattern: new RegExp(source, "g"),
|
|
1897
|
+
representedLength
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
function formEncodedRedactionPattern(formEncoded) {
|
|
1901
|
+
let pattern = "";
|
|
1902
|
+
for (let index = 0; index < formEncoded.length; index += 1) {
|
|
1903
|
+
const character = formEncoded[index];
|
|
1904
|
+
const encodedByte = formEncoded.slice(index + 1, index + 3);
|
|
1905
|
+
if (character === "%" && /^[0-9A-F]{2}$/.test(encodedByte)) {
|
|
1906
|
+
pattern += `%${percentEncodedBytePattern(encodedByte)}`;
|
|
1907
|
+
index += 2;
|
|
1908
|
+
continue;
|
|
1909
|
+
}
|
|
1910
|
+
if (character === "+") {
|
|
1911
|
+
pattern += "(?:\\+|%20)";
|
|
1912
|
+
continue;
|
|
1913
|
+
}
|
|
1914
|
+
pattern += escapeRegExp(character);
|
|
1915
|
+
}
|
|
1916
|
+
return pattern;
|
|
1917
|
+
}
|
|
1918
|
+
function percentEncodedBytePattern(encodedByte) {
|
|
1919
|
+
return [...encodedByte].map(
|
|
1920
|
+
(character) => /[A-F]/.test(character) ? `[${character}${character.toLowerCase()}]` : character
|
|
1921
|
+
).join("");
|
|
1922
|
+
}
|
|
1923
|
+
function escapeRegExp(value) {
|
|
1924
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1925
|
+
}
|
|
1926
|
+
function applyTokenClientAuthentication(input, body, headers) {
|
|
1927
|
+
const method = input.tokenClientAuthMethod ?? "client_secret_post";
|
|
1928
|
+
if (method === "none") {
|
|
1929
|
+
body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
if (!input.clientSecret) {
|
|
1933
|
+
throw new Error(`OAuth ${method} client authentication requires a client secret`);
|
|
1934
|
+
}
|
|
1935
|
+
if (method === "client_secret_post") {
|
|
1936
|
+
body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
|
|
1937
|
+
body.set(
|
|
1938
|
+
oauthParameterName(input.tokenClientSecretParam, "client_secret"),
|
|
1939
|
+
input.clientSecret
|
|
1940
|
+
);
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
if (method === "client_secret_basic") {
|
|
1944
|
+
headers.authorization = createOAuthBasicAuthorizationHeader(
|
|
1945
|
+
input.clientId,
|
|
1946
|
+
input.clientSecret
|
|
1947
|
+
);
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
throw new Error("Unsupported OAuth token client authentication method");
|
|
1951
|
+
}
|
|
1952
|
+
function base64Url(buf) {
|
|
1953
|
+
return buf.toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
1954
|
+
}
|
|
1955
|
+
function oauthParameterName(value, fallback) {
|
|
1956
|
+
const name = value ?? fallback;
|
|
1957
|
+
if (!/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(name)) {
|
|
1958
|
+
throw new Error("Invalid OAuth parameter name");
|
|
1959
|
+
}
|
|
1960
|
+
return name;
|
|
1961
|
+
}
|
|
1962
|
+
function _resetPendingFlowsForTests() {
|
|
1963
|
+
defaultFlowStore.clear?.();
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
// src/connectors/adapters/client-credentials-rest.ts
|
|
1632
1967
|
function clientCredentialsRestConnector(spec) {
|
|
1633
1968
|
const regionMetadataKey = spec.regionMetadataKey ?? "region";
|
|
1634
1969
|
const delegated = declarativeRestConnector({
|
|
@@ -1747,7 +2082,7 @@ function readRegionName(bundle, metadata, metadataKey, fallback) {
|
|
|
1747
2082
|
return (bundle.region ?? metadataRegion ?? fallback).toLowerCase().trim();
|
|
1748
2083
|
}
|
|
1749
2084
|
function credentialFingerprint(bundle, region, scope) {
|
|
1750
|
-
return
|
|
2085
|
+
return createHash3("sha256").update(bundle.clientId).update("\0").update(bundle.clientSecret).update("\0").update(region.tokenUrl).update("\0").update(scope ?? "").digest("hex");
|
|
1751
2086
|
}
|
|
1752
2087
|
function renderConnectionMetadata(template, metadata) {
|
|
1753
2088
|
const rendered = template.replace(/\{connection\.([a-zA-Z0-9_.-]+)\}/g, (_match, key) => {
|
|
@@ -1778,7 +2113,10 @@ async function exchangeClientCredentials(displayName, sourceId, bundle, region,
|
|
|
1778
2113
|
"content-type": "application/x-www-form-urlencoded"
|
|
1779
2114
|
};
|
|
1780
2115
|
if (credentialPlacement === "basic") {
|
|
1781
|
-
headers.authorization =
|
|
2116
|
+
headers.authorization = createOAuthBasicAuthorizationHeader(
|
|
2117
|
+
bundle.clientId,
|
|
2118
|
+
bundle.clientSecret
|
|
2119
|
+
);
|
|
1782
2120
|
}
|
|
1783
2121
|
const response = await fetch(region.tokenUrl, {
|
|
1784
2122
|
method: "POST",
|
|
@@ -16132,39 +16470,46 @@ var pushbulletConnector = declarativeRestConnector({
|
|
|
16132
16470
|
});
|
|
16133
16471
|
|
|
16134
16472
|
// src/connectors/adapters/reddit.ts
|
|
16135
|
-
var
|
|
16473
|
+
var REDDIT_USER_AGENT = "web:tools.tangle.integration-hub:v1.0 (contact: https://tangle.tools)";
|
|
16474
|
+
var REDDIT_TOKEN_URL = "https://www.reddit.com/api/v1/access_token";
|
|
16475
|
+
var redditSpec = {
|
|
16136
16476
|
kind: "reddit",
|
|
16137
16477
|
displayName: "Reddit",
|
|
16138
16478
|
description: "Interact with Reddit \u2014 fetch and submit posts, retrieve comments, create and edit posts/comments.",
|
|
16139
16479
|
auth: {
|
|
16140
16480
|
kind: "oauth2",
|
|
16141
16481
|
authorizationUrl: "https://www.reddit.com/api/v1/authorize",
|
|
16142
|
-
tokenUrl:
|
|
16143
|
-
scopes: ["read", "submit", "edit"],
|
|
16482
|
+
tokenUrl: REDDIT_TOKEN_URL,
|
|
16483
|
+
scopes: ["identity", "read", "submit", "edit"],
|
|
16484
|
+
pkce: "unsupported",
|
|
16485
|
+
tokenClientAuthMethod: "client_secret_basic",
|
|
16486
|
+
extraAuthParams: { duration: "permanent" },
|
|
16487
|
+
tokenRequestHeaders: { "User-Agent": REDDIT_USER_AGENT },
|
|
16144
16488
|
clientIdEnv: "REDDIT_OAUTH_CLIENT_ID",
|
|
16145
16489
|
clientSecretEnv: "REDDIT_OAUTH_CLIENT_SECRET"
|
|
16146
16490
|
},
|
|
16147
16491
|
category: "comms",
|
|
16148
16492
|
defaultConsistencyModel: "authoritative",
|
|
16149
16493
|
baseUrl: "https://oauth.reddit.com",
|
|
16494
|
+
defaultHeaders: { "User-Agent": REDDIT_USER_AGENT },
|
|
16150
16495
|
test: { method: "GET", path: "/api/v1/me" },
|
|
16151
16496
|
capabilities: [
|
|
16152
16497
|
{
|
|
16153
16498
|
name: "post.retrieve",
|
|
16154
16499
|
class: "read",
|
|
16155
|
-
description: "Retrieve a Reddit post by its
|
|
16500
|
+
description: "Retrieve a Reddit post by its fullname, such as t3_abc123.",
|
|
16156
16501
|
parameters: {
|
|
16157
16502
|
type: "object",
|
|
16158
16503
|
properties: {
|
|
16159
|
-
postId: { type: "string" }
|
|
16504
|
+
postId: { type: "string", description: "Reddit post fullname, such as t3_abc123." }
|
|
16160
16505
|
},
|
|
16161
16506
|
required: ["postId"]
|
|
16162
16507
|
},
|
|
16163
16508
|
request: {
|
|
16164
16509
|
method: "GET",
|
|
16165
|
-
path: "/
|
|
16166
|
-
|
|
16167
|
-
|
|
16510
|
+
path: "/api/info",
|
|
16511
|
+
query: {
|
|
16512
|
+
id: "{postId}"
|
|
16168
16513
|
}
|
|
16169
16514
|
},
|
|
16170
16515
|
requiredScopes: ["read"]
|
|
@@ -16183,10 +16528,7 @@ var redditConnector = declarativeRestConnector({
|
|
|
16183
16528
|
},
|
|
16184
16529
|
request: {
|
|
16185
16530
|
method: "GET",
|
|
16186
|
-
path: "/r/{subreddit}/comments/{postId}"
|
|
16187
|
-
headers: {
|
|
16188
|
-
"User-Agent": "AgentDev/1.0"
|
|
16189
|
-
}
|
|
16531
|
+
path: "/r/{subreddit}/comments/{postId}"
|
|
16190
16532
|
},
|
|
16191
16533
|
requiredScopes: ["read"]
|
|
16192
16534
|
},
|
|
@@ -16199,27 +16541,28 @@ var redditConnector = declarativeRestConnector({
|
|
|
16199
16541
|
properties: {
|
|
16200
16542
|
subreddit: { type: "string" },
|
|
16201
16543
|
title: { type: "string" },
|
|
16544
|
+
kind: { type: "string", enum: ["self", "link"] },
|
|
16202
16545
|
text: { type: "string" },
|
|
16203
16546
|
url: { type: "string" },
|
|
16204
16547
|
flair_id: { type: "string" }
|
|
16205
16548
|
},
|
|
16206
|
-
required: ["subreddit", "title"]
|
|
16549
|
+
required: ["subreddit", "title", "kind"]
|
|
16207
16550
|
},
|
|
16208
16551
|
request: {
|
|
16209
16552
|
method: "POST",
|
|
16210
|
-
path: "/
|
|
16553
|
+
path: "/api/submit",
|
|
16554
|
+
bodyEncoding: "form",
|
|
16211
16555
|
body: {
|
|
16556
|
+
api_type: "json",
|
|
16557
|
+
sr: "{subreddit}",
|
|
16212
16558
|
title: "{title}",
|
|
16559
|
+
kind: "{kind}",
|
|
16213
16560
|
text: "{text}",
|
|
16214
16561
|
url: "{url}",
|
|
16215
|
-
flair_id: "{flair_id}"
|
|
16216
|
-
kind: "self"
|
|
16217
|
-
},
|
|
16218
|
-
headers: {
|
|
16219
|
-
"User-Agent": "AgentDev/1.0"
|
|
16562
|
+
flair_id: "{flair_id}"
|
|
16220
16563
|
}
|
|
16221
16564
|
},
|
|
16222
|
-
cas: "
|
|
16565
|
+
cas: "none",
|
|
16223
16566
|
externalEffect: true,
|
|
16224
16567
|
requiredScopes: ["submit"]
|
|
16225
16568
|
},
|
|
@@ -16238,15 +16581,14 @@ var redditConnector = declarativeRestConnector({
|
|
|
16238
16581
|
request: {
|
|
16239
16582
|
method: "POST",
|
|
16240
16583
|
path: "/api/comment",
|
|
16584
|
+
bodyEncoding: "form",
|
|
16241
16585
|
body: {
|
|
16586
|
+
api_type: "json",
|
|
16242
16587
|
thing_id: "{parentId}",
|
|
16243
16588
|
text: "{text}"
|
|
16244
|
-
},
|
|
16245
|
-
headers: {
|
|
16246
|
-
"User-Agent": "AgentDev/1.0"
|
|
16247
16589
|
}
|
|
16248
16590
|
},
|
|
16249
|
-
cas: "
|
|
16591
|
+
cas: "none",
|
|
16250
16592
|
externalEffect: true,
|
|
16251
16593
|
requiredScopes: ["submit"]
|
|
16252
16594
|
},
|
|
@@ -16270,9 +16612,6 @@ var redditConnector = declarativeRestConnector({
|
|
|
16270
16612
|
query: {
|
|
16271
16613
|
sort: "{sort}",
|
|
16272
16614
|
limit: "{limit}"
|
|
16273
|
-
},
|
|
16274
|
-
headers: {
|
|
16275
|
-
"User-Agent": "AgentDev/1.0"
|
|
16276
16615
|
}
|
|
16277
16616
|
},
|
|
16278
16617
|
requiredScopes: ["read"]
|
|
@@ -16292,15 +16631,15 @@ var redditConnector = declarativeRestConnector({
|
|
|
16292
16631
|
request: {
|
|
16293
16632
|
method: "POST",
|
|
16294
16633
|
path: "/api/editusertext",
|
|
16634
|
+
bodyEncoding: "form",
|
|
16295
16635
|
body: {
|
|
16636
|
+
api_type: "json",
|
|
16296
16637
|
thing_id: "{thingId}",
|
|
16297
16638
|
text: "{text}"
|
|
16298
|
-
},
|
|
16299
|
-
headers: {
|
|
16300
|
-
"User-Agent": "AgentDev/1.0"
|
|
16301
16639
|
}
|
|
16302
16640
|
},
|
|
16303
|
-
cas: "
|
|
16641
|
+
cas: "none",
|
|
16642
|
+
externalEffect: true,
|
|
16304
16643
|
requiredScopes: ["edit"]
|
|
16305
16644
|
},
|
|
16306
16645
|
{
|
|
@@ -16318,15 +16657,15 @@ var redditConnector = declarativeRestConnector({
|
|
|
16318
16657
|
request: {
|
|
16319
16658
|
method: "POST",
|
|
16320
16659
|
path: "/api/editusertext",
|
|
16660
|
+
bodyEncoding: "form",
|
|
16321
16661
|
body: {
|
|
16662
|
+
api_type: "json",
|
|
16322
16663
|
thing_id: "{thingId}",
|
|
16323
16664
|
text: "{text}"
|
|
16324
|
-
},
|
|
16325
|
-
headers: {
|
|
16326
|
-
"User-Agent": "AgentDev/1.0"
|
|
16327
16665
|
}
|
|
16328
16666
|
},
|
|
16329
|
-
cas: "
|
|
16667
|
+
cas: "none",
|
|
16668
|
+
externalEffect: true,
|
|
16330
16669
|
requiredScopes: ["edit"]
|
|
16331
16670
|
},
|
|
16332
16671
|
{
|
|
@@ -16343,13 +16682,12 @@ var redditConnector = declarativeRestConnector({
|
|
|
16343
16682
|
request: {
|
|
16344
16683
|
method: "POST",
|
|
16345
16684
|
path: "/api/del",
|
|
16685
|
+
bodyEncoding: "form",
|
|
16346
16686
|
body: {
|
|
16347
16687
|
id: "{thingId}"
|
|
16348
|
-
},
|
|
16349
|
-
headers: {
|
|
16350
|
-
"User-Agent": "AgentDev/1.0"
|
|
16351
16688
|
}
|
|
16352
16689
|
},
|
|
16690
|
+
cas: "none",
|
|
16353
16691
|
externalEffect: true,
|
|
16354
16692
|
requiredScopes: ["edit"]
|
|
16355
16693
|
},
|
|
@@ -16367,18 +16705,150 @@ var redditConnector = declarativeRestConnector({
|
|
|
16367
16705
|
request: {
|
|
16368
16706
|
method: "POST",
|
|
16369
16707
|
path: "/api/del",
|
|
16708
|
+
bodyEncoding: "form",
|
|
16370
16709
|
body: {
|
|
16371
16710
|
id: "{thingId}"
|
|
16372
|
-
},
|
|
16373
|
-
headers: {
|
|
16374
|
-
"User-Agent": "AgentDev/1.0"
|
|
16375
16711
|
}
|
|
16376
16712
|
},
|
|
16713
|
+
cas: "none",
|
|
16377
16714
|
externalEffect: true,
|
|
16378
16715
|
requiredScopes: ["edit"]
|
|
16379
16716
|
}
|
|
16380
16717
|
]
|
|
16381
|
-
}
|
|
16718
|
+
};
|
|
16719
|
+
var redditConnector = declarativeRestConnector(redditSpec);
|
|
16720
|
+
function reddit(options) {
|
|
16721
|
+
const adapter = declarativeRestConnector(redditSpec);
|
|
16722
|
+
const now = options.now ?? Date.now;
|
|
16723
|
+
const refreshes = /* @__PURE__ */ new Map();
|
|
16724
|
+
const refresh = async (credentials) => {
|
|
16725
|
+
if (credentials.kind !== "oauth2" || !credentials.refreshToken) {
|
|
16726
|
+
throw new Error("reddit.refreshToken: missing refresh token");
|
|
16727
|
+
}
|
|
16728
|
+
const tokens = await refreshAccessToken({
|
|
16729
|
+
tokenUrl: REDDIT_TOKEN_URL,
|
|
16730
|
+
clientId: options.clientId,
|
|
16731
|
+
clientSecret: options.clientSecret,
|
|
16732
|
+
tokenClientAuthMethod: "client_secret_basic",
|
|
16733
|
+
refreshToken: credentials.refreshToken,
|
|
16734
|
+
tokenRequestHeaders: { "User-Agent": REDDIT_USER_AGENT },
|
|
16735
|
+
fetchImpl: options.fetchImpl
|
|
16736
|
+
});
|
|
16737
|
+
if (!tokens.accessToken || !tokens.expiresIn) {
|
|
16738
|
+
throw new Error("Reddit token refresh returned an incomplete grant");
|
|
16739
|
+
}
|
|
16740
|
+
return {
|
|
16741
|
+
kind: "oauth2",
|
|
16742
|
+
accessToken: tokens.accessToken,
|
|
16743
|
+
refreshToken: tokens.refreshToken ?? credentials.refreshToken,
|
|
16744
|
+
expiresAt: now() + tokens.expiresIn * 1e3
|
|
16745
|
+
};
|
|
16746
|
+
};
|
|
16747
|
+
adapter.refreshToken = refresh;
|
|
16748
|
+
const withFreshCredentials = async (invocation) => {
|
|
16749
|
+
const credentials = invocation.source.credentials;
|
|
16750
|
+
if (credentials.kind !== "oauth2") {
|
|
16751
|
+
throw new CredentialsExpired("Reddit requires OAuth2 credentials.", invocation.source.id);
|
|
16752
|
+
}
|
|
16753
|
+
if (credentials.expiresAt !== void 0 && credentials.expiresAt > now() + 6e4) {
|
|
16754
|
+
return invocation;
|
|
16755
|
+
}
|
|
16756
|
+
if (!credentials.refreshToken) {
|
|
16757
|
+
throw new CredentialsExpired(
|
|
16758
|
+
"Reddit access token expired and no refresh token is available.",
|
|
16759
|
+
invocation.source.id
|
|
16760
|
+
);
|
|
16761
|
+
}
|
|
16762
|
+
let pending = refreshes.get(invocation.source.id);
|
|
16763
|
+
if (!pending) {
|
|
16764
|
+
let next;
|
|
16765
|
+
const promise = Promise.resolve().then(() => {
|
|
16766
|
+
if (!next.onCredentialsRotated) {
|
|
16767
|
+
throw new Error("reddit: credential rotation persistence callback is required before refreshing");
|
|
16768
|
+
}
|
|
16769
|
+
return refresh(credentials);
|
|
16770
|
+
});
|
|
16771
|
+
next = {
|
|
16772
|
+
promise,
|
|
16773
|
+
onCredentialsRotated: invocation.onCredentialsRotated
|
|
16774
|
+
};
|
|
16775
|
+
pending = next;
|
|
16776
|
+
refreshes.set(invocation.source.id, pending);
|
|
16777
|
+
} else if (!pending.onCredentialsRotated && invocation.onCredentialsRotated) {
|
|
16778
|
+
pending.onCredentialsRotated = invocation.onCredentialsRotated;
|
|
16779
|
+
}
|
|
16780
|
+
const current = pending;
|
|
16781
|
+
try {
|
|
16782
|
+
const refreshed = await current.promise;
|
|
16783
|
+
current.persistence ??= Promise.resolve().then(
|
|
16784
|
+
() => current.onCredentialsRotated?.(refreshed)
|
|
16785
|
+
);
|
|
16786
|
+
await current.persistence;
|
|
16787
|
+
return {
|
|
16788
|
+
...invocation,
|
|
16789
|
+
source: { ...invocation.source, credentials: refreshed }
|
|
16790
|
+
};
|
|
16791
|
+
} finally {
|
|
16792
|
+
if (refreshes.get(invocation.source.id) === current) {
|
|
16793
|
+
refreshes.delete(invocation.source.id);
|
|
16794
|
+
}
|
|
16795
|
+
}
|
|
16796
|
+
};
|
|
16797
|
+
return {
|
|
16798
|
+
...adapter,
|
|
16799
|
+
async exchangeOAuth(input) {
|
|
16800
|
+
const tokens = await exchangeAuthorizationCode({
|
|
16801
|
+
tokenUrl: REDDIT_TOKEN_URL,
|
|
16802
|
+
clientId: options.clientId,
|
|
16803
|
+
clientSecret: options.clientSecret,
|
|
16804
|
+
tokenClientAuthMethod: "client_secret_basic",
|
|
16805
|
+
code: input.code,
|
|
16806
|
+
codeVerifier: input.codeVerifier,
|
|
16807
|
+
pkce: "unsupported",
|
|
16808
|
+
redirectUri: input.redirectUri,
|
|
16809
|
+
tokenRequestHeaders: { "User-Agent": REDDIT_USER_AGENT },
|
|
16810
|
+
fetchImpl: options.fetchImpl
|
|
16811
|
+
});
|
|
16812
|
+
if (!tokens.accessToken || !tokens.refreshToken || !tokens.expiresIn) {
|
|
16813
|
+
throw new Error("Reddit token exchange returned an incomplete permanent grant");
|
|
16814
|
+
}
|
|
16815
|
+
return {
|
|
16816
|
+
credentials: {
|
|
16817
|
+
kind: "oauth2",
|
|
16818
|
+
accessToken: tokens.accessToken,
|
|
16819
|
+
refreshToken: tokens.refreshToken,
|
|
16820
|
+
expiresAt: now() + tokens.expiresIn * 1e3
|
|
16821
|
+
},
|
|
16822
|
+
scopes: tokens.scope?.split(/[\s,]+/).filter(Boolean) ?? [...redditSpec.auth.scopes],
|
|
16823
|
+
metadata: {}
|
|
16824
|
+
};
|
|
16825
|
+
},
|
|
16826
|
+
refreshToken: refresh,
|
|
16827
|
+
async executeRead(invocation) {
|
|
16828
|
+
return adapter.executeRead(await withFreshCredentials(invocation));
|
|
16829
|
+
},
|
|
16830
|
+
async executeMutation(invocation) {
|
|
16831
|
+
return adapter.executeMutation(await withFreshCredentials(invocation));
|
|
16832
|
+
},
|
|
16833
|
+
async test(source, onCredentialsRotated) {
|
|
16834
|
+
try {
|
|
16835
|
+
const invocation = await withFreshCredentials({
|
|
16836
|
+
source,
|
|
16837
|
+
capabilityName: "__test__",
|
|
16838
|
+
args: {},
|
|
16839
|
+
idempotencyKey: "reddit-connection-test",
|
|
16840
|
+
onCredentialsRotated
|
|
16841
|
+
});
|
|
16842
|
+
return adapter.test(invocation.source);
|
|
16843
|
+
} catch (error) {
|
|
16844
|
+
return {
|
|
16845
|
+
ok: false,
|
|
16846
|
+
reason: error instanceof Error ? error.message : "unknown error"
|
|
16847
|
+
};
|
|
16848
|
+
}
|
|
16849
|
+
}
|
|
16850
|
+
};
|
|
16851
|
+
}
|
|
16382
16852
|
|
|
16383
16853
|
// src/connectors/adapters/rippling.ts
|
|
16384
16854
|
var ripplingConnector = declarativeRestConnector({
|
|
@@ -24774,7 +25244,7 @@ function numberOrUndefined(value) {
|
|
|
24774
25244
|
}
|
|
24775
25245
|
|
|
24776
25246
|
// src/connectors/adapters/azure-event-grid.ts
|
|
24777
|
-
import { createHash as
|
|
25247
|
+
import { createHash as createHash4, timingSafeEqual } from "crypto";
|
|
24778
25248
|
var API_VERSION2 = "2018-01-01";
|
|
24779
25249
|
var MAX_BATCH_BYTES = 1024 * 1024;
|
|
24780
25250
|
var MAX_EVENTS = 5e3;
|
|
@@ -24843,8 +25313,8 @@ var azureEventGridConnector = {
|
|
|
24843
25313
|
}
|
|
24844
25314
|
const provided = headerValue(headers, "x-tangle-eventgrid-secret");
|
|
24845
25315
|
if (!provided) return { valid: false, reason: "Missing x-tangle-eventgrid-secret delivery header" };
|
|
24846
|
-
const expectedDigest =
|
|
24847
|
-
const providedDigest =
|
|
25316
|
+
const expectedDigest = createHash4("sha256").update(credentials.deliverySecret).digest();
|
|
25317
|
+
const providedDigest = createHash4("sha256").update(provided).digest();
|
|
24848
25318
|
return timingSafeEqual(expectedDigest, providedDigest) ? { valid: true } : { valid: false, reason: "Invalid x-tangle-eventgrid-secret delivery header" };
|
|
24849
25319
|
},
|
|
24850
25320
|
async handleInboundEvent({ rawBody }) {
|
|
@@ -27362,186 +27832,6 @@ var billplzConnector = declarativeRestConnector({
|
|
|
27362
27832
|
]
|
|
27363
27833
|
});
|
|
27364
27834
|
|
|
27365
|
-
// src/connectors/oauth.ts
|
|
27366
|
-
import { createHash as createHash4, randomBytes } from "crypto";
|
|
27367
|
-
var PENDING_TTL_MS = 10 * 60 * 1e3;
|
|
27368
|
-
var InMemoryOAuthFlowStore = class {
|
|
27369
|
-
pendingFlows = /* @__PURE__ */ new Map();
|
|
27370
|
-
put(state, flow) {
|
|
27371
|
-
this.pendingFlows.set(state, flow);
|
|
27372
|
-
}
|
|
27373
|
-
consume(state) {
|
|
27374
|
-
const flow = this.pendingFlows.get(state);
|
|
27375
|
-
this.pendingFlows.delete(state);
|
|
27376
|
-
if (!flow || flow.expiresAt <= Date.now()) return void 0;
|
|
27377
|
-
return flow;
|
|
27378
|
-
}
|
|
27379
|
-
sweep(now) {
|
|
27380
|
-
for (const [k, v] of this.pendingFlows) {
|
|
27381
|
-
if (v.expiresAt <= now) this.pendingFlows.delete(k);
|
|
27382
|
-
}
|
|
27383
|
-
}
|
|
27384
|
-
clear() {
|
|
27385
|
-
this.pendingFlows.clear();
|
|
27386
|
-
}
|
|
27387
|
-
};
|
|
27388
|
-
var defaultFlowStore = new InMemoryOAuthFlowStore();
|
|
27389
|
-
function startOAuthFlow(input) {
|
|
27390
|
-
const store = input.store ?? defaultFlowStore;
|
|
27391
|
-
const now = input.now ?? Date.now();
|
|
27392
|
-
store.sweep?.(now);
|
|
27393
|
-
const usePkce = (input.pkce ?? "required") !== "unsupported";
|
|
27394
|
-
const codeVerifier = usePkce ? base64Url(randomBytes(48)) : void 0;
|
|
27395
|
-
const codeChallenge = codeVerifier ? base64Url(createHash4("sha256").update(codeVerifier).digest()) : void 0;
|
|
27396
|
-
const state = base64Url(randomBytes(24));
|
|
27397
|
-
store.put(state, {
|
|
27398
|
-
codeVerifier,
|
|
27399
|
-
state,
|
|
27400
|
-
projectId: input.projectId,
|
|
27401
|
-
kind: input.kind,
|
|
27402
|
-
label: input.label,
|
|
27403
|
-
redirectUri: input.redirectUri,
|
|
27404
|
-
expiresAt: now + PENDING_TTL_MS
|
|
27405
|
-
});
|
|
27406
|
-
const url = new URL(input.authorizationUrl);
|
|
27407
|
-
url.searchParams.set("response_type", "code");
|
|
27408
|
-
url.searchParams.set(
|
|
27409
|
-
oauthParameterName(input.authorizationClientIdParam, "client_id"),
|
|
27410
|
-
input.clientId
|
|
27411
|
-
);
|
|
27412
|
-
url.searchParams.set("redirect_uri", input.redirectUri);
|
|
27413
|
-
url.searchParams.set("scope", input.scopes.join(input.scopeSeparator ?? " "));
|
|
27414
|
-
url.searchParams.set("state", state);
|
|
27415
|
-
if (input.extraAuthParams) {
|
|
27416
|
-
for (const [k, v] of Object.entries(input.extraAuthParams)) {
|
|
27417
|
-
url.searchParams.set(k, v);
|
|
27418
|
-
}
|
|
27419
|
-
}
|
|
27420
|
-
if (codeChallenge) {
|
|
27421
|
-
url.searchParams.set("code_challenge", codeChallenge);
|
|
27422
|
-
url.searchParams.set("code_challenge_method", "S256");
|
|
27423
|
-
} else {
|
|
27424
|
-
url.searchParams.delete("code_challenge");
|
|
27425
|
-
url.searchParams.delete("code_challenge_method");
|
|
27426
|
-
}
|
|
27427
|
-
return { authorizationUrl: url.toString(), state };
|
|
27428
|
-
}
|
|
27429
|
-
async function consumePendingFlow(state, store = defaultFlowStore) {
|
|
27430
|
-
await store.sweep?.(Date.now());
|
|
27431
|
-
const flow = await store.consume(state);
|
|
27432
|
-
if (!flow) {
|
|
27433
|
-
throw new Error("Unknown or expired OAuth state: possible CSRF, replay, or stale flow");
|
|
27434
|
-
}
|
|
27435
|
-
return flow;
|
|
27436
|
-
}
|
|
27437
|
-
async function exchangeAuthorizationCode(input) {
|
|
27438
|
-
const usePkce = (input.pkce ?? "required") !== "unsupported";
|
|
27439
|
-
if (usePkce && !input.codeVerifier) {
|
|
27440
|
-
throw new Error("OAuth token exchange requires a PKCE code_verifier");
|
|
27441
|
-
}
|
|
27442
|
-
const body = new URLSearchParams({
|
|
27443
|
-
grant_type: "authorization_code",
|
|
27444
|
-
code: input.code,
|
|
27445
|
-
redirect_uri: input.redirectUri
|
|
27446
|
-
});
|
|
27447
|
-
if (usePkce) body.set("code_verifier", input.codeVerifier);
|
|
27448
|
-
const headers = {
|
|
27449
|
-
"content-type": "application/x-www-form-urlencoded",
|
|
27450
|
-
accept: "application/json"
|
|
27451
|
-
};
|
|
27452
|
-
applyTokenClientAuthentication(input, body, headers);
|
|
27453
|
-
const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
|
|
27454
|
-
method: "POST",
|
|
27455
|
-
headers,
|
|
27456
|
-
body,
|
|
27457
|
-
signal: input.signal
|
|
27458
|
-
});
|
|
27459
|
-
if (!res.ok) {
|
|
27460
|
-
const text = await res.text().catch(() => "");
|
|
27461
|
-
throw new Error(`OAuth token exchange failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
|
|
27462
|
-
}
|
|
27463
|
-
const json = await res.json();
|
|
27464
|
-
return {
|
|
27465
|
-
accessToken: json.access_token,
|
|
27466
|
-
refreshToken: json.refresh_token,
|
|
27467
|
-
expiresIn: json.expires_in,
|
|
27468
|
-
scope: json.scope,
|
|
27469
|
-
tokenType: json.token_type,
|
|
27470
|
-
idToken: json.id_token
|
|
27471
|
-
};
|
|
27472
|
-
}
|
|
27473
|
-
async function refreshAccessToken(input) {
|
|
27474
|
-
const body = new URLSearchParams({
|
|
27475
|
-
grant_type: "refresh_token",
|
|
27476
|
-
refresh_token: input.refreshToken
|
|
27477
|
-
});
|
|
27478
|
-
const headers = {
|
|
27479
|
-
"content-type": "application/x-www-form-urlencoded",
|
|
27480
|
-
accept: "application/json"
|
|
27481
|
-
};
|
|
27482
|
-
applyTokenClientAuthentication(input, body, headers);
|
|
27483
|
-
const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
|
|
27484
|
-
method: "POST",
|
|
27485
|
-
headers,
|
|
27486
|
-
body,
|
|
27487
|
-
signal: input.signal
|
|
27488
|
-
});
|
|
27489
|
-
if (!res.ok) {
|
|
27490
|
-
const text = await res.text().catch(() => "");
|
|
27491
|
-
throw new Error(`OAuth refresh failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
|
|
27492
|
-
}
|
|
27493
|
-
const json = await res.json();
|
|
27494
|
-
return {
|
|
27495
|
-
accessToken: json.access_token,
|
|
27496
|
-
// Some providers omit refresh_token on refresh — keep the previous one
|
|
27497
|
-
// in that case (caller passes through if undefined).
|
|
27498
|
-
refreshToken: json.refresh_token,
|
|
27499
|
-
expiresIn: json.expires_in,
|
|
27500
|
-
scope: json.scope,
|
|
27501
|
-
tokenType: json.token_type,
|
|
27502
|
-
idToken: json.id_token
|
|
27503
|
-
};
|
|
27504
|
-
}
|
|
27505
|
-
function applyTokenClientAuthentication(input, body, headers) {
|
|
27506
|
-
const method = input.tokenClientAuthMethod ?? "client_secret_post";
|
|
27507
|
-
if (method === "none") {
|
|
27508
|
-
body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
|
|
27509
|
-
return;
|
|
27510
|
-
}
|
|
27511
|
-
if (!input.clientSecret) {
|
|
27512
|
-
throw new Error(`OAuth ${method} client authentication requires a client secret`);
|
|
27513
|
-
}
|
|
27514
|
-
if (method === "client_secret_post") {
|
|
27515
|
-
body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
|
|
27516
|
-
body.set(
|
|
27517
|
-
oauthParameterName(input.tokenClientSecretParam, "client_secret"),
|
|
27518
|
-
input.clientSecret
|
|
27519
|
-
);
|
|
27520
|
-
return;
|
|
27521
|
-
}
|
|
27522
|
-
if (method === "client_secret_basic") {
|
|
27523
|
-
headers.authorization = `Basic ${Buffer.from(
|
|
27524
|
-
`${input.clientId}:${input.clientSecret}`,
|
|
27525
|
-
"utf8"
|
|
27526
|
-
).toString("base64")}`;
|
|
27527
|
-
return;
|
|
27528
|
-
}
|
|
27529
|
-
throw new Error("Unsupported OAuth token client authentication method");
|
|
27530
|
-
}
|
|
27531
|
-
function base64Url(buf) {
|
|
27532
|
-
return buf.toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
27533
|
-
}
|
|
27534
|
-
function oauthParameterName(value, fallback) {
|
|
27535
|
-
const name = value ?? fallback;
|
|
27536
|
-
if (!/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(name)) {
|
|
27537
|
-
throw new Error("Invalid OAuth parameter name");
|
|
27538
|
-
}
|
|
27539
|
-
return name;
|
|
27540
|
-
}
|
|
27541
|
-
function _resetPendingFlowsForTests() {
|
|
27542
|
-
defaultFlowStore.clear?.();
|
|
27543
|
-
}
|
|
27544
|
-
|
|
27545
27835
|
// src/connectors/adapters/cal-com.ts
|
|
27546
27836
|
var authorizeUrl = "https://app.cal.com/auth/oauth2/authorize";
|
|
27547
27837
|
var tokenUrl = "https://api.cal.com/v2/auth/oauth2/token";
|
|
@@ -52737,13 +53027,11 @@ function microsoftTeams(opts) {
|
|
|
52737
53027
|
async test(source) {
|
|
52738
53028
|
try {
|
|
52739
53029
|
const accessToken4 = await ensureFreshAccessToken11(source.credentials, clientId, clientSecret);
|
|
52740
|
-
const res = await fetch(`${GRAPH2}/me
|
|
53030
|
+
const res = await fetch(`${GRAPH2}/me/joinedTeams`, {
|
|
52741
53031
|
headers: { authorization: `Bearer ${accessToken4}` },
|
|
52742
53032
|
signal: AbortSignal.timeout(8e3)
|
|
52743
53033
|
});
|
|
52744
|
-
if (res.status === 401 || res.status === 403)
|
|
52745
|
-
return { ok: false, reason: `Microsoft rejected token (${res.status}) \u2014 reconnect required` };
|
|
52746
|
-
}
|
|
53034
|
+
if (res.status === 401 || res.status === 403) return microsoftGraphTestFailure(res);
|
|
52747
53035
|
if (!res.ok) return { ok: false, reason: `Microsoft Graph returned ${res.status}` };
|
|
52748
53036
|
return { ok: true };
|
|
52749
53037
|
} catch (err) {
|
|
@@ -52804,7 +53092,7 @@ async function graphGet2(url, accessToken4, dataSourceId) {
|
|
|
52804
53092
|
signal: AbortSignal.timeout(1e4)
|
|
52805
53093
|
});
|
|
52806
53094
|
if (res.status === 401 || res.status === 403) {
|
|
52807
|
-
|
|
53095
|
+
await throwMicrosoftGraphAccessError(res, dataSourceId);
|
|
52808
53096
|
}
|
|
52809
53097
|
if (!res.ok) {
|
|
52810
53098
|
const text = await res.text().catch(() => "");
|
|
@@ -52824,7 +53112,7 @@ async function graphPost(url, accessToken4, body, dataSourceId, op) {
|
|
|
52824
53112
|
signal: AbortSignal.timeout(15e3)
|
|
52825
53113
|
});
|
|
52826
53114
|
if (res.status === 401 || res.status === 403) {
|
|
52827
|
-
|
|
53115
|
+
await throwMicrosoftGraphAccessError(res, dataSourceId);
|
|
52828
53116
|
}
|
|
52829
53117
|
if (!res.ok) {
|
|
52830
53118
|
const text = await res.text().catch(() => "");
|
|
@@ -52832,6 +53120,57 @@ async function graphPost(url, accessToken4, body, dataSourceId, op) {
|
|
|
52832
53120
|
}
|
|
52833
53121
|
return await res.json();
|
|
52834
53122
|
}
|
|
53123
|
+
async function microsoftGraphErrorBody(res) {
|
|
53124
|
+
try {
|
|
53125
|
+
const body = await res.json();
|
|
53126
|
+
return body && typeof body === "object" ? body : void 0;
|
|
53127
|
+
} catch {
|
|
53128
|
+
return void 0;
|
|
53129
|
+
}
|
|
53130
|
+
}
|
|
53131
|
+
function microsoftGraphErrorText(body) {
|
|
53132
|
+
const code = typeof body?.error?.code === "string" ? body.error.code : "";
|
|
53133
|
+
const message = typeof body?.error?.message === "string" ? body.error.message : "";
|
|
53134
|
+
return `${code} ${message}`.trim();
|
|
53135
|
+
}
|
|
53136
|
+
function microsoftGraphRequiresLicense(body) {
|
|
53137
|
+
return /\b(?:valid\s+)?licen[cs]e\b/i.test(microsoftGraphErrorText(body));
|
|
53138
|
+
}
|
|
53139
|
+
async function throwMicrosoftGraphAccessError(res, dataSourceId) {
|
|
53140
|
+
const body = await microsoftGraphErrorBody(res);
|
|
53141
|
+
if (microsoftGraphRequiresLicense(body)) {
|
|
53142
|
+
throw new ProviderConfigError(
|
|
53143
|
+
"Microsoft Teams requires a valid Microsoft 365 or Teams license",
|
|
53144
|
+
dataSourceId,
|
|
53145
|
+
{ status: res.status, reason: "licenseRequired", body }
|
|
53146
|
+
);
|
|
53147
|
+
}
|
|
53148
|
+
if (res.status === 403) {
|
|
53149
|
+
throw new ProviderConfigError("Microsoft Graph denied the requested permission", dataSourceId, {
|
|
53150
|
+
status: res.status,
|
|
53151
|
+
reason: typeof body?.error?.code === "string" && body.error.code ? body.error.code : "forbidden",
|
|
53152
|
+
body
|
|
53153
|
+
});
|
|
53154
|
+
}
|
|
53155
|
+
throw new CredentialsExpired(`Microsoft Graph rejected token (${res.status})`, dataSourceId, {
|
|
53156
|
+
status: res.status,
|
|
53157
|
+
reason: typeof body?.error?.code === "string" && body.error.code ? body.error.code : "unauthorized",
|
|
53158
|
+
body
|
|
53159
|
+
});
|
|
53160
|
+
}
|
|
53161
|
+
async function microsoftGraphTestFailure(res) {
|
|
53162
|
+
const body = await microsoftGraphErrorBody(res);
|
|
53163
|
+
if (microsoftGraphRequiresLicense(body)) {
|
|
53164
|
+
return {
|
|
53165
|
+
ok: false,
|
|
53166
|
+
reason: "Microsoft Teams requires a valid Microsoft 365 or Teams license"
|
|
53167
|
+
};
|
|
53168
|
+
}
|
|
53169
|
+
if (res.status === 403) {
|
|
53170
|
+
return { ok: false, reason: "Microsoft Graph denied the requested permission" };
|
|
53171
|
+
}
|
|
53172
|
+
return { ok: false, reason: `Microsoft rejected token (${res.status}) \u2014 reconnect required` };
|
|
53173
|
+
}
|
|
52835
53174
|
function escapeOData2(value) {
|
|
52836
53175
|
return value.replace(/'/g, "''");
|
|
52837
53176
|
}
|
|
@@ -55827,6 +56166,7 @@ var NOTION_SPEC = {
|
|
|
55827
56166
|
scopes: [],
|
|
55828
56167
|
clientIdEnv: "NOTION_OAUTH_CLIENT_ID",
|
|
55829
56168
|
clientSecretEnv: "NOTION_OAUTH_CLIENT_SECRET",
|
|
56169
|
+
tokenClientAuthMethod: "client_secret_basic",
|
|
55830
56170
|
extraAuthParams: { owner: "user" }
|
|
55831
56171
|
},
|
|
55832
56172
|
category: "doc",
|
|
@@ -56149,11 +56489,9 @@ function notion(opts) {
|
|
|
56149
56489
|
...withNotionOverrides(declarativeRestConnector(NOTION_SPEC)),
|
|
56150
56490
|
/**
|
|
56151
56491
|
* Notion's token endpoint follows RFC 6749 with one twist — it REQUIRES
|
|
56152
|
-
* HTTP Basic auth
|
|
56153
|
-
*
|
|
56154
|
-
*
|
|
56155
|
-
* back in the response and we stash them in `metadata` so the agent can
|
|
56156
|
-
* address resources by workspace where useful.
|
|
56492
|
+
* HTTP Basic auth and returns workspace metadata with the grant. We use
|
|
56493
|
+
* the shared Basic encoding and redaction primitives, then retain that
|
|
56494
|
+
* metadata for resource selection.
|
|
56157
56495
|
*/
|
|
56158
56496
|
async exchangeOAuth(input) {
|
|
56159
56497
|
if (!clientId || !clientSecret) {
|
|
@@ -56168,22 +56506,62 @@ function notion(opts) {
|
|
|
56168
56506
|
redirect_uri: input.redirectUri,
|
|
56169
56507
|
code_verifier: input.codeVerifier
|
|
56170
56508
|
});
|
|
56171
|
-
const
|
|
56172
|
-
|
|
56173
|
-
|
|
56174
|
-
|
|
56175
|
-
|
|
56176
|
-
|
|
56177
|
-
|
|
56178
|
-
|
|
56179
|
-
|
|
56180
|
-
|
|
56181
|
-
|
|
56509
|
+
const authorization = createOAuthBasicAuthorizationHeader(
|
|
56510
|
+
clientId,
|
|
56511
|
+
clientSecret
|
|
56512
|
+
);
|
|
56513
|
+
const redactionValues = [
|
|
56514
|
+
input.code,
|
|
56515
|
+
input.codeVerifier,
|
|
56516
|
+
...oauthClientCredentialRedactionValues(
|
|
56517
|
+
clientId,
|
|
56518
|
+
clientSecret,
|
|
56519
|
+
authorization
|
|
56520
|
+
)
|
|
56521
|
+
];
|
|
56522
|
+
let res;
|
|
56523
|
+
try {
|
|
56524
|
+
res = await fetch(TOKEN_URL13, {
|
|
56525
|
+
method: "POST",
|
|
56526
|
+
headers: {
|
|
56527
|
+
authorization,
|
|
56528
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
56529
|
+
accept: "application/json",
|
|
56530
|
+
"Notion-Version": NOTION_VERSION
|
|
56531
|
+
},
|
|
56532
|
+
body,
|
|
56533
|
+
signal: AbortSignal.timeout(15e3)
|
|
56534
|
+
});
|
|
56535
|
+
} catch (cause) {
|
|
56536
|
+
const detail = redactOAuthSensitiveText(
|
|
56537
|
+
cause?.message ?? "unknown",
|
|
56538
|
+
redactionValues
|
|
56539
|
+
);
|
|
56540
|
+
throw new Error(`Notion OAuth token exchange transport error: ${detail}`);
|
|
56541
|
+
}
|
|
56182
56542
|
if (!res.ok) {
|
|
56183
56543
|
const text = await res.text().catch(() => "");
|
|
56184
|
-
|
|
56544
|
+
const statusText = redactOAuthSensitiveText(
|
|
56545
|
+
res.statusText,
|
|
56546
|
+
redactionValues
|
|
56547
|
+
);
|
|
56548
|
+
const detail = redactOAuthSensitiveText(text, redactionValues).slice(
|
|
56549
|
+
0,
|
|
56550
|
+
200
|
|
56551
|
+
);
|
|
56552
|
+
throw new Error(
|
|
56553
|
+
`Notion OAuth token exchange failed: ${res.status} ${statusText} \u2014 ${detail}`
|
|
56554
|
+
);
|
|
56555
|
+
}
|
|
56556
|
+
let json;
|
|
56557
|
+
try {
|
|
56558
|
+
json = await res.json();
|
|
56559
|
+
} catch {
|
|
56560
|
+
throw new Error("Notion OAuth token exchange returned invalid JSON");
|
|
56561
|
+
}
|
|
56562
|
+
if (!json.access_token) {
|
|
56563
|
+
throw new Error("Notion OAuth token exchange returned no access_token");
|
|
56185
56564
|
}
|
|
56186
|
-
const json = await res.json();
|
|
56187
56565
|
return {
|
|
56188
56566
|
credentials: {
|
|
56189
56567
|
kind: "oauth2",
|
|
@@ -56214,6 +56592,7 @@ function notion(opts) {
|
|
|
56214
56592
|
tokenUrl: TOKEN_URL13,
|
|
56215
56593
|
clientId,
|
|
56216
56594
|
clientSecret,
|
|
56595
|
+
tokenClientAuthMethod: "client_secret_basic",
|
|
56217
56596
|
refreshToken: creds.refreshToken
|
|
56218
56597
|
});
|
|
56219
56598
|
return {
|
|
@@ -69160,7 +69539,8 @@ var TWITTER_SPEC = {
|
|
|
69160
69539
|
tokenUrl: TOKEN_URL19,
|
|
69161
69540
|
scopes: SCOPES13,
|
|
69162
69541
|
clientIdEnv: "TWITTER_OAUTH_CLIENT_ID",
|
|
69163
|
-
clientSecretEnv: "TWITTER_OAUTH_CLIENT_SECRET"
|
|
69542
|
+
clientSecretEnv: "TWITTER_OAUTH_CLIENT_SECRET",
|
|
69543
|
+
tokenClientAuthMethod: "client_secret_basic"
|
|
69164
69544
|
},
|
|
69165
69545
|
{
|
|
69166
69546
|
kind: "api-key",
|
|
@@ -69457,21 +69837,61 @@ function twitter(opts) {
|
|
|
69457
69837
|
};
|
|
69458
69838
|
}
|
|
69459
69839
|
async function twitterTokenRequest(clientId, clientSecret, params) {
|
|
69460
|
-
const
|
|
69461
|
-
|
|
69462
|
-
|
|
69463
|
-
|
|
69464
|
-
|
|
69465
|
-
|
|
69466
|
-
|
|
69467
|
-
|
|
69468
|
-
|
|
69469
|
-
|
|
69840
|
+
const authorization = createOAuthBasicAuthorizationHeader(
|
|
69841
|
+
clientId,
|
|
69842
|
+
clientSecret
|
|
69843
|
+
);
|
|
69844
|
+
const requestSecrets = [
|
|
69845
|
+
params.code,
|
|
69846
|
+
params.code_verifier,
|
|
69847
|
+
params.refresh_token
|
|
69848
|
+
].filter((value) => typeof value === "string" && value.length > 0);
|
|
69849
|
+
const redactionValues = [
|
|
69850
|
+
...requestSecrets,
|
|
69851
|
+
...oauthClientCredentialRedactionValues(
|
|
69852
|
+
clientId,
|
|
69853
|
+
clientSecret,
|
|
69854
|
+
authorization
|
|
69855
|
+
)
|
|
69856
|
+
];
|
|
69857
|
+
let res;
|
|
69858
|
+
try {
|
|
69859
|
+
res = await fetch(TOKEN_URL19, {
|
|
69860
|
+
method: "POST",
|
|
69861
|
+
headers: {
|
|
69862
|
+
authorization,
|
|
69863
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
69864
|
+
accept: "application/json"
|
|
69865
|
+
},
|
|
69866
|
+
body: new URLSearchParams(params),
|
|
69867
|
+
signal: AbortSignal.timeout(15e3)
|
|
69868
|
+
});
|
|
69869
|
+
} catch (cause) {
|
|
69870
|
+
const detail = redactOAuthSensitiveText(
|
|
69871
|
+
cause?.message ?? "unknown",
|
|
69872
|
+
redactionValues
|
|
69873
|
+
);
|
|
69874
|
+
throw new Error(
|
|
69875
|
+
`twitter ${params.grant_type} token transport error: ${detail}`
|
|
69876
|
+
);
|
|
69877
|
+
}
|
|
69470
69878
|
if (!res.ok) {
|
|
69471
69879
|
const text = await res.text().catch(() => "");
|
|
69472
|
-
|
|
69880
|
+
const statusText = redactOAuthSensitiveText(res.statusText, redactionValues);
|
|
69881
|
+
const detail = redactOAuthSensitiveText(text, redactionValues).slice(0, 200);
|
|
69882
|
+
throw new Error(
|
|
69883
|
+
`twitter ${params.grant_type} token request failed: ${res.status} ${statusText} \u2014 ${detail}`
|
|
69884
|
+
);
|
|
69885
|
+
}
|
|
69886
|
+
let json;
|
|
69887
|
+
try {
|
|
69888
|
+
json = await res.json();
|
|
69889
|
+
} catch {
|
|
69890
|
+
throw new Error(`twitter ${params.grant_type} token request returned invalid JSON`);
|
|
69891
|
+
}
|
|
69892
|
+
if (!json.access_token) {
|
|
69893
|
+
throw new Error(`twitter ${params.grant_type} token request returned no access_token`);
|
|
69473
69894
|
}
|
|
69474
|
-
const json = await res.json();
|
|
69475
69895
|
return {
|
|
69476
69896
|
accessToken: json.access_token,
|
|
69477
69897
|
refreshToken: json.refresh_token,
|
|
@@ -83842,7 +84262,7 @@ var CONNECTOR_ADAPTER_FACTORIES = [
|
|
|
83842
84262
|
clientId: "PUSHBULLET_OAUTH_CLIENT_ID",
|
|
83843
84263
|
clientSecret: "PUSHBULLET_OAUTH_CLIENT_SECRET"
|
|
83844
84264
|
}),
|
|
83845
|
-
defineFactoryAdapter(
|
|
84265
|
+
defineFactoryAdapter(reddit, {
|
|
83846
84266
|
clientId: "REDDIT_OAUTH_CLIENT_ID",
|
|
83847
84267
|
clientSecret: "REDDIT_OAUTH_CLIENT_SECRET"
|
|
83848
84268
|
}),
|
|
@@ -148676,6 +149096,11 @@ export {
|
|
|
148676
149096
|
consumePendingFlow,
|
|
148677
149097
|
exchangeAuthorizationCode,
|
|
148678
149098
|
refreshAccessToken,
|
|
149099
|
+
createOAuthTokenRequestHeaders,
|
|
149100
|
+
formEncodeOAuthClientCredential,
|
|
149101
|
+
createOAuthBasicAuthorizationHeader,
|
|
149102
|
+
oauthClientCredentialRedactionValues,
|
|
149103
|
+
redactOAuthSensitiveText,
|
|
148679
149104
|
_resetPendingFlowsForTests,
|
|
148680
149105
|
declarativeRestConnector,
|
|
148681
149106
|
oktaConnector,
|
|
@@ -148752,6 +149177,7 @@ export {
|
|
|
148752
149177
|
paychexConnector,
|
|
148753
149178
|
pushbulletConnector,
|
|
148754
149179
|
redditConnector,
|
|
149180
|
+
reddit,
|
|
148755
149181
|
ripplingConnector,
|
|
148756
149182
|
sanityConnector,
|
|
148757
149183
|
sendpulseConnector,
|
|
@@ -149332,4 +149758,4 @@ export {
|
|
|
149332
149758
|
getresponseConnector,
|
|
149333
149759
|
adapters_exports
|
|
149334
149760
|
};
|
|
149335
|
-
//# sourceMappingURL=chunk-
|
|
149761
|
+
//# sourceMappingURL=chunk-2JRYKWYX.js.map
|