@backstage/integration 2.1.3-next.0 → 2.1.3-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @backstage/integration
2
2
 
3
+ ## 2.1.3-next.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 0c9d72c: Update Bitbucket Cloud Authentication logic to support bearer API token
8
+
3
9
  ## 2.1.3-next.0
4
10
 
5
11
  ### Patch Changes
@@ -132,6 +132,9 @@ async function getBitbucketCloudRequestOptions(config) {
132
132
  );
133
133
  headers.Authorization = `Basic ${buffer.toString("base64")}`;
134
134
  }
135
+ if (config.token && !config.username) {
136
+ headers.Authorization = `Bearer ${config.token}`;
137
+ }
135
138
  return { headers };
136
139
  }
137
140
 
@@ -1 +1 @@
1
- {"version":3,"file":"core.cjs.js","sources":["../../src/bitbucketCloud/core.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fetch from 'cross-fetch';\nimport parseGitUrl from 'git-url-parse';\nimport { parseGitUrlSafe } from '../helpers';\nimport { BitbucketCloudIntegrationConfig } from './config';\nimport { DateTime } from 'luxon';\n\ntype OAuthTokenData = {\n token: string;\n expiresAt: DateTime;\n};\n\n// In-memory token cache keyed by credentials, so each distinct\n// clientId/clientSecret pair (i.e. each Bitbucket Cloud integration) caches\n// its own token independently.\nconst tokenCache = new Map<string, OAuthTokenData>();\n\n// Track in-flight token refresh requests per credential set to prevent\n// concurrent fetches for the same credentials.\nconst refreshPromises = new Map<string, Promise<string>>();\n\n/**\n * Fetches an OAuth access token from Bitbucket Cloud using client credentials flow.\n * Tokens are cached with a 10-minute grace period to account for clock skew.\n * Implements concurrent refresh protection to prevent multiple simultaneous token requests.\n *\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @public\n */\nexport async function getBitbucketCloudOAuthToken(\n clientId: string,\n clientSecret: string,\n): Promise<string> {\n // Derive a cache key from the credentials. Using JSON.stringify of a tuple\n // avoids ambiguity if a clientId contained a delimiter character.\n const cacheKey = JSON.stringify([clientId, clientSecret]);\n\n // Check cache\n const cached = tokenCache.get(cacheKey);\n if (cached && DateTime.now() < cached.expiresAt) {\n return cached.token;\n }\n\n // Check if there's already a refresh in progress for these credentials\n const inFlight = refreshPromises.get(cacheKey);\n if (inFlight) {\n return inFlight;\n }\n\n // Start a new token fetch and track it\n const refreshPromise = (async () => {\n try {\n // Fetch new token\n const credentials = Buffer.from(\n `${clientId}:${clientSecret}`,\n 'utf8',\n ).toString('base64');\n\n const response = await fetch(\n 'https://bitbucket.org/site/oauth2/access_token',\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: 'grant_type=client_credentials',\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch OAuth token from Bitbucket Cloud: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n\n if (!data.access_token) {\n throw new Error('OAuth token response missing access_token field');\n }\n\n // Calculate expiration with 10-minute grace period\n const expiresIn = data.expires_in || 3600; // Default to 1 hour\n const expiresAt = DateTime.now()\n .plus({ seconds: expiresIn })\n .minus({ minutes: 10 });\n\n // Cache the token\n tokenCache.set(cacheKey, {\n token: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n } catch (error) {\n throw new Error(\n `Failed to fetch OAuth token for Bitbucket Cloud: ${error}`,\n );\n } finally {\n // Clean up the in-flight promise tracking for these credentials\n refreshPromises.delete(cacheKey);\n }\n })();\n\n refreshPromises.set(cacheKey, refreshPromise);\n\n return refreshPromise;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns the default branch.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDefaultBranch(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const { name: repoName, owner: project } = parseGitUrl(url);\n\n const branchUrl = `${config.apiBaseUrl}/repositories/${project}/${repoName}`;\n const response = await fetch(\n branchUrl,\n await getBitbucketCloudRequestOptions(config),\n );\n\n if (!response.ok) {\n const message = `Failed to retrieve default branch from ${branchUrl}, ${response.status} ${response.statusText}`;\n throw new Error(message);\n }\n\n const repoInfo = await response.json();\n const defaultBranch = repoInfo.mainbranch.name;\n if (!defaultBranch) {\n throw new Error(\n `Failed to read default branch from ${branchUrl}. ` +\n `Response ${response.status} ${response.json()}`,\n );\n }\n return defaultBranch;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns a URL that is suitable\n * for downloading the subtree.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDownloadUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const {\n name: repoName,\n owner: project,\n ref,\n protocol,\n resource,\n } = parseGitUrlSafe(url);\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketCloudDefaultBranch(url, config);\n }\n return `${protocol}://${resource}/${project}/${repoName}/get/${branch}.tar.gz`;\n}\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * from: https://bitbucket.org/orgname/reponame/src/master/file.yaml\n * to: https://api.bitbucket.org/2.0/repositories/orgname/reponame/src/master/file.yaml\n *\n * @param url - A URL pointing to a file\n * @param config - The relevant provider config\n * @public\n */\nexport function getBitbucketCloudFileFetchUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): string {\n try {\n const { owner, name, ref, filepathtype, filepath } = parseGitUrlSafe(url);\n if (!owner || !name || (filepathtype !== 'src' && filepathtype !== 'raw')) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n\n const pathWithoutSlash = filepath.replace(/^\\//, '');\n\n if (!ref) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n return `${config.apiBaseUrl}/repositories/${owner}/${name}/src/${ref}/${pathWithoutSlash}`;\n } catch (e) {\n throw new Error(`Incorrect URL: ${url}, ${e}`);\n }\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n * Returns headers for authenticating with Bitbucket Cloud.\n * Supports OAuth (clientId/clientSecret), username/token, and username/appPassword auth.\n *\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudRequestOptions(\n config: BitbucketCloudIntegrationConfig,\n): Promise<{\n headers: Record<string, string>;\n}> {\n const headers: Record<string, string> = {};\n\n // OAuth authentication (clientId/clientSecret)\n if (config.clientId && config.clientSecret) {\n const token = await getBitbucketCloudOAuthToken(\n config.clientId,\n config.clientSecret,\n );\n headers.Authorization = `Bearer ${token}`;\n return { headers };\n }\n\n // Basic authentication (username + token/appPassword)\n // TODO: appPassword can be removed once fully\n // deprecated by BitBucket on 9th June 2026.\n if (config.username && (config.token ?? config.appPassword)) {\n const buffer = Buffer.from(\n `${config.username}:${config.token ?? config.appPassword}`,\n 'utf8',\n );\n headers.Authorization = `Basic ${buffer.toString('base64')}`;\n }\n\n return { headers };\n}\n"],"names":["DateTime","fetch","parseGitUrl","parseGitUrlSafe"],"mappings":"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"}
1
+ {"version":3,"file":"core.cjs.js","sources":["../../src/bitbucketCloud/core.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fetch from 'cross-fetch';\nimport parseGitUrl from 'git-url-parse';\nimport { parseGitUrlSafe } from '../helpers';\nimport { BitbucketCloudIntegrationConfig } from './config';\nimport { DateTime } from 'luxon';\n\ntype OAuthTokenData = {\n token: string;\n expiresAt: DateTime;\n};\n\n// In-memory token cache keyed by credentials, so each distinct\n// clientId/clientSecret pair (i.e. each Bitbucket Cloud integration) caches\n// its own token independently.\nconst tokenCache = new Map<string, OAuthTokenData>();\n\n// Track in-flight token refresh requests per credential set to prevent\n// concurrent fetches for the same credentials.\nconst refreshPromises = new Map<string, Promise<string>>();\n\n/**\n * Fetches an OAuth access token from Bitbucket Cloud using client credentials flow.\n * Tokens are cached with a 10-minute grace period to account for clock skew.\n * Implements concurrent refresh protection to prevent multiple simultaneous token requests.\n *\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @public\n */\nexport async function getBitbucketCloudOAuthToken(\n clientId: string,\n clientSecret: string,\n): Promise<string> {\n // Derive a cache key from the credentials. Using JSON.stringify of a tuple\n // avoids ambiguity if a clientId contained a delimiter character.\n const cacheKey = JSON.stringify([clientId, clientSecret]);\n\n // Check cache\n const cached = tokenCache.get(cacheKey);\n if (cached && DateTime.now() < cached.expiresAt) {\n return cached.token;\n }\n\n // Check if there's already a refresh in progress for these credentials\n const inFlight = refreshPromises.get(cacheKey);\n if (inFlight) {\n return inFlight;\n }\n\n // Start a new token fetch and track it\n const refreshPromise = (async () => {\n try {\n // Fetch new token\n const credentials = Buffer.from(\n `${clientId}:${clientSecret}`,\n 'utf8',\n ).toString('base64');\n\n const response = await fetch(\n 'https://bitbucket.org/site/oauth2/access_token',\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: 'grant_type=client_credentials',\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch OAuth token from Bitbucket Cloud: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n\n if (!data.access_token) {\n throw new Error('OAuth token response missing access_token field');\n }\n\n // Calculate expiration with 10-minute grace period\n const expiresIn = data.expires_in || 3600; // Default to 1 hour\n const expiresAt = DateTime.now()\n .plus({ seconds: expiresIn })\n .minus({ minutes: 10 });\n\n // Cache the token\n tokenCache.set(cacheKey, {\n token: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n } catch (error) {\n throw new Error(\n `Failed to fetch OAuth token for Bitbucket Cloud: ${error}`,\n );\n } finally {\n // Clean up the in-flight promise tracking for these credentials\n refreshPromises.delete(cacheKey);\n }\n })();\n\n refreshPromises.set(cacheKey, refreshPromise);\n\n return refreshPromise;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns the default branch.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDefaultBranch(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const { name: repoName, owner: project } = parseGitUrl(url);\n\n const branchUrl = `${config.apiBaseUrl}/repositories/${project}/${repoName}`;\n const response = await fetch(\n branchUrl,\n await getBitbucketCloudRequestOptions(config),\n );\n\n if (!response.ok) {\n const message = `Failed to retrieve default branch from ${branchUrl}, ${response.status} ${response.statusText}`;\n throw new Error(message);\n }\n\n const repoInfo = await response.json();\n const defaultBranch = repoInfo.mainbranch.name;\n if (!defaultBranch) {\n throw new Error(\n `Failed to read default branch from ${branchUrl}. ` +\n `Response ${response.status} ${response.json()}`,\n );\n }\n return defaultBranch;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns a URL that is suitable\n * for downloading the subtree.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDownloadUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const {\n name: repoName,\n owner: project,\n ref,\n protocol,\n resource,\n } = parseGitUrlSafe(url);\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketCloudDefaultBranch(url, config);\n }\n return `${protocol}://${resource}/${project}/${repoName}/get/${branch}.tar.gz`;\n}\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * from: https://bitbucket.org/orgname/reponame/src/master/file.yaml\n * to: https://api.bitbucket.org/2.0/repositories/orgname/reponame/src/master/file.yaml\n *\n * @param url - A URL pointing to a file\n * @param config - The relevant provider config\n * @public\n */\nexport function getBitbucketCloudFileFetchUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): string {\n try {\n const { owner, name, ref, filepathtype, filepath } = parseGitUrlSafe(url);\n if (!owner || !name || (filepathtype !== 'src' && filepathtype !== 'raw')) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n\n const pathWithoutSlash = filepath.replace(/^\\//, '');\n\n if (!ref) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n return `${config.apiBaseUrl}/repositories/${owner}/${name}/src/${ref}/${pathWithoutSlash}`;\n } catch (e) {\n throw new Error(`Incorrect URL: ${url}, ${e}`);\n }\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n * Returns headers for authenticating with Bitbucket Cloud.\n * Supports OAuth (clientId/clientSecret), username/token, username/appPassword,\n * and Bearer token auth.\n *\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudRequestOptions(\n config: BitbucketCloudIntegrationConfig,\n): Promise<{\n headers: Record<string, string>;\n}> {\n const headers: Record<string, string> = {};\n\n // OAuth authentication (clientId/clientSecret)\n if (config.clientId && config.clientSecret) {\n const token = await getBitbucketCloudOAuthToken(\n config.clientId,\n config.clientSecret,\n );\n headers.Authorization = `Bearer ${token}`;\n return { headers };\n }\n\n // Basic authentication (username + token/appPassword)\n // TODO: appPassword can be removed once fully\n // deprecated by BitBucket on 9th June 2026.\n if (config.username && (config.token ?? config.appPassword)) {\n const buffer = Buffer.from(\n `${config.username}:${config.token ?? config.appPassword}`,\n 'utf8',\n );\n headers.Authorization = `Basic ${buffer.toString('base64')}`;\n }\n\n // Using Bearer authentication (token only)\n if (config.token && !config.username) {\n headers.Authorization = `Bearer ${config.token}`;\n }\n\n return { headers };\n}\n"],"names":["DateTime","fetch","parseGitUrl","parseGitUrlSafe"],"mappings":"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"}
@@ -125,6 +125,9 @@ async function getBitbucketCloudRequestOptions(config) {
125
125
  );
