@tangle-network/agent-integrations 0.53.49 → 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.
@@ -1645,7 +1645,325 @@ function membershipCapability(name, method, description) {
1645
1645
  }
1646
1646
 
1647
1647
  // src/connectors/adapters/client-credentials-rest.ts
1648
- import { createHash as createHash2 } from "crypto";
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
1649
1967
  function clientCredentialsRestConnector(spec) {
1650
1968
  const regionMetadataKey = spec.regionMetadataKey ?? "region";
1651
1969
  const delegated = declarativeRestConnector({
@@ -1764,7 +2082,7 @@ function readRegionName(bundle, metadata, metadataKey, fallback) {
1764
2082
  return (bundle.region ?? metadataRegion ?? fallback).toLowerCase().trim();
1765
2083
  }
1766
2084
  function credentialFingerprint(bundle, region, scope) {
1767
- return createHash2("sha256").update(bundle.clientId).update("\0").update(bundle.clientSecret).update("\0").update(region.tokenUrl).update("\0").update(scope ?? "").digest("hex");
2085
+ return createHash3("sha256").update(bundle.clientId).update("\0").update(bundle.clientSecret).update("\0").update(region.tokenUrl).update("\0").update(scope ?? "").digest("hex");
1768
2086
  }
1769
2087
  function renderConnectionMetadata(template, metadata) {
1770
2088
  const rendered = template.replace(/\{connection\.([a-zA-Z0-9_.-]+)\}/g, (_match, key) => {
@@ -1795,7 +2113,10 @@ async function exchangeClientCredentials(displayName, sourceId, bundle, region,
1795
2113
  "content-type": "application/x-www-form-urlencoded"
1796
2114
  };
1797
2115
  if (credentialPlacement === "basic") {
1798
- headers.authorization = `Basic ${Buffer.from(`${bundle.clientId}:${bundle.clientSecret}`).toString("base64")}`;
2116
+ headers.authorization = createOAuthBasicAuthorizationHeader(
2117
+ bundle.clientId,
2118
+ bundle.clientSecret
2119
+ );
1799
2120
  }
1800
2121
  const response = await fetch(region.tokenUrl, {
1801
2122
  method: "POST",
@@ -16148,187 +16469,6 @@ var pushbulletConnector = declarativeRestConnector({
16148
16469
  ]
16149
16470
  });
16150
16471
 
16151
- // src/connectors/oauth.ts
16152
- import { createHash as createHash3, randomBytes } from "crypto";
16153
- var PENDING_TTL_MS = 10 * 60 * 1e3;
16154
- var InMemoryOAuthFlowStore = class {
16155
- pendingFlows = /* @__PURE__ */ new Map();
16156
- put(state, flow) {
16157
- this.pendingFlows.set(state, flow);
16158
- }
16159
- consume(state) {
16160
- const flow = this.pendingFlows.get(state);
16161
- this.pendingFlows.delete(state);
16162
- if (!flow || flow.expiresAt <= Date.now()) return void 0;
16163
- return flow;
16164
- }
16165
- sweep(now) {
16166
- for (const [k, v] of this.pendingFlows) {
16167
- if (v.expiresAt <= now) this.pendingFlows.delete(k);
16168
- }
16169
- }
16170
- clear() {
16171
- this.pendingFlows.clear();
16172
- }
16173
- };
16174
- var defaultFlowStore = new InMemoryOAuthFlowStore();
16175
- function startOAuthFlow(input) {
16176
- const store = input.store ?? defaultFlowStore;
16177
- const now = input.now ?? Date.now();
16178
- store.sweep?.(now);
16179
- const usePkce = (input.pkce ?? "required") !== "unsupported";
16180
- const codeVerifier = usePkce ? base64Url(randomBytes(48)) : void 0;
16181
- const codeChallenge = codeVerifier ? base64Url(createHash3("sha256").update(codeVerifier).digest()) : void 0;
16182
- const state = base64Url(randomBytes(24));
16183
- store.put(state, {
16184
- codeVerifier,
16185
- state,
16186
- projectId: input.projectId,
16187
- kind: input.kind,
16188
- label: input.label,
16189
- redirectUri: input.redirectUri,
16190
- expiresAt: now + PENDING_TTL_MS
16191
- });
16192
- const url = new URL(input.authorizationUrl);
16193
- url.searchParams.set("response_type", "code");
16194
- url.searchParams.set(
16195
- oauthParameterName(input.authorizationClientIdParam, "client_id"),
16196
- input.clientId
16197
- );
16198
- url.searchParams.set("redirect_uri", input.redirectUri);
16199
- url.searchParams.set("scope", input.scopes.join(input.scopeSeparator ?? " "));
16200
- url.searchParams.set("state", state);
16201
- if (input.extraAuthParams) {
16202
- for (const [k, v] of Object.entries(input.extraAuthParams)) {
16203
- url.searchParams.set(k, v);
16204
- }
16205
- }
16206
- if (codeChallenge) {
16207
- url.searchParams.set("code_challenge", codeChallenge);
16208
- url.searchParams.set("code_challenge_method", "S256");
16209
- } else {
16210
- url.searchParams.delete("code_challenge");
16211
- url.searchParams.delete("code_challenge_method");
16212
- }
16213
- return { authorizationUrl: url.toString(), state };
16214
- }
16215
- async function consumePendingFlow(state, store = defaultFlowStore) {
16216
- await store.sweep?.(Date.now());
16217
- const flow = await store.consume(state);
16218
- if (!flow) {
16219
- throw new Error("Unknown or expired OAuth state: possible CSRF, replay, or stale flow");
16220
- }
16221
- return flow;
16222
- }
16223
- async function exchangeAuthorizationCode(input) {
16224
- const usePkce = (input.pkce ?? "required") !== "unsupported";
16225
- if (usePkce && !input.codeVerifier) {
16226
- throw new Error("OAuth token exchange requires a PKCE code_verifier");
16227
- }
16228
- const body = new URLSearchParams({
16229
- grant_type: "authorization_code",
16230
- code: input.code,
16231
- redirect_uri: input.redirectUri
16232
- });
16233
- if (usePkce) body.set("code_verifier", input.codeVerifier);
16234
- const headers = createOAuthTokenRequestHeaders(input.tokenRequestHeaders);
16235
- applyTokenClientAuthentication(input, body, headers);
16236
- const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
16237
- method: "POST",
16238
- headers,
16239
- body,
16240
- signal: input.signal
16241
- });
16242
- if (!res.ok) {
16243
- const text = await res.text().catch(() => "");
16244
- throw new Error(`OAuth token exchange failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
16245
- }
16246
- const json = await res.json();
16247
- return {
16248
- accessToken: json.access_token,
16249
- refreshToken: json.refresh_token,
16250
- expiresIn: json.expires_in,
16251
- scope: json.scope,
16252
- tokenType: json.token_type,
16253
- idToken: json.id_token
16254
- };
16255
- }
16256
- async function refreshAccessToken(input) {
16257
- const body = new URLSearchParams({
16258
- grant_type: "refresh_token",
16259
- refresh_token: input.refreshToken
16260
- });
16261
- const headers = createOAuthTokenRequestHeaders(input.tokenRequestHeaders);
16262
- applyTokenClientAuthentication(input, body, headers);
16263
- const res = await (input.fetchImpl ?? fetch)(input.tokenUrl, {
16264
- method: "POST",
16265
- headers,
16266
- body,
16267
- signal: input.signal
16268
- });
16269
- if (!res.ok) {
16270
- const text = await res.text().catch(() => "");
16271
- throw new Error(`OAuth refresh failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
16272
- }
16273
- const json = await res.json();
16274
- return {
16275
- accessToken: json.access_token,
16276
- // Some providers omit refresh_token on refresh — keep the previous one
16277
- // in that case (caller passes through if undefined).
16278
- refreshToken: json.refresh_token,
16279
- expiresIn: json.expires_in,
16280
- scope: json.scope,
16281
- tokenType: json.token_type,
16282
- idToken: json.id_token
16283
- };
16284
- }
16285
- function createOAuthTokenRequestHeaders(additional) {
16286
- const headers = new Headers(additional);
16287
- headers.set("content-type", "application/x-www-form-urlencoded");
16288
- headers.set("accept", "application/json");
16289
- headers.delete("authorization");
16290
- return Object.fromEntries(headers.entries());
16291
- }
16292
- function applyTokenClientAuthentication(input, body, headers) {
16293
- const method = input.tokenClientAuthMethod ?? "client_secret_post";
16294
- if (method === "none") {
16295
- body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
16296
- return;
16297
- }
16298
- if (!input.clientSecret) {
16299
- throw new Error(`OAuth ${method} client authentication requires a client secret`);
16300
- }
16301
- if (method === "client_secret_post") {
16302
- body.set(oauthParameterName(input.tokenClientIdParam, "client_id"), input.clientId);
16303
- body.set(
16304
- oauthParameterName(input.tokenClientSecretParam, "client_secret"),
16305
- input.clientSecret
16306
- );
16307
- return;
16308
- }
16309
- if (method === "client_secret_basic") {
16310
- headers.authorization = `Basic ${Buffer.from(
16311
- `${input.clientId}:${input.clientSecret}`,
16312
- "utf8"
16313
- ).toString("base64")}`;
16314
- return;
16315
- }
16316
- throw new Error("Unsupported OAuth token client authentication method");
16317
- }
16318
- function base64Url(buf) {
16319
- return buf.toString("base64").replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_");
16320
- }
16321
- function oauthParameterName(value, fallback) {
16322
- const name = value ?? fallback;
16323
- if (!/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(name)) {
16324
- throw new Error("Invalid OAuth parameter name");
16325
- }
16326
- return name;
16327
- }
16328
- function _resetPendingFlowsForTests() {
16329
- defaultFlowStore.clear?.();
16330
- }
16331
-
16332
16472
  // src/connectors/adapters/reddit.ts
16333
16473
  var REDDIT_USER_AGENT = "web:tools.tangle.integration-hub:v1.0 (contact: https://tangle.tools)";
16334
16474
  var REDDIT_TOKEN_URL = "https://www.reddit.com/api/v1/access_token";
@@ -56026,6 +56166,7 @@ var NOTION_SPEC = {
56026
56166
  scopes: [],
56027
56167
  clientIdEnv: "NOTION_OAUTH_CLIENT_ID",
56028
56168
  clientSecretEnv: "NOTION_OAUTH_CLIENT_SECRET",
56169
+ tokenClientAuthMethod: "client_secret_basic",
56029
56170
  extraAuthParams: { owner: "user" }
56030
56171
  },
56031
56172
  category: "doc",
@@ -56348,11 +56489,9 @@ function notion(opts) {
56348
56489
  ...withNotionOverrides(declarativeRestConnector(NOTION_SPEC)),
56349
56490
  /**
56350
56491
  * Notion's token endpoint follows RFC 6749 with one twist — it REQUIRES
56351
- * HTTP Basic auth (client_id:client_secret) and does NOT accept the client
56352
- * credentials in the form body, so we POST inline rather than via the
56353
- * generic `exchangeAuthorizationCode` helper. The workspace_id/bot_id come
56354
- * back in the response and we stash them in `metadata` so the agent can
56355
- * 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.
56356
56495
  */
56357
56496
  async exchangeOAuth(input) {
56358
56497
  if (!clientId || !clientSecret) {
@@ -56367,22 +56506,62 @@ function notion(opts) {
56367
56506
  redirect_uri: input.redirectUri,
56368
56507
  code_verifier: input.codeVerifier
56369
56508
  });
56370
- const res = await fetch(TOKEN_URL13, {
56371
- method: "POST",
56372
- headers: {
56373
- authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
56374
- "content-type": "application/x-www-form-urlencoded",
56375
- accept: "application/json",
56376
- "Notion-Version": NOTION_VERSION
56377
- },
56378
- body,
56379
- signal: AbortSignal.timeout(15e3)
56380
- });
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
+ }
56381
56542
  if (!res.ok) {
56382
56543
  const text = await res.text().catch(() => "");
56383
- throw new Error(`Notion OAuth token exchange failed: ${res.status} \u2014 ${text.slice(0, 200)}`);
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");
56384
56564
  }
56385
- const json = await res.json();
56386
56565
  return {
56387
56566
  credentials: {
56388
56567
  kind: "oauth2",
@@ -56413,6 +56592,7 @@ function notion(opts) {
56413
56592
  tokenUrl: TOKEN_URL13,
56414
56593
  clientId,
56415
56594
  clientSecret,
56595
+ tokenClientAuthMethod: "client_secret_basic",
56416
56596
  refreshToken: creds.refreshToken
56417
56597
  });
56418
56598
  return {
@@ -69359,7 +69539,8 @@ var TWITTER_SPEC = {
69359
69539
  tokenUrl: TOKEN_URL19,
69360
69540
  scopes: SCOPES13,
69361
69541
  clientIdEnv: "TWITTER_OAUTH_CLIENT_ID",
69362
- clientSecretEnv: "TWITTER_OAUTH_CLIENT_SECRET"
69542
+ clientSecretEnv: "TWITTER_OAUTH_CLIENT_SECRET",
69543
+ tokenClientAuthMethod: "client_secret_basic"
69363
69544
  },
69364
69545
  {
69365
69546
  kind: "api-key",
@@ -69656,21 +69837,61 @@ function twitter(opts) {
69656
69837
  };
69657
69838
  }
69658
69839
  async function twitterTokenRequest(clientId, clientSecret, params) {
69659
- const res = await fetch(TOKEN_URL19, {
69660
- method: "POST",
69661
- headers: {
69662
- authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
69663
- "content-type": "application/x-www-form-urlencoded",
69664
- accept: "application/json"
69665
- },
69666
- body: new URLSearchParams(params),
69667
- signal: AbortSignal.timeout(15e3)
69668
- });
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
+ }
69669
69878
  if (!res.ok) {
69670
69879
  const text = await res.text().catch(() => "");
69671
- throw new Error(`twitter ${params.grant_type} token request failed: ${res.status} ${res.statusText} \u2014 ${text.slice(0, 200)}`);
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`);
69672
69894
  }
69673
- const json = await res.json();
69674
69895
  return {
69675
69896
  accessToken: json.access_token,
69676
69897
  refreshToken: json.refresh_token,
@@ -148876,6 +149097,10 @@ export {
148876
149097
  exchangeAuthorizationCode,
148877
149098
  refreshAccessToken,
148878
149099
  createOAuthTokenRequestHeaders,
149100
+ formEncodeOAuthClientCredential,
149101
+ createOAuthBasicAuthorizationHeader,
149102
+ oauthClientCredentialRedactionValues,
149103
+ redactOAuthSensitiveText,
148879
149104
  _resetPendingFlowsForTests,
148880
149105
  declarativeRestConnector,
148881
149106
  oktaConnector,
@@ -149533,4 +149758,4 @@ export {
149533
149758
  getresponseConnector,
149534
149759
  adapters_exports
149535
149760
  };
149536
- //# sourceMappingURL=chunk-H5UCSRF4.js.map
149761
+ //# sourceMappingURL=chunk-2JRYKWYX.js.map