@abapify/adt-auth 0.4.36 → 0.4.39

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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import authPlugin from "./plugins/basic.mjs";
2
- import { t as authPlugin$1 } from "./service-key-DEYaMW4g.mjs";
2
+ import { t as authPlugin$1 } from "./service-key-C11sqpQ1.mjs";
3
3
  import { readServiceKey, resolveServiceKeyFromEnv } from "./utils/env.mjs";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
5
5
  import { dirname, join } from "node:path";
@@ -1,3 +1,3 @@
1
- import { t as authPlugin } from "../service-key-DEYaMW4g.mjs";
1
+ import { t as authPlugin } from "../service-key-C11sqpQ1.mjs";
2
2
 
3
3
  export { authPlugin as default };
@@ -238,7 +238,7 @@ const authPlugin = { async authenticate(options) {
238
238
  };
239
239
  } catch (err) {
240
240
  classifyAttemptError(err, port, hasExplicitRedirect, log);
241
- lastError = err;
241
+ lastError = err instanceof Error ? err : new Error(String(err));
242
242
  continue;
243
243
  }
244
244
  }
@@ -246,4 +246,4 @@ const authPlugin = { async authenticate(options) {
246
246
  } };
247
247
 
248
248
  export { authPlugin as t };
249
- //# sourceMappingURL=service-key-DEYaMW4g.mjs.map
249
+ //# sourceMappingURL=service-key-C11sqpQ1.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-key-DEYaMW4g.mjs","names":["parseUrl"],"sources":["../src/utils/pkce.ts","../src/plugins/service-key.ts"],"sourcesContent":["import { createHash, randomBytes } from 'node:crypto';\n\n/**\n * Generates a cryptographically secure code verifier for PKCE flow\n */\nexport function generateCodeVerifier(): string {\n return randomBytes(32).toString('base64url');\n}\n\n/**\n * Generates a code challenge from the verifier using SHA256\n */\nexport function generateCodeChallenge(verifier: string): string {\n return createHash('sha256').update(verifier).digest('base64url');\n}\n\n/**\n * Generates a random state parameter for OAuth flow\n */\nexport function generateState(): string {\n return randomBytes(16).toString('hex');\n}\n","import { createServer, type Server } from 'node:http';\nimport { spawn } from 'node:child_process';\nimport { parse as parseUrl } from 'node:url';\nimport type { AuthPlugin, AuthPluginOptions, CookieAuthResult } from '../types';\nimport {\n ServiceKeyParser,\n type BTPServiceKey,\n type ServiceKeyPluginOptions,\n} from '../types/service-key';\nimport {\n generateCodeVerifier,\n generateCodeChallenge,\n generateState,\n} from '../utils/pkce';\n\nconst DEFAULT_PORT = 3000;\nconst DEFAULT_REDIRECT_PATH = '/callback';\nconst DEFAULT_TIMEOUT_MS = 300_000; // 5 minutes\nconst MAX_PORT_RETRIES = 5; // Try up to 5 consecutive ports on EADDRINUSE\n\n/**\n * Copy text to system clipboard (best-effort, never throws).\n * Tries platform-appropriate commands: pbcopy (macOS), clip.exe (WSL), xclip/xsel (Linux).\n */\nasync function copyToClipboard(text: string): Promise<void> {\n let candidates: string[][];\n if (process.platform === 'darwin') {\n candidates = [['pbcopy']];\n } else if (process.platform === 'win32') {\n candidates = [['clip']];\n } else {\n candidates = [\n ['clip.exe'],\n ['xclip', '-selection', 'clipboard'],\n ['xsel', '--clipboard'],\n ];\n }\n\n for (const [cmd, ...args] of candidates) {\n try {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(cmd, args, {\n stdio: ['pipe', 'ignore', 'ignore'],\n });\n child.on('error', reject);\n child.on('close', (code) =>\n code === 0\n ? resolve()\n : reject(new Error(`${cmd} exited with code ${code}`)),\n );\n child.stdin.write(text);\n child.stdin.end();\n });\n return;\n } catch {\n continue;\n }\n }\n throw new Error('No clipboard utility available');\n}\n\ninterface OAuthTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n scope?: string;\n refresh_token?: string;\n}\n\n/**\n * Exchange an authorization code for tokens using the PKCE flow.\n */\nasync function exchangeCodeForToken(\n serviceKey: BTPServiceKey,\n code: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<OAuthTokenResponse> {\n const { clientid, clientsecret, url: uaaUrl } = serviceKey.uaa;\n const credentials = Buffer.from(`${clientid}:${clientsecret}`).toString(\n 'base64',\n );\n\n const response = await fetch(`${uaaUrl}/oauth/token`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Token exchange failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as OAuthTokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token response missing access_token');\n }\n\n return data;\n}\n\n/**\n * Run the OAuth PKCE authorization code flow:\n * 1. Start local callback server\n * 2. Build XSUAA authorize URL with PKCE\n * 3. Open browser for user login\n * 4. Receive auth code via redirect\n * 5. Exchange code for user token\n */\nasync function performPkceFlow(\n serviceKey: BTPServiceKey,\n openBrowser: (url: string) => Promise<void>,\n port: number,\n timeoutMs: number,\n redirectUri?: string,\n): Promise<OAuthTokenResponse> {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n const state = generateState();\n\n const resolvedRedirectUri =\n redirectUri ?? `http://localhost:${port}${DEFAULT_REDIRECT_PATH}`;\n const callbackPath = (() => {\n try {\n const pathname = new URL(resolvedRedirectUri).pathname;\n return pathname && pathname.length > 0 ? pathname : '/';\n } catch {\n return DEFAULT_REDIRECT_PATH;\n }\n })();\n\n // Build XSUAA authorize URL\n const authUrl = new URL(`${serviceKey.uaa.url}/oauth/authorize`);\n authUrl.searchParams.set('client_id', serviceKey.uaa.clientid);\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('redirect_uri', resolvedRedirectUri);\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('state', state);\n authUrl.searchParams.set('scope', 'openid');\n\n return new Promise<OAuthTokenResponse>((resolve, reject) => {\n // eslint-disable-next-line prefer-const -- server must be declared before timeout but assigned after\n let server: Server;\n\n const timeout = setTimeout(() => {\n server?.close();\n reject(new Error('Authentication timed out'));\n }, timeoutMs);\n\n server = createServer(async (req, res) => {\n try {\n const url = parseUrl(req.url || '', true);\n\n if (url.pathname !== callbackPath) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n return;\n }\n\n const {\n code,\n state: returnedState,\n error,\n error_description,\n } = url.query;\n\n if (error) {\n const errorSuffix = error_description\n ? ` - ${error_description}`\n : '';\n throw new Error(`OAuth error: ${error}${errorSuffix}`);\n }\n\n if (returnedState !== state) {\n throw new Error('State mismatch - possible CSRF attack');\n }\n\n if (!code) {\n throw new Error('No authorization code received');\n }\n\n const tokenData = await exchangeCodeForToken(\n serviceKey,\n code as string,\n codeVerifier,\n resolvedRedirectUri,\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(\n '<html><body style=\"font-family:Arial;text-align:center;padding:50px\">' +\n '<h2>Authentication successful!</h2>' +\n '<p>You can close this window and return to the terminal.</p>' +\n '<script>setTimeout(()=>window.close(),2000)</script>' +\n '</body></html>',\n );\n\n clearTimeout(timeout);\n setTimeout(() => {\n server.close();\n resolve(tokenData);\n }, 500);\n } catch (err) {\n // Escape error message before embedding into HTML response to prevent\n // reflected XSS / XSS-through-exception. The error message may contain\n // data derived from the (attacker-controllable) OAuth callback URL\n // (e.g. error_description) and must never be treated as trusted.\n const rawMessage = err instanceof Error ? err.message : String(err);\n const escaped = rawMessage.replaceAll(/[&<>\"']/g, (c) => {\n switch (c) {\n case '&':\n return '&amp;';\n case '<':\n return '&lt;';\n case '>':\n return '&gt;';\n case '\"':\n return '&quot;';\n default:\n return '&#39;';\n }\n });\n res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(\n '<html><body style=\"font-family:Arial;text-align:center;padding:50px\">' +\n `<h2>Authentication failed</h2><p>${escaped}</p>` +\n '</body></html>',\n );\n\n clearTimeout(timeout);\n server.close(() => reject(err));\n }\n });\n\n server.on('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n\n server.listen(port, () => {\n openBrowser(authUrl.toString()).catch((err) => {\n clearTimeout(timeout);\n server.close();\n reject(\n new Error('Could not open browser for authentication', {\n cause: err,\n }),\n );\n });\n });\n });\n}\n\n/**\n * Resolve the browser opener: use the provided callback, or dynamically\n * import the `open` package. Throws when neither is available.\n */\nasync function resolveBrowserOpener(\n openBrowser: ((url: string) => Promise<void>) | undefined,\n): Promise<(url: string) => Promise<void>> {\n if (openBrowser) {\n return openBrowser;\n }\n try {\n const openModule = await import('open');\n const openFn = openModule.default;\n return async (url: string) => {\n await openFn(url);\n };\n } catch {\n throw new Error(\n 'No openBrowser callback provided and \"open\" package not available. ' +\n 'Install \"open\" or pass an openBrowser function in plugin options.',\n );\n }\n}\n\n/**\n * Classify a failed PKCE attempt. EADDRINUSE is retried on the next port;\n * when an explicit redirectUri is set, retrying on a different port is\n * pointless because the OAuth callback will still go to the original port\n * encoded in the redirect URI — so that combination is fatal. Everything\n * else is rethrown unchanged.\n */\nfunction classifyAttemptError(\n err: unknown,\n port: number,\n hasExplicitRedirect: boolean,\n log: (msg: string) => void,\n): void {\n const isAddrInUse =\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'EADDRINUSE';\n if (!isAddrInUse) {\n throw err; // Non-port error — rethrow immediately\n }\n if (hasExplicitRedirect) {\n throw new Error(\n `Port ${port} is in use and redirectUri is explicitly set — cannot retry on a different port`,\n { cause: err },\n );\n }\n log(`⚠️ Port ${port} in use, trying ${port + 1}...`);\n}\n\nconst authPlugin: AuthPlugin = {\n async authenticate(options: AuthPluginOptions): Promise<CookieAuthResult> {\n const { serviceKey, openBrowser, callbackPort, timeoutMs, redirectUri } =\n options as ServiceKeyPluginOptions;\n\n if (!serviceKey) {\n throw new Error('service-key plugin requires a serviceKey option');\n }\n\n const parsed = ServiceKeyParser.parse(serviceKey);\n\n // Resolve openBrowser: use provided callback, or dynamically import 'open'\n const browserOpener = await resolveBrowserOpener(openBrowser);\n\n const startPort =\n typeof callbackPort === 'number' ? callbackPort : DEFAULT_PORT;\n const timeout =\n typeof timeoutMs === 'number' ? timeoutMs : DEFAULT_TIMEOUT_MS;\n\n // Extract log from options (passed by AuthManager during refresh, or by CLI)\n const log = (options as { log?: (msg: string) => void }).log ?? console.log;\n\n // Wrap browser opener: always print the URL and try clipboard copy before opening\n const wrappedBrowserOpener = async (url: string) => {\n log(`🔗 Open this URL to authenticate:\\n ${url}`);\n\n try {\n await copyToClipboard(url);\n log('📋 URL copied to clipboard');\n } catch {\n // Clipboard not available — URL is already printed above\n }\n\n await browserOpener(url);\n };\n\n // Try ports starting from startPort, retrying on EADDRINUSE\n const hasExplicitRedirect = typeof redirectUri === 'string';\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {\n const port = startPort + attempt;\n // When redirectUri is explicitly set, use it as-is (don't rewrite for new port)\n const effectiveRedirectUri = hasExplicitRedirect\n ? redirectUri\n : undefined;\n\n try {\n const tokenData = await performPkceFlow(\n parsed,\n wrappedBrowserOpener,\n port,\n timeout,\n effectiveRedirectUri,\n );\n\n const expiresAt = new Date(Date.now() + tokenData.expires_in * 1000);\n\n return {\n method: 'cookie',\n credentials: {\n cookies: `Authorization: Bearer ${tokenData.access_token}`,\n expiresAt,\n },\n };\n } catch (err) {\n classifyAttemptError(err, port, hasExplicitRedirect, log);\n lastError = err;\n continue;\n }\n }\n\n throw new Error(\n `All ports ${startPort}-${startPort + MAX_PORT_RETRIES - 1} are in use. ` +\n `Free a port or set callbackPort in plugin options.`,\n { cause: lastError },\n );\n },\n};\n\nexport default authPlugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"service-key-C11sqpQ1.mjs","names":["parseUrl"],"sources":["../src/utils/pkce.ts","../src/plugins/service-key.ts"],"sourcesContent":["import { createHash, randomBytes } from 'node:crypto';\n\n/**\n * Generates a cryptographically secure code verifier for PKCE flow\n */\nexport function generateCodeVerifier(): string {\n return randomBytes(32).toString('base64url');\n}\n\n/**\n * Generates a code challenge from the verifier using SHA256\n */\nexport function generateCodeChallenge(verifier: string): string {\n return createHash('sha256').update(verifier).digest('base64url');\n}\n\n/**\n * Generates a random state parameter for OAuth flow\n */\nexport function generateState(): string {\n return randomBytes(16).toString('hex');\n}\n","import { createServer, type Server } from 'node:http';\nimport { spawn } from 'node:child_process';\nimport { parse as parseUrl } from 'node:url';\nimport type { AuthPlugin, AuthPluginOptions, CookieAuthResult } from '../types';\nimport {\n ServiceKeyParser,\n type BTPServiceKey,\n type ServiceKeyPluginOptions,\n} from '../types/service-key';\nimport {\n generateCodeVerifier,\n generateCodeChallenge,\n generateState,\n} from '../utils/pkce';\n\nconst DEFAULT_PORT = 3000;\nconst DEFAULT_REDIRECT_PATH = '/callback';\nconst DEFAULT_TIMEOUT_MS = 300_000; // 5 minutes\nconst MAX_PORT_RETRIES = 5; // Try up to 5 consecutive ports on EADDRINUSE\n\n/**\n * Copy text to system clipboard (best-effort, never throws).\n * Tries platform-appropriate commands: pbcopy (macOS), clip.exe (WSL), xclip/xsel (Linux).\n */\nasync function copyToClipboard(text: string): Promise<void> {\n let candidates: string[][];\n if (process.platform === 'darwin') {\n candidates = [['pbcopy']];\n } else if (process.platform === 'win32') {\n candidates = [['clip']];\n } else {\n candidates = [\n ['clip.exe'],\n ['xclip', '-selection', 'clipboard'],\n ['xsel', '--clipboard'],\n ];\n }\n\n for (const [cmd, ...args] of candidates) {\n try {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(cmd, args, {\n stdio: ['pipe', 'ignore', 'ignore'],\n });\n child.on('error', reject);\n child.on('close', (code) =>\n code === 0\n ? resolve()\n : reject(new Error(`${cmd} exited with code ${code}`)),\n );\n child.stdin.write(text);\n child.stdin.end();\n });\n return;\n } catch {\n continue;\n }\n }\n throw new Error('No clipboard utility available');\n}\n\ninterface OAuthTokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n scope?: string;\n refresh_token?: string;\n}\n\n/**\n * Exchange an authorization code for tokens using the PKCE flow.\n */\nasync function exchangeCodeForToken(\n serviceKey: BTPServiceKey,\n code: string,\n codeVerifier: string,\n redirectUri: string,\n): Promise<OAuthTokenResponse> {\n const { clientid, clientsecret, url: uaaUrl } = serviceKey.uaa;\n const credentials = Buffer.from(`${clientid}:${clientsecret}`).toString(\n 'base64',\n );\n\n const response = await fetch(`${uaaUrl}/oauth/token`, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${credentials}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n code_verifier: codeVerifier,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(`Token exchange failed (${response.status}): ${text}`);\n }\n\n const data = (await response.json()) as OAuthTokenResponse;\n\n if (!data.access_token) {\n throw new Error('Token response missing access_token');\n }\n\n return data;\n}\n\n/**\n * Run the OAuth PKCE authorization code flow:\n * 1. Start local callback server\n * 2. Build XSUAA authorize URL with PKCE\n * 3. Open browser for user login\n * 4. Receive auth code via redirect\n * 5. Exchange code for user token\n */\nasync function performPkceFlow(\n serviceKey: BTPServiceKey,\n openBrowser: (url: string) => Promise<void>,\n port: number,\n timeoutMs: number,\n redirectUri?: string,\n): Promise<OAuthTokenResponse> {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n const state = generateState();\n\n const resolvedRedirectUri =\n redirectUri ?? `http://localhost:${port}${DEFAULT_REDIRECT_PATH}`;\n const callbackPath = (() => {\n try {\n const pathname = new URL(resolvedRedirectUri).pathname;\n return pathname && pathname.length > 0 ? pathname : '/';\n } catch {\n return DEFAULT_REDIRECT_PATH;\n }\n })();\n\n // Build XSUAA authorize URL\n const authUrl = new URL(`${serviceKey.uaa.url}/oauth/authorize`);\n authUrl.searchParams.set('client_id', serviceKey.uaa.clientid);\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('redirect_uri', resolvedRedirectUri);\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('state', state);\n authUrl.searchParams.set('scope', 'openid');\n\n return new Promise<OAuthTokenResponse>((resolve, reject) => {\n // eslint-disable-next-line prefer-const -- server must be declared before timeout but assigned after\n let server: Server;\n\n const timeout = setTimeout(() => {\n server?.close();\n reject(new Error('Authentication timed out'));\n }, timeoutMs);\n\n server = createServer(async (req, res) => {\n try {\n const url = parseUrl(req.url || '', true);\n\n if (url.pathname !== callbackPath) {\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not Found');\n return;\n }\n\n const {\n code,\n state: returnedState,\n error,\n error_description,\n } = url.query;\n\n if (error) {\n const errorSuffix = error_description\n ? ` - ${error_description}`\n : '';\n throw new Error(`OAuth error: ${error}${errorSuffix}`);\n }\n\n if (returnedState !== state) {\n throw new Error('State mismatch - possible CSRF attack');\n }\n\n if (!code) {\n throw new Error('No authorization code received');\n }\n\n const tokenData = await exchangeCodeForToken(\n serviceKey,\n code as string,\n codeVerifier,\n resolvedRedirectUri,\n );\n\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(\n '<html><body style=\"font-family:Arial;text-align:center;padding:50px\">' +\n '<h2>Authentication successful!</h2>' +\n '<p>You can close this window and return to the terminal.</p>' +\n '<script>setTimeout(()=>window.close(),2000)</script>' +\n '</body></html>',\n );\n\n clearTimeout(timeout);\n setTimeout(() => {\n server.close();\n resolve(tokenData);\n }, 500);\n } catch (err) {\n // Escape error message before embedding into HTML response to prevent\n // reflected XSS / XSS-through-exception. The error message may contain\n // data derived from the (attacker-controllable) OAuth callback URL\n // (e.g. error_description) and must never be treated as trusted.\n const rawMessage = err instanceof Error ? err.message : String(err);\n const escaped = rawMessage.replaceAll(/[&<>\"']/g, (c) => {\n switch (c) {\n case '&':\n return '&amp;';\n case '<':\n return '&lt;';\n case '>':\n return '&gt;';\n case '\"':\n return '&quot;';\n default:\n return '&#39;';\n }\n });\n res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(\n '<html><body style=\"font-family:Arial;text-align:center;padding:50px\">' +\n `<h2>Authentication failed</h2><p>${escaped}</p>` +\n '</body></html>',\n );\n\n clearTimeout(timeout);\n server.close(() => reject(err));\n }\n });\n\n server.on('error', (err) => {\n clearTimeout(timeout);\n reject(err);\n });\n\n server.listen(port, () => {\n openBrowser(authUrl.toString()).catch((err) => {\n clearTimeout(timeout);\n server.close();\n reject(\n new Error('Could not open browser for authentication', {\n cause: err,\n }),\n );\n });\n });\n });\n}\n\n/**\n * Resolve the browser opener: use the provided callback, or dynamically\n * import the `open` package. Throws when neither is available.\n */\nasync function resolveBrowserOpener(\n openBrowser: ((url: string) => Promise<void>) | undefined,\n): Promise<(url: string) => Promise<void>> {\n if (openBrowser) {\n return openBrowser;\n }\n try {\n const openModule = await import('open');\n const openFn = openModule.default;\n return async (url: string) => {\n await openFn(url);\n };\n } catch {\n throw new Error(\n 'No openBrowser callback provided and \"open\" package not available. ' +\n 'Install \"open\" or pass an openBrowser function in plugin options.',\n );\n }\n}\n\n/**\n * Classify a failed PKCE attempt. EADDRINUSE is retried on the next port;\n * when an explicit redirectUri is set, retrying on a different port is\n * pointless because the OAuth callback will still go to the original port\n * encoded in the redirect URI — so that combination is fatal. Everything\n * else is rethrown unchanged.\n */\nfunction classifyAttemptError(\n err: unknown,\n port: number,\n hasExplicitRedirect: boolean,\n log: (msg: string) => void,\n): void {\n const isAddrInUse =\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'EADDRINUSE';\n if (!isAddrInUse) {\n throw err; // Non-port error — rethrow immediately\n }\n if (hasExplicitRedirect) {\n throw new Error(\n `Port ${port} is in use and redirectUri is explicitly set — cannot retry on a different port`,\n { cause: err },\n );\n }\n log(`⚠️ Port ${port} in use, trying ${port + 1}...`);\n}\n\nconst authPlugin: AuthPlugin = {\n async authenticate(options: AuthPluginOptions): Promise<CookieAuthResult> {\n const { serviceKey, openBrowser, callbackPort, timeoutMs, redirectUri } =\n options as ServiceKeyPluginOptions;\n\n if (!serviceKey) {\n throw new Error('service-key plugin requires a serviceKey option');\n }\n\n const parsed = ServiceKeyParser.parse(serviceKey);\n\n // Resolve openBrowser: use provided callback, or dynamically import 'open'\n const browserOpener = await resolveBrowserOpener(openBrowser);\n\n const startPort =\n typeof callbackPort === 'number' ? callbackPort : DEFAULT_PORT;\n const timeout =\n typeof timeoutMs === 'number' ? timeoutMs : DEFAULT_TIMEOUT_MS;\n\n // Extract log from options (passed by AuthManager during refresh, or by CLI)\n const log = (options as { log?: (msg: string) => void }).log ?? console.log;\n\n // Wrap browser opener: always print the URL and try clipboard copy before opening\n const wrappedBrowserOpener = async (url: string) => {\n log(`🔗 Open this URL to authenticate:\\n ${url}`);\n\n try {\n await copyToClipboard(url);\n log('📋 URL copied to clipboard');\n } catch {\n // Clipboard not available — URL is already printed above\n }\n\n await browserOpener(url);\n };\n\n // Try ports starting from startPort, retrying on EADDRINUSE\n const hasExplicitRedirect = typeof redirectUri === 'string';\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < MAX_PORT_RETRIES; attempt++) {\n const port = startPort + attempt;\n // When redirectUri is explicitly set, use it as-is (don't rewrite for new port)\n const effectiveRedirectUri = hasExplicitRedirect\n ? redirectUri\n : undefined;\n\n try {\n const tokenData = await performPkceFlow(\n parsed,\n wrappedBrowserOpener,\n port,\n timeout,\n effectiveRedirectUri,\n );\n\n const expiresAt = new Date(Date.now() + tokenData.expires_in * 1000);\n\n return {\n method: 'cookie',\n credentials: {\n cookies: `Authorization: Bearer ${tokenData.access_token}`,\n expiresAt,\n },\n };\n } catch (err) {\n classifyAttemptError(err, port, hasExplicitRedirect, log);\n lastError = err instanceof Error ? err : new Error(String(err));\n continue;\n }\n }\n\n throw new Error(\n `All ports ${startPort}-${startPort + MAX_PORT_RETRIES - 1} are in use. ` +\n `Free a port or set callbackPort in plugin options.`,\n { cause: lastError },\n );\n },\n};\n\nexport default authPlugin;\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as authPlugin } from "./service-key-DEYaMW4g.mjs";
1
+ import { t as authPlugin } from "./service-key-C11sqpQ1.mjs";
2
2
 
3
3
  export { authPlugin as default };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.4.36",
6
+ "version": "0.4.39",
7
7
  "description": "Authentication package for SAP ADT systems - supports multiple auth methods",
8
8
  "type": "module",
9
9
  "types": "./dist/index.d.mts",
@@ -21,7 +21,7 @@
21
21
  "README.md"
22
22
  ],
23
23
  "dependencies": {
24
- "@abapify/logger": "0.4.36",
24
+ "@abapify/logger": "0.4.38",
25
25
  "open": "^11.0.4",
26
26
  "proxy-agent": "^6.4.0"
27
27
  },