@abapify/adt-auth 0.4.17 → 0.4.18

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/basic.d.mts CHANGED
@@ -1,5 +1,4 @@
1
- import { i as AuthPluginOptions, r as AuthPlugin } from "./types-C6-wI7SQ.mjs";
2
- //#region src/plugins/basic.d.ts
1
+ import { i as AuthPluginOptions, r as AuthPlugin } from "./types-DRCpFrpT.mjs";
3
2
  interface BasicAuthOptions extends AuthPluginOptions {
4
3
  username: string;
5
4
  password: string;
@@ -8,6 +7,5 @@ interface BasicAuthOptions extends AuthPluginOptions {
8
7
  * Basic auth plugin - uses provided credentials
9
8
  */
10
9
  declare const authPlugin: AuthPlugin;
11
- //#endregion
12
10
  export { BasicAuthOptions, authPlugin as default };
13
11
  //# sourceMappingURL=basic.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"basic.d.mts","names":[],"sources":["../src/plugins/basic.ts"],"mappings":";;UASiB,yBAAyB;EACxC;EACA;;;;;cAMI,YAAY"}
1
+ {"version":3,"file":"basic.d.mts","names":[],"sources":["../src/plugins/basic.ts"],"mappings":";UASiB,yBAAyB;EACxC;EACA;;;;;cAMI,YAAY"}
@@ -1,5 +1,4 @@
1
- import { i as AuthPluginOptions, o as AuthSession } from "./types-C6-wI7SQ.mjs";
2
- //#region src/storage/file-storage.d.ts
1
+ import { i as AuthPluginOptions, o as AuthSession } from "./types-DRCpFrpT.mjs";
3
2
  declare class FileStorage {
4
3
  private readonly baseDir;
5
4
  private readonly storageDir;
@@ -42,8 +41,6 @@ declare class FileStorage {
42
41
  private loadConfig;
43
42
  private saveConfig;
44
43
  }
45
- //#endregion
46
- //#region src/auth-manager.d.ts
47
44
  /**
48
45
  * Destination configuration (from adt.config.ts)
49
46
  */
@@ -121,8 +118,6 @@ declare class AuthManager {
121
118
  password: string;
122
119
  } | null;
123
120
  }
124
- //#endregion
125
- //#region src/types/service-key.d.ts
126
121
  interface UAACredentials {
127
122
  tenantmode: string;
128
123
  sburl: string;
@@ -175,8 +170,6 @@ interface ServiceKeyPluginOptions {
175
170
  redirectUri?: string;
176
171
  [key: string]: unknown;
177
172
  }
178
- //#endregion
179
- //#region src/utils/env.d.ts
180
173
  /**
181
174
  * Read a BTP service key from a file path.
182
175
  *
@@ -197,6 +190,5 @@ declare function readServiceKey(filePath: string): BTPServiceKey;
197
190
  * `ADT_SERVICE_KEY` is not set.
198
191
  */
199
192
  declare function resolveServiceKeyFromEnv(): Destination | null;
200
- //#endregion
201
193
  export { UAACredentials as a, FileStorage as c, ServiceKeyPluginOptions as i, resolveServiceKeyFromEnv as n, AuthManager as o, BTPServiceKey as r, Destination as s, readServiceKey as t };
202
- //# sourceMappingURL=env-Co2ABx6K.d.mts.map
194
+ //# sourceMappingURL=env-B1kvodv4.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-B1kvodv4.d.mts","names":[],"sources":["../src/storage/file-storage.ts","../src/auth-manager.ts","../src/types/service-key.ts","../src/utils/env.ts"],"mappings":";cAuBa;mBACM;mBACA;mBACA;EAEL,YAAA;;;;EAcZ,KAAK,SAAS;;;;EASd,KAAK,cAAc;;;;EAoBnB,OAAO;;;;EAUP;;;;EAaA,OAAO;;;;EAWP,cAAc;;;;EASd;;;;EAQA;UAUQ;UAIA;UAMA;UAWA;;;;;UCpIO;;EAEf;;EAEA,SAAS;;cAGE;UACH;EAEI,YAAA,UAAU;;;;;;;;;EAgBhB,MAAM,aAAa,aAAa,cAAc,QAAQ;;;;UAgCpD;;;;EA0CR,YAAY,SAAS;;;;EAOrB,WAAW,eAAe;;;;EAW1B,cAAc;;;;EAOd;;;;EAWA,cAAc;;;;EAOd;;;;EAOA;;;;EAWA,UAAU,SAAS;;;;;;EAab,mBACJ,SAAS,aACT;IAAY,OAAO;MAClB,QAAQ;;;;EAyFX,gBAAgB,SAAS;;;;EAWzB,aACE,SAAS;IACN;IAAkB;;;UC1SR;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf,KAAK;EACL;EACA;EACA;EACA,WAAW;EACX,UAAU,eAAe;EACzB,SAAS;EACT;;UAYe;EACf;EACA;EACA;;EAEA,eAAe,gBAAgB;;EAE/B;;EAEA;;EAEA;GACC;;;;;;;;;;iBCrDa,eAAe,mBAAmB;;;;;;;;;;;iBA6BlC,4BAA4B"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as AuthPluginResult, c as BasicCredentials, d as CookieCredentials, f as Credentials, i as AuthPluginOptions, l as ConnectionTestResult, n as AuthMethod, o as AuthSession, r as AuthPlugin, s as BasicAuthResult, t as AuthConfig, u as CookieAuthResult } from "./types-C6-wI7SQ.mjs";
2
- import { a as UAACredentials, c as FileStorage, i as ServiceKeyPluginOptions, n as resolveServiceKeyFromEnv, o as AuthManager, r as BTPServiceKey, s as Destination, t as readServiceKey } from "./env-Co2ABx6K.mjs";
1
+ import { a as AuthPluginResult, c as BasicCredentials, d as CookieCredentials, f as Credentials, i as AuthPluginOptions, l as ConnectionTestResult, n as AuthMethod, o as AuthSession, r as AuthPlugin, s as BasicAuthResult, t as AuthConfig, u as CookieAuthResult } from "./types-DRCpFrpT.mjs";
2
+ import { a as UAACredentials, c as FileStorage, i as ServiceKeyPluginOptions, n as resolveServiceKeyFromEnv, o as AuthManager, r as BTPServiceKey, s as Destination, t as readServiceKey } from "./env-B1kvodv4.mjs";
3
3
  import authPlugin from "./basic.mjs";
4
4
  import authPlugin$1 from "./service-key.mjs";
5
5
  export { type AuthConfig, AuthManager, type AuthMethod, type AuthPlugin, type AuthPluginOptions, type AuthPluginResult, type AuthSession, type BTPServiceKey, type BasicAuthResult, type BasicCredentials, type ConnectionTestResult, type CookieAuthResult, type CookieCredentials, type Credentials, type Destination, FileStorage, type ServiceKeyPluginOptions, type UAACredentials, authPlugin as basicAuthPlugin, readServiceKey, resolveServiceKeyFromEnv, authPlugin$1 as serviceKeyAuthPlugin };
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  import authPlugin from "./plugins/basic.mjs";
2
- import { t as authPlugin$1 } from "./service-key-2AKKsYxf.mjs";
2
+ import { t as authPlugin$1 } from "./service-key-upymvzHr.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";
6
6
  import { homedir } from "node:os";
7
7
 
8
- //#region src/storage/file-storage.ts
8
+ // src/storage/file-storage.ts
9
9
  /**
10
10
  * File-based session storage
11
11
  *
@@ -108,8 +108,7 @@ var FileStorage = class {
108
108
  }
109
109
  };
110
110
 
111
- //#endregion
112
- //#region src/auth-manager.ts
111
+ // src/auth-manager.ts
113
112
  var AuthManager = class {
114
113
  storage;
115
114
  constructor(storage) {
@@ -286,6 +285,5 @@ var AuthManager = class {
286
285
  }
287
286
  };
288
287
 
289
- //#endregion
290
288
  export { AuthManager, FileStorage, authPlugin as basicAuthPlugin, readServiceKey, resolveServiceKeyFromEnv, authPlugin$1 as serviceKeyAuthPlugin };
291
289
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/storage/file-storage.ts","../src/auth-manager.ts"],"sourcesContent":["/**\n * File-based session storage\n *\n * Stores auth sessions in ~/.adt/sessions/\n * Stores config in ~/.adt/config.json\n */\n\nimport {\n readFileSync,\n writeFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n unlinkSync,\n} from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { AuthSession } from '../types';\n\ninterface Config {\n defaultSid?: string;\n}\n\nexport class FileStorage {\n private readonly baseDir: string;\n private readonly storageDir: string;\n private readonly configPath: string;\n\n constructor(baseDir?: string) {\n this.baseDir = baseDir || join(homedir(), '.adt');\n this.storageDir = join(this.baseDir, 'sessions');\n this.configPath = join(this.baseDir, 'config.json');\n this.ensureStorageDir();\n }\n\n // ===========================================================================\n // Session Storage\n // ===========================================================================\n\n /**\n * Save session to file\n */\n save(session: AuthSession): void {\n const filePath = this.getSessionPath(session.sid);\n const data = JSON.stringify(session, null, 2);\n writeFileSync(filePath, data, { mode: 0o600 }); // Owner read/write only\n }\n\n /**\n * Load session from file\n */\n load(sid: string): AuthSession | null {\n const filePath = this.getSessionPath(sid);\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const data = readFileSync(filePath, 'utf8');\n return JSON.parse(data) as AuthSession;\n } catch (error) {\n throw new Error(\n `Failed to load session ${sid}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n }\n\n /**\n * Delete session file\n */\n delete(sid: string): void {\n const filePath = this.getSessionPath(sid);\n if (existsSync(filePath)) {\n unlinkSync(filePath);\n }\n }\n\n /**\n * List all available SIDs\n */\n list(): string[] {\n if (!existsSync(this.storageDir)) {\n return [];\n }\n\n return readdirSync(this.storageDir)\n .filter((file) => file.endsWith('.json'))\n .map((file) => file.replace('.json', ''));\n }\n\n /**\n * Check if session exists\n */\n exists(sid: string): boolean {\n return existsSync(this.getSessionPath(sid));\n }\n\n // ===========================================================================\n // Default SID Management\n // ===========================================================================\n\n /**\n * Set default SID\n */\n setDefaultSid(sid: string): void {\n const config = this.loadConfig();\n config.defaultSid = sid;\n this.saveConfig(config);\n }\n\n /**\n * Get default SID\n */\n getDefaultSid(): string | null {\n const config = this.loadConfig();\n return config.defaultSid ?? null;\n }\n\n /**\n * Clear default SID\n */\n clearDefaultSid(): void {\n const config = this.loadConfig();\n delete config.defaultSid;\n this.saveConfig(config);\n }\n\n // ===========================================================================\n // Private Helpers\n // ===========================================================================\n\n private getSessionPath(sid: string): string {\n return join(this.storageDir, `${sid}.json`);\n }\n\n private ensureStorageDir(): void {\n if (!existsSync(this.storageDir)) {\n mkdirSync(this.storageDir, { recursive: true, mode: 0o700 }); // Owner only\n }\n }\n\n private loadConfig(): Config {\n if (!existsSync(this.configPath)) {\n return {};\n }\n try {\n return JSON.parse(readFileSync(this.configPath, 'utf8'));\n } catch {\n return {};\n }\n }\n\n private saveConfig(config: Config): void {\n mkdirSync(dirname(this.configPath), { recursive: true });\n writeFileSync(this.configPath, JSON.stringify(config, null, 2), {\n mode: 0o600,\n });\n }\n}\n","/**\n * Authentication Manager\n *\n * Single source of truth for authentication across all consumers:\n * - CLI\n * - MCP Server\n * - Other tools\n */\n\nimport type {\n AuthSession,\n CookieCredentials,\n AuthPlugin,\n AuthPluginOptions,\n AuthPluginResult,\n} from './types';\nimport { FileStorage } from './storage/file-storage';\n\n/**\n * Destination configuration (from adt.config.ts)\n */\nexport interface Destination {\n /** Plugin package to use (e.g., '@abapify/adt-puppeteer', '@abapify/adt-auth/basic') */\n type: string;\n /** Plugin-specific options */\n options: AuthPluginOptions;\n}\n\nexport class AuthManager {\n private storage: FileStorage;\n\n constructor(storage?: FileStorage) {\n this.storage = storage || new FileStorage();\n }\n\n // ===========================================================================\n // Login - Main entry point\n // ===========================================================================\n\n /**\n * Login using a destination configuration\n *\n * Dynamically loads the plugin specified in destination.type and authenticates.\n *\n * @param sid - System ID (e.g., 'TRL')\n * @param destination - Destination config with plugin type and options\n */\n async login(sid: string, destination: Destination): Promise<AuthSession> {\n // Dynamic import of the auth plugin\n const pluginModule = (await import(destination.type)) as {\n default?: AuthPlugin;\n };\n\n if (!pluginModule.default?.authenticate) {\n throw new Error(\n `Plugin ${destination.type} does not have a default export with authenticate method`,\n );\n }\n\n // Authenticate using the plugin\n const result = await pluginModule.default.authenticate(destination.options);\n\n // Build session based on result type\n const session = this.buildSession(sid, destination, result);\n\n // Save session\n this.saveSession(session);\n\n // Set as default if first system\n if (this.listSids().length === 1) {\n this.setDefaultSid(sid);\n }\n\n return session;\n }\n\n /**\n * Build session from plugin result\n */\n private buildSession(\n sid: string,\n destination: Destination,\n result: AuthPluginResult,\n ): AuthSession {\n if (result.method === 'cookie') {\n return {\n sid: sid.toUpperCase(),\n host: destination.options.url,\n client: destination.options.client,\n auth: {\n method: 'cookie',\n plugin: destination.type,\n pluginOptions: destination.options, // Store full plugin options for refresh fallback\n credentials: {\n cookies: result.credentials.cookies,\n expiresAt: result.credentials.expiresAt.toISOString(),\n },\n },\n };\n } else {\n return {\n sid: sid.toUpperCase(),\n host: destination.options.url,\n client: destination.options.client,\n auth: {\n method: 'basic',\n plugin: destination.type,\n pluginOptions: destination.options, // Store full plugin options for consistency\n credentials: result.credentials,\n },\n };\n }\n }\n\n // ===========================================================================\n // Session Management\n // ===========================================================================\n\n /**\n * Save a session (after successful authentication)\n */\n saveSession(session: AuthSession): void {\n this.storage.save(session);\n }\n\n /**\n * Get session by SID\n */\n getSession(sid?: string): AuthSession | null {\n const targetSid = sid || this.getDefaultSid();\n if (!targetSid) {\n return null;\n }\n return this.storage.load(targetSid);\n }\n\n /**\n * Delete session (logout)\n */\n deleteSession(sid: string): void {\n this.storage.delete(sid);\n }\n\n /**\n * List all available SIDs\n */\n listSids(): string[] {\n return this.storage.list();\n }\n\n // ===========================================================================\n // Default SID Management\n // ===========================================================================\n\n /**\n * Set default SID (persisted to config)\n */\n setDefaultSid(sid: string): void {\n this.storage.setDefaultSid(sid);\n }\n\n /**\n * Get default SID\n */\n getDefaultSid(): string | null {\n return this.storage.getDefaultSid() || (this.storage.list()[0] ?? null);\n }\n\n /**\n * Clear default SID\n */\n clearDefaultSid(): void {\n this.storage.clearDefaultSid();\n }\n\n // ===========================================================================\n // Credential Helpers\n // ===========================================================================\n\n /**\n * Check if session credentials are expired\n */\n isExpired(session: AuthSession): boolean {\n if (session.auth.method !== 'cookie') {\n return false; // Basic auth doesn't expire\n }\n const creds = session.auth.credentials as CookieCredentials;\n return new Date(creds.expiresAt) < new Date();\n }\n\n /**\n * Refresh credentials using the auth plugin\n *\n * @returns Updated session with new credentials, or null if refresh not supported/failed\n */\n async refreshCredentials(\n session: AuthSession,\n options?: { log?: (message: string) => void },\n ): Promise<AuthSession | null> {\n const log = options?.log ?? console.log;\n\n if (!session.auth.plugin) {\n return null; // No plugin = can't refresh\n }\n\n // Dynamic import of the auth plugin (expects default export)\n const pluginModule = (await import(session.auth.plugin)) as {\n default?: AuthPlugin;\n };\n\n if (!pluginModule.default) {\n throw new Error(\n `Plugin ${session.auth.plugin} does not have a default export`,\n );\n }\n\n const plugin = pluginModule.default;\n\n // Try plugin's refresh method first (preferred for session-based auth)\n if (plugin.refresh) {\n const sessionWithLog: AuthSession = {\n ...session,\n auth: {\n ...session.auth,\n pluginOptions: {\n url: session.host,\n client: session.client,\n ...session.auth.pluginOptions,\n log,\n },\n },\n };\n const result = await plugin.refresh(sessionWithLog);\n\n if (result) {\n // Refresh succeeded - build and save updated session\n // Preserve original plugin options (including userDataDir)\n const destination: Destination = {\n type: session.auth.plugin,\n options: session.auth.pluginOptions || {\n url: session.host,\n client: session.client,\n },\n };\n\n const updatedSession = this.buildSession(\n session.sid,\n destination,\n result,\n );\n this.saveSession(updatedSession);\n\n return updatedSession;\n }\n\n // Refresh failed - fall through to interactive authenticate\n log(\n '⚠️ Silent refresh failed - falling back to interactive authentication...',\n );\n }\n\n // Fallback: Call authenticate (full re-auth with browser interaction)\n // Use stored plugin options to preserve settings like userDataDir\n const baseOptions: AuthPluginOptions = session.auth.pluginOptions || {\n url: session.host,\n client: session.client,\n };\n const runtimeOptions = { ...baseOptions, log };\n\n const result = await plugin.authenticate(runtimeOptions);\n\n // Build destination for buildSession\n const destination: Destination = {\n type: session.auth.plugin,\n options: baseOptions,\n };\n\n // Build and save updated session\n const updatedSession = this.buildSession(session.sid, destination, result);\n this.saveSession(updatedSession);\n\n return updatedSession;\n }\n\n /**\n * Get cookie header for HTTP client (convenience method)\n */\n getCookieHeader(session: AuthSession): string | null {\n if (session.auth.method !== 'cookie') {\n return null;\n }\n const creds = session.auth.credentials as CookieCredentials;\n return creds.cookies;\n }\n\n /**\n * Get basic auth credentials (convenience method)\n */\n getBasicAuth(\n session: AuthSession,\n ): { username: string; password: string } | null {\n if (session.auth.method !== 'basic') {\n return null;\n }\n return session.auth.credentials as { username: string; password: string };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/storage/file-storage.ts","../src/auth-manager.ts"],"sourcesContent":["/**\n * File-based session storage\n *\n * Stores auth sessions in ~/.adt/sessions/\n * Stores config in ~/.adt/config.json\n */\n\nimport {\n readFileSync,\n writeFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n unlinkSync,\n} from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { AuthSession } from '../types';\n\ninterface Config {\n defaultSid?: string;\n}\n\nexport class FileStorage {\n private readonly baseDir: string;\n private readonly storageDir: string;\n private readonly configPath: string;\n\n constructor(baseDir?: string) {\n this.baseDir = baseDir || join(homedir(), '.adt');\n this.storageDir = join(this.baseDir, 'sessions');\n this.configPath = join(this.baseDir, 'config.json');\n this.ensureStorageDir();\n }\n\n // ===========================================================================\n // Session Storage\n // ===========================================================================\n\n /**\n * Save session to file\n */\n save(session: AuthSession): void {\n const filePath = this.getSessionPath(session.sid);\n const data = JSON.stringify(session, null, 2);\n writeFileSync(filePath, data, { mode: 0o600 }); // Owner read/write only\n }\n\n /**\n * Load session from file\n */\n load(sid: string): AuthSession | null {\n const filePath = this.getSessionPath(sid);\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const data = readFileSync(filePath, 'utf8');\n return JSON.parse(data) as AuthSession;\n } catch (error) {\n throw new Error(\n `Failed to load session ${sid}: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error },\n );\n }\n }\n\n /**\n * Delete session file\n */\n delete(sid: string): void {\n const filePath = this.getSessionPath(sid);\n if (existsSync(filePath)) {\n unlinkSync(filePath);\n }\n }\n\n /**\n * List all available SIDs\n */\n list(): string[] {\n if (!existsSync(this.storageDir)) {\n return [];\n }\n\n return readdirSync(this.storageDir)\n .filter((file) => file.endsWith('.json'))\n .map((file) => file.replace('.json', ''));\n }\n\n /**\n * Check if session exists\n */\n exists(sid: string): boolean {\n return existsSync(this.getSessionPath(sid));\n }\n\n // ===========================================================================\n // Default SID Management\n // ===========================================================================\n\n /**\n * Set default SID\n */\n setDefaultSid(sid: string): void {\n const config = this.loadConfig();\n config.defaultSid = sid;\n this.saveConfig(config);\n }\n\n /**\n * Get default SID\n */\n getDefaultSid(): string | null {\n const config = this.loadConfig();\n return config.defaultSid ?? null;\n }\n\n /**\n * Clear default SID\n */\n clearDefaultSid(): void {\n const config = this.loadConfig();\n delete config.defaultSid;\n this.saveConfig(config);\n }\n\n // ===========================================================================\n // Private Helpers\n // ===========================================================================\n\n private getSessionPath(sid: string): string {\n return join(this.storageDir, `${sid}.json`);\n }\n\n private ensureStorageDir(): void {\n if (!existsSync(this.storageDir)) {\n mkdirSync(this.storageDir, { recursive: true, mode: 0o700 }); // Owner only\n }\n }\n\n private loadConfig(): Config {\n if (!existsSync(this.configPath)) {\n return {};\n }\n try {\n return JSON.parse(readFileSync(this.configPath, 'utf8'));\n } catch {\n return {};\n }\n }\n\n private saveConfig(config: Config): void {\n mkdirSync(dirname(this.configPath), { recursive: true });\n writeFileSync(this.configPath, JSON.stringify(config, null, 2), {\n mode: 0o600,\n });\n }\n}\n","/**\n * Authentication Manager\n *\n * Single source of truth for authentication across all consumers:\n * - CLI\n * - MCP Server\n * - Other tools\n */\n\nimport type {\n AuthSession,\n CookieCredentials,\n AuthPlugin,\n AuthPluginOptions,\n AuthPluginResult,\n} from './types';\nimport { FileStorage } from './storage/file-storage';\n\n/**\n * Destination configuration (from adt.config.ts)\n */\nexport interface Destination {\n /** Plugin package to use (e.g., '@abapify/adt-puppeteer', '@abapify/adt-auth/basic') */\n type: string;\n /** Plugin-specific options */\n options: AuthPluginOptions;\n}\n\nexport class AuthManager {\n private storage: FileStorage;\n\n constructor(storage?: FileStorage) {\n this.storage = storage || new FileStorage();\n }\n\n // ===========================================================================\n // Login - Main entry point\n // ===========================================================================\n\n /**\n * Login using a destination configuration\n *\n * Dynamically loads the plugin specified in destination.type and authenticates.\n *\n * @param sid - System ID (e.g., 'TRL')\n * @param destination - Destination config with plugin type and options\n */\n async login(sid: string, destination: Destination): Promise<AuthSession> {\n // Dynamic import of the auth plugin\n const pluginModule = (await import(destination.type)) as {\n default?: AuthPlugin;\n };\n\n if (!pluginModule.default?.authenticate) {\n throw new Error(\n `Plugin ${destination.type} does not have a default export with authenticate method`,\n );\n }\n\n // Authenticate using the plugin\n const result = await pluginModule.default.authenticate(destination.options);\n\n // Build session based on result type\n const session = this.buildSession(sid, destination, result);\n\n // Save session\n this.saveSession(session);\n\n // Set as default if first system\n if (this.listSids().length === 1) {\n this.setDefaultSid(sid);\n }\n\n return session;\n }\n\n /**\n * Build session from plugin result\n */\n private buildSession(\n sid: string,\n destination: Destination,\n result: AuthPluginResult,\n ): AuthSession {\n if (result.method === 'cookie') {\n return {\n sid: sid.toUpperCase(),\n host: destination.options.url,\n client: destination.options.client,\n auth: {\n method: 'cookie',\n plugin: destination.type,\n pluginOptions: destination.options, // Store full plugin options for refresh fallback\n credentials: {\n cookies: result.credentials.cookies,\n expiresAt: result.credentials.expiresAt.toISOString(),\n },\n },\n };\n } else {\n return {\n sid: sid.toUpperCase(),\n host: destination.options.url,\n client: destination.options.client,\n auth: {\n method: 'basic',\n plugin: destination.type,\n pluginOptions: destination.options, // Store full plugin options for consistency\n credentials: result.credentials,\n },\n };\n }\n }\n\n // ===========================================================================\n // Session Management\n // ===========================================================================\n\n /**\n * Save a session (after successful authentication)\n */\n saveSession(session: AuthSession): void {\n this.storage.save(session);\n }\n\n /**\n * Get session by SID\n */\n getSession(sid?: string): AuthSession | null {\n const targetSid = sid || this.getDefaultSid();\n if (!targetSid) {\n return null;\n }\n return this.storage.load(targetSid);\n }\n\n /**\n * Delete session (logout)\n */\n deleteSession(sid: string): void {\n this.storage.delete(sid);\n }\n\n /**\n * List all available SIDs\n */\n listSids(): string[] {\n return this.storage.list();\n }\n\n // ===========================================================================\n // Default SID Management\n // ===========================================================================\n\n /**\n * Set default SID (persisted to config)\n */\n setDefaultSid(sid: string): void {\n this.storage.setDefaultSid(sid);\n }\n\n /**\n * Get default SID\n */\n getDefaultSid(): string | null {\n return this.storage.getDefaultSid() || (this.storage.list()[0] ?? null);\n }\n\n /**\n * Clear default SID\n */\n clearDefaultSid(): void {\n this.storage.clearDefaultSid();\n }\n\n // ===========================================================================\n // Credential Helpers\n // ===========================================================================\n\n /**\n * Check if session credentials are expired\n */\n isExpired(session: AuthSession): boolean {\n if (session.auth.method !== 'cookie') {\n return false; // Basic auth doesn't expire\n }\n const creds = session.auth.credentials as CookieCredentials;\n return new Date(creds.expiresAt) < new Date();\n }\n\n /**\n * Refresh credentials using the auth plugin\n *\n * @returns Updated session with new credentials, or null if refresh not supported/failed\n */\n async refreshCredentials(\n session: AuthSession,\n options?: { log?: (message: string) => void },\n ): Promise<AuthSession | null> {\n const log = options?.log ?? console.log;\n\n if (!session.auth.plugin) {\n return null; // No plugin = can't refresh\n }\n\n // Dynamic import of the auth plugin (expects default export)\n const pluginModule = (await import(session.auth.plugin)) as {\n default?: AuthPlugin;\n };\n\n if (!pluginModule.default) {\n throw new Error(\n `Plugin ${session.auth.plugin} does not have a default export`,\n );\n }\n\n const plugin = pluginModule.default;\n\n // Try plugin's refresh method first (preferred for session-based auth)\n if (plugin.refresh) {\n const sessionWithLog: AuthSession = {\n ...session,\n auth: {\n ...session.auth,\n pluginOptions: {\n url: session.host,\n client: session.client,\n ...session.auth.pluginOptions,\n log,\n },\n },\n };\n const result = await plugin.refresh(sessionWithLog);\n\n if (result) {\n // Refresh succeeded - build and save updated session\n // Preserve original plugin options (including userDataDir)\n const destination: Destination = {\n type: session.auth.plugin,\n options: session.auth.pluginOptions || {\n url: session.host,\n client: session.client,\n },\n };\n\n const updatedSession = this.buildSession(\n session.sid,\n destination,\n result,\n );\n this.saveSession(updatedSession);\n\n return updatedSession;\n }\n\n // Refresh failed - fall through to interactive authenticate\n log(\n '⚠️ Silent refresh failed - falling back to interactive authentication...',\n );\n }\n\n // Fallback: Call authenticate (full re-auth with browser interaction)\n // Use stored plugin options to preserve settings like userDataDir\n const baseOptions: AuthPluginOptions = session.auth.pluginOptions || {\n url: session.host,\n client: session.client,\n };\n const runtimeOptions = { ...baseOptions, log };\n\n const result = await plugin.authenticate(runtimeOptions);\n\n // Build destination for buildSession\n const destination: Destination = {\n type: session.auth.plugin,\n options: baseOptions,\n };\n\n // Build and save updated session\n const updatedSession = this.buildSession(session.sid, destination, result);\n this.saveSession(updatedSession);\n\n return updatedSession;\n }\n\n /**\n * Get cookie header for HTTP client (convenience method)\n */\n getCookieHeader(session: AuthSession): string | null {\n if (session.auth.method !== 'cookie') {\n return null;\n }\n const creds = session.auth.credentials as CookieCredentials;\n return creds.cookies;\n }\n\n /**\n * Get basic auth credentials (convenience method)\n */\n getBasicAuth(\n session: AuthSession,\n ): { username: string; password: string } | null {\n if (session.auth.method !== 'basic') {\n return null;\n }\n return session.auth.credentials as { username: string; password: string };\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- //#region src/plugins/basic.ts
1
+ // src/plugins/basic.ts
2
2
  /**
3
3
  * Basic auth plugin - uses provided credentials
4
4
  */
@@ -14,6 +14,5 @@ const authPlugin = { async authenticate(options) {
14
14
  };
15
15
  } };
16
16
 
17
- //#endregion
18
17
  export { authPlugin as default };
19
18
  //# sourceMappingURL=basic.mjs.map
@@ -1,3 +1,3 @@
1
- import { t as authPlugin } from "../service-key-2AKKsYxf.mjs";
1
+ import { t as authPlugin } from "../service-key-upymvzHr.mjs";
2
2
 
3
3
  export { authPlugin as default };
@@ -1,4 +1,4 @@
1
- //#region src/types/service-key.ts
1
+ // src/types/service-key.ts
2
2
  var ServiceKeyParser = class {
3
3
  static parse(serviceKeyJson) {
4
4
  let parsed;
@@ -15,6 +15,5 @@ var ServiceKeyParser = class {
15
15
  }
16
16
  };
17
17
 
18
- //#endregion
19
18
  export { ServiceKeyParser as t };
20
- //# sourceMappingURL=service-key-eMRV2aSt.mjs.map
19
+ //# sourceMappingURL=service-key-CJYW5WMd.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-key-eMRV2aSt.mjs","names":[],"sources":["../src/types/service-key.ts"],"sourcesContent":["// BTP Service Key types\n\nexport interface UAACredentials {\n tenantmode: string;\n sburl: string;\n subaccountid: string;\n 'credential-type': string;\n clientid: string;\n xsappname: string;\n clientsecret: string;\n serviceInstanceId: string;\n url: string;\n uaadomain: string;\n verificationkey: string;\n apiurl: string;\n identityzone: string;\n identityzoneid: string;\n tenantid: string;\n zoneid: string;\n}\n\nexport interface Catalog {\n path: string;\n type: string;\n}\n\nexport interface Binding {\n env: string;\n version: string;\n type: string;\n id: string;\n}\n\nexport interface BTPServiceKey {\n uaa: UAACredentials;\n url: string;\n 'sap.cloud.service': string;\n systemid: string;\n endpoints: Record<string, string>;\n catalogs: Record<string, Catalog>;\n binding: Binding;\n preserve_host_header: boolean;\n}\n\nexport interface OAuthToken {\n access_token: string;\n token_type: string;\n expires_in: number;\n scope: string;\n refresh_token?: string;\n expires_at: Date;\n}\n\nexport interface ServiceKeyPluginOptions {\n url: string;\n client?: string;\n serviceKey: string | object;\n /** Callback to open a URL in the user's browser. Falls back to dynamic import of 'open'. */\n openBrowser?: (url: string) => Promise<void>;\n /** Port for the local OAuth callback server (default: 3000) */\n callbackPort?: number;\n /** Timeout for the auth flow in ms (default: 300000 = 5 min) */\n timeoutMs?: number;\n /** Full redirect URI for the OAuth callback (e.g. in tunnelled/forwarded environments). Defaults to http://localhost:<port>/callback */\n redirectUri?: string;\n [key: string]: unknown;\n}\n\nexport class ServiceKeyParser {\n static parse(serviceKeyJson: string | object): BTPServiceKey {\n let parsed: unknown;\n\n if (typeof serviceKeyJson === 'string') {\n try {\n parsed = JSON.parse(serviceKeyJson);\n } catch (error) {\n throw new Error('Invalid JSON format in service key', { cause: error });\n }\n } else {\n parsed = serviceKeyJson;\n }\n\n if (!parsed || typeof parsed !== 'object') {\n throw new Error('Invalid service key format');\n }\n\n const serviceKey = parsed as Record<string, unknown>;\n\n if (!serviceKey['uaa'] || !serviceKey['url'] || !serviceKey['systemid']) {\n throw new Error('Missing required fields in service key');\n }\n\n return serviceKey as unknown as BTPServiceKey;\n }\n}\n"],"mappings":";AAoEA,IAAa,mBAAb,MAA8B;CAC5B,OAAO,MAAM,gBAAgD;EAC3D,IAAI;EAEJ,IAAI,OAAO,mBAAmB,UAC5B,IAAI;GACF,SAAS,KAAK,MAAM,cAAc;EACpC,SAAS,OAAO;GACd,MAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,MAAM,CAAC;EACxE;OAEA,SAAS;EAGX,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,MAAM,IAAI,MAAM,4BAA4B;EAG9C,MAAM,aAAa;EAEnB,IAAI,CAAC,WAAW,UAAU,CAAC,WAAW,UAAU,CAAC,WAAW,aAC1D,MAAM,IAAI,MAAM,wCAAwC;EAG1D,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"service-key-CJYW5WMd.mjs","names":[],"sources":["../src/types/service-key.ts"],"sourcesContent":["// BTP Service Key types\n\nexport interface UAACredentials {\n tenantmode: string;\n sburl: string;\n subaccountid: string;\n 'credential-type': string;\n clientid: string;\n xsappname: string;\n clientsecret: string;\n serviceInstanceId: string;\n url: string;\n uaadomain: string;\n verificationkey: string;\n apiurl: string;\n identityzone: string;\n identityzoneid: string;\n tenantid: string;\n zoneid: string;\n}\n\nexport interface Catalog {\n path: string;\n type: string;\n}\n\nexport interface Binding {\n env: string;\n version: string;\n type: string;\n id: string;\n}\n\nexport interface BTPServiceKey {\n uaa: UAACredentials;\n url: string;\n 'sap.cloud.service': string;\n systemid: string;\n endpoints: Record<string, string>;\n catalogs: Record<string, Catalog>;\n binding: Binding;\n preserve_host_header: boolean;\n}\n\nexport interface OAuthToken {\n access_token: string;\n token_type: string;\n expires_in: number;\n scope: string;\n refresh_token?: string;\n expires_at: Date;\n}\n\nexport interface ServiceKeyPluginOptions {\n url: string;\n client?: string;\n serviceKey: string | object;\n /** Callback to open a URL in the user's browser. Falls back to dynamic import of 'open'. */\n openBrowser?: (url: string) => Promise<void>;\n /** Port for the local OAuth callback server (default: 3000) */\n callbackPort?: number;\n /** Timeout for the auth flow in ms (default: 300000 = 5 min) */\n timeoutMs?: number;\n /** Full redirect URI for the OAuth callback (e.g. in tunnelled/forwarded environments). Defaults to http://localhost:<port>/callback */\n redirectUri?: string;\n [key: string]: unknown;\n}\n\nexport class ServiceKeyParser {\n static parse(serviceKeyJson: string | object): BTPServiceKey {\n let parsed: unknown;\n\n if (typeof serviceKeyJson === 'string') {\n try {\n parsed = JSON.parse(serviceKeyJson);\n } catch (error) {\n throw new Error('Invalid JSON format in service key', { cause: error });\n }\n } else {\n parsed = serviceKeyJson;\n }\n\n if (!parsed || typeof parsed !== 'object') {\n throw new Error('Invalid service key format');\n }\n\n const serviceKey = parsed as Record<string, unknown>;\n\n if (!serviceKey['uaa'] || !serviceKey['url'] || !serviceKey['systemid']) {\n throw new Error('Missing required fields in service key');\n }\n\n return serviceKey as unknown as BTPServiceKey;\n }\n}\n"],"mappings":";AAoEA,IAAa,mBAAb,MAA8B;CAC5B,OAAO,MAAM,gBAAgD;EAC3D,IAAI;EAEJ,IAAI,OAAO,mBAAmB,UAC5B,IAAI;GACF,SAAS,KAAK,MAAM,cAAc;EACpC,SAAS,OAAO;GACd,MAAM,IAAI,MAAM,sCAAsC,EAAE,OAAO,MAAM,CAAC;EACxE;OAEA,SAAS;EAGX,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,MAAM,IAAI,MAAM,4BAA4B;EAG9C,MAAM,aAAa;EAEnB,IAAI,CAAC,WAAW,UAAU,CAAC,WAAW,UAAU,CAAC,WAAW,aAC1D,MAAM,IAAI,MAAM,wCAAwC;EAG1D,OAAO;CACT;AACF"}
@@ -1,10 +1,10 @@
1
- import { t as ServiceKeyParser } from "./service-key-eMRV2aSt.mjs";
1
+ import { t as ServiceKeyParser } from "./service-key-CJYW5WMd.mjs";
2
2
  import { createServer } from "node:http";
3
3
  import { spawn } from "node:child_process";
4
4
  import { parse } from "node:url";
5
5
  import { createHash, randomBytes } from "node:crypto";
6
6
 
7
- //#region src/utils/pkce.ts
7
+ // src/utils/pkce.ts
8
8
  /**
9
9
  * Generates a cryptographically secure code verifier for PKCE flow
10
10
  */
@@ -24,8 +24,7 @@ function generateState() {
24
24
  return randomBytes(16).toString("hex");
25
25
  }
26
26
 
27
- //#endregion
28
- //#region src/plugins/service-key.ts
27
+ // src/plugins/service-key.ts
29
28
  const DEFAULT_PORT = 3e3;
30
29
  const DEFAULT_REDIRECT_PATH = "/callback";
31
30
  const DEFAULT_TIMEOUT_MS = 3e5;
@@ -229,6 +228,5 @@ const authPlugin = { async authenticate(options) {
229
228
  throw new Error(`All ports ${startPort}-${startPort + MAX_PORT_RETRIES - 1} are in use. Free a port or set callbackPort in plugin options.`, { cause: lastError });
230
229
  } };
231
230
 
232
- //#endregion
233
231
  export { authPlugin as t };
234
- //# sourceMappingURL=service-key-2AKKsYxf.mjs.map
232
+ //# sourceMappingURL=service-key-upymvzHr.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-key-2AKKsYxf.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 const candidates =\n process.platform === 'darwin'\n ? [['pbcopy']]\n : process.platform === 'win32'\n ? [['clip']]\n : [\n ['clip.exe'],\n ['xclip', '-selection', 'clipboard'],\n ['xsel', '--clipboard'],\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\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 let browserOpener: (url: string) => Promise<void>;\n if (openBrowser) {\n browserOpener = openBrowser;\n } else {\n // Fallback: try dynamic import of 'open' package\n try {\n const openModule = await import('open');\n const openFn = openModule.default;\n browserOpener = 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 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 if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'EADDRINUSE'\n ) {\n // When an explicit redirectUri is set, retrying on a different port\n // is pointless because the OAuth callback will still go to the\n // original port encoded in the redirect URI.\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 lastError = err;\n log(`⚠️ Port ${port} in use, trying ${port + 1}...`);\n continue;\n }\n throw err; // Non-port error — rethrow immediately\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-upymvzHr.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 const candidates =\n process.platform === 'darwin'\n ? [['pbcopy']]\n : process.platform === 'win32'\n ? [['clip']]\n : [\n ['clip.exe'],\n ['xclip', '-selection', 'clipboard'],\n ['xsel', '--clipboard'],\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\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 let browserOpener: (url: string) => Promise<void>;\n if (openBrowser) {\n browserOpener = openBrowser;\n } else {\n // Fallback: try dynamic import of 'open' package\n try {\n const openModule = await import('open');\n const openFn = openModule.default;\n browserOpener = 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 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 if (\n err instanceof Error &&\n 'code' in err &&\n (err as NodeJS.ErrnoException).code === 'EADDRINUSE'\n ) {\n // When an explicit redirectUri is set, retrying on a different port\n // is pointless because the OAuth callback will still go to the\n // original port encoded in the redirect URI.\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 lastError = err;\n log(`⚠️ Port ${port} in use, trying ${port + 1}...`);\n continue;\n }\n throw err; // Non-port error — rethrow immediately\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,6 +1,4 @@
1
- import { r as AuthPlugin } from "./types-C6-wI7SQ.mjs";
2
- //#region src/plugins/service-key.d.ts
1
+ import { r as AuthPlugin } from "./types-DRCpFrpT.mjs";
3
2
  declare const authPlugin: AuthPlugin;
4
- //#endregion
5
3
  export { authPlugin as default };
6
4
  //# sourceMappingURL=service-key.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-key.d.mts","names":[],"sources":["../src/plugins/service-key.ts"],"mappings":";;cAsQM,YAAY"}
1
+ {"version":3,"file":"service-key.d.mts","names":[],"sources":["../src/plugins/service-key.ts"],"mappings":";cAsQM,YAAY"}
@@ -1,3 +1,3 @@
1
- import { t as authPlugin } from "./service-key-2AKKsYxf.mjs";
1
+ import { t as authPlugin } from "./service-key-upymvzHr.mjs";
2
2
 
3
3
  export { authPlugin as default };
@@ -1,4 +1,3 @@
1
- //#region src/types.d.ts
2
1
  /**
3
2
  * Core types for ADT authentication
4
3
  *
@@ -102,6 +101,5 @@ interface ConnectionTestResult {
102
101
  statusCode?: number;
103
102
  responseTime?: number;
104
103
  }
105
- //#endregion
106
104
  export { AuthPluginResult as a, BasicCredentials as c, CookieCredentials as d, Credentials as f, AuthPluginOptions as i, ConnectionTestResult as l, AuthMethod as n, AuthSession as o, AuthPlugin as r, BasicAuthResult as s, AuthConfig as t, CookieAuthResult as u };
107
- //# sourceMappingURL=types-C6-wI7SQ.d.mts.map
105
+ //# sourceMappingURL=types-DRCpFrpT.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-DRCpFrpT.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;KAgBY;;;;UAKK;EACf;EACA;;;;;UAMe;EACf;EACA;;;;;KAMU,cAAc,mBAAmB;;;;;;;;;UAc5B;EACf,QAAQ;EACR;EACA,gBAAgB;EAChB,aAAa;;;;;;;;;;UAeE;EACf;EACA;EACA;EACA,MAAM;;;;;;;;;UAcS;;EAEf,aAAa,SAAS,oBAAoB,QAAQ;;EAGlD,SAAS,SAAS,cAAc,QAAQ;;UAGzB;EACf;EACA;GACC;;;UAIc;EACf;EACA;IACE;IACA,WAAW;;;;UAKE;EACf;EACA;IACE;IACA;;;;KAKQ,mBAAmB,mBAAmB;;;;UASjC;EACf;EACA;EACA;EACA"}
@@ -1,2 +1,2 @@
1
- import { n as resolveServiceKeyFromEnv, t as readServiceKey } from "../env-Co2ABx6K.mjs";
1
+ import { n as resolveServiceKeyFromEnv, t as readServiceKey } from "../env-B1kvodv4.mjs";
2
2
  export { readServiceKey, resolveServiceKeyFromEnv };
@@ -1,7 +1,7 @@
1
- import { t as ServiceKeyParser } from "../service-key-eMRV2aSt.mjs";
1
+ import { t as ServiceKeyParser } from "../service-key-CJYW5WMd.mjs";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
 
4
- //#region src/utils/env.ts
4
+ // src/utils/env.ts
5
5
  /**
6
6
  * Read a BTP service key from a file path.
7
7
  *
@@ -43,6 +43,5 @@ function resolveServiceKeyFromEnv() {
43
43
  };
44
44
  }
45
45
 
46
- //#endregion
47
46
  export { readServiceKey, resolveServiceKeyFromEnv };
48
47
  //# sourceMappingURL=env.mjs.map
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.4.17",
6
+ "version": "0.4.18",
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.16",
24
+ "@abapify/logger": "0.4.17",
25
25
  "proxy-agent": "^6.4.0"
26
26
  },
27
27
  "keywords": [
@@ -1 +0,0 @@
1
- {"version":3,"file":"env-Co2ABx6K.d.mts","names":[],"sources":["../src/storage/file-storage.ts","../src/auth-manager.ts","../src/types/service-key.ts","../src/utils/env.ts"],"mappings":";;cAuBa;mBACM;mBACA;mBACA;EAEL,YAAA;;;;EAcZ,KAAK,SAAS;;;;EASd,KAAK,cAAc;;;;EAoBnB,OAAO;;;;EAUP;;;;EAaA,OAAO;;;;EAWP,cAAc;;;;EASd;;;;EAQA;UAUQ;UAIA;UAMA;UAWA;;;;;;;UCpIO;;EAEf;;EAEA,SAAS;;cAGE;UACH;EAEI,YAAA,UAAU;;;;;;;;;EAgBhB,MAAM,aAAa,aAAa,cAAc,QAAQ;;;;UAgCpD;;;;EA0CR,YAAY,SAAS;;;;EAOrB,WAAW,eAAe;;;;EAW1B,cAAc;;;;EAOd;;;;EAWA,cAAc;;;;EAOd;;;;EAOA;;;;EAWA,UAAU,SAAS;;;;;;EAab,mBACJ,SAAS,aACT;IAAY,OAAO;MAClB,QAAQ;;;;EAyFX,gBAAgB,SAAS;;;;EAWzB,aACE,SAAS;IACN;IAAkB;;;;;UC1SR;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf,KAAK;EACL;EACA;EACA;EACA,WAAW;EACX,UAAU,eAAe;EACzB,SAAS;EACT;;UAYe;EACf;EACA;EACA;;EAEA,eAAe,gBAAgB;;EAE/B;;EAEA;;EAEA;GACC;;;;;;;;;;;;iBCrDa,eAAe,mBAAmB;;;;;;;;;;;iBA6BlC,4BAA4B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-C6-wI7SQ.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;;;KAgBY;;;;UAKK;EACf;EACA;;;;;UAMe;EACf;EACA;;;;;KAMU,cAAc,mBAAmB;;;;;;;;;UAc5B;EACf,QAAQ;EACR;EACA,gBAAgB;EAChB,aAAa;;;;;;;;;;UAeE;EACf;EACA;EACA;EACA,MAAM;;;;;;;;;UAcS;;EAEf,aAAa,SAAS,oBAAoB,QAAQ;;EAGlD,SAAS,SAAS,cAAc,QAAQ;;UAGzB;EACf;EACA;GACC;;;UAIc;EACf;EACA;IACE;IACA,WAAW;;;;UAKE;EACf;EACA;IACE;IACA;;;;KAKQ,mBAAmB,mBAAmB;;;;UASjC;EACf;EACA;EACA;EACA"}