126
126
  headers.Authorization = `Basic ${buffer.toString("base64")}`;
127
127
  }
128
+ if (config.token && !config.username) {
129
+ headers.Authorization = `Bearer ${config.token}`;
130
+ }
128
131
  return { headers };
129
132
  }
130
133
 
@@ -1 +1 @@
1
- {"version":3,"file":"core.esm.js","sources":["../../src/bitbucketCloud/core.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fetch from 'cross-fetch';\nimport parseGitUrl from 'git-url-parse';\nimport { parseGitUrlSafe } from '../helpers';\nimport { BitbucketCloudIntegrationConfig } from './config';\nimport { DateTime } from 'luxon';\n\ntype OAuthTokenData = {\n token: string;\n expiresAt: DateTime;\n};\n\n// In-memory token cache keyed by credentials, so each distinct\n// clientId/clientSecret pair (i.e. each Bitbucket Cloud integration) caches\n// its own token independently.\nconst tokenCache = new Map<string, OAuthTokenData>();\n\n// Track in-flight token refresh requests per credential set to prevent\n// concurrent fetches for the same credentials.\nconst refreshPromises = new Map<string, Promise<string>>();\n\n/**\n * Fetches an OAuth access token from Bitbucket Cloud using client credentials flow.\n * Tokens are cached with a 10-minute grace period to account for clock skew.\n * Implements concurrent refresh protection to prevent multiple simultaneous token requests.\n *\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @public\n */\nexport async function getBitbucketCloudOAuthToken(\n clientId: string,\n clientSecret: string,\n): Promise<string> {\n // Derive a cache key from the credentials. Using JSON.stringify of a tuple\n // avoids ambiguity if a clientId contained a delimiter character.\n const cacheKey = JSON.stringify([clientId, clientSecret]);\n\n // Check cache\n const cached = tokenCache.get(cacheKey);\n if (cached && DateTime.now() < cached.expiresAt) {\n return cached.token;\n }\n\n // Check if there's already a refresh in progress for these credentials\n const inFlight = refreshPromises.get(cacheKey);\n if (inFlight) {\n return inFlight;\n }\n\n // Start a new token fetch and track it\n const refreshPromise = (async () => {\n try {\n // Fetch new token\n const credentials = Buffer.from(\n `${clientId}:${clientSecret}`,\n 'utf8',\n ).toString('base64');\n\n const response = await fetch(\n 'https://bitbucket.org/site/oauth2/access_token',\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: 'grant_type=client_credentials',\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch OAuth token from Bitbucket Cloud: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n\n if (!data.access_token) {\n throw new Error('OAuth token response missing access_token field');\n }\n\n // Calculate expiration with 10-minute grace period\n const expiresIn = data.expires_in || 3600; // Default to 1 hour\n const expiresAt = DateTime.now()\n .plus({ seconds: expiresIn })\n .minus({ minutes: 10 });\n\n // Cache the token\n tokenCache.set(cacheKey, {\n token: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n } catch (error) {\n throw new Error(\n `Failed to fetch OAuth token for Bitbucket Cloud: ${error}`,\n );\n } finally {\n // Clean up the in-flight promise tracking for these credentials\n refreshPromises.delete(cacheKey);\n }\n })();\n\n refreshPromises.set(cacheKey, refreshPromise);\n\n return refreshPromise;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns the default branch.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDefaultBranch(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const { name: repoName, owner: project } = parseGitUrl(url);\n\n const branchUrl = `${config.apiBaseUrl}/repositories/${project}/${repoName}`;\n const response = await fetch(\n branchUrl,\n await getBitbucketCloudRequestOptions(config),\n );\n\n if (!response.ok) {\n const message = `Failed to retrieve default branch from ${branchUrl}, ${response.status} ${response.statusText}`;\n throw new Error(message);\n }\n\n const repoInfo = await response.json();\n const defaultBranch = repoInfo.mainbranch.name;\n if (!defaultBranch) {\n throw new Error(\n `Failed to read default branch from ${branchUrl}. ` +\n `Response ${response.status} ${response.json()}`,\n );\n }\n return defaultBranch;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns a URL that is suitable\n * for downloading the subtree.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDownloadUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const {\n name: repoName,\n owner: project,\n ref,\n protocol,\n resource,\n } = parseGitUrlSafe(url);\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketCloudDefaultBranch(url, config);\n }\n return `${protocol}://${resource}/${project}/${repoName}/get/${branch}.tar.gz`;\n}\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * from: https://bitbucket.org/orgname/reponame/src/master/file.yaml\n * to: https://api.bitbucket.org/2.0/repositories/orgname/reponame/src/master/file.yaml\n *\n * @param url - A URL pointing to a file\n * @param config - The relevant provider config\n * @public\n */\nexport function getBitbucketCloudFileFetchUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): string {\n try {\n const { owner, name, ref, filepathtype, filepath } = parseGitUrlSafe(url);\n if (!owner || !name || (filepathtype !== 'src' && filepathtype !== 'raw')) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n\n const pathWithoutSlash = filepath.replace(/^\\//, '');\n\n if (!ref) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n return `${config.apiBaseUrl}/repositories/${owner}/${name}/src/${ref}/${pathWithoutSlash}`;\n } catch (e) {\n throw new Error(`Incorrect URL: ${url}, ${e}`);\n }\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n * Returns headers for authenticating with Bitbucket Cloud.\n * Supports OAuth (clientId/clientSecret), username/token, and username/appPassword auth.\n *\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudRequestOptions(\n config: BitbucketCloudIntegrationConfig,\n): Promise<{\n headers: Record<string, string>;\n}> {\n const headers: Record<string, string> = {};\n\n // OAuth authentication (clientId/clientSecret)\n if (config.clientId && config.clientSecret) {\n const token = await getBitbucketCloudOAuthToken(\n config.clientId,\n config.clientSecret,\n );\n headers.Authorization = `Bearer ${token}`;\n return { headers };\n }\n\n // Basic authentication (username + token/appPassword)\n // TODO: appPassword can be removed once fully\n // deprecated by BitBucket on 9th June 2026.\n if (config.username && (config.token ?? config.appPassword)) {\n const buffer = Buffer.from(\n `${config.username}:${config.token ?? config.appPassword}`,\n 'utf8',\n );\n headers.Authorization = `Basic ${buffer.toString('base64')}`;\n }\n\n return { headers };\n}\n"],"names":[],"mappings":";;;;;AA8BA,MAAM,UAAA,uBAAiB,GAAA,EAA4B;AAInD,MAAM,eAAA,uBAAsB,GAAA,EAA6B;AAWzD,eAAsB,2BAAA,CACpB,UACA,YAAA,EACiB;AAGjB,EAAA,MAAM,WAAW,IAAA,CAAK,SAAA,CAAU,CAAC,QAAA,EAAU,YAAY,CAAC,CAAA;AAGxD,EAAA,MAAM,MAAA,GAAS,UAAA,CAAW,GAAA,CAAI,QAAQ,CAAA;AACtC,EAAA,IAAI,MAAA,IAAU,QAAA,CAAS,GAAA,EAAI,GAAI,OAAO,SAAA,EAAW;AAC/C,IAAA,OAAO,MAAA,CAAO,KAAA;AAAA,EAChB;AAGA,EAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA;AAC7C,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AAGA,EAAA,MAAM,kBAAkB,YAAY;AAClC,IAAA,IAAI;AAEF,MAAA,MAAM,cAAc,MAAA,CAAO,IAAA;AAAA,QACzB,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AAAA,QAC3B;AAAA,OACF,CAAE,SAAS,QAAQ,CAAA;AAEnB,MAAA,MAAM,WAAW,MAAM,KAAA;AAAA,QACrB,gDAAA;AAAA,QACA;AAAA,UACE,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,mCAAA;AAAA,YAChB,aAAA,EAAe,SAAS,WAAW,CAAA;AAAA,WACrC;AAAA,UACA,IAAA,EAAM;AAAA;AACR,OACF;AAEA,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,kDAAA,EAAqD,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA;AAAA,SAC7F;AAAA,MACF;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AAEjC,MAAA,IAAI,CAAC,KAAK,YAAA,EAAc;AACtB,QAAA,MAAM,IAAI,MAAM,iDAAiD,CAAA;AAAA,MACnE;AAGA,MAAA,MAAM,SAAA,GAAY,KAAK,UAAA,IAAc,IAAA;AACrC,MAAA,MAAM,SAAA,GAAY,QAAA,CAAS,GAAA,EAAI,CAC5B,KAAK,EAAE,OAAA,EAAS,SAAA,EAAW,CAAA,CAC3B,KAAA,CAAM,EAAE,OAAA,EAAS,IAAI,CAAA;AAGxB,MAAA,UAAA,CAAW,IAAI,QAAA,EAAU;AAAA,QACvB,OAAO,IAAA,CAAK,YAAA;AAAA,QACZ;AAAA,OACD,CAAA;AAED,MAAA,OAAO,IAAA,CAAK,YAAA;AAAA,IACd,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,oDAAoD,KAAK,CAAA;AAAA,OAC3D;AAAA,IACF,CAAA,SAAE;AAEA,MAAA,eAAA,CAAgB,OAAO,QAAQ,CAAA;AAAA,IACjC;AAAA,EACF,CAAA,GAAG;AAEH,EAAA,eAAA,CAAgB,GAAA,CAAI,UAAU,cAAc,CAAA;AAE5C,EAAA,OAAO,cAAA;AACT;AASA,eAAsB,8BAAA,CACpB,KACA,MAAA,EACiB;AACjB,EAAA,MAAM,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,OAAA,EAAQ,GAAI,YAAY,GAAG,CAAA;AAE1D,EAAA,MAAM,YAAY,CAAA,EAAG,MAAA,CAAO,UAAU,CAAA,cAAA,EAAiB,OAAO,IAAI,QAAQ,CAAA,CAAA;AAC1E,EAAA,MAAM,WAAW,MAAM,KAAA;AAAA,IACrB,SAAA;AAAA,IACA,MAAM,gCAAgC,MAAM;AAAA,GAC9C;AAEA,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,MAAM,OAAA,GAAU,0CAA0C,SAAS,CAAA,EAAA,EAAK,SAAS,MAAM,CAAA,CAAA,EAAI,SAAS,UAAU,CAAA,CAAA;AAC9G,IAAA,MAAM,IAAI,MAAM,OAAO,CAAA;AAAA,EACzB;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,QAAA,CAAS,IAAA,EAAK;AACrC,EAAA,MAAM,aAAA,GAAgB,SAAS,UAAA,CAAW,IAAA;AAC1C,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,mCAAA,EAAsC,SAAS,CAAA,WAAA,EACjC,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,QAAA,CAAS,MAAM,CAAA;AAAA,KAClD;AAAA,EACF;AACA,EAAA,OAAO,aAAA;AACT;AAUA,eAAsB,4BAAA,CACpB,KACA,MAAA,EACiB;AACjB,EAAA,MAAM;AAAA,IACJ,IAAA,EAAM,QAAA;AAAA,IACN,KAAA,EAAO,OAAA;AAAA,IACP,GAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF,GAAI,gBAAgB,GAAG,CAAA;AAEvB,EAAA,IAAI,MAAA,GAAS,GAAA;AACb,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAA,GAAS,MAAM,8BAAA,CAA+B,GAAA,EAAK,MAAM,CAAA;AAAA,EAC3D;AACA,EAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,GAAA,EAAM,QAAQ,IAAI,OAAO,CAAA,CAAA,EAAI,QAAQ,CAAA,KAAA,EAAQ,MAAM,CAAA,OAAA,CAAA;AACvE;AAgBO,SAAS,6BAAA,CACd,KACA,MAAA,EACQ;AACR,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,OAAO,IAAA,EAAM,GAAA,EAAK,cAAc,QAAA,EAAS,GAAI,gBAAgB,GAAG,CAAA;AACxE,IAAA,IAAI,CAAC,KAAA,IAAS,CAAC,QAAS,YAAA,KAAiB,KAAA,IAAS,iBAAiB,KAAA,EAAQ;AACzE,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AAEA,IAAA,MAAM,gBAAA,GAAmB,QAAA,CAAS,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAEnD,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,IAC5D;AACA,IAAA,OAAO,CAAA,EAAG,MAAA,CAAO,UAAU,CAAA,cAAA,EAAiB,KAAK,IAAI,IAAI,CAAA,KAAA,EAAQ,GAAG,CAAA,CAAA,EAAI,gBAAgB,CAAA,CAAA;AAAA,EAC1F,SAAS,CAAA,EAAG;AACV,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,GAAG,CAAA,EAAA,EAAK,CAAC,CAAA,CAAE,CAAA;AAAA,EAC/C;AACF;AAUA,eAAsB,gCACpB,MAAA,EAGC;AACD,EAAA,MAAM,UAAkC,EAAC;AAGzC,EAAA,IAAI,MAAA,CAAO,QAAA,IAAY,MAAA,CAAO,YAAA,EAAc;AAC1C,IAAA,MAAM,QAAQ,MAAM,2BAAA;AAAA,MAClB,MAAA,CAAO,QAAA;AAAA,MACP,MAAA,CAAO;AAAA,KACT;AACA,IAAA,OAAA,CAAQ,aAAA,GAAgB,UAAU,KAAK,CAAA,CAAA;AACvC,IAAA,OAAO,EAAE,OAAA,EAAQ;AAAA,EACnB;AAKA,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,MAAA,CAAO,KAAA,IAAS,OAAO,WAAA,CAAA,EAAc;AAC3D,IAAA,MAAM,SAAS,MAAA,CAAO,IAAA;AAAA,MACpB,GAAG,MAAA,CAAO,QAAQ,IAAI,MAAA,CAAO,KAAA,IAAS,OAAO,WAAW,CAAA,CAAA;AAAA,MACxD;AAAA,KACF;AACA,IAAA,OAAA,CAAQ,aAAA,GAAgB,CAAA,MAAA,EAAS,MAAA,CAAO,QAAA,CAAS,QAAQ,CAAC,CAAA,CAAA;AAAA,EAC5D;AAEA,EAAA,OAAO,EAAE,OAAA,EAAQ;AACnB;;"}
1
+ {"version":3,"file":"core.esm.js","sources":["../../src/bitbucketCloud/core.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport fetch from 'cross-fetch';\nimport parseGitUrl from 'git-url-parse';\nimport { parseGitUrlSafe } from '../helpers';\nimport { BitbucketCloudIntegrationConfig } from './config';\nimport { DateTime } from 'luxon';\n\ntype OAuthTokenData = {\n token: string;\n expiresAt: DateTime;\n};\n\n// In-memory token cache keyed by credentials, so each distinct\n// clientId/clientSecret pair (i.e. each Bitbucket Cloud integration) caches\n// its own token independently.\nconst tokenCache = new Map<string, OAuthTokenData>();\n\n// Track in-flight token refresh requests per credential set to prevent\n// concurrent fetches for the same credentials.\nconst refreshPromises = new Map<string, Promise<string>>();\n\n/**\n * Fetches an OAuth access token from Bitbucket Cloud using client credentials flow.\n * Tokens are cached with a 10-minute grace period to account for clock skew.\n * Implements concurrent refresh protection to prevent multiple simultaneous token requests.\n *\n * @param clientId - OAuth client ID\n * @param clientSecret - OAuth client secret\n * @public\n */\nexport async function getBitbucketCloudOAuthToken(\n clientId: string,\n clientSecret: string,\n): Promise<string> {\n // Derive a cache key from the credentials. Using JSON.stringify of a tuple\n // avoids ambiguity if a clientId contained a delimiter character.\n const cacheKey = JSON.stringify([clientId, clientSecret]);\n\n // Check cache\n const cached = tokenCache.get(cacheKey);\n if (cached && DateTime.now() < cached.expiresAt) {\n return cached.token;\n }\n\n // Check if there's already a refresh in progress for these credentials\n const inFlight = refreshPromises.get(cacheKey);\n if (inFlight) {\n return inFlight;\n }\n\n // Start a new token fetch and track it\n const refreshPromise = (async () => {\n try {\n // Fetch new token\n const credentials = Buffer.from(\n `${clientId}:${clientSecret}`,\n 'utf8',\n ).toString('base64');\n\n const response = await fetch(\n 'https://bitbucket.org/site/oauth2/access_token',\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Authorization: `Basic ${credentials}`,\n },\n body: 'grant_type=client_credentials',\n },\n );\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch OAuth token from Bitbucket Cloud: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n\n if (!data.access_token) {\n throw new Error('OAuth token response missing access_token field');\n }\n\n // Calculate expiration with 10-minute grace period\n const expiresIn = data.expires_in || 3600; // Default to 1 hour\n const expiresAt = DateTime.now()\n .plus({ seconds: expiresIn })\n .minus({ minutes: 10 });\n\n // Cache the token\n tokenCache.set(cacheKey, {\n token: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n } catch (error) {\n throw new Error(\n `Failed to fetch OAuth token for Bitbucket Cloud: ${error}`,\n );\n } finally {\n // Clean up the in-flight promise tracking for these credentials\n refreshPromises.delete(cacheKey);\n }\n })();\n\n refreshPromises.set(cacheKey, refreshPromise);\n\n return refreshPromise;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns the default branch.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDefaultBranch(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const { name: repoName, owner: project } = parseGitUrl(url);\n\n const branchUrl = `${config.apiBaseUrl}/repositories/${project}/${repoName}`;\n const response = await fetch(\n branchUrl,\n await getBitbucketCloudRequestOptions(config),\n );\n\n if (!response.ok) {\n const message = `Failed to retrieve default branch from ${branchUrl}, ${response.status} ${response.statusText}`;\n throw new Error(message);\n }\n\n const repoInfo = await response.json();\n const defaultBranch = repoInfo.mainbranch.name;\n if (!defaultBranch) {\n throw new Error(\n `Failed to read default branch from ${branchUrl}. ` +\n `Response ${response.status} ${response.json()}`,\n );\n }\n return defaultBranch;\n}\n\n/**\n * Given a URL pointing to a path on a provider, returns a URL that is suitable\n * for downloading the subtree.\n *\n * @param url - A URL pointing to a path\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudDownloadUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): Promise<string> {\n const {\n name: repoName,\n owner: project,\n ref,\n protocol,\n resource,\n } = parseGitUrlSafe(url);\n\n let branch = ref;\n if (!branch) {\n branch = await getBitbucketCloudDefaultBranch(url, config);\n }\n return `${protocol}://${resource}/${project}/${repoName}/get/${branch}.tar.gz`;\n}\n\n/**\n * Given a URL pointing to a file on a provider, returns a URL that is suitable\n * for fetching the contents of the data.\n *\n * @remarks\n *\n * Converts\n * from: https://bitbucket.org/orgname/reponame/src/master/file.yaml\n * to: https://api.bitbucket.org/2.0/repositories/orgname/reponame/src/master/file.yaml\n *\n * @param url - A URL pointing to a file\n * @param config - The relevant provider config\n * @public\n */\nexport function getBitbucketCloudFileFetchUrl(\n url: string,\n config: BitbucketCloudIntegrationConfig,\n): string {\n try {\n const { owner, name, ref, filepathtype, filepath } = parseGitUrlSafe(url);\n if (!owner || !name || (filepathtype !== 'src' && filepathtype !== 'raw')) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n\n const pathWithoutSlash = filepath.replace(/^\\//, '');\n\n if (!ref) {\n throw new Error('Invalid Bitbucket Cloud URL or file path');\n }\n return `${config.apiBaseUrl}/repositories/${owner}/${name}/src/${ref}/${pathWithoutSlash}`;\n } catch (e) {\n throw new Error(`Incorrect URL: ${url}, ${e}`);\n }\n}\n\n/**\n * Gets the request options necessary to make requests to a given provider.\n * Returns headers for authenticating with Bitbucket Cloud.\n * Supports OAuth (clientId/clientSecret), username/token, username/appPassword,\n * and Bearer token auth.\n *\n * @param config - The relevant provider config\n * @public\n */\nexport async function getBitbucketCloudRequestOptions(\n config: BitbucketCloudIntegrationConfig,\n): Promise<{\n headers: Record<string, string>;\n}> {\n const headers: Record<string, string> = {};\n\n // OAuth authentication (clientId/clientSecret)\n if (config.clientId && config.clientSecret) {\n const token = await getBitbucketCloudOAuthToken(\n config.clientId,\n config.clientSecret,\n );\n headers.Authorization = `Bearer ${token}`;\n return { headers };\n }\n\n // Basic authentication (username + token/appPassword)\n // TODO: appPassword can be removed once fully\n // deprecated by BitBucket on 9th June 2026.\n if (config.username && (config.token ?? config.appPassword)) {\n const buffer = Buffer.from(\n `${config.username}:${config.token ?? config.appPassword}`,\n 'utf8',\n );\n headers.Authorization = `Basic ${buffer.toString('base64')}`;\n }\n\n // Using Bearer authentication (token only)\n if (config.token && !config.username) {\n headers.Authorization = `Bearer ${config.token}`;\n }\n\n return { headers };\n}\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1287,7 +1287,8 @@ declare function getBitbucketCloudFileFetchUrl(url: string, config: BitbucketClo
1287
1287
  /**
1288
1288
  * Gets the request options necessary to make requests to a given provider.
1289
1289
  * Returns headers for authenticating with Bitbucket Cloud.
1290
- * Supports OAuth (clientId/clientSecret), username/token, and username/appPassword auth.
1290
+ * Supports OAuth (clientId/clientSecret), username/token, username/appPassword,
1291
+ * and Bearer token auth.
1291
1292
  *
1292
1293
  * @param config - The relevant provider config
1293
1294
  * @public
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/integration",
3
- "version": "2.1.3-next.0",
3
+ "version": "2.1.3-next.1",
4
4
  "description": "Helpers for managing integrations towards external systems",
5
5
  "backstage": {
6
6
  "role": "common-library"
@@ -73,7 +73,7 @@
73
73
  "p-throttle": "^4.1.1"
74
74
  },
75
75
  "devDependencies": {
76
- "@backstage/backend-test-utils": "1.11.8-next.0",
76
+ "@backstage/backend-test-utils": "1.11.8-next.1",
77
77
  "@backstage/cli": "0.36.7-next.0",
78
78
  "@backstage/config-loader": "1.11.4-next.0",
79
79
  "msw": "^2.0.0"