catalyst-relay 0.2.0 → 0.2.2
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/README.md +64 -7
- package/dist/index.d.mts +35 -26
- package/dist/index.d.ts +35 -26
- package/dist/index.js +718 -260
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +715 -260
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/result.ts","../src/core/utils/xml.ts","../src/core/utils/sql.ts","../src/core/utils/csrf.ts","../src/core/utils/headers.ts","../src/core/utils/logging.ts","../src/types/config.ts","../src/core/session/login.ts","../src/core/adt/types.ts","../src/core/adt/helpers.ts","../src/core/adt/read.ts","../src/core/adt/lock.ts","../src/core/adt/create.ts","../src/core/adt/update.ts","../src/core/adt/delete.ts","../src/core/adt/activation.ts","../src/core/adt/tree.ts","../src/core/adt/packages.ts","../src/core/adt/transports.ts","../src/core/adt/queryBuilder.ts","../src/core/adt/previewParser.ts","../src/core/adt/data.ts","../src/core/adt/distinct.ts","../src/core/adt/count.ts","../src/core/adt/searchObjects.ts","../src/core/adt/whereUsed.ts","../src/core/adt/createTransport.ts","../src/core/adt/gitDiff.ts","../src/core/client.ts","../src/core/config.ts"],"sourcesContent":["/**\n * Result type for error handling (Go-style tuples)\n *\n * Usage:\n * const [data, error] = await someFunction();\n * if (error) {\n * console.error(error);\n * return;\n * }\n * // data is guaranteed non-null\n */\n\nexport type Result<T, E = Error> = [T, null] | [null, E];\n\n/**\n * Async result type alias for convenience\n */\nexport type AsyncResult<T, E = Error> = Promise<Result<T, E>>;\n\n/**\n * Create a success result\n */\nexport function ok<T>(value: T): Result<T, never> {\n return [value, null];\n}\n\n/**\n * Create an error result\n */\nexport function err<E = Error>(error: E): Result<never, E> {\n return [null, error];\n}\n","/**\n * XML Parsing Utilities\n *\n * Secure XML parsing and manipulation for ADT responses.\n * Uses @xmldom/xmldom for cross-platform XML parsing.\n */\n\nimport { DOMParser } from '@xmldom/xmldom';\nimport type { Result } from '../../types/result';\nimport { ok, err } from '../../types/result';\n\n/**\n * Securely parse XML string into a Document object (throws on error)\n *\n * @param xmlString - The XML string to parse\n * @returns Parsed XML Document\n * @throws Error if XML is malformed\n * @deprecated Use safeParseXml for Result-based error handling\n */\nexport function parseXml(xmlString: string): Document {\n if (!xmlString || xmlString.trim().length === 0) {\n throw new Error('Empty XML string provided');\n }\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlString, 'text/xml');\n\n // Check for parser errors\n const parseError = doc.getElementsByTagName('parsererror');\n if (parseError.length > 0) {\n const errorNode = parseError[0];\n const errorText = errorNode?.textContent || 'Unknown XML parsing error';\n throw new Error(`XML parsing failed: ${errorText}`);\n }\n\n return doc;\n}\n\n/**\n * Safely parse XML string into a Document object\n *\n * @param xmlString - The XML string to parse\n * @returns Result tuple with Document or Error\n */\nexport function safeParseXml(xmlString: string): Result<Document, Error> {\n // Validate input.\n if (!xmlString || xmlString.trim().length === 0) {\n return err(new Error('Empty XML string provided'));\n }\n\n try {\n // Parse XML string.\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlString, 'text/xml');\n\n // Check for parser errors.\n const parseError = doc.getElementsByTagName('parsererror');\n if (parseError.length > 0) {\n const errorNode = parseError[0];\n const errorText = errorNode?.textContent || 'Unknown XML parsing error';\n return err(new Error(`XML parsing failed: ${errorText}`));\n }\n\n return ok(doc);\n } catch (error) {\n if (error instanceof Error) {\n return err(error);\n }\n return err(new Error('Unknown XML parsing error'));\n }\n}\n\n/**\n * Extract LOCK_HANDLE from ADT XML response\n *\n * @param xml - XML string containing lock handle\n * @returns Result tuple with lock handle or error\n */\nexport function extractLockHandle(xml: string): Result<string, Error> {\n // Validate input.\n if (!xml) {\n return err(new Error('Empty XML provided'));\n }\n\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Find LOCK_HANDLE element.\n const lockHandleElements = doc.getElementsByTagName('LOCK_HANDLE');\n if (lockHandleElements.length === 0) {\n return err(new Error('LOCK_HANDLE element not found in XML'));\n }\n\n // Extract and validate lock handle value.\n const lockHandleElement = lockHandleElements[0];\n const lockHandle = lockHandleElement?.textContent;\n if (!lockHandle || lockHandle.trim().length === 0) {\n return err(new Error('LOCK_HANDLE element is empty'));\n }\n\n return ok(lockHandle.trim());\n}\n\n/**\n * Extract error message from ADT XML error response\n *\n * @param xml - XML string containing error message\n * @returns Error message or default message\n */\nexport function extractError(xml: string): string {\n // Handle empty input.\n if (!xml) {\n return 'No error message found';\n }\n\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) {\n return 'Failed to parse error XML';\n }\n\n // Find message element.\n const messageElements = doc.getElementsByTagName('message');\n if (messageElements.length === 0) {\n return 'No message found';\n }\n\n // Extract message text.\n const messageElement = messageElements[0];\n const message = messageElement?.textContent;\n return message || 'No message found';\n}\n\n/**\n * Escape special XML characters\n *\n * @param str - String to escape\n * @returns XML-safe string\n */\nexport function escapeXml(str: string): string {\n // Handle empty input.\n if (!str) {\n return '';\n }\n\n // Replace special XML characters with entities.\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Convert a dictionary to ABAP-style XML\n *\n * This creates XML in the format expected by SAP ADT endpoints:\n * <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n * <asx:abap xmlns:asx=\"http://www.sap.com/abapxml\" version=\"1.0\">\n * <asx:values>\n * <DATA>\n * <KEY>value</KEY>\n * </DATA>\n * </asx:values>\n * </asx:abap>\n *\n * @param data - Key-value pairs to convert to XML\n * @param root - Root element name (default: \"DATA\")\n * @returns ABAP-formatted XML string\n */\nexport function dictToAbapXml(data: Record<string, string>, root: string = 'DATA'): string {\n // Build inner XML elements from key-value pairs.\n const innerElements = Object.entries(data)\n .map(([key, value]) => {\n if (value) {\n return `<${key}>${escapeXml(value)}</${key}>`;\n }\n return `<${key}/>`;\n })\n .join('\\n ');\n\n // Return complete ABAP XML structure.\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<asx:abap xmlns:asx=\"http://www.sap.com/abapxml\" version=\"1.0\">\n <asx:values>\n <${root}>\n ${innerElements}\n </${root}>\n </asx:values>\n</asx:abap>`;\n}\n","/**\n * SQL Input Validation\n *\n * Protects against SQL injection attacks in data preview queries.\n */\n\nimport type { Result } from '../../types/result';\nimport { ok, err } from '../../types/result';\n\n/**\n * Custom error class for SQL validation failures\n */\nexport class SqlValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SqlValidationError';\n }\n}\n\n/**\n * Validate SQL input to prevent injection attacks\n *\n * Checks for:\n * - Dangerous SQL keywords (DROP, DELETE, INSERT, etc.)\n * - Statement terminators followed by new statements\n * - SQL comments\n * - Procedure execution\n * - Union-based injection\n * - System variables\n * - Excessive special characters\n * - Unbalanced quotes\n *\n * @param input - SQL input string to validate\n * @param maxLength - Maximum allowed length (default: 10000)\n * @returns Result tuple with true on success or SqlValidationError on failure\n *\n * @example\n * const [valid, error] = validateSqlInput(\"SELECT * FROM users WHERE id = 1\");\n * if (error) {\n * console.error('Invalid SQL:', error.message);\n * return;\n * }\n */\nexport function validateSqlInput(\n input: string,\n maxLength: number = 10000\n): Result<true, SqlValidationError> {\n // Verify input is a string type.\n if (typeof input !== 'string') {\n return err(new SqlValidationError('Input must be a string'));\n }\n\n // Enforce maximum input length to prevent resource exhaustion.\n if (input.length > maxLength) {\n return err(new SqlValidationError(`Input exceeds maximum length of ${maxLength}`));\n }\n\n // Define patterns for SQL injection detection.\n const dangerousPatterns: Array<{ pattern: RegExp; description: string }> = [\n {\n pattern: /\\b(DROP|DELETE|INSERT|UPDATE|ALTER|CREATE|TRUNCATE)\\s+/i,\n description: 'DDL/DML keywords (DROP, DELETE, INSERT, etc.)'\n },\n {\n pattern: /;[\\s]*\\w/,\n description: 'Statement termination followed by another statement'\n },\n {\n pattern: /--[\\s]*\\w/,\n description: 'SQL comments with content'\n },\n {\n pattern: /\\/\\*.*?\\*\\//,\n description: 'Block comments'\n },\n {\n pattern: /\\bEXEC(UTE)?\\s*\\(/i,\n description: 'Procedure execution'\n },\n {\n pattern: /\\bSP_\\w+/i,\n description: 'Stored procedures'\n },\n {\n pattern: /\\bXP_\\w+/i,\n description: 'Extended stored procedures'\n },\n {\n pattern: /\\bUNION\\s+(ALL\\s+)?SELECT/i,\n description: 'Union-based injection'\n },\n {\n pattern: /@@\\w+/,\n description: 'System variables'\n },\n {\n pattern: /\\bDECLARE\\s+@/i,\n description: 'Variable declarations'\n },\n {\n pattern: /\\bCAST\\s*\\(/i,\n description: 'Type casting'\n },\n {\n pattern: /\\bCONVERT\\s*\\(/i,\n description: 'Type conversion'\n }\n ];\n\n // Test input against each dangerous pattern.\n for (const { pattern, description } of dangerousPatterns) {\n if (pattern.test(input)) {\n return err(new SqlValidationError(\n `Input contains potentially dangerous SQL pattern: ${description}`\n ));\n }\n }\n\n // Count special characters that could indicate injection attempts.\n const specialCharMatches = input.match(/[;'\"\\\\]/g);\n const specialCharCount = specialCharMatches ? specialCharMatches.length : 0;\n\n // Reject inputs with too many special characters.\n if (specialCharCount > 5) {\n return err(new SqlValidationError('Input contains excessive special characters'));\n }\n\n // Ensure single quotes are balanced.\n const singleQuoteCount = (input.match(/'/g) || []).length;\n if (singleQuoteCount % 2 !== 0) {\n return err(new SqlValidationError('Unbalanced single quotes detected'));\n }\n\n // Ensure double quotes are balanced.\n const doubleQuoteCount = (input.match(/\"/g) || []).length;\n if (doubleQuoteCount % 2 !== 0) {\n return err(new SqlValidationError('Unbalanced double quotes detected'));\n }\n\n return ok(true);\n}\n","/**\n * CSRF Token Constants\n *\n * Constants for CSRF token handling with SAP ADT endpoints.\n */\n\n/**\n * Special value to request a CSRF token from the server\n *\n * When sent in the x-csrf-token header, SAP returns a valid token\n * in the response headers.\n */\nexport const FETCH_CSRF_TOKEN = 'fetch';\n\n/**\n * HTTP header name for CSRF token\n *\n * Used both for requesting tokens (with FETCH_CSRF_TOKEN value)\n * and sending tokens with authenticated requests.\n */\nexport const CSRF_TOKEN_HEADER = 'x-csrf-token';\n","/**\n * HTTP Header Utilities for ADT Requests\n *\n * Provides header building utilities and constants for SAP ADT HTTP requests.\n * Centralizes header management to avoid duplication across client code.\n */\n\nimport { CSRF_TOKEN_HEADER, FETCH_CSRF_TOKEN } from './csrf';\nimport type { AuthConfig } from '../../types/config';\n\n// Mimic Eclipse ADT plugin for compatibility\nexport const BASE_HEADERS = {\n 'X-sap-adt-sessiontype': 'stateful',\n 'User-Agent': 'Eclipse/4.34.0 ADT/3.46.0',\n 'X-sap-adt-profiling': 'server-time',\n} as const;\n\n// Default request timeout in milliseconds\nexport const DEFAULT_TIMEOUT = 30000;\n\n/**\n * Build request headers with auth and CSRF token\n *\n * @param baseHeaders - Base headers to include in all requests\n * @param customHeaders - Request-specific headers\n * @param auth - Authentication config (for basic auth header)\n * @param csrfToken - Current CSRF token (if available)\n * @returns Combined headers object\n */\nexport function buildRequestHeaders(\n baseHeaders: Record<string, string>,\n customHeaders?: Record<string, string>,\n auth?: AuthConfig,\n csrfToken?: string | null\n): Record<string, string> {\n // Merge base and custom headers.\n const headers: Record<string, string> = {\n ...baseHeaders,\n ...(customHeaders ?? {}),\n };\n\n // Add basic auth header if using basic authentication.\n if (auth?.type === 'basic') {\n // Use btoa for base64 encoding (web standard, available in both Node 18+ and Bun)\n const credentials = btoa(`${auth.username}:${auth.password}`);\n headers['Authorization'] = `Basic ${credentials}`;\n }\n\n // Add CSRF token if we have one (but not the 'fetch' placeholder).\n // Don't overwrite if custom headers already set the CSRF token (e.g., for token refresh).\n if (csrfToken && csrfToken !== FETCH_CSRF_TOKEN && !customHeaders?.[CSRF_TOKEN_HEADER]) {\n headers[CSRF_TOKEN_HEADER] = csrfToken;\n }\n\n return headers;\n}\n\n/**\n * Extract CSRF token from response headers\n *\n * SAP returns token in both upper and lowercase variations,\n * so we need to check both.\n *\n * @param headers - Response headers from SAP ADT server\n * @returns Extracted CSRF token or null if not found\n */\nexport function extractCsrfToken(headers: Headers): string | null {\n // Try both upper and lowercase header names.\n const token = headers.get(CSRF_TOKEN_HEADER) ||\n headers.get(CSRF_TOKEN_HEADER.toLowerCase());\n\n // Ignore the fetch token itself.\n if (!token || token === FETCH_CSRF_TOKEN) {\n return null;\n }\n\n return token;\n}\n","/**\r\n * Logging Utility — Debug logging with activation control\r\n *\r\n * Logs are silent by default. Call activateLogging() to enable console output.\r\n */\r\n\r\nlet isActive = false;\r\n\r\n/**\r\n * Enable debug logging to console\r\n */\r\nexport function activateLogging(): void {\r\n isActive = true;\r\n}\r\n\r\n/**\r\n * Disable debug logging (default state)\r\n */\r\nexport function deactivateLogging(): void {\r\n isActive = false;\r\n}\r\n\r\n/**\r\n * Check if logging is currently active\r\n */\r\nexport function isLoggingActive(): boolean {\r\n return isActive;\r\n}\r\n\r\n/**\r\n * Log a debug message (only prints when logging is active)\r\n */\r\nexport function debug(message: string): void {\r\n if (isActive) {\r\n console.log(`[DEBUG] ${message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Log a debug error message (only prints when logging is active)\r\n */\r\nexport function debugError(message: string, cause?: unknown): void {\r\n if (!isActive) return;\r\n\r\n console.error(`[DEBUG] ${message}`);\r\n if (cause !== undefined) {\r\n console.error(`[DEBUG] Cause:`, cause);\r\n }\r\n}\r\n","import { z } from 'zod';\n\n/**\n * Authentication types supported by SAP ADT\n */\nexport type AuthType = 'basic' | 'saml' | 'sso';\n\n/**\n * Basic authentication configuration\n */\nexport interface BasicAuthConfig {\n type: 'basic';\n username: string;\n password: string;\n}\n\n/**\n * SAML authentication configuration\n */\nexport interface SamlAuthConfig {\n type: 'saml';\n username: string;\n password: string;\n provider?: string;\n}\n\n/**\n * SSO (Kerberos) authentication configuration\n */\nexport interface SsoAuthConfig {\n type: 'sso';\n certificate?: string;\n}\n\n/**\n * Union of all auth configurations\n */\nexport type AuthConfig = BasicAuthConfig | SamlAuthConfig | SsoAuthConfig;\n\n/**\n * Client configuration for connecting to SAP ADT\n */\nexport interface ClientConfig {\n /** ADT server URL (e.g., https://server:port) */\n url: string;\n /** SAP client number (e.g., '100') */\n client: string;\n /** Authentication configuration */\n auth: AuthConfig;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n /** Skip SSL verification (dev only) */\n insecure?: boolean;\n}\n\n/**\n * Zod schema for runtime validation of ClientConfig\n */\nexport const clientConfigSchema = z.object({\n url: z.string().url(),\n client: z.string().min(1).max(3),\n auth: z.discriminatedUnion('type', [\n z.object({\n type: z.literal('basic'),\n username: z.string().min(1),\n password: z.string().min(1),\n }),\n z.object({\n type: z.literal('saml'),\n username: z.string().min(1),\n password: z.string().min(1),\n provider: z.string().optional(),\n }),\n z.object({\n type: z.literal('sso'),\n certificate: z.string().optional(),\n }),\n ]),\n timeout: z.number().positive().optional(),\n insecure: z.boolean().optional(),\n});\n","/**\r\n * Session Lifecycle Operations\r\n *\r\n * Internal helpers for login/logout/session reset operations.\r\n * Used by ADTClient to manage session state.\r\n *\r\n * Handles:\r\n * - CSRF token fetching\r\n * - Basic authentication login flow\r\n * - Session reset on 500 errors\r\n * - Logout/cleanup\r\n */\r\n\r\nimport type { AuthConfig } from '../../types/config';\r\nimport type { Session } from './types';\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport {\r\n FETCH_CSRF_TOKEN,\r\n CSRF_TOKEN_HEADER,\r\n extractCsrfToken,\r\n debug,\r\n} from '../utils';\r\n\r\n// Request function type signature (provided by client.ts)\r\ntype RequestFn = (options: {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n params?: Record<string, string | number>;\r\n headers?: Record<string, string>;\r\n body?: string;\r\n}) => AsyncResult<Response, Error>;\r\n\r\n// Session state management (provided by client.ts)\r\nexport interface SessionState {\r\n csrfToken: string | null;\r\n session: Session | null;\r\n config: { auth: AuthConfig };\r\n}\r\n\r\n/**\r\n * Fetch CSRF token from SAP ADT server\r\n *\r\n * Endpoint and content type vary by auth type:\r\n * - SAML: /sap/bc/adt/core/http/sessions\r\n * - Basic/SSO: /sap/bc/adt/compatibility/graph\r\n *\r\n * @param state - Session state to update with new token\r\n * @param request - HTTP request function from client\r\n * @returns CSRF token string or error\r\n */\r\nexport async function fetchCsrfToken(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<string, Error> {\r\n // Select endpoint based on authentication type.\r\n const endpoint = state.config.auth.type === 'saml'\r\n ? '/sap/bc/adt/core/http/sessions'\r\n : '/sap/bc/adt/compatibility/graph';\r\n\r\n // Select content type based on authentication type.\r\n const contentType = state.config.auth.type === 'saml'\r\n ? 'application/vnd.sap.adt.core.http.session.v3+xml'\r\n : 'application/xml';\r\n\r\n // Build request headers with CSRF token fetch flag.\r\n const headers = {\r\n [CSRF_TOKEN_HEADER]: FETCH_CSRF_TOKEN,\r\n 'Content-Type': contentType,\r\n 'Accept': contentType,\r\n };\r\n\r\n // Execute CSRF token request.\r\n const [response, requestErr] = await request({\r\n method: 'GET',\r\n path: endpoint,\r\n headers,\r\n });\r\n\r\n if (requestErr) {\r\n return err(new Error(`Failed to fetch CSRF token: ${requestErr.message}`));\r\n }\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n return err(new Error(`CSRF token fetch failed with status ${response.status}: ${text}`));\r\n }\r\n\r\n // Extract CSRF token from response headers.\r\n const token = extractCsrfToken(response.headers);\r\n debug(`CSRF token from headers: ${token ? token.substring(0, 20) + '...' : 'null'}`);\r\n if (!token) {\r\n // Debug: show all headers\r\n debug('Response headers:');\r\n response.headers.forEach((value, key) => debug(` ${key}: ${value.substring(0, 50)}`));\r\n return err(new Error('No CSRF token returned in response headers'));\r\n }\r\n\r\n // Update session state with new token.\r\n state.csrfToken = token;\r\n debug(`Stored CSRF token in state: ${state.csrfToken?.substring(0, 20)}...`);\r\n\r\n return ok(token);\r\n}\r\n\r\n/**\r\n * Login to SAP ADT server\r\n *\r\n * Currently supports basic authentication only.\r\n * SAML and SSO flows are not yet implemented.\r\n *\r\n * @param state - Session state to update\r\n * @param request - HTTP request function from client\r\n * @returns Session object or error\r\n */\r\nexport async function login(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<Session, Error> {\r\n // Validate authentication type is supported.\r\n if (state.config.auth.type === 'saml') {\r\n return err(new Error('SAML authentication not yet implemented'));\r\n }\r\n\r\n if (state.config.auth.type === 'sso') {\r\n return err(new Error('SSO authentication not yet implemented'));\r\n }\r\n\r\n // Fetch CSRF token from SAP server.\r\n const [token, tokenErr] = await fetchCsrfToken(state, request);\r\n if (tokenErr) {\r\n return err(new Error(`Login failed: ${tokenErr.message}`));\r\n }\r\n\r\n // Extract username from authentication config.\r\n const username = state.config.auth.type === 'basic' ? state.config.auth.username : '';\r\n\r\n // Create session object with 8-hour expiration.\r\n const session: Session = {\r\n sessionId: token,\r\n username,\r\n expiresAt: Date.now() + (8 * 60 * 60 * 1000),\r\n };\r\n\r\n // Update session state.\r\n state.session = session;\r\n\r\n return ok(session);\r\n}\r\n\r\n/**\r\n * Logout from SAP ADT server\r\n *\r\n * Calls the SAP logoff endpoint and clears local state.\r\n *\r\n * @param state - Session state to clear\r\n * @param request - HTTP request function from client\r\n * @returns void or error\r\n */\r\nexport async function logout(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<void, Error> {\r\n // Execute logout request to SAP server.\r\n const [response, requestErr] = await request({\r\n method: 'POST',\r\n path: '/sap/public/bc/icf/logoff',\r\n });\r\n\r\n if (requestErr) {\r\n return err(new Error(`Logout failed: ${requestErr.message}`));\r\n }\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n return err(new Error(`Logout failed with status ${response.status}: ${text}`));\r\n }\r\n\r\n // Clear local session state.\r\n state.csrfToken = null;\r\n state.session = null;\r\n\r\n return ok(undefined);\r\n}\r\n\r\n/**\r\n * Reset session by logging out and back in\r\n *\r\n * Called automatically on 500 errors to recover from session expiration.\r\n *\r\n * @param state - Session state to reset\r\n * @param request - HTTP request function from client\r\n * @returns void or error\r\n */\r\nexport async function sessionReset(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<void, Error> {\r\n // Attempt to logout from current session.\r\n await logout(state, request);\r\n\r\n // Clear session state regardless of logout result.\r\n state.csrfToken = null;\r\n state.session = null;\r\n\r\n // Re-login to establish new session.\r\n const [, loginErr] = await login(state, request);\r\n if (loginErr) {\r\n return err(loginErr);\r\n }\r\n\r\n return ok(undefined);\r\n}\r\n","// ADT Object Type Configuration — metadata for SAP development objects\n\nimport type { AsyncResult } from '../../types/result';\n\n// Client interface for ADT requests\nexport interface AdtRequestor {\n request(options: {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\n path: string;\n params?: Record<string, string | number>;\n headers?: Record<string, string>;\n body?: string;\n }): AsyncResult<Response, Error>;\n}\n\n// Configuration for a specific SAP object type\nexport interface ObjectConfig {\n /** ADT endpoint path (e.g., 'ddic/ddl/sources') */\n endpoint: string;\n /** XML namespace for creation requests */\n nameSpace: string;\n /** Root element name for creation XML */\n rootName: string;\n /** SAP ADT object type identifier (e.g., 'DDLS/DF') */\n type: string;\n /** Human-readable label (e.g., 'View') */\n label: string;\n /** File extension (e.g., 'asddls') */\n extension: string;\n /** Data preview endpoint (if supported) */\n dpEndpoint?: string;\n /** Data preview parameter name (if supported) */\n dpParam?: string;\n}\n\n/**\n * Result of upsert operation\n */\nexport interface UpsertResult {\n name: string;\n extension: string;\n status: 'created' | 'updated' | 'unchanged';\n transport?: string;\n}\n\n/**\n * Supported object types\n */\nexport type ConfiguredExtension = 'asddls' | 'asdcls' | 'astabldt' | 'aclass' | 'asprog';\n\n/**\n * Object type labels\n */\nexport enum ObjectTypeLabel {\n VIEW = 'View',\n ACCESS_CONTROL = 'Access Control',\n TABLE = 'Table',\n CLASS = 'Class',\n PROGRAM = 'ABAP Program',\n}\n\n/**\n * Configuration map for all supported object types\n *\n * Maps file extensions to their ADT configuration.\n * This is the central registry for object type metadata.\n */\nexport const OBJECT_CONFIG_MAP: Record<ConfiguredExtension, ObjectConfig> = {\n 'asddls': {\n endpoint: 'ddic/ddl/sources',\n nameSpace: 'xmlns:ddl=\"http://www.sap.com/adt/ddic/ddlsources\"',\n rootName: 'ddl:ddlSource',\n type: 'DDLS/DF',\n label: ObjectTypeLabel.VIEW,\n extension: 'asddls',\n dpEndpoint: 'cds',\n dpParam: 'ddlSourceName',\n },\n 'asdcls': {\n endpoint: 'acm/dcl/sources',\n nameSpace: 'xmlns:dcl=\"http://www.sap.com/adt/acm/dclsources\"',\n rootName: 'dcl:dclSource',\n type: 'DCLS/DL',\n label: ObjectTypeLabel.ACCESS_CONTROL,\n extension: 'asdcls',\n },\n 'aclass': {\n endpoint: 'oo/classes',\n nameSpace: 'xmlns:class=\"http://www.sap.com/adt/oo/classes\"',\n rootName: 'class:abapClass',\n type: 'CLAS/OC',\n label: ObjectTypeLabel.CLASS,\n extension: 'aclass',\n },\n 'astabldt': {\n endpoint: 'ddic/tables',\n nameSpace: 'xmlns:blue=\"http://www.sap.com/wbobj/blue\"',\n rootName: 'blue:blueSource',\n type: 'TABL/DT',\n label: ObjectTypeLabel.TABLE,\n extension: 'astabldt',\n dpEndpoint: 'ddic',\n dpParam: 'ddicEntityName',\n },\n 'asprog': {\n endpoint: 'programs/programs',\n nameSpace: 'xmlns:program=\"http://www.sap.com/adt/programs/programs\"',\n rootName: 'program:abapProgram',\n type: 'PROG/P',\n label: ObjectTypeLabel.PROGRAM,\n extension: 'asprog',\n },\n};\n\n/**\n * Get object configuration by extension\n *\n * @param extension - File extension (e.g., 'asddls')\n * @returns Configuration or null if not found\n */\nexport function getConfigByExtension(extension: string): ObjectConfig | null {\n return OBJECT_CONFIG_MAP[extension as ConfiguredExtension] ?? null;\n}\n\n/**\n * Get object configuration by ADT type\n *\n * @param type - ADT type identifier (e.g., 'DDLS/DF')\n * @returns Configuration or null if not found\n */\nexport function getConfigByType(type: string): ObjectConfig | null {\n for (const config of Object.values(OBJECT_CONFIG_MAP)) {\n if (config.type === type) {\n return config;\n }\n }\n return null;\n}\n\n/**\n * Get all configured extensions\n *\n * @returns Array of supported extensions\n */\nexport function getAllExtensions(): ConfiguredExtension[] {\n return Object.keys(OBJECT_CONFIG_MAP) as ConfiguredExtension[];\n}\n\n/**\n * Get all configured ADT types\n *\n * @returns Array of supported ADT types\n */\nexport function getAllTypes(): string[] {\n return Object.values(OBJECT_CONFIG_MAP).map(config => config.type);\n}\n\n/**\n * Check if extension is supported\n *\n * @param extension - Extension to check\n * @returns True if supported\n */\nexport function isExtensionSupported(extension: string): extension is ConfiguredExtension {\n return extension in OBJECT_CONFIG_MAP;\n}\n","/**\n * ADT Helpers — shared utilities for ADT operations\n *\n * Internal helpers used across multiple ADT files.\n * Not exported from the adt/ barrel.\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { extractError } from '../utils/xml';\nimport { getConfigByExtension } from './types';\nimport type { ObjectConfig } from './types';\n\n/**\n * Check response for errors and return text content\n */\nexport async function checkResponse(\n response: Response | null,\n requestErr: Error | null,\n operation: string\n): AsyncResult<string, Error> {\n // Handle request errors.\n if (requestErr) return [null, requestErr];\n if (!response) return [null, new Error(`${operation}: No response`)];\n\n // Handle HTTP errors.\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n // Include status and raw text if no message found for debugging\n if (errorMsg === 'No message found' || errorMsg === 'Failed to parse error XML') {\n return [null, new Error(`${operation}: HTTP ${response.status} - ${text.substring(0, 500)}`)];\n }\n return [null, new Error(`${operation}: ${errorMsg}`)];\n }\n\n // Return successful response text.\n return [await response.text(), null];\n}\n\n/**\n * Validate extension and return config\n */\nexport function requireConfig(extension: string): [ObjectConfig, null] | [null, Error] {\n // Lookup configuration for extension.\n const config = getConfigByExtension(extension);\n if (!config) return [null, new Error(`Unsupported extension: ${extension}`)];\n\n // Return valid configuration.\n return [config, null];\n}\n","/**\n * POST /objects/read — Read object source content\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectRef } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { checkResponse, requireConfig } from './helpers';\n\n/**\n * Object metadata\n */\nexport interface ObjectMetadata {\n name: string;\n extension: string;\n package: string;\n description?: string;\n createdBy?: string;\n createdAt?: string;\n modifiedBy?: string;\n modifiedAt?: string;\n}\n\n/**\n * Object with content (read response)\n */\nexport interface ObjectWithContent extends ObjectMetadata {\n content: string;\n}\n\n/**\n * Read object source content\n *\n * @param client - ADT client\n * @param object - Object reference (name + extension)\n * @returns Object with content or error\n */\nexport async function readObject(\n client: AdtRequestor,\n object: ObjectRef\n): AsyncResult<ObjectWithContent, Error> {\n // Validate object extension is supported.\n const [config, configErr] = requireConfig(object.extension);\n if (configErr) return err(configErr);\n\n // Execute GET request for object source content.\n const [response, requestErr] = await client.request({\n method: 'GET',\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\n headers: { 'Accept': 'text/plain' },\n });\n\n // Validate successful response and extract content.\n const [content, checkErr] = await checkResponse(\n response,\n requestErr,\n `Failed to read ${config.label} ${object.name}`\n );\n if (checkErr) return err(checkErr);\n\n // Build result object with content.\n const result: ObjectWithContent = {\n name: object.name,\n extension: object.extension,\n package: '',\n content,\n };\n\n return ok(result);\n}\n","/**\r\n * Lock/Unlock — Object lock management for editing\r\n */\r\n\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { ObjectRef } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport { extractLockHandle } from '../utils/xml';\r\nimport { checkResponse, requireConfig } from './helpers';\r\nimport { debug } from '../utils/logging';\r\n\r\n/**\r\n * Lock an object for editing\r\n *\r\n * @param client - ADT client\r\n * @param object - Object reference (name + extension)\r\n * @returns Lock handle string or error\r\n */\r\nexport async function lockObject(\r\n client: AdtRequestor,\r\n object: ObjectRef\r\n): AsyncResult<string, Error> {\r\n // Validate object extension is supported.\r\n const [config, configErr] = requireConfig(object.extension);\r\n if (configErr) return err(configErr);\r\n\r\n // Execute lock request.\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\r\n params: {\r\n '_action': 'LOCK',\r\n 'accessMode': 'MODIFY',\r\n },\r\n headers: {\r\n 'Accept': 'application/*,application/vnd.sap.as+xml;charset=UTF-8;dataname=com.sap.adt.lock.result',\r\n },\r\n });\r\n\r\n // Validate successful response.\r\n const [text, checkErr] = await checkResponse(\r\n response,\r\n requestErr,\r\n `Failed to lock ${config.label} ${object.name}`\r\n );\r\n if (checkErr) return err(checkErr);\r\n\r\n // Extract lock handle from XML response.\r\n const [lockHandle, extractErr] = extractLockHandle(text);\r\n if (extractErr) {\r\n return err(new Error(`Failed to extract lock handle: ${extractErr.message}`));\r\n }\r\n debug(`Lock acquired: handle=${lockHandle}`);\r\n\r\n return ok(lockHandle);\r\n}\r\n\r\n/**\r\n * Unlock an object after editing\r\n *\r\n * @param client - ADT client\r\n * @param object - Object reference (name + extension)\r\n * @param lockHandle - Lock handle from lockObject()\r\n * @returns void or error\r\n */\r\nexport async function unlockObject(\r\n client: AdtRequestor,\r\n object: ObjectRef,\r\n lockHandle: string\r\n): AsyncResult<void, Error> {\r\n // Validate object extension is supported.\r\n const [config, configErr] = requireConfig(object.extension);\r\n if (configErr) return err(configErr);\r\n\r\n // Execute unlock request.\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\r\n params: {\r\n '_action': 'UNLOCK',\r\n 'lockHandle': lockHandle,\r\n },\r\n });\r\n\r\n // Validate successful response.\r\n const [_, checkErr] = await checkResponse(\r\n response,\r\n requestErr,\r\n `Failed to unlock ${config.label} ${object.name}`\r\n );\r\n if (checkErr) return err(checkErr);\r\n\r\n return ok(undefined);\r\n}\r\n","/**\n * Create — Create new SAP development object\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectContent } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { escapeXml } from '../utils/xml';\nimport { checkResponse, requireConfig } from './helpers';\n\n/**\n * Create a new object in SAP\n *\n * @param client - ADT client\n * @param object - Object with content (name, extension, content, description)\n * @param packageName - Target package\n * @param transport - Transport request (required for non-$TMP packages)\n * @param username - Creating user\n * @returns void or error\n */\nexport async function createObject(\n client: AdtRequestor,\n object: ObjectContent,\n packageName: string,\n transport: string | undefined,\n username: string\n): AsyncResult<void, Error> {\n // Validate object extension is supported.\n const [config, configErr] = requireConfig(object.extension);\n if (configErr) return err(configErr);\n\n // Default empty description if not provided.\n const description = object.description ?? '';\n\n // Build XML request body with object metadata.\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<${config.rootName} ${config.nameSpace}\n xmlns:adtcore=\"http://www.sap.com/adt/core\"\n adtcore:description=\"${escapeXml(description)}\"\n adtcore:language=\"EN\"\n adtcore:name=\"${object.name.toUpperCase()}\"\n adtcore:type=\"${config.type}\"\n adtcore:responsible=\"${username.toUpperCase()}\">\n\n <adtcore:packageRef adtcore:name=\"${packageName}\"/>\n\n</${config.rootName}>`;\n\n // Add transport parameter if provided.\n const params: Record<string, string> = {};\n if (transport) {\n params['corrNr'] = transport;\n }\n\n // Execute create request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: `/sap/bc/adt/${config.endpoint}`,\n params,\n headers: { 'Content-Type': 'application/*' },\n body: body.trim(),\n });\n\n // Validate successful response.\n const [_, checkErr] = await checkResponse(\n response,\n requestErr,\n `Failed to create ${config.label} ${object.name}`\n );\n if (checkErr) return err(checkErr);\n\n return ok(undefined);\n}\n","/**\r\n * Update — Update existing SAP development object\r\n */\r\n\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { ObjectContent } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport { checkResponse, requireConfig } from './helpers';\r\nimport { debug } from '../utils/logging';\r\n\r\n/**\r\n * Update an existing object's source content\r\n *\r\n * @param client - ADT client\r\n * @param object - Object with new content\r\n * @param lockHandle - Lock handle from lockObject()\r\n * @param transport - Transport request (required for non-$TMP packages)\r\n * @returns void or error\r\n */\r\nexport async function updateObject(\r\n client: AdtRequestor,\r\n object: ObjectContent,\r\n lockHandle: string,\r\n transport: string | undefined\r\n): AsyncResult<void, Error> {\r\n // Validate object extension is supported.\r\n const [config, configErr] = requireConfig(object.extension);\r\n if (configErr) return err(configErr);\r\n\r\n // Build request parameters with lock handle.\r\n const params: Record<string, string> = {\r\n 'lockHandle': lockHandle,\r\n };\r\n if (transport) {\r\n params['corrNr'] = transport;\r\n }\r\n\r\n // Execute update request to ADT server.\r\n debug(`Update ${object.name}: content length=${object.content?.length ?? 0}`);\r\n const [response, requestErr] = await client.request({\r\n method: 'PUT',\r\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\r\n params,\r\n headers: { 'Content-Type': '*/*' },\r\n body: object.content,\r\n });\r\n debug(`Update response: ${response?.status ?? 'no response'}, err=${requestErr?.message ?? 'none'}`);\r\n\r\n // Validate successful response.\r\n const [_, checkErr] = await checkResponse(\r\n response,\r\n requestErr,\r\n `Failed to update ${config.label} ${object.name}`\r\n );\r\n if (checkErr) return err(checkErr);\r\n\r\n return ok(undefined);\r\n}\r\n","/**\n * Delete — Delete SAP development object\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectRef } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { checkResponse, requireConfig } from './helpers';\n\n/**\n * Delete an object from SAP\n *\n * @param client - ADT client\n * @param object - Object reference (name + extension)\n * @param lockHandle - Lock handle from lockObject()\n * @param transport - Transport request (required for non-$TMP packages)\n * @returns void or error\n */\nexport async function deleteObject(\n client: AdtRequestor,\n object: ObjectRef,\n lockHandle: string,\n transport: string | undefined\n): AsyncResult<void, Error> {\n // Validate object extension is supported.\n const [config, configErr] = requireConfig(object.extension);\n if (configErr) return err(configErr);\n\n // Build request parameters with lock handle.\n const params: Record<string, string> = {\n 'lockHandle': lockHandle,\n };\n if (transport) {\n params['corrNr'] = transport;\n }\n\n // Execute delete request.\n const [response, requestErr] = await client.request({\n method: 'DELETE',\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\n params,\n headers: { 'Accept': 'text/plain' },\n });\n\n // Validate successful response.\n const [_, checkErr] = await checkResponse(\n response,\n requestErr,\n `Failed to delete ${config.label} ${object.name}`\n );\n if (checkErr) return err(checkErr);\n\n return ok(undefined);\n}\n","// ADT Activation — activate ADT objects\r\n\r\nimport type { Result, AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { ObjectRef } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport { getConfigByExtension } from './types';\r\nimport { extractError, safeParseXml } from '../utils/xml';\r\nimport { debug } from '../utils/logging';\r\n\r\n/**\r\n * Result of activation operation\r\n */\r\nexport interface ActivationResult {\r\n name: string;\r\n extension: string;\r\n status: 'success' | 'warning' | 'error';\r\n messages: ActivationMessage[];\r\n}\r\n\r\nexport interface ActivationMessage {\r\n severity: 'error' | 'warning' | 'info';\r\n text: string;\r\n line?: number;\r\n column?: number;\r\n}\r\n\r\nexport async function activateObjects(\r\n client: AdtRequestor,\r\n objects: ObjectRef[]\r\n): AsyncResult<ActivationResult[], Error> {\r\n // Handle empty input.\r\n if (objects.length === 0) {\r\n return ok([]);\r\n }\r\n\r\n // Validate object extension is supported.\r\n const extension = objects[0]!.extension;\r\n const config = getConfigByExtension(extension);\r\n if (!config) return err(new Error(`Unsupported extension: ${extension}`));\r\n\r\n // Verify all objects have same extension for batch activation.\r\n for (const obj of objects) {\r\n if (obj.extension !== extension) {\r\n return err(new Error('All objects must have the same extension for batch activation'));\r\n }\r\n }\r\n\r\n // Build XML request body with object references.\r\n const objectRefs = objects.map(obj => `<adtcore:objectReference\r\n adtcore:uri=\"/sap/bc/adt/${config.endpoint}/${obj.name.toLowerCase()}\"\r\n adtcore:type=\"${config.type}\"\r\n adtcore:name=\"${obj.name}\"\r\n adtcore:description=\"*\"/>`).join('\\n ');\r\n\r\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n <adtcore:objectReferences xmlns:adtcore=\"http://www.sap.com/adt/core\">\r\n ${objectRefs}\r\n </adtcore:objectReferences>`;\r\n\r\n // Execute activation request.\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: '/sap/bc/adt/activation',\r\n params: {\r\n 'method': 'activate',\r\n 'preAuditRequested': 'true',\r\n },\r\n headers: {\r\n 'Content-Type': 'application/xml',\r\n 'Accept': 'application/xml',\r\n },\r\n body,\r\n });\r\n\r\n // Validate successful response.\r\n if (requestErr) { return err(requestErr); }\r\n const text = await response.text();\r\n debug(`Activation response status: ${response.status}`);\r\n debug(`Activation response: ${text.substring(0, 500)}`);\r\n if (!response.ok) {\r\n const errorMsg = extractError(text);\r\n return err(new Error(`Activation failed: ${errorMsg}`));\r\n }\r\n\r\n // Parse activation results from response.\r\n const [results, parseErr] = extractActivationErrors(objects, text, extension);\r\n if (parseErr) { return err(parseErr); }\r\n return ok(results);\r\n}\r\n\r\n// Parse activation response XML for errors\r\nfunction extractActivationErrors(\r\n objects: ObjectRef[],\r\n xml: string,\r\n _extension: string\r\n): Result<ActivationResult[], Error> {\r\n // Parse XML response.\r\n const [doc, parseErr] = safeParseXml(xml);\r\n if (parseErr) { return err(parseErr); }\r\n\r\n // Initialize error map with empty arrays for each object.\r\n const errorMap: Map<string, ActivationMessage[]> = new Map();\r\n objects.forEach(obj => errorMap.set(obj.name.toLowerCase(), []));\r\n\r\n // Extract message elements and prepare regex for position parsing.\r\n const msgElements = doc.getElementsByTagName('msg');\r\n const startRegex = /#start=(\\d+),(\\d+)/;\r\n\r\n // Process each message element.\r\n for (let i = 0; i < msgElements.length; i++) {\r\n const msg = msgElements[i];\r\n if (!msg) continue;\r\n\r\n // Skip warning messages (type 'W').\r\n const type = msg.getAttribute('type');\r\n if (type === 'W') continue;\r\n\r\n // Extract object description and href for position info.\r\n const objDescr = msg.getAttribute('objDescr');\r\n const href = msg.getAttribute('href');\r\n if (!objDescr || !href) continue;\r\n\r\n // Parse line and column from href.\r\n let line: number | undefined;\r\n let column: number | undefined;\r\n const match = startRegex.exec(href);\r\n if (match && match[1] && match[2]) {\r\n line = parseInt(match[1], 10);\r\n column = parseInt(match[2], 10);\r\n }\r\n if (!line || !column) continue;\r\n\r\n // Find matching object by name.\r\n const matchingObj = objects.find(obj =>\r\n objDescr.toLowerCase().includes(obj.name.toLowerCase())\r\n );\r\n if (!matchingObj) continue;\r\n\r\n // Extract message text elements.\r\n const shortTextElements = msg.getElementsByTagName('txt');\r\n for (let j = 0; j < shortTextElements.length; j++) {\r\n const txt = shortTextElements[j];\r\n if (!txt) continue;\r\n\r\n const text = txt.textContent;\r\n if (!text) continue;\r\n\r\n // Build activation message with severity and position.\r\n const message: ActivationMessage = {\r\n severity: type === 'E' ? 'error' : 'warning',\r\n text,\r\n line,\r\n column,\r\n };\r\n\r\n // Add message to object's error list.\r\n const messages = errorMap.get(matchingObj.name.toLowerCase()) || [];\r\n messages.push(message);\r\n errorMap.set(matchingObj.name.toLowerCase(), messages);\r\n }\r\n }\r\n\r\n // Build final results with status based on message severity.\r\n const results: ActivationResult[] = objects.map(obj => {\r\n const messages = errorMap.get(obj.name.toLowerCase()) || [];\r\n const hasErrors = messages.some(m => m.severity === 'error');\r\n\r\n return {\r\n name: obj.name,\r\n extension: obj.extension,\r\n status: hasErrors ? 'error' : messages.length > 0 ? 'warning' : 'success',\r\n messages,\r\n };\r\n });\r\n\r\n return ok(results);\r\n}\r\n","/**\n * Tree — Hierarchical tree browsing for packages\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { TreeQuery } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { getConfigByType } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Tree node for hierarchical browsing\n */\nexport interface TreeNode {\n name: string;\n type: 'folder' | 'object';\n objectType?: string;\n extension?: string;\n hasChildren?: boolean;\n children?: TreeNode[];\n}\n\n/**\n * Package info\n */\nexport interface Package {\n name: string;\n description?: string;\n parentPackage?: string;\n}\n\n/**\n * Virtual folder for tree discovery (internal)\n */\ninterface VirtualFolder {\n name: string;\n hasChildrenOfSameFacet: boolean;\n count?: string;\n}\n\n/**\n * Tree discovery internal query (internal)\n */\ninterface TreeDiscoveryQuery {\n PACKAGE?: VirtualFolder;\n TYPE?: VirtualFolder;\n GROUP?: VirtualFolder;\n API?: VirtualFolder;\n}\n\n/**\n * Get hierarchical tree of objects\n *\n * @param client - ADT client\n * @param query - Tree query parameters\n * @returns Tree nodes or error\n */\nexport async function getTree(\n client: AdtRequestor,\n query: TreeQuery\n): AsyncResult<TreeNode[], Error> {\n // Build internal query with package filter.\n const internalQuery: TreeDiscoveryQuery = {};\n if (query.package) {\n internalQuery.PACKAGE = {\n name: query.package.startsWith('..') ? query.package : `..${query.package}`,\n hasChildrenOfSameFacet: false,\n };\n }\n\n // Execute tree discovery and return nodes.\n const [result, resultErr] = await getTreeInternal(client, internalQuery, '*');\n if (resultErr) { return err(resultErr); }\n return ok(result.nodes);\n}\n\n/**\n * Internal tree discovery with full options\n *\n * Exported for use by packages.ts\n */\nexport async function getTreeInternal(\n client: AdtRequestor,\n query: TreeDiscoveryQuery,\n searchPattern: string\n): AsyncResult<{ nodes: TreeNode[]; packages: Package[] }, Error> {\n // Build XML request body.\n const body = constructTreeBody(query, searchPattern);\n\n // Execute virtual folders request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/repository/informationsystem/virtualfolders/contents',\n headers: {\n 'Content-Type': 'application/vnd.sap.adt.repository.virtualfolders.request.v1+xml',\n 'Accept': 'application/vnd.sap.adt.repository.virtualfolders.result.v1+xml',\n },\n body,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Tree discovery failed: ${errorMsg}`));\n }\n\n // Parse tree response.\n const text = await response.text();\n const [result, parseErr] = parseTreeResponse(text);\n if (parseErr) { return err(parseErr); }\n return ok(result);\n}\n\n// Construct tree discovery request body.\nfunction constructTreeBody(query: TreeDiscoveryQuery, searchPattern: string): string {\n // Determine which facets are specified vs requested.\n const facets: string[] = [];\n const specified: Record<string, string> = {};\n const sortedFacets = ['PACKAGE', 'GROUP', 'TYPE', 'API'];\n\n for (const facet of sortedFacets) {\n const value = query[facet as keyof TreeDiscoveryQuery];\n if (value) {\n specified[facet] = value.name;\n if (!value.hasChildrenOfSameFacet) {\n facets.push(facet);\n }\n } else {\n facets.push(facet);\n }\n }\n\n // Build XML elements for specified facets using preselection structure.\n const specifiedXml = Object.entries(specified)\n .map(([facet, name]) => ` <vfs:preselection facet=\"${facet.toLowerCase()}\">\n <vfs:value>${name}</vfs:value>\n </vfs:preselection>`)\n .join('\\n');\n\n // Build XML elements for requested facets (lowercase).\n const facetsXml = facets\n .map(facet => ` <vfs:facet>${facet.toLowerCase()}</vfs:facet>`)\n .join('\\n');\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vfs:virtualFoldersRequest xmlns:vfs=\"http://www.sap.com/adt/ris/virtualFolders\" objectSearchPattern=\"${searchPattern}\">\n${specifiedXml}\n <vfs:facetorder>\n${facetsXml}\n </vfs:facetorder>\n</vfs:virtualFoldersRequest>`;\n}\n\n// Parse tree discovery response.\nfunction parseTreeResponse(xml: string): Result<{ nodes: TreeNode[]; packages: Package[] }, Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n const nodes: TreeNode[] = [];\n const packages: Package[] = [];\n\n // Process virtual folder elements (packages, groups, etc).\n const virtualFolders = doc.getElementsByTagName('vfs:virtualFolder');\n for (let i = 0; i < virtualFolders.length; i++) {\n const vf = virtualFolders[i];\n if (!vf) continue;\n\n const facet = vf.getAttribute('facet');\n const name = vf.getAttribute('name');\n\n // Extract package metadata if this is a package facet.\n if (facet === 'PACKAGE' && name) {\n const desc = vf.getAttribute('description');\n const pkg: Package = {\n name: name.startsWith('..') ? name.substring(2) : name,\n };\n if (desc) {\n pkg.description = desc;\n }\n packages.push(pkg);\n }\n\n if (!name || !facet) continue;\n\n // Add folder node (strip '..' prefix from name).\n nodes.push({\n name: name.startsWith('..') ? name.substring(2) : name,\n type: 'folder',\n hasChildren: vf.getAttribute('hasChildrenOfSameFacet') === 'true',\n });\n }\n\n // Process object elements (actual ADT objects).\n const objects = doc.getElementsByTagName('vfs:object');\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n if (!obj) continue;\n\n const name = obj.getAttribute('name');\n const type = obj.getAttribute('type');\n if (!name || !type) continue;\n\n // Look up object type configuration.\n const config = getConfigByType(type);\n if (!config) continue;\n\n nodes.push({\n name,\n type: 'object',\n objectType: config.label,\n extension: config.extension,\n });\n }\n\n return ok({ nodes, packages });\n}\n","/**\n * Packages — List available packages\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport type { Package } from './tree';\nimport { getTreeInternal } from './tree';\n\n/**\n * Get list of available packages\n *\n * @param client - ADT client\n * @returns Array of packages or error\n */\nexport async function getPackages(\n client: AdtRequestor\n): AsyncResult<Package[], Error> {\n // Fetch tree with all packages using wildcard filter.\n const [treeResult, treeErr] = await getTreeInternal(client, {}, '*');\n\n // Validate successful tree retrieval.\n if (treeErr) {\n return err(treeErr);\n }\n\n // Extract packages from tree result.\n return ok(treeResult.packages);\n}\n","/**\n * Transports — List transport requests for a package\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\n\n/**\n * Transport request\n */\nexport interface Transport {\n id: string;\n description: string;\n owner: string;\n status: 'modifiable' | 'released';\n}\n\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Get transports for a package\n *\n * @param client - ADT client\n * @param packageName - Package name\n * @returns Array of transports or error\n */\nexport async function getTransports(\n client: AdtRequestor,\n packageName: string\n): AsyncResult<Transport[], Error> {\n // Build XML request body for transport check.\n const contentType = 'application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData';\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <asx:abap version=\"1.0\" xmlns:asx=\"http://www.sap.com/abapxml\">\n <asx:values>\n <DATA>\n <PGMID></PGMID>\n <OBJECT></OBJECT>\n <OBJECTNAME></OBJECTNAME>\n <DEVCLASS>${packageName}</DEVCLASS>\n <SUPER_PACKAGE></SUPER_PACKAGE>\n <OPERATION>I</OPERATION>\n <URI>/sap/bc/adt/ddic/ddl/sources/transport_check</URI>\n </DATA>\n </asx:values>\n </asx:abap>`;\n\n // Execute transport check request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/cts/transportchecks',\n headers: {\n 'Accept': contentType,\n 'Content-Type': contentType,\n },\n body,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Failed to fetch transports for ${packageName}: ${errorMsg}`));\n }\n\n // Parse transports from response.\n const text = await response.text();\n const [transports, parseErr] = extractTransports(text);\n if (parseErr) { return err(parseErr); }\n return ok(transports);\n}\n\n// Extract transports from XML response.\nfunction extractTransports(xml: string): Result<Transport[], Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Extract transport headers from response.\n const transports: Transport[] = [];\n const reqHeaders = doc.getElementsByTagName('REQ_HEADER');\n\n // Process each transport header.\n for (let i = 0; i < reqHeaders.length; i++) {\n const header = reqHeaders[i];\n if (!header) continue;\n\n // Extract transport metadata elements.\n const trkorrElement = header.getElementsByTagName('TRKORR')[0];\n const userElement = header.getElementsByTagName('AS4USER')[0];\n const textElement = header.getElementsByTagName('AS4TEXT')[0];\n if (!trkorrElement || !userElement || !textElement) continue;\n\n // Extract text content from elements.\n const id = trkorrElement.textContent;\n const owner = userElement.textContent;\n const description = textElement.textContent;\n if (!id || !owner || !description) continue;\n\n // Build transport object.\n transports.push({\n id,\n owner,\n description,\n status: 'modifiable',\n });\n }\n\n return ok(transports);\n}\n","// SQL Query Builder — construct safe SQL queries for ADT data preview\n\nimport type { Filter, OrderBy } from '../../types/requests';\n\n// Quote SQL identifier to prevent injection\nexport function quoteIdentifier(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\nexport function buildWhereClauses(filters: Filter[] | undefined): string {\n // Handle empty or undefined filters.\n if (!filters || filters.length === 0) {\n return '';\n }\n\n // Build individual filter conditions.\n const clauses = filters.map(filter => {\n const { column, operator, value } = filter;\n\n // Map operator to SQL syntax.\n switch (operator) {\n case 'eq':\n return `${column} = ${formatValue(value)}`;\n case 'ne':\n return `${column} != ${formatValue(value)}`;\n case 'gt':\n return `${column} > ${formatValue(value)}`;\n case 'ge':\n return `${column} >= ${formatValue(value)}`;\n case 'lt':\n return `${column} < ${formatValue(value)}`;\n case 'le':\n return `${column} <= ${formatValue(value)}`;\n case 'like':\n return `${column} LIKE ${formatValue(value)}`;\n case 'in':\n // Handle array values for IN operator.\n if (Array.isArray(value)) {\n const values = value.map(v => formatValue(v)).join(', ');\n return `${column} IN (${values})`;\n }\n return `${column} IN (${formatValue(value)})`;\n default:\n return '';\n }\n }).filter(c => c);\n\n // Return empty string if no valid clauses.\n if (clauses.length === 0) {\n return '';\n }\n\n // Join clauses with AND.\n return ` WHERE ${clauses.join(' AND ')}`;\n}\n\nexport function buildOrderByClauses(orderBy: OrderBy[] | undefined): string {\n // Handle empty or undefined order by.\n if (!orderBy || orderBy.length === 0) {\n return '';\n }\n\n // Build order by clauses with direction.\n const clauses = orderBy.map(o => `${o.column} ${o.direction.toUpperCase()}`);\n return ` ORDER BY ${clauses.join(', ')}`;\n}\n\nexport function formatValue(value: unknown): string {\n // Handle null values.\n if (value === null) {\n return 'NULL';\n }\n\n // Escape and quote strings.\n if (typeof value === 'string') {\n return `'${value.replace(/'/g, \"''\")}'`;\n }\n\n // Convert booleans to 1 or 0.\n if (typeof value === 'boolean') {\n return value ? '1' : '0';\n }\n\n // Convert other types to string.\n return String(value);\n}\n","/**\n * Preview Parser — Parse data preview XML responses\n *\n * Internal helper used by data.ts, distinct.ts, and count.ts\n */\n\nimport type { Result } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport { safeParseXml } from '../utils/xml';\n\n/**\n * Data preview result (columnar format)\n */\nexport interface DataFrame {\n columns: ColumnInfo[];\n rows: unknown[][];\n totalRows?: number;\n}\n\nexport interface ColumnInfo {\n name: string;\n dataType: string;\n label?: string;\n}\n\n/**\n * Parse data preview XML response\n *\n * @param xml - XML response from SAP\n * @param maxRows - Maximum rows to parse\n * @param isTable - Whether source is a table (affects column name attribute)\n * @returns DataFrame or error\n */\nexport function parseDataPreview(\n xml: string,\n maxRows: number,\n isTable: boolean\n): Result<DataFrame, Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n const namespace = 'http://www.sap.com/adt/dataPreview';\n\n // Extract column metadata from response.\n const metadataElements = doc.getElementsByTagNameNS(namespace, 'metadata');\n const columns: ColumnInfo[] = [];\n\n for (let i = 0; i < metadataElements.length; i++) {\n const meta = metadataElements[i];\n if (!meta) continue;\n\n // Tables use 'name', views use 'camelCaseName'.\n const nameAttr = isTable ? 'name' : 'camelCaseName';\n const name = meta.getAttributeNS(namespace, nameAttr) || meta.getAttribute('name');\n const dataType = meta.getAttributeNS(namespace, 'colType') || meta.getAttribute('colType');\n if (!name || !dataType) continue;\n\n columns.push({ name, dataType });\n }\n\n // Validate columns were found.\n if (columns.length === 0) {\n return err(new Error('No columns found in preview response'));\n }\n\n // Extract data values organized by column.\n const dataSetElements = doc.getElementsByTagNameNS(namespace, 'dataSet');\n const columnData: string[][] = Array.from({ length: columns.length }, () => []);\n\n for (let i = 0; i < dataSetElements.length; i++) {\n const dataSet = dataSetElements[i];\n if (!dataSet) continue;\n\n const dataElements = dataSet.getElementsByTagNameNS(namespace, 'data');\n for (let j = 0; j < dataElements.length; j++) {\n const data = dataElements[j];\n if (!data) continue;\n\n const value = data.textContent?.trim() || '';\n columnData[i]!.push(value);\n }\n }\n\n // Transform column-oriented data into row-oriented format.\n const rows: unknown[][] = [];\n const rowCount = columnData[0]?.length || 0;\n for (let i = 0; i < Math.min(rowCount, maxRows); i++) {\n const row: unknown[] = [];\n for (let j = 0; j < columns.length; j++) {\n row.push(columnData[j]![i]);\n }\n rows.push(row);\n }\n\n // Build final DataFrame result.\n const dataFrame: DataFrame = {\n columns,\n rows,\n totalRows: rowCount,\n };\n\n return ok(dataFrame);\n}\n","/**\r\n * Data Preview — Query table/view data\r\n */\r\n\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { PreviewQuery } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport type { DataFrame } from './previewParser';\r\nimport { getConfigByExtension } from './types';\r\nimport { extractError } from '../utils/xml';\r\nimport { validateSqlInput } from '../utils/sql';\r\nimport { debug } from '../utils/logging';\r\nimport { buildWhereClauses, buildOrderByClauses } from './queryBuilder';\r\nimport { parseDataPreview } from './previewParser';\r\n\r\n/**\r\n * Preview table/view data with filters and sorting\r\n *\r\n * @param client - ADT client\r\n * @param query - Preview query parameters\r\n * @returns DataFrame or error\r\n */\r\nexport async function previewData(\r\n client: AdtRequestor,\r\n query: PreviewQuery\r\n): AsyncResult<DataFrame, Error> {\r\n // Confirm object is valid for data previews.\r\n const extension = query.objectType === 'table' ? 'astabldt' : 'asddls';\r\n const config = getConfigByExtension(extension);\r\n if (!config || !config.dpEndpoint || !config.dpParam) {\r\n return err(new Error(`Data preview not supported for object type: ${query.objectType}`));\r\n }\r\n\r\n // Construct SQL query for data preview\r\n const limit = query.limit ?? 100;\r\n\r\n const whereClauses = buildWhereClauses(query.filters);\r\n const orderByClauses = buildOrderByClauses(query.orderBy);\r\n // SAP SQL doesn't use quoted identifiers for object names\r\n const sqlQuery = `select * from ${query.objectName}${whereClauses}${orderByClauses}`;\r\n\r\n const [, validationErr] = validateSqlInput(sqlQuery);\r\n if (validationErr) {\r\n return err(new Error(`SQL validation failed: ${validationErr.message}`));\r\n }\r\n\r\n // Execute data preview request.\r\n debug(`Data preview: endpoint=${config.dpEndpoint}, param=${config.dpParam}=${query.objectName}`);\r\n debug(`SQL: ${sqlQuery}`);\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: `/sap/bc/adt/datapreview/${config.dpEndpoint}`,\r\n params: {\r\n 'rowNumber': limit,\r\n [config.dpParam]: query.objectName,\r\n },\r\n headers: {\r\n 'Accept': 'application/vnd.sap.adt.datapreview.table.v1+xml',\r\n 'Content-Type': 'text/plain',\r\n },\r\n body: sqlQuery,\r\n });\r\n\r\n // Validate successful response.\r\n if (requestErr) { return err(requestErr); }\r\n if (!response.ok) {\r\n const text = await response.text();\r\n debug(`Data preview error response: ${text.substring(0, 500)}`);\r\n const errorMsg = extractError(text);\r\n return err(new Error(`Data preview failed: ${errorMsg}`));\r\n }\r\n const text = await response.text();\r\n\r\n // Confirm successful dataframe format\r\n const [dataFrame, parseErr] = parseDataPreview(text, limit, query.objectType === 'table');\r\n if (parseErr) { return err(parseErr); }\r\n return ok(dataFrame);\r\n}\r\n","/**\n * Distinct Values — Get distinct column values with counts\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\n\n/**\n * Distinct values result\n */\nexport interface DistinctResult {\n column: string;\n values: Array<{\n value: unknown;\n count: number;\n }>;\n}\n\nimport { getConfigByExtension } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\nimport { validateSqlInput } from '../utils/sql';\n\nconst MAX_ROW_COUNT = 50000;\n\n/**\n * Get distinct values for a column with counts\n *\n * @param client - ADT client\n * @param objectName - Table or view name\n * @param column - Column name\n * @param objectType - 'table' or 'view'\n * @returns Distinct values with counts or error\n */\nexport async function getDistinctValues(\n client: AdtRequestor,\n objectName: string,\n column: string,\n objectType: 'table' | 'view' = 'view'\n): AsyncResult<DistinctResult, Error> {\n // Determine endpoint configuration based on object type.\n const extension = objectType === 'table' ? 'astabldt' : 'asddls';\n const config = getConfigByExtension(extension);\n\n // Validate object type supports data preview operations.\n if (!config || !config.dpEndpoint || !config.dpParam) {\n return err(new Error(`Data preview not supported for object type: ${objectType}`));\n }\n\n // Construct SQL query for distinct values with counts.\n // SAP ADT data preview uses ABAP Open SQL which does not support quoted identifiers.\n const columnName = column.toUpperCase();\n const sqlQuery = `SELECT ${columnName} AS value, COUNT(*) AS count FROM ${objectName} GROUP BY ${columnName}`;\n\n // Validate SQL query for injection risks.\n const [, validationErr] = validateSqlInput(sqlQuery);\n if (validationErr) {\n return err(new Error(`SQL validation failed: ${validationErr.message}`));\n }\n\n // Execute distinct values request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: `/sap/bc/adt/datapreview/${config.dpEndpoint}`,\n params: {\n 'rowNumber': MAX_ROW_COUNT,\n [config.dpParam]: objectName,\n },\n headers: {\n 'Accept': 'application/vnd.sap.adt.datapreview.table.v1+xml',\n },\n body: sqlQuery,\n });\n\n // Validate successful response.\n if (requestErr) {\n return err(requestErr);\n }\n\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Distinct values query failed: ${errorMsg}`));\n }\n\n // Parse XML response to extract distinct values directly.\n // GROUP BY queries return simpler structure without full column metadata.\n const text = await response.text();\n const [doc, parseErr] = safeParseXml(text);\n if (parseErr) {\n return err(parseErr);\n }\n\n // Extract data from dataPreview:dataSet elements.\n // Each dataSet contains two data elements: value and count.\n const dataSets = doc.getElementsByTagNameNS('http://www.sap.com/adt/dataPreview', 'dataSet');\n const values: Array<{ value: unknown; count: number }> = [];\n\n for (let i = 0; i < dataSets.length; i++) {\n const dataSet = dataSets[i];\n if (!dataSet) continue;\n\n const dataElements = dataSet.getElementsByTagNameNS('http://www.sap.com/adt/dataPreview', 'data');\n if (dataElements.length < 2) continue;\n\n const value = dataElements[0]?.textContent ?? '';\n const countText = dataElements[1]?.textContent?.trim() ?? '0';\n values.push({\n value,\n count: parseInt(countText, 10),\n });\n }\n\n const result: DistinctResult = {\n column,\n values,\n };\n\n return ok(result);\n}\n","/**\n * Count Rows — Get total row count for table/view\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport { getConfigByExtension } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\nimport { validateSqlInput } from '../utils/sql';\n\n/**\n * Count total rows in a table or view\n *\n * @param client - ADT client\n * @param objectName - Table or view name\n * @param objectType - 'table' or 'view'\n * @returns Row count or error\n */\nexport async function countRows(\n client: AdtRequestor,\n objectName: string,\n objectType: 'table' | 'view'\n): AsyncResult<number, Error> {\n // Determine endpoint configuration based on object type.\n const extension = objectType === 'table' ? 'astabldt' : 'asddls';\n const config = getConfigByExtension(extension);\n\n // Validate object type supports data preview.\n if (!config || !config.dpEndpoint || !config.dpParam) {\n return err(new Error(`Data preview not supported for object type: ${objectType}`));\n }\n\n // Build SQL query to count rows.\n // SAP ADT data preview uses ABAP Open SQL which does not support quoted identifiers.\n const sqlQuery = `SELECT COUNT(*) AS count FROM ${objectName}`;\n\n // Validate SQL query for safety.\n const [, validationErr] = validateSqlInput(sqlQuery);\n if (validationErr) {\n return err(new Error(`SQL validation failed: ${validationErr.message}`));\n }\n\n // Execute count query request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: `/sap/bc/adt/datapreview/${config.dpEndpoint}`,\n params: {\n 'rowNumber': 1,\n [config.dpParam]: objectName,\n },\n headers: {\n 'Accept': 'application/vnd.sap.adt.datapreview.table.v1+xml',\n },\n body: sqlQuery,\n });\n\n // Validate successful request.\n if (requestErr) {\n return err(requestErr);\n }\n\n // Validate successful response.\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Row count query failed: ${errorMsg}`));\n }\n\n // Parse XML response to extract count value directly.\n // COUNT responses have simpler structure without column metadata.\n const text = await response.text();\n const [doc, parseErr] = safeParseXml(text);\n if (parseErr) {\n return err(parseErr);\n }\n\n // Extract count from dataPreview:data elements.\n const dataElements = doc.getElementsByTagNameNS('http://www.sap.com/adt/dataPreview', 'data');\n if (dataElements.length === 0) {\n return err(new Error('No count value returned'));\n }\n\n // Get the first data element's text content (the count value).\n const countText = dataElements[0]?.textContent?.trim();\n if (!countText) {\n return err(new Error('Empty count value returned'));\n }\n\n // Parse and validate count as integer.\n const count = parseInt(countText, 10);\n if (isNaN(count)) {\n return err(new Error('Invalid count value returned'));\n }\n\n return ok(count);\n}\n","/**\n * Search Objects — Quick search by name pattern\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\n\n/**\n * Search result\n */\nexport interface SearchResult {\n name: string;\n extension: string;\n package: string;\n description?: string;\n objectType: string;\n}\n\nimport { getConfigByType, getAllTypes } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Search for objects by name pattern\n *\n * @param client - ADT client\n * @param query - Search pattern (supports wildcards)\n * @param types - Optional array of object type filters\n * @returns Array of matching objects or error\n */\nexport async function searchObjects(\n client: AdtRequestor,\n query: string,\n types?: string[]\n): AsyncResult<SearchResult[], Error> {\n // Build search parameters.\n const searchPattern = query || '*';\n const objectTypes = types && types.length > 0 ? types : getAllTypes();\n\n // Construct query parameters (matching Python reference exactly).\n const params: Array<[string, string]> = [\n ['operation', 'quickSearch'],\n ['query', searchPattern],\n ['maxResults', '10001'],\n ];\n for (const type of objectTypes) {\n params.push(['objectType', type]);\n }\n\n // Build URL search params.\n const urlParams = new URLSearchParams();\n for (const [key, value] of params) {\n urlParams.append(key, value);\n }\n\n // Execute search request.\n const [response, requestErr] = await client.request({\n method: 'GET',\n path: `/sap/bc/adt/repository/informationsystem/search?${urlParams.toString()}`,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Search failed: ${errorMsg}`));\n }\n\n // Parse search results from response.\n const text = await response.text();\n const [results, parseErr] = parseSearchResults(text);\n if (parseErr) { return err(parseErr); }\n return ok(results);\n}\n\n// Parse search results from XML.\nfunction parseSearchResults(xml: string): Result<SearchResult[], Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Extract object reference elements.\n const results: SearchResult[] = [];\n const objectRefs = doc.getElementsByTagNameNS('http://www.sap.com/adt/core', 'objectReference');\n\n // Process each object reference.\n for (let i = 0; i < objectRefs.length; i++) {\n const obj = objectRefs[i];\n if (!obj) continue;\n\n // Extract object metadata.\n const name = obj.getAttributeNS('http://www.sap.com/adt/core', 'name') || obj.getAttribute('adtcore:name');\n const type = obj.getAttributeNS('http://www.sap.com/adt/core', 'type') || obj.getAttribute('adtcore:type');\n const description = obj.getAttributeNS('http://www.sap.com/adt/core', 'description') || obj.getAttribute('adtcore:description');\n if (!name || !type) continue;\n\n // Look up object type configuration.\n const config = getConfigByType(type);\n if (!config) continue;\n\n // Extract package reference if available.\n const packageRef = obj.getElementsByTagNameNS('http://www.sap.com/adt/core', 'packageRef')[0];\n const packageName = packageRef\n ? (packageRef.getAttributeNS('http://www.sap.com/adt/core', 'name') || packageRef.getAttribute('adtcore:name'))\n : '';\n\n // Build search result object.\n const result: SearchResult = {\n name,\n extension: config.extension,\n package: packageName || '',\n objectType: config.label,\n };\n if (description) {\n result.description = description;\n }\n results.push(result);\n }\n\n return ok(results);\n}\n","/**\n * Where-Used — Find object dependencies\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectRef } from '../../types/requests';\nimport type { AdtRequestor } from './types';\n\n/**\n * Where-used dependency\n */\nexport interface Dependency {\n name: string;\n extension: string;\n package: string;\n usageType: string;\n}\n\nimport { getConfigByType, getConfigByExtension } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Find where an object is used (dependencies)\n *\n * @param client - ADT client\n * @param object - Object to analyze\n * @returns Array of dependent objects or error\n */\nexport async function findWhereUsed(\n client: AdtRequestor,\n object: ObjectRef\n): AsyncResult<Dependency[], Error> {\n // Validate object extension is supported.\n const config = getConfigByExtension(object.extension);\n if (!config) {\n return err(new Error(`Unsupported extension: ${object.extension}`));\n }\n\n // Build object URI and request body.\n const uri = `/sap/bc/adt/${config.endpoint}/${object.name}`;\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <usagereferences:usageReferenceRequest xmlns:usagereferences=\"http://www.sap.com/adt/ris/usageReferences\">\n <usagereferences:affectedObjects/>\n </usagereferences:usageReferenceRequest>`;\n\n // Execute where-used query.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/repository/informationsystem/usageReferences',\n params: {\n 'uri': uri,\n 'ris_request_type': 'usageReferences',\n },\n headers: {\n 'Content-Type': 'application/vnd.sap.adt.repository.usagereferences.request.v1+xml',\n 'Accept': 'application/vnd.sap.adt.repository.usagereferences.result.v1+xml',\n },\n body,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Where-used query failed: ${errorMsg}`));\n }\n\n // Parse dependencies from response.\n const text = await response.text();\n const [dependencies, parseErr] = parseWhereUsed(text);\n if (parseErr) { return err(parseErr); }\n return ok(dependencies);\n}\n\n// Parse where-used results from XML.\nfunction parseWhereUsed(xml: string): Result<Dependency[], Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Extract referenced object elements.\n const dependencies: Dependency[] = [];\n const referencedObjects = doc.getElementsByTagNameNS(\n 'http://www.sap.com/adt/ris/usageReferences',\n 'referencedObject'\n );\n\n // Process each referenced object.\n for (let i = 0; i < referencedObjects.length; i++) {\n const refObj = referencedObjects[i];\n if (!refObj) continue;\n\n // Extract ADT object element.\n const adtObject = refObj.getElementsByTagNameNS(\n 'http://www.sap.com/adt/ris/usageReferences',\n 'adtObject'\n )[0];\n if (!adtObject) continue;\n\n // Extract object name and type.\n const name = adtObject.getAttributeNS('http://www.sap.com/adt/core', 'name') || adtObject.getAttribute('adtcore:name');\n const type = adtObject.getAttributeNS('http://www.sap.com/adt/core', 'type') || adtObject.getAttribute('adtcore:type');\n if (!name || !type) continue;\n\n // Look up object type configuration.\n const config = getConfigByType(type);\n if (!config) continue;\n\n // Extract package reference if available.\n const packageRef = adtObject.getElementsByTagNameNS('http://www.sap.com/adt/core', 'packageRef')[0];\n const packageName = packageRef\n ? (packageRef.getAttributeNS('http://www.sap.com/adt/core', 'name') || packageRef.getAttribute('adtcore:name'))\n : '';\n\n // Build dependency object.\n dependencies.push({\n name,\n extension: config.extension,\n package: packageName || '',\n usageType: 'reference',\n });\n }\n\n return ok(dependencies);\n}\n","/**\n * Create Transport — Create a new transport request for a package\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport { dictToAbapXml, extractError } from '../utils/xml';\n\n/**\n * Configuration for creating a transport\n */\nexport interface TransportConfig {\n /** Package name (DEVCLASS) */\n package: string;\n /** Transport description/text */\n description: string;\n}\n\n/**\n * Create a new transport request\n *\n * @param client - ADT client\n * @param config - Transport configuration\n * @returns Transport ID or error\n */\nexport async function createTransport(\n client: AdtRequestor,\n config: TransportConfig\n): AsyncResult<string, Error> {\n // Build XML request body.\n const body = dictToAbapXml({\n DEVCLASS: config.package,\n REQUEST_TEXT: config.description,\n REF: '',\n OPERATION: 'I',\n });\n\n // Execute transport creation request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/cts/transports',\n headers: {\n 'Content-Type': 'application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.CreateCorrectionRequest',\n 'Accept': 'text/plain',\n },\n body,\n });\n\n // Validate response.\n if (requestErr) return err(requestErr);\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Failed to create transport for ${config.package}: ${errorMsg}`));\n }\n\n // Extract transport ID from response.\n const text = await response.text();\n const transportId = text.trim().split('/').pop();\n\n if (!transportId) {\n return err(new Error('Failed to parse transport ID from response'));\n }\n\n return ok(transportId);\n}\n","/**\n * Git Diff — Compare local content with server content\n *\n * Uses Myers diff algorithm to compute line-by-line differences.\n */\n\nimport { diffArrays, type ChangeObject } from 'diff';\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport type { ObjectContent } from '../../types/requests';\nimport { readObject } from './read';\nimport { getConfigByExtension } from './types';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types (colocated - only used by this function)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Base fields for all diff hunks */\ninterface BaseDiffHunk {\n /** Total number of lines in the hunk */\n length: number;\n /** Starting line in the diff output (0-indexed) */\n diffStart: number;\n /** Starting line in the local file (0-indexed) */\n localStart: number;\n}\n\n/** Addition or deletion hunk */\nexport interface SimpleDiffHunk extends BaseDiffHunk {\n type: 'addition' | 'deletion';\n /** Lines added or removed */\n changes: string[];\n}\n\n/** Modification hunk (deletion immediately followed by addition) */\nexport interface ModifiedDiffHunk extends BaseDiffHunk {\n type: 'modification';\n /** Tuple of [server_lines, local_lines] */\n changes: [string[], string[]];\n}\n\n/** Any diff hunk */\nexport type DiffHunk = SimpleDiffHunk | ModifiedDiffHunk;\n\n/** Result of comparing a single object */\nexport interface DiffResult {\n name: string;\n extension: string;\n label: string;\n diffs: DiffHunk[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Compute diff between server and local content\n *\n * Converts jsdiff ChangeObject[] output to the hunk format matching Python behavior.\n */\nfunction computeDiff(serverLines: string[], localLines: string[]): DiffHunk[] {\n const changes = diffArrays(serverLines, localLines);\n const hunks: DiffHunk[] = [];\n\n let diffIndex = 0;\n let localIndex = 0;\n\n for (let i = 0; i < changes.length; i++) {\n const change = changes[i] as ChangeObject<string[]>;\n if (!change) continue;\n\n if (!change.added && !change.removed) {\n // Unchanged lines - advance both indices\n const count = change.count ?? change.value.length;\n diffIndex += count;\n localIndex += count;\n continue;\n }\n\n if (change.removed) {\n // Check if next change is an addition (making this a modification)\n const nextChange = changes[i + 1] as ChangeObject<string[]> | undefined;\n\n if (nextChange?.added) {\n // Modification: deletion followed by addition\n const serverChanges = change.value;\n const localChanges = nextChange.value;\n const modHunk: ModifiedDiffHunk = {\n type: 'modification',\n length: serverChanges.length + localChanges.length,\n diffStart: diffIndex,\n localStart: localIndex,\n changes: [serverChanges, localChanges],\n };\n hunks.push(modHunk);\n\n // Advance indices and skip the next addition\n diffIndex += serverChanges.length + localChanges.length;\n localIndex += localChanges.length;\n i++; // Skip the addition we just processed\n continue;\n }\n\n // Pure deletion\n const deletionHunk: SimpleDiffHunk = {\n type: 'deletion',\n length: change.value.length,\n diffStart: diffIndex,\n localStart: localIndex,\n changes: change.value,\n };\n hunks.push(deletionHunk);\n diffIndex += change.value.length;\n continue;\n }\n\n if (!change.added) continue;\n\n // Pure addition (not preceded by deletion - handled above)\n const additionHunk: SimpleDiffHunk = {\n type: 'addition',\n length: change.value.length,\n diffStart: diffIndex,\n localStart: localIndex,\n changes: change.value,\n };\n hunks.push(additionHunk);\n diffIndex += change.value.length;\n localIndex += change.value.length;\n }\n\n return hunks;\n}\n\n/**\n * Compare local object content with server content\n *\n * @param client - ADT client\n * @param object - Object with local content to compare\n * @returns Diff result or error\n */\nexport async function gitDiff(\n client: AdtRequestor,\n object: ObjectContent\n): AsyncResult<DiffResult, Error> {\n // Read current server content.\n const [serverObj, readErr] = await readObject(client, {\n name: object.name,\n extension: object.extension,\n });\n\n if (readErr) {\n return err(new Error(`${object.name} does not exist on server`));\n }\n\n // Get label from config.\n const config = getConfigByExtension(object.extension);\n const label = config?.label ?? object.extension;\n\n // Split content into lines for comparison.\n const serverLines = serverObj.content.split('\\n');\n const localLines = object.content.split('\\n');\n\n // Compute diff.\n const diffs = computeDiff(serverLines, localLines);\n\n return ok({\n name: serverObj.name,\n extension: serverObj.extension,\n label,\n diffs,\n });\n}\n","/**\r\n * ADT Client Core Implementation\r\n *\r\n * HTTP client for SAP ADT (ABAP Development Tools) with:\r\n * - Session management (login/logout)\r\n * - CSRF token fetching and automatic refresh\r\n * - Basic authentication (SAML and SSO to be implemented)\r\n * - Automatic retry on 403 CSRF errors\r\n * - Session reset on 500 errors\r\n *\r\n * Uses web standard APIs (fetch, Request, Response) - runtime-agnostic.\r\n * High-level ADT operations (CRAUD, preview, etc.) are stubs to be implemented.\r\n */\r\n\r\nimport type { ClientConfig } from '../types/config';\r\nimport type {\r\n ObjectRef,\r\n ObjectContent,\r\n TreeQuery,\r\n PreviewQuery,\r\n} from '../types/requests';\r\nimport type { Session } from './session/types';\r\nimport type {\r\n ObjectWithContent,\r\n UpsertResult,\r\n ActivationResult,\r\n TreeNode,\r\n Transport,\r\n Package,\r\n DataFrame,\r\n DistinctResult,\r\n SearchResult,\r\n Dependency,\r\n TransportConfig,\r\n DiffResult,\r\n ObjectConfig,\r\n} from './adt';\r\nimport type { Result, AsyncResult } from '../types/result';\r\nimport { ok, err } from '../types/result';\r\nimport {\r\n CSRF_TOKEN_HEADER,\r\n BASE_HEADERS,\r\n DEFAULT_TIMEOUT,\r\n buildRequestHeaders,\r\n debug,\r\n debugError,\r\n} from './utils';\r\nimport { clientConfigSchema } from '../types/config';\r\nimport * as sessionOps from './session/login';\r\nimport * as adt from './adt';\r\nimport { Agent, fetch as undiciFetch } from 'undici';\r\n\r\n// HTTP request options for internal operations\r\ninterface RequestOptions {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n params?: Record<string, string | number>;\r\n headers?: Record<string, string>;\r\n body?: string;\r\n}\r\n\r\n// ADT Client interface - provides all operations for interacting with SAP ADT servers\r\nexport interface ADTClient {\r\n /** Current session info (null if not logged in) */\r\n readonly session: Session | null;\r\n\r\n // Lifecycle\r\n login(): AsyncResult<Session>;\r\n logout(): AsyncResult<void>;\r\n\r\n // CRAUD Operations\r\n read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]>;\r\n create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void>;\r\n update(object: ObjectContent, transport?: string): AsyncResult<void>;\r\n upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;\r\n activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;\r\n delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;\r\n\r\n // Discovery\r\n getPackages(): AsyncResult<Package[]>;\r\n getTree(query: TreeQuery): AsyncResult<TreeNode[]>;\r\n getTransports(packageName: string): AsyncResult<Transport[]>;\r\n\r\n // Data Preview\r\n previewData(query: PreviewQuery): AsyncResult<DataFrame>;\r\n getDistinctValues(objectName: string, column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;\r\n countRows(objectName: string, objectType: 'table' | 'view'): AsyncResult<number>;\r\n\r\n // Search\r\n search(query: string, types?: string[]): AsyncResult<SearchResult[]>;\r\n whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;\r\n\r\n // Transport Management\r\n createTransport(config: TransportConfig): AsyncResult<string>;\r\n\r\n // Diff Operations\r\n gitDiff(objects: ObjectContent[]): AsyncResult<DiffResult[]>;\r\n\r\n // Configuration\r\n getObjectConfig(): ObjectConfig[];\r\n}\r\n\r\n// Internal client state (implements SessionState interface from session/login)\r\ninterface ClientState extends sessionOps.SessionState {\r\n config: ClientConfig;\r\n cookies: Map<string, string>;\r\n}\r\n\r\n// Build URL search parameters with sap-client\r\nfunction buildParams(\r\n baseParams: Record<string, string | number> | undefined,\r\n clientNum: string\r\n): URLSearchParams {\r\n const params = new URLSearchParams();\r\n\r\n // Add any custom parameters from the request.\r\n if (baseParams) {\r\n for (const [key, value] of Object.entries(baseParams)) {\r\n params.append(key, String(value));\r\n }\r\n }\r\n\r\n // Always append sap-client parameter.\r\n params.append('sap-client', clientNum);\r\n\r\n return params;\r\n}\r\n\r\n// Build full URL from base URL and path\r\nfunction buildUrl(baseUrl: string, path: string, params?: URLSearchParams): string {\r\n // Construct URL from base and path.\r\n const url = new URL(path, baseUrl);\r\n\r\n // Merge query parameters: preserve existing ones from path, add new ones.\r\n if (params) {\r\n for (const [key, value] of params.entries()) {\r\n url.searchParams.append(key, value);\r\n }\r\n }\r\n\r\n return url.toString();\r\n}\r\n\r\n/**\r\n * ADT Client implementation class.\r\n * Methods are defined on the prototype (not recreated per instance).\r\n */\r\nclass ADTClientImpl implements ADTClient {\r\n private state: ClientState;\r\n private requestor: adt.AdtRequestor;\r\n private agent: Agent | undefined;\r\n\r\n constructor(config: ClientConfig) {\r\n this.state = {\r\n config,\r\n session: null,\r\n csrfToken: null,\r\n cookies: new Map(),\r\n };\r\n // Bind request method for use as requestor\r\n this.requestor = { request: this.request.bind(this) };\r\n // Create insecure agent if SSL verification should be skipped\r\n if (config.insecure) {\r\n this.agent = new Agent({\r\n connect: {\r\n rejectUnauthorized: false,\r\n checkServerIdentity: () => undefined, // Skip hostname verification\r\n },\r\n });\r\n }\r\n }\r\n\r\n get session(): Session | null {\r\n return this.state.session;\r\n }\r\n\r\n // --- Private helpers ---\r\n\r\n private storeCookies(response: Response): void {\r\n const setCookieHeader = response.headers.get('set-cookie');\r\n if (!setCookieHeader) return;\r\n\r\n // Parse Set-Cookie header(s) - may be multiple cookies\r\n // Format: \"name=value; Path=/; HttpOnly\" or multiple separated\r\n const cookieStrings = setCookieHeader.split(/,(?=\\s*\\w+=)/);\r\n for (const cookieStr of cookieStrings) {\r\n const match = cookieStr.match(/^([^=]+)=([^;]*)/);\r\n if (match && match[1] && match[2]) {\r\n this.state.cookies.set(match[1].trim(), match[2].trim());\r\n }\r\n }\r\n }\r\n\r\n private buildCookieHeader(): string | null {\r\n if (this.state.cookies.size === 0) return null;\r\n return Array.from(this.state.cookies.entries())\r\n .map(([name, value]) => `${name}=${value}`)\r\n .join('; ');\r\n }\r\n\r\n // Core HTTP request function with CSRF token injection and automatic retry on 403 errors\r\n private async request(options: RequestOptions): AsyncResult<Response, Error> {\r\n const { method, path, params, headers: customHeaders, body } = options;\r\n const { config } = this.state;\r\n\r\n // Build headers with auth and CSRF token.\r\n debug(`Request ${method} ${path} - CSRF token in state: ${this.state.csrfToken?.substring(0, 20) || 'null'}...`);\r\n const headers = buildRequestHeaders(\r\n BASE_HEADERS,\r\n customHeaders,\r\n config.auth,\r\n this.state.csrfToken\r\n );\r\n debug(`CSRF header being sent: ${headers['x-csrf-token']?.substring(0, 20) || 'none'}...`);\r\n\r\n // Add stored cookies to request\r\n const cookieHeader = this.buildCookieHeader();\r\n if (cookieHeader) {\r\n headers['Cookie'] = cookieHeader;\r\n debug(`Cookies being sent: ${cookieHeader.substring(0, 50)}...`);\r\n }\r\n\r\n // Build URL with parameters.\r\n const urlParams = buildParams(params, config.client);\r\n const url = buildUrl(config.url, path, urlParams);\r\n\r\n // Build fetch options with timeout and optional insecure agent.\r\n const fetchOptions: RequestInit & { dispatcher?: Agent } = {\r\n method,\r\n headers,\r\n signal: AbortSignal.timeout(config.timeout ?? DEFAULT_TIMEOUT),\r\n };\r\n\r\n // Add insecure agent if configured\r\n if (this.agent) {\r\n fetchOptions.dispatcher = this.agent;\r\n }\r\n\r\n // Add request body if provided.\r\n if (body) {\r\n fetchOptions.body = body;\r\n }\r\n\r\n try {\r\n // Execute HTTP request.\r\n debug(`Fetching URL: ${url}`);\r\n debug(`Insecure mode: ${!!this.agent}`);\r\n // Use undici fetch directly to support dispatcher option for SSL bypass\r\n const response = await undiciFetch(url, fetchOptions as Parameters<typeof undiciFetch>[1]) as unknown as Response;\r\n\r\n // Store any cookies from response\r\n this.storeCookies(response);\r\n\r\n // Handle CSRF token validation failure with automatic refresh.\r\n if (response.status === 403) {\r\n const text = await response.text();\r\n if (text.includes('CSRF token validation failed')) {\r\n // Fetch new CSRF token.\r\n const [newToken, tokenErr] = await sessionOps.fetchCsrfToken(this.state, this.request.bind(this));\r\n if (tokenErr) {\r\n return err(new Error(`CSRF token refresh failed: ${tokenErr.message}`));\r\n }\r\n\r\n // Retry request with new token and cookies.\r\n headers[CSRF_TOKEN_HEADER] = newToken;\r\n const retryCookieHeader = this.buildCookieHeader();\r\n if (retryCookieHeader) {\r\n headers['Cookie'] = retryCookieHeader;\r\n }\r\n debug(`Retrying with new CSRF token: ${newToken.substring(0, 20)}...`);\r\n const retryResponse = await undiciFetch(url, { ...fetchOptions, headers } as Parameters<typeof undiciFetch>[1]) as unknown as Response;\r\n this.storeCookies(retryResponse);\r\n return ok(retryResponse);\r\n }\r\n\r\n // Return 403 response if not CSRF-related.\r\n return ok(new Response(text, {\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n }));\r\n }\r\n\r\n // Handle session expiration with automatic reset.\r\n if (response.status === 500) {\r\n const text = await response.text();\r\n\r\n // Attempt session reset.\r\n const [, resetErr] = await sessionOps.sessionReset(this.state, this.request.bind(this));\r\n if (resetErr) {\r\n return err(new Error(`Session reset failed: ${resetErr.message}`));\r\n }\r\n\r\n // Return original 500 response.\r\n return ok(new Response(text, {\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n }));\r\n }\r\n\r\n return ok(response);\r\n } catch (error) {\r\n // Log detailed error info for debugging\r\n if (error instanceof Error) {\r\n debugError(`Fetch error: ${error.name}: ${error.message}`, error.cause);\r\n if ('code' in error) {\r\n debugError(`Error code: ${(error as NodeJS.ErrnoException).code}`);\r\n }\r\n return err(error);\r\n }\r\n return err(new Error(`Network error: ${String(error)}`));\r\n }\r\n }\r\n\r\n // --- Lifecycle ---\r\n\r\n async login(): AsyncResult<Session> {\r\n return sessionOps.login(this.state, this.request.bind(this));\r\n }\r\n\r\n async logout(): AsyncResult<void> {\r\n return sessionOps.logout(this.state, this.request.bind(this));\r\n }\r\n\r\n // --- CRAUD Operations ---\r\n\r\n async read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n const results: ObjectWithContent[] = [];\r\n for (const obj of objects) {\r\n const [result, readErr] = await adt.readObject(this.requestor, obj);\r\n if (readErr) return err(readErr);\r\n results.push(result);\r\n }\r\n return ok(results);\r\n }\r\n\r\n async create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n // Step 1: Create empty object shell\r\n const [, createErr] = await adt.createObject(this.requestor, object, packageName, transport, this.state.session.username);\r\n if (createErr) return err(createErr);\r\n\r\n // Step 2: Populate content via lock → update → unlock\r\n const objRef: ObjectRef = { name: object.name, extension: object.extension };\r\n\r\n const [lockHandle, lockErr] = await adt.lockObject(this.requestor, objRef);\r\n if (lockErr) return err(lockErr);\r\n\r\n const [, updateErr] = await adt.updateObject(this.requestor, object, lockHandle, transport);\r\n\r\n // Always unlock after update attempt\r\n const [, unlockErr] = await adt.unlockObject(this.requestor, objRef, lockHandle);\r\n\r\n if (updateErr) return err(updateErr);\r\n if (unlockErr) return err(unlockErr);\r\n\r\n return ok(undefined);\r\n }\r\n\r\n async update(object: ObjectContent, transport?: string): AsyncResult<void> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n const objRef: ObjectRef = { name: object.name, extension: object.extension };\r\n\r\n // Lock object before update\r\n const [lockHandle, lockErr] = await adt.lockObject(this.requestor, objRef);\r\n if (lockErr) return err(lockErr);\r\n\r\n // Update object content\r\n const [, updateErr] = await adt.updateObject(this.requestor, object, lockHandle, transport);\r\n\r\n // Always unlock after update attempt\r\n const [, unlockErr] = await adt.unlockObject(this.requestor, objRef, lockHandle);\r\n\r\n // Return first error encountered\r\n if (updateErr) return err(updateErr);\r\n if (unlockErr) return err(unlockErr);\r\n\r\n return ok(undefined);\r\n }\r\n\r\n async upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n if (objects.length === 0) return ok([]);\r\n\r\n const results: UpsertResult[] = [];\r\n for (const obj of objects) {\r\n if (!obj.name || !obj.extension) continue;\r\n\r\n const objRef: ObjectRef = { name: obj.name, extension: obj.extension };\r\n\r\n // Try to read existing object\r\n const [existing] = await adt.readObject(this.requestor, objRef);\r\n\r\n // Object doesn't exist - create it\r\n if (!existing) {\r\n const [, createErr] = await this.create(obj, packageName, transport);\r\n if (createErr) return err(createErr);\r\n\r\n const result: UpsertResult = {\r\n name: obj.name,\r\n extension: obj.extension,\r\n status: 'created',\r\n };\r\n if (transport) result.transport = transport;\r\n results.push(result);\r\n continue;\r\n }\r\n\r\n // Object exists - update it\r\n const [, updateErr] = await this.update(obj, transport);\r\n if (updateErr) return err(updateErr);\r\n\r\n const result: UpsertResult = {\r\n name: obj.name,\r\n extension: obj.extension,\r\n status: 'updated',\r\n };\r\n if (transport) result.transport = transport;\r\n results.push(result);\r\n }\r\n return ok(results);\r\n }\r\n\r\n async activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.activateObjects(this.requestor, objects);\r\n }\r\n\r\n async delete(objects: ObjectRef[], transport?: string): AsyncResult<void> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n for (const obj of objects) {\r\n // Lock object before deletion\r\n const [lockHandle, lockErr] = await adt.lockObject(this.requestor, obj);\r\n if (lockErr) return err(lockErr);\r\n\r\n // Delete object\r\n const [, deleteErr] = await adt.deleteObject(this.requestor, obj, lockHandle, transport);\r\n if (deleteErr) {\r\n // Attempt to unlock on failure\r\n await adt.unlockObject(this.requestor, obj, lockHandle);\r\n return err(deleteErr);\r\n }\r\n }\r\n return ok(undefined);\r\n }\r\n\r\n // --- Discovery ---\r\n\r\n async getPackages(): AsyncResult<Package[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getPackages(this.requestor);\r\n }\r\n\r\n async getTree(query: TreeQuery): AsyncResult<TreeNode[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getTree(this.requestor, query);\r\n }\r\n\r\n async getTransports(packageName: string): AsyncResult<Transport[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getTransports(this.requestor, packageName);\r\n }\r\n\r\n // --- Data Preview ---\r\n\r\n async previewData(query: PreviewQuery): AsyncResult<DataFrame> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.previewData(this.requestor, query);\r\n }\r\n\r\n async getDistinctValues(objectName: string, column: string, objectType: 'table' | 'view' = 'view'): AsyncResult<DistinctResult> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getDistinctValues(this.requestor, objectName, column, objectType);\r\n }\r\n\r\n async countRows(objectName: string, objectType: 'table' | 'view'): AsyncResult<number> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.countRows(this.requestor, objectName, objectType);\r\n }\r\n\r\n // --- Search ---\r\n\r\n async search(query: string, types?: string[]): AsyncResult<SearchResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.searchObjects(this.requestor, query, types);\r\n }\r\n\r\n async whereUsed(object: ObjectRef): AsyncResult<Dependency[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.findWhereUsed(this.requestor, object);\r\n }\r\n\r\n // --- Transport Management ---\r\n\r\n async createTransport(transportConfig: TransportConfig): AsyncResult<string> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.createTransport(this.requestor, transportConfig);\r\n }\r\n\r\n // --- Diff Operations ---\r\n\r\n async gitDiff(objects: ObjectContent[]): AsyncResult<DiffResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n if (objects.length === 0) return ok([]);\r\n\r\n const results: DiffResult[] = [];\r\n for (const obj of objects) {\r\n const [result, diffErr] = await adt.gitDiff(this.requestor, obj);\r\n if (diffErr) return err(diffErr);\r\n results.push(result);\r\n }\r\n return ok(results);\r\n }\r\n\r\n // --- Configuration ---\r\n\r\n getObjectConfig(): ObjectConfig[] {\r\n return Object.values(adt.OBJECT_CONFIG_MAP);\r\n }\r\n}\r\n\r\n// Create a new ADT client - validates config and returns client instance\r\nexport function createClient(config: ClientConfig): Result<ADTClient, Error> {\r\n // Validate config using Zod schema.\r\n const validation = clientConfigSchema.safeParse(config);\r\n if (!validation.success) {\r\n const issues = validation.error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join(', ');\r\n return err(new Error(`Invalid client configuration: ${issues}`));\r\n }\r\n\r\n return ok(new ADTClientImpl(config));\r\n}\r\n","/**\n * Configuration loading utilities\n *\n * Matches Python reference behavior:\n * - Load system URLs from config.json\n * - Parse clientId format: \"SystemId-ClientNumber\" (e.g., \"MediaDemo-DM1-200\")\n * - Support RELAY_CONFIG environment variable\n */\n\nimport { readFileSync } from 'node:fs';\nimport { z } from 'zod';\nimport type { Result } from '../types/result';\nimport { ok, err } from '../types/result';\n\n/**\n * System configuration from config.json\n */\nexport interface SystemConfig {\n /** ADT server URL */\n adt: string | undefined;\n /** OData server URL (optional) */\n odata: string | undefined;\n /** Instance number (optional) */\n instanceNum: string | undefined;\n}\n\n/**\n * Loaded configuration map\n * Key: System ID (e.g., \"MediaDemo-DM1\")\n * Value: System configuration\n */\nexport type ConfigMap = Map<string, SystemConfig>;\n\n/**\n * Zod schema for config.json validation\n */\nconst systemConfigSchema = z.record(\n z.string(),\n z.object({\n adt: z.string().url().optional(),\n odata: z.string().url().optional(),\n instance_num: z.string().optional(),\n })\n);\n\n/**\n * Parsed client ID components\n */\nexport interface ParsedClientId {\n /** System ID for config lookup (e.g., \"MediaDemo-DM1\") */\n systemId: string;\n /** SAP client number (e.g., \"200\") */\n clientNumber: string;\n}\n\n/**\n * Global config storage\n */\nlet globalConfig: ConfigMap | null = null;\n\n/**\n * Load configuration from a JSON file\n *\n * @param path - Path to config.json\n * @returns Result with ConfigMap or error\n *\n * @example\n * ```typescript\n * const [config, err] = loadConfig('./config.json');\n * if (err) {\n * console.error('Failed to load config:', err);\n * return;\n * }\n * ```\n */\nexport function loadConfig(path: string): Result<ConfigMap, Error> {\n try {\n // Read and parse the JSON file.\n const content = readFileSync(path, 'utf-8');\n const raw = JSON.parse(content);\n\n // Validate config structure with Zod schema.\n const validation = systemConfigSchema.safeParse(raw);\n if (!validation.success) {\n const issues = validation.error.issues\n .map((i) => `${i.path.join('.')}: ${i.message}`)\n .join(', ');\n return err(new Error(`Invalid config format: ${issues}`));\n }\n\n // Convert validated data to ConfigMap.\n const configMap: ConfigMap = new Map();\n for (const [key, value] of Object.entries(validation.data)) {\n configMap.set(key, {\n adt: value.adt,\n odata: value.odata,\n instanceNum: value.instance_num,\n });\n }\n\n // Store globally for later access.\n globalConfig = configMap;\n\n return ok(configMap);\n } catch (error) {\n // Handle JSON parsing errors.\n if (error instanceof SyntaxError) {\n return err(new Error(`Invalid JSON in config file: ${error.message}`));\n }\n // Handle file not found errors.\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n return err(new Error(`Config file not found: ${path}`));\n }\n return err(error instanceof Error ? error : new Error(String(error)));\n }\n}\n\n/**\n * Default config file path\n */\nconst DEFAULT_CONFIG_PATH = './config.json';\n\n/**\n * Load configuration from RELAY_CONFIG environment variable\n *\n * Defaults to './config.json' if RELAY_CONFIG is not set.\n *\n * @returns Result with ConfigMap or error\n *\n * @example\n * ```typescript\n * // Uses RELAY_CONFIG env var, or defaults to './config.json'\n * const [config, err] = loadConfigFromEnv();\n * ```\n */\n\nexport function loadConfigFromEnv(): Result<ConfigMap, Error> {\n // Resolve config path from environment or use default.\n const configPath = process.env['RELAY_CONFIG'] ?? DEFAULT_CONFIG_PATH;\n return loadConfig(configPath);\n}\n\n/**\n * Get the currently loaded config\n *\n * @returns ConfigMap or null if not loaded\n */\nexport function getConfig(): ConfigMap | null {\n return globalConfig;\n}\n\n/**\n * Get system config by ID\n *\n * @param systemId - System ID (e.g., \"MediaDemo-DM1\")\n * @returns SystemConfig or null if not found\n */\nexport function getSystemConfig(systemId: string): SystemConfig | null {\n if (!globalConfig) return null;\n return globalConfig.get(systemId) ?? null;\n}\n\n/**\n * Parse a client ID into system ID and client number\n *\n * Format: \"SystemId-ClientNumber\" where SystemId can contain hyphens\n * Example: \"MediaDemo-DM1-200\" → { systemId: \"MediaDemo-DM1\", clientNumber: \"200\" }\n *\n * @param clientId - Full client ID string\n * @returns Result with parsed components or error\n *\n * @example\n * ```typescript\n * const [parsed, err] = parseClientId('MediaDemo-DM1-200');\n * if (err) return;\n * console.log(parsed.systemId); // \"MediaDemo-DM1\"\n * console.log(parsed.clientNumber); // \"200\"\n * ```\n */\nexport function parseClientId(clientId: string): Result<ParsedClientId, Error> {\n if (!clientId) {\n return err(new Error('Client ID is required'));\n }\n\n // Split by hyphen to extract components.\n const parts = clientId.split('-');\n if (parts.length < 2) {\n return err(new Error(`Invalid client ID format: \"${clientId}\". Expected \"SystemId-ClientNumber\" (e.g., \"MediaDemo-DM1-200\")`));\n }\n\n // Extract client number (last part) and system ID (everything before).\n const clientNumber = parts[parts.length - 1];\n const systemId = parts.slice(0, -1).join('-');\n\n // Validate client number is numeric.\n if (!clientNumber || !/^\\d+$/.test(clientNumber)) {\n return err(new Error(`Invalid client number: \"${clientNumber}\". Must be numeric (e.g., \"100\", \"200\")`));\n }\n\n // Validate system ID is not empty.\n if (!systemId) {\n return err(new Error(`Invalid system ID in client ID: \"${clientId}\"`));\n }\n\n return ok({ systemId, clientNumber });\n}\n\n/**\n * Resolve a client ID to a full URL and client number\n *\n * @param clientId - Full client ID (e.g., \"MediaDemo-DM1-200\")\n * @returns Result with URL and client number or error\n *\n * @example\n * ```typescript\n * loadConfig('./config.json');\n * const [resolved, err] = resolveClientId('MediaDemo-DM1-200');\n * if (err) return;\n * console.log(resolved.url); // \"https://50.19.106.63:443\"\n * console.log(resolved.clientNumber); // \"200\"\n * ```\n */\nexport function resolveClientId(clientId: string): Result<{ url: string; clientNumber: string }, Error> {\n // Parse the client ID into components.\n const [parsed, parseErr] = parseClientId(clientId);\n if (parseErr) {\n return err(parseErr);\n }\n\n // Ensure config is loaded.\n if (!globalConfig) {\n return err(new Error('Config not loaded. Call loadConfig() or loadConfigFromEnv() first.'));\n }\n\n // Lookup system configuration.\n const systemConfig = globalConfig.get(parsed.systemId);\n if (!systemConfig) {\n return err(new Error(`Unknown system ID: \"${parsed.systemId}\". Available: ${Array.from(globalConfig.keys()).join(', ')}`));\n }\n\n // Validate ADT URL is configured.\n if (!systemConfig.adt) {\n return err(new Error(`No ADT URL configured for system: \"${parsed.systemId}\"`));\n }\n\n return ok({\n url: systemConfig.adt,\n clientNumber: parsed.clientNumber,\n });\n}\n\n/**\n * Build a ClientConfig from a client ID and auth config\n *\n * Convenience function that resolves the client ID and builds\n * a complete ClientConfig ready for createClient().\n *\n * @param clientId - Full client ID (e.g., \"MediaDemo-DM1-200\")\n * @param auth - Authentication configuration\n * @returns Result with ClientConfig or error\n *\n * @example\n * ```typescript\n * loadConfig('./config.json');\n *\n * const [config, err] = buildClientConfig('MediaDemo-DM1-200', {\n * type: 'basic',\n * username: 'user',\n * password: 'pass',\n * });\n * if (err) return;\n *\n * const [client, clientErr] = createClient(config);\n * ```\n */\nexport function buildClientConfig(\n clientId: string,\n auth: { type: 'basic'; username: string; password: string } |\n { type: 'saml'; username: string; password: string; provider?: string } |\n { type: 'sso'; certificate?: string }\n): Result<{ url: string; client: string; auth: typeof auth }, Error> {\n // Resolve client ID to URL and client number.\n const [resolved, resolveErr] = resolveClientId(clientId);\n if (resolveErr) {\n return err(resolveErr);\n }\n\n // Build complete client configuration.\n return ok({\n url: resolved.url,\n client: resolved.clientNumber,\n auth,\n });\n}\n"],"mappings":"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","names":["text","text","text","text","text","text","text","text","buildUrl","result","z","z"]}
|
|
1
|
+
{"version":3,"sources":["../src/types/result.ts","../src/core/utils/xml.ts","../src/core/utils/csrf.ts","../src/core/utils/headers.ts","../src/core/utils/logging.ts","../src/types/config.ts","../src/core/session/types.ts","../src/core/session/login.ts","../src/core/adt/types.ts","../src/core/adt/helpers.ts","../src/core/adt/read.ts","../src/core/adt/lock.ts","../src/core/adt/create.ts","../src/core/adt/update.ts","../src/core/adt/delete.ts","../src/core/adt/activation.ts","../src/core/adt/tree.ts","../src/core/adt/packages.ts","../src/core/adt/transports.ts","../src/core/adt/previewParser.ts","../src/core/adt/dataPreview.ts","../src/core/adt/distinct.ts","../src/core/adt/count.ts","../src/core/adt/searchObjects.ts","../src/core/adt/whereUsed.ts","../src/core/adt/createTransport.ts","../src/core/adt/gitDiff.ts","../src/core/client.ts","../src/core/auth/basic/basic.ts","../src/core/auth/sso/slsClient.ts","../src/core/auth/sso/types.ts","../src/core/auth/sso/kerberos.ts","../src/core/auth/sso/certificate.ts","../src/core/auth/sso/pkcs7.ts","../src/core/auth/sso/storage.ts","../src/core/auth/sso/sso.ts","../src/core/auth/saml/types.ts","../src/core/auth/saml/browser.ts","../src/core/auth/saml/cookies.ts","../src/core/auth/saml/saml.ts","../src/core/auth/factory.ts","../src/core/config.ts"],"sourcesContent":["/**\n * Result type for error handling (Go-style tuples)\n *\n * Usage:\n * const [data, error] = await someFunction();\n * if (error) {\n * console.error(error);\n * return;\n * }\n * // data is guaranteed non-null\n */\n\nexport type Result<T, E = Error> = [T, null] | [null, E];\n\n/**\n * Async result type alias for convenience\n */\nexport type AsyncResult<T, E = Error> = Promise<Result<T, E>>;\n\n/**\n * Create a success result\n */\nexport function ok<T>(value: T): Result<T, never> {\n return [value, null];\n}\n\n/**\n * Create an error result\n */\nexport function err<E = Error>(error: E): Result<never, E> {\n return [null, error];\n}\n","/**\n * XML Parsing Utilities\n *\n * Secure XML parsing and manipulation for ADT responses.\n * Uses @xmldom/xmldom for cross-platform XML parsing.\n */\n\nimport { DOMParser } from '@xmldom/xmldom';\nimport type { Result } from '../../types/result';\nimport { ok, err } from '../../types/result';\n\n/**\n * Securely parse XML string into a Document object (throws on error)\n *\n * @param xmlString - The XML string to parse\n * @returns Parsed XML Document\n * @throws Error if XML is malformed\n * @deprecated Use safeParseXml for Result-based error handling\n */\nexport function parseXml(xmlString: string): Document {\n if (!xmlString || xmlString.trim().length === 0) {\n throw new Error('Empty XML string provided');\n }\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlString, 'text/xml');\n\n // Check for parser errors\n const parseError = doc.getElementsByTagName('parsererror');\n if (parseError.length > 0) {\n const errorNode = parseError[0];\n const errorText = errorNode?.textContent || 'Unknown XML parsing error';\n throw new Error(`XML parsing failed: ${errorText}`);\n }\n\n return doc;\n}\n\n/**\n * Safely parse XML string into a Document object\n *\n * @param xmlString - The XML string to parse\n * @returns Result tuple with Document or Error\n */\nexport function safeParseXml(xmlString: string): Result<Document, Error> {\n // Validate input.\n if (!xmlString || xmlString.trim().length === 0) {\n return err(new Error('Empty XML string provided'));\n }\n\n try {\n // Parse XML string.\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlString, 'text/xml');\n\n // Check for parser errors.\n const parseError = doc.getElementsByTagName('parsererror');\n if (parseError.length > 0) {\n const errorNode = parseError[0];\n const errorText = errorNode?.textContent || 'Unknown XML parsing error';\n return err(new Error(`XML parsing failed: ${errorText}`));\n }\n\n return ok(doc);\n } catch (error) {\n if (error instanceof Error) {\n return err(error);\n }\n return err(new Error('Unknown XML parsing error'));\n }\n}\n\n/**\n * Extract LOCK_HANDLE from ADT XML response\n *\n * @param xml - XML string containing lock handle\n * @returns Result tuple with lock handle or error\n */\nexport function extractLockHandle(xml: string): Result<string, Error> {\n // Validate input.\n if (!xml) {\n return err(new Error('Empty XML provided'));\n }\n\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Find LOCK_HANDLE element.\n const lockHandleElements = doc.getElementsByTagName('LOCK_HANDLE');\n if (lockHandleElements.length === 0) {\n return err(new Error('LOCK_HANDLE element not found in XML'));\n }\n\n // Extract and validate lock handle value.\n const lockHandleElement = lockHandleElements[0];\n const lockHandle = lockHandleElement?.textContent;\n if (!lockHandle || lockHandle.trim().length === 0) {\n return err(new Error('LOCK_HANDLE element is empty'));\n }\n\n return ok(lockHandle.trim());\n}\n\n/**\n * Extract error message from ADT XML error response\n *\n * @param xml - XML string containing error message\n * @returns Error message or default message\n */\nexport function extractError(xml: string): string {\n // Handle empty input.\n if (!xml) {\n return 'No error message found';\n }\n\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) {\n return 'Failed to parse error XML';\n }\n\n // Find message element.\n const messageElements = doc.getElementsByTagName('message');\n if (messageElements.length === 0) {\n return 'No message found';\n }\n\n // Extract message text.\n const messageElement = messageElements[0];\n const message = messageElement?.textContent;\n return message || 'No message found';\n}\n\n/**\n * Escape special XML characters\n *\n * @param str - String to escape\n * @returns XML-safe string\n */\nexport function escapeXml(str: string): string {\n // Handle empty input.\n if (!str) {\n return '';\n }\n\n // Replace special XML characters with entities.\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Convert a dictionary to ABAP-style XML\n *\n * This creates XML in the format expected by SAP ADT endpoints:\n * <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n * <asx:abap xmlns:asx=\"http://www.sap.com/abapxml\" version=\"1.0\">\n * <asx:values>\n * <DATA>\n * <KEY>value</KEY>\n * </DATA>\n * </asx:values>\n * </asx:abap>\n *\n * @param data - Key-value pairs to convert to XML\n * @param root - Root element name (default: \"DATA\")\n * @returns ABAP-formatted XML string\n */\nexport function dictToAbapXml(data: Record<string, string>, root: string = 'DATA'): string {\n // Build inner XML elements from key-value pairs.\n const innerElements = Object.entries(data)\n .map(([key, value]) => {\n if (value) {\n return `<${key}>${escapeXml(value)}</${key}>`;\n }\n return `<${key}/>`;\n })\n .join('\\n ');\n\n // Return complete ABAP XML structure.\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<asx:abap xmlns:asx=\"http://www.sap.com/abapxml\" version=\"1.0\">\n <asx:values>\n <${root}>\n ${innerElements}\n </${root}>\n </asx:values>\n</asx:abap>`;\n}\n","/**\n * CSRF Token Constants\n *\n * Constants for CSRF token handling with SAP ADT endpoints.\n */\n\n/**\n * Special value to request a CSRF token from the server\n *\n * When sent in the x-csrf-token header, SAP returns a valid token\n * in the response headers.\n */\nexport const FETCH_CSRF_TOKEN = 'fetch';\n\n/**\n * HTTP header name for CSRF token\n *\n * Used both for requesting tokens (with FETCH_CSRF_TOKEN value)\n * and sending tokens with authenticated requests.\n */\nexport const CSRF_TOKEN_HEADER = 'x-csrf-token';\n","/**\n * HTTP Header Utilities for ADT Requests\n *\n * Provides header building utilities and constants for SAP ADT HTTP requests.\n * Centralizes header management to avoid duplication across client code.\n */\n\nimport { CSRF_TOKEN_HEADER, FETCH_CSRF_TOKEN } from './csrf';\nimport type { AuthConfig } from '../../types/config';\n\n// Mimic Eclipse ADT plugin for compatibility\nexport const BASE_HEADERS = {\n 'X-sap-adt-sessiontype': 'stateful',\n 'User-Agent': 'Eclipse/4.34.0 ADT/3.46.0',\n 'X-sap-adt-profiling': 'server-time',\n} as const;\n\n// Default request timeout in milliseconds\nexport const DEFAULT_TIMEOUT = 30000;\n\n/**\n * Build request headers with auth and CSRF token\n *\n * @param baseHeaders - Base headers to include in all requests\n * @param customHeaders - Request-specific headers\n * @param auth - Authentication config (for basic auth header)\n * @param csrfToken - Current CSRF token (if available)\n * @returns Combined headers object\n */\nexport function buildRequestHeaders(\n baseHeaders: Record<string, string>,\n customHeaders?: Record<string, string>,\n auth?: AuthConfig,\n csrfToken?: string | null\n): Record<string, string> {\n // Merge base and custom headers.\n const headers: Record<string, string> = {\n ...baseHeaders,\n ...(customHeaders ?? {}),\n };\n\n // Add basic auth header if using basic authentication.\n if (auth?.type === 'basic') {\n // Use btoa for base64 encoding (web standard, available in both Node 18+ and Bun)\n const credentials = btoa(`${auth.username}:${auth.password}`);\n headers['Authorization'] = `Basic ${credentials}`;\n }\n\n // Add CSRF token if we have one (but not the 'fetch' placeholder).\n // Don't overwrite if custom headers already set the CSRF token (e.g., for token refresh).\n if (csrfToken && csrfToken !== FETCH_CSRF_TOKEN && !customHeaders?.[CSRF_TOKEN_HEADER]) {\n headers[CSRF_TOKEN_HEADER] = csrfToken;\n }\n\n return headers;\n}\n\n/**\n * Extract CSRF token from response headers\n *\n * SAP returns token in both upper and lowercase variations,\n * so we need to check both.\n *\n * @param headers - Response headers from SAP ADT server\n * @returns Extracted CSRF token or null if not found\n */\nexport function extractCsrfToken(headers: Headers): string | null {\n // Try both upper and lowercase header names.\n const token = headers.get(CSRF_TOKEN_HEADER) ||\n headers.get(CSRF_TOKEN_HEADER.toLowerCase());\n\n // Ignore the fetch token itself.\n if (!token || token === FETCH_CSRF_TOKEN) {\n return null;\n }\n\n return token;\n}\n","/**\r\n * Logging Utility — Debug logging with activation control\r\n *\r\n * Logs are silent by default. Call activateLogging() to enable console output.\r\n */\r\n\r\nlet isActive = false;\r\n\r\n/**\r\n * Enable debug logging to console\r\n */\r\nexport function activateLogging(): void {\r\n isActive = true;\r\n}\r\n\r\n/**\r\n * Disable debug logging (default state)\r\n */\r\nexport function deactivateLogging(): void {\r\n isActive = false;\r\n}\r\n\r\n/**\r\n * Check if logging is currently active\r\n */\r\nexport function isLoggingActive(): boolean {\r\n return isActive;\r\n}\r\n\r\n/**\r\n * Log a debug message (only prints when logging is active)\r\n */\r\nexport function debug(message: string): void {\r\n if (isActive) {\r\n console.log(`[DEBUG] ${message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Log a debug error message (only prints when logging is active)\r\n */\r\nexport function debugError(message: string, cause?: unknown): void {\r\n if (!isActive) return;\r\n\r\n console.error(`[DEBUG] ${message}`);\r\n if (cause !== undefined) {\r\n console.error(`[DEBUG] Cause:`, cause);\r\n }\r\n}\r\n","import { z } from 'zod';\r\n\r\n/**\r\n * Authentication types supported by SAP ADT\r\n */\r\nexport type AuthType = 'basic' | 'saml' | 'sso';\r\n\r\n/**\r\n * Basic authentication configuration\r\n */\r\nexport interface BasicAuthConfig {\r\n type: 'basic';\r\n username: string;\r\n password: string;\r\n}\r\n\r\n/**\r\n * CSS selectors for SAML login form\r\n */\r\nexport interface SamlFormSelectors {\r\n /** CSS selector for username input field */\r\n username: string;\r\n /** CSS selector for password input field */\r\n password: string;\r\n /** CSS selector for submit button */\r\n submit: string;\r\n}\r\n\r\n/**\r\n * SAML provider configuration\r\n */\r\nexport interface SamlProviderConfig {\r\n /** Whether to ignore HTTPS certificate errors */\r\n ignoreHttpsErrors: boolean;\r\n /** CSS selectors for login form elements */\r\n formSelectors: SamlFormSelectors;\r\n}\r\n\r\n/**\r\n * SAML authentication configuration\r\n */\r\nexport interface SamlAuthConfig {\r\n type: 'saml';\r\n username: string;\r\n password: string;\r\n /** Optional custom provider configuration for non-standard login forms */\r\n providerConfig?: SamlProviderConfig;\r\n}\r\n\r\n/**\r\n * SSO (Kerberos) authentication configuration\r\n */\r\nexport interface SsoAuthConfig {\r\n type: 'sso';\r\n /** Secure Login Server URL (e.g., https://sapsso.corp.example.com) */\r\n slsUrl: string;\r\n /** SLS profile name (default: SAPSSO_P) */\r\n profile?: string;\r\n /** Kerberos service principal name override */\r\n servicePrincipalName?: string;\r\n /** Force certificate re-enrollment even if valid cert exists */\r\n forceEnroll?: boolean;\r\n /** @deprecated Use slsUrl instead */\r\n certificate?: string;\r\n}\r\n\r\n/**\r\n * Union of all auth configurations\r\n */\r\nexport type AuthConfig = BasicAuthConfig | SamlAuthConfig | SsoAuthConfig;\r\n\r\n/**\r\n * Client configuration for connecting to SAP ADT\r\n */\r\nexport interface ClientConfig {\r\n /** ADT server URL (e.g., https://server:port) */\r\n url: string;\r\n /** SAP client number (e.g., '100') */\r\n client: string;\r\n /** Authentication configuration */\r\n auth: AuthConfig;\r\n /** Request timeout in milliseconds (default: 30000) */\r\n timeout?: number;\r\n /** Skip SSL verification (dev only) */\r\n insecure?: boolean;\r\n}\r\n\r\n/**\r\n * Zod schema for SAML form selectors\r\n */\r\nconst samlFormSelectorsSchema = z.object({\r\n username: z.string().min(1),\r\n password: z.string().min(1),\r\n submit: z.string().min(1),\r\n});\r\n\r\n/**\r\n * Zod schema for SAML provider configuration\r\n */\r\nconst samlProviderConfigSchema = z.object({\r\n ignoreHttpsErrors: z.boolean(),\r\n formSelectors: samlFormSelectorsSchema,\r\n});\r\n\r\n/**\r\n * Zod schema for runtime validation of ClientConfig\r\n */\r\nexport const clientConfigSchema = z.object({\r\n url: z.string().url(),\r\n client: z.string().min(1).max(3),\r\n auth: z.discriminatedUnion('type', [\r\n z.object({\r\n type: z.literal('basic'),\r\n username: z.string().min(1),\r\n password: z.string().min(1),\r\n }),\r\n z.object({\r\n type: z.literal('saml'),\r\n username: z.string().min(1),\r\n password: z.string().min(1),\r\n providerConfig: samlProviderConfigSchema.optional(),\r\n }),\r\n z.object({\r\n type: z.literal('sso'),\r\n slsUrl: z.string().url(),\r\n profile: z.string().optional(),\r\n servicePrincipalName: z.string().optional(),\r\n forceEnroll: z.boolean().optional(),\r\n certificate: z.string().optional(),\r\n }),\r\n ]),\r\n timeout: z.number().positive().optional(),\r\n insecure: z.boolean().optional(),\r\n});\r\n","/**\r\n * Session management type definitions\r\n */\r\n\r\nimport type { AuthType } from '../../types';\r\n\r\n/**\r\n * Session data returned after successful login\r\n */\r\nexport interface Session {\r\n /** Unique session identifier */\r\n sessionId: string;\r\n /** Authenticated username */\r\n username: string;\r\n /** Session expiration timestamp */\r\n expiresAt: number;\r\n}\r\n\r\n/**\r\n * Session entry stored in memory\r\n */\r\nexport interface SessionEntry {\r\n /** The ADT client instance (typed as unknown until client is implemented) */\r\n client: unknown;\r\n /** Last activity timestamp for timeout tracking */\r\n lastActivity: Date;\r\n /** Authentication type used for this session */\r\n authType: AuthType;\r\n}\r\n\r\n/**\r\n * Configuration for session manager\r\n *\r\n * Session timeouts vary by authentication type:\r\n * - Basic: 3 hours (SAP server default)\r\n * - SSO: 3 hours (certificate-based, same as basic)\r\n * - SAML: 30 minutes (IDP session typically shorter)\r\n */\r\nexport interface SessionConfig {\r\n /** Session timeout in seconds for Basic and SSO auth (default: 10800 = 3 hours) */\r\n sessionTimeout: number;\r\n /** Session timeout in seconds for SAML auth (default: 1800 = 30 minutes) */\r\n samlSessionTimeout: number;\r\n /** Cleanup interval in seconds (default: 60) */\r\n cleanupInterval: number;\r\n}\r\n\r\n/**\r\n * Default session configuration values\r\n */\r\nexport const DEFAULT_SESSION_CONFIG: SessionConfig = {\r\n sessionTimeout: 10800, // 3 hours (Basic/SSO)\r\n samlSessionTimeout: 1800, // 30 minutes (SAML)\r\n cleanupInterval: 60, // 1 minute\r\n};\r\n","/**\r\n * Session Lifecycle Operations\r\n *\r\n * Internal helpers for login/logout/session reset operations.\r\n * Used by ADTClient to manage session state.\r\n *\r\n * Handles:\r\n * - CSRF token fetching (auth-type-aware endpoints)\r\n * - Basic, SAML, and SSO authentication login flows\r\n * - Session reset on 500 errors\r\n * - Auth-type-aware session timeouts\r\n * - Logout/cleanup\r\n */\r\n\r\nimport type { AuthConfig, AuthType } from '../../types/config';\r\nimport type { Session } from './types';\r\nimport { DEFAULT_SESSION_CONFIG } from './types';\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport {\r\n FETCH_CSRF_TOKEN,\r\n CSRF_TOKEN_HEADER,\r\n extractCsrfToken,\r\n debug,\r\n} from '../utils';\r\n\r\n// Request function type signature (provided by client.ts)\r\ntype RequestFn = (options: {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n params?: Record<string, string | number>;\r\n headers?: Record<string, string>;\r\n body?: string;\r\n}) => AsyncResult<Response, Error>;\r\n\r\n// Session state management (provided by client.ts)\r\nexport interface SessionState {\r\n csrfToken: string | null;\r\n session: Session | null;\r\n config: { auth: AuthConfig };\r\n}\r\n\r\n/**\r\n * Fetch CSRF token from SAP ADT server\r\n *\r\n * Endpoint and content type vary by auth type:\r\n * - SAML: /sap/bc/adt/core/http/sessions\r\n * - Basic/SSO: /sap/bc/adt/compatibility/graph\r\n *\r\n * @param state - Session state to update with new token\r\n * @param request - HTTP request function from client\r\n * @returns CSRF token string or error\r\n */\r\nexport async function fetchCsrfToken(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<string, Error> {\r\n // Select endpoint based on authentication type.\r\n const endpoint = state.config.auth.type === 'saml'\r\n ? '/sap/bc/adt/core/http/sessions'\r\n : '/sap/bc/adt/compatibility/graph';\r\n\r\n // Select content type based on authentication type.\r\n const contentType = state.config.auth.type === 'saml'\r\n ? 'application/vnd.sap.adt.core.http.session.v3+xml'\r\n : 'application/xml';\r\n\r\n // Build request headers with CSRF token fetch flag.\r\n const headers = {\r\n [CSRF_TOKEN_HEADER]: FETCH_CSRF_TOKEN,\r\n 'Content-Type': contentType,\r\n 'Accept': contentType,\r\n };\r\n\r\n // Execute CSRF token request.\r\n const [response, requestErr] = await request({\r\n method: 'GET',\r\n path: endpoint,\r\n headers,\r\n });\r\n\r\n if (requestErr) {\r\n return err(new Error(`Failed to fetch CSRF token: ${requestErr.message}`));\r\n }\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n return err(new Error(`CSRF token fetch failed with status ${response.status}: ${text}`));\r\n }\r\n\r\n // Extract CSRF token from response headers.\r\n const token = extractCsrfToken(response.headers);\r\n debug(`CSRF token from headers: ${token ? token.substring(0, 20) + '...' : 'null'}`);\r\n if (!token) {\r\n // Debug: show all headers\r\n debug('Response headers:');\r\n response.headers.forEach((value, key) => debug(` ${key}: ${value.substring(0, 50)}`));\r\n return err(new Error('No CSRF token returned in response headers'));\r\n }\r\n\r\n // Update session state with new token.\r\n state.csrfToken = token;\r\n debug(`Stored CSRF token in state: ${state.csrfToken?.substring(0, 20)}...`);\r\n\r\n return ok(token);\r\n}\r\n\r\n/**\r\n * Get session timeout based on authentication type\r\n *\r\n * @param authType - Authentication type\r\n * @returns Session timeout in milliseconds\r\n */\r\nfunction getSessionTimeout(authType: AuthType): number {\r\n switch (authType) {\r\n case 'saml':\r\n return DEFAULT_SESSION_CONFIG.samlSessionTimeout * 1000;\r\n case 'basic':\r\n case 'sso':\r\n return DEFAULT_SESSION_CONFIG.sessionTimeout * 1000;\r\n default: {\r\n const _exhaustive: never = authType;\r\n return DEFAULT_SESSION_CONFIG.sessionTimeout * 1000;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Extract username from authentication config\r\n *\r\n * @param auth - Authentication config\r\n * @returns Username or 'SSO_USER' for SSO\r\n */\r\nfunction extractUsername(auth: AuthConfig): string {\r\n switch (auth.type) {\r\n case 'basic':\r\n case 'saml':\r\n return auth.username;\r\n case 'sso':\r\n // For SSO, username comes from Kerberos/system\r\n return process.env['USERNAME'] ?? process.env['USER'] ?? 'SSO_USER';\r\n default: {\r\n const _exhaustive: never = auth;\r\n return '';\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Login to SAP ADT server\r\n *\r\n * Supports all authentication types:\r\n * - Basic: Username/password via Authorization header\r\n * - SAML: Browser automation (cookies already set by auth strategy)\r\n * - SSO: Kerberos/mTLS (certificates already loaded by auth strategy)\r\n *\r\n * For SAML and SSO, the auth strategy's performLogin() is called\r\n * before this function, so authentication is already complete.\r\n * This function fetches the CSRF token and creates the session.\r\n *\r\n * @param state - Session state to update\r\n * @param request - HTTP request function from client\r\n * @returns Session object or error\r\n */\r\nexport async function login(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<Session, Error> {\r\n // Fetch CSRF token from SAP server.\r\n // Endpoint varies by auth type (handled in fetchCsrfToken).\r\n const [token, tokenErr] = await fetchCsrfToken(state, request);\r\n if (tokenErr) {\r\n return err(new Error(`Login failed: ${tokenErr.message}`));\r\n }\r\n\r\n // Extract username from authentication config.\r\n const username = extractUsername(state.config.auth);\r\n\r\n // Calculate session expiration based on auth type.\r\n const timeout = getSessionTimeout(state.config.auth.type);\r\n\r\n // Create session object.\r\n const session: Session = {\r\n sessionId: token,\r\n username,\r\n expiresAt: Date.now() + timeout,\r\n };\r\n\r\n // Update session state.\r\n state.session = session;\r\n\r\n return ok(session);\r\n}\r\n\r\n/**\r\n * Logout from SAP ADT server\r\n *\r\n * Calls the SAP logoff endpoint and clears local state.\r\n *\r\n * @param state - Session state to clear\r\n * @param request - HTTP request function from client\r\n * @returns void or error\r\n */\r\nexport async function logout(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<void, Error> {\r\n // Execute logout request to SAP server.\r\n const [response, requestErr] = await request({\r\n method: 'POST',\r\n path: '/sap/public/bc/icf/logoff',\r\n });\r\n\r\n if (requestErr) {\r\n return err(new Error(`Logout failed: ${requestErr.message}`));\r\n }\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n return err(new Error(`Logout failed with status ${response.status}: ${text}`));\r\n }\r\n\r\n // Clear local session state.\r\n state.csrfToken = null;\r\n state.session = null;\r\n\r\n return ok(undefined);\r\n}\r\n\r\n/**\r\n * Reset session by logging out and back in\r\n *\r\n * Called automatically on 500 errors to recover from session expiration.\r\n *\r\n * @param state - Session state to reset\r\n * @param request - HTTP request function from client\r\n * @returns void or error\r\n */\r\nexport async function sessionReset(\r\n state: SessionState,\r\n request: RequestFn\r\n): AsyncResult<void, Error> {\r\n // Attempt to logout from current session.\r\n await logout(state, request);\r\n\r\n // Clear session state regardless of logout result.\r\n state.csrfToken = null;\r\n state.session = null;\r\n\r\n // Re-login to establish new session.\r\n const [, loginErr] = await login(state, request);\r\n if (loginErr) {\r\n return err(loginErr);\r\n }\r\n\r\n return ok(undefined);\r\n}\r\n","// ADT Object Type Configuration — metadata for SAP development objects\n\nimport type { AsyncResult } from '../../types/result';\n\n// Client interface for ADT requests\nexport interface AdtRequestor {\n request(options: {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\n path: string;\n params?: Record<string, string | number>;\n headers?: Record<string, string>;\n body?: string;\n }): AsyncResult<Response, Error>;\n}\n\n// Configuration for a specific SAP object type\nexport interface ObjectConfig {\n /** ADT endpoint path (e.g., 'ddic/ddl/sources') */\n endpoint: string;\n /** XML namespace for creation requests */\n nameSpace: string;\n /** Root element name for creation XML */\n rootName: string;\n /** SAP ADT object type identifier (e.g., 'DDLS/DF') */\n type: string;\n /** Human-readable label (e.g., 'View') */\n label: string;\n /** File extension (e.g., 'asddls') */\n extension: string;\n /** Data preview endpoint (if supported) */\n dpEndpoint?: string;\n /** Data preview parameter name (if supported) */\n dpParam?: string;\n}\n\n/**\n * Result of upsert operation\n */\nexport interface UpsertResult {\n name: string;\n extension: string;\n status: 'created' | 'updated' | 'unchanged';\n transport?: string;\n}\n\n/**\n * Supported object types\n */\nexport type ConfiguredExtension = 'asddls' | 'asdcls' | 'astabldt' | 'aclass' | 'asprog';\n\n/**\n * Object type labels\n */\nexport enum ObjectTypeLabel {\n VIEW = 'View',\n ACCESS_CONTROL = 'Access Control',\n TABLE = 'Table',\n CLASS = 'Class',\n PROGRAM = 'ABAP Program',\n}\n\n/**\n * Configuration map for all supported object types\n *\n * Maps file extensions to their ADT configuration.\n * This is the central registry for object type metadata.\n */\nexport const OBJECT_CONFIG_MAP: Record<ConfiguredExtension, ObjectConfig> = {\n 'asddls': {\n endpoint: 'ddic/ddl/sources',\n nameSpace: 'xmlns:ddl=\"http://www.sap.com/adt/ddic/ddlsources\"',\n rootName: 'ddl:ddlSource',\n type: 'DDLS/DF',\n label: ObjectTypeLabel.VIEW,\n extension: 'asddls',\n dpEndpoint: 'cds',\n dpParam: 'ddlSourceName',\n },\n 'asdcls': {\n endpoint: 'acm/dcl/sources',\n nameSpace: 'xmlns:dcl=\"http://www.sap.com/adt/acm/dclsources\"',\n rootName: 'dcl:dclSource',\n type: 'DCLS/DL',\n label: ObjectTypeLabel.ACCESS_CONTROL,\n extension: 'asdcls',\n },\n 'aclass': {\n endpoint: 'oo/classes',\n nameSpace: 'xmlns:class=\"http://www.sap.com/adt/oo/classes\"',\n rootName: 'class:abapClass',\n type: 'CLAS/OC',\n label: ObjectTypeLabel.CLASS,\n extension: 'aclass',\n },\n 'astabldt': {\n endpoint: 'ddic/tables',\n nameSpace: 'xmlns:blue=\"http://www.sap.com/wbobj/blue\"',\n rootName: 'blue:blueSource',\n type: 'TABL/DT',\n label: ObjectTypeLabel.TABLE,\n extension: 'astabldt',\n dpEndpoint: 'ddic',\n dpParam: 'ddicEntityName',\n },\n 'asprog': {\n endpoint: 'programs/programs',\n nameSpace: 'xmlns:program=\"http://www.sap.com/adt/programs/programs\"',\n rootName: 'program:abapProgram',\n type: 'PROG/P',\n label: ObjectTypeLabel.PROGRAM,\n extension: 'asprog',\n },\n};\n\n/**\n * Get object configuration by extension\n *\n * @param extension - File extension (e.g., 'asddls')\n * @returns Configuration or null if not found\n */\nexport function getConfigByExtension(extension: string): ObjectConfig | null {\n return OBJECT_CONFIG_MAP[extension as ConfiguredExtension] ?? null;\n}\n\n/**\n * Get object configuration by ADT type\n *\n * @param type - ADT type identifier (e.g., 'DDLS/DF')\n * @returns Configuration or null if not found\n */\nexport function getConfigByType(type: string): ObjectConfig | null {\n for (const config of Object.values(OBJECT_CONFIG_MAP)) {\n if (config.type === type) {\n return config;\n }\n }\n return null;\n}\n\n/**\n * Get all configured extensions\n *\n * @returns Array of supported extensions\n */\nexport function getAllExtensions(): ConfiguredExtension[] {\n return Object.keys(OBJECT_CONFIG_MAP) as ConfiguredExtension[];\n}\n\n/**\n * Get all configured ADT types\n *\n * @returns Array of supported ADT types\n */\nexport function getAllTypes(): string[] {\n return Object.values(OBJECT_CONFIG_MAP).map(config => config.type);\n}\n\n/**\n * Check if extension is supported\n *\n * @param extension - Extension to check\n * @returns True if supported\n */\nexport function isExtensionSupported(extension: string): extension is ConfiguredExtension {\n return extension in OBJECT_CONFIG_MAP;\n}\n","/**\n * ADT Helpers — shared utilities for ADT operations\n *\n * Internal helpers used across multiple ADT files.\n * Not exported from the adt/ barrel.\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { extractError } from '../utils/xml';\nimport { getConfigByExtension } from './types';\nimport type { ObjectConfig } from './types';\n\n/**\n * Check response for errors and return text content\n */\nexport async function checkResponse(\n response: Response | null,\n requestErr: Error | null,\n operation: string\n): AsyncResult<string, Error> {\n // Handle request errors.\n if (requestErr) return [null, requestErr];\n if (!response) return [null, new Error(`${operation}: No response`)];\n\n // Handle HTTP errors.\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n // Include status and raw text if no message found for debugging\n if (errorMsg === 'No message found' || errorMsg === 'Failed to parse error XML') {\n return [null, new Error(`${operation}: HTTP ${response.status} - ${text.substring(0, 500)}`)];\n }\n return [null, new Error(`${operation}: ${errorMsg}`)];\n }\n\n // Return successful response text.\n return [await response.text(), null];\n}\n\n/**\n * Validate extension and return config\n */\nexport function requireConfig(extension: string): [ObjectConfig, null] | [null, Error] {\n // Lookup configuration for extension.\n const config = getConfigByExtension(extension);\n if (!config) return [null, new Error(`Unsupported extension: ${extension}`)];\n\n // Return valid configuration.\n return [config, null];\n}\n","/**\n * POST /objects/read — Read object source content\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectRef } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { checkResponse, requireConfig } from './helpers';\n\n/**\n * Object metadata\n */\nexport interface ObjectMetadata {\n name: string;\n extension: string;\n package: string;\n description?: string;\n createdBy?: string;\n createdAt?: string;\n modifiedBy?: string;\n modifiedAt?: string;\n}\n\n/**\n * Object with content (read response)\n */\nexport interface ObjectWithContent extends ObjectMetadata {\n content: string;\n}\n\n/**\n * Read object source content\n *\n * @param client - ADT client\n * @param object - Object reference (name + extension)\n * @returns Object with content or error\n */\nexport async function readObject(\n client: AdtRequestor,\n object: ObjectRef\n): AsyncResult<ObjectWithContent, Error> {\n // Validate object extension is supported.\n const [config, configErr] = requireConfig(object.extension);\n if (configErr) return err(configErr);\n\n // Execute GET request for object source content.\n const [response, requestErr] = await client.request({\n method: 'GET',\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\n headers: { 'Accept': 'text/plain' },\n });\n\n // Validate successful response and extract content.\n const [content, checkErr] = await checkResponse(\n response,\n requestErr,\n `Failed to read ${config.label} ${object.name}`\n );\n if (checkErr) return err(checkErr);\n\n // Build result object with content.\n const result: ObjectWithContent = {\n name: object.name,\n extension: object.extension,\n package: '',\n content,\n };\n\n return ok(result);\n}\n","/**\r\n * Lock/Unlock — Object lock management for editing\r\n */\r\n\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { ObjectRef } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport { extractLockHandle } from '../utils/xml';\r\nimport { checkResponse, requireConfig } from './helpers';\r\nimport { debug } from '../utils/logging';\r\n\r\n/**\r\n * Lock an object for editing\r\n *\r\n * @param client - ADT client\r\n * @param object - Object reference (name + extension)\r\n * @returns Lock handle string or error\r\n */\r\nexport async function lockObject(\r\n client: AdtRequestor,\r\n object: ObjectRef\r\n): AsyncResult<string, Error> {\r\n // Validate object extension is supported.\r\n const [config, configErr] = requireConfig(object.extension);\r\n if (configErr) return err(configErr);\r\n\r\n // Execute lock request.\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\r\n params: {\r\n '_action': 'LOCK',\r\n 'accessMode': 'MODIFY',\r\n },\r\n headers: {\r\n 'Accept': 'application/*,application/vnd.sap.as+xml;charset=UTF-8;dataname=com.sap.adt.lock.result',\r\n },\r\n });\r\n\r\n // Validate successful response.\r\n const [text, checkErr] = await checkResponse(\r\n response,\r\n requestErr,\r\n `Failed to lock ${config.label} ${object.name}`\r\n );\r\n if (checkErr) return err(checkErr);\r\n\r\n // Extract lock handle from XML response.\r\n const [lockHandle, extractErr] = extractLockHandle(text);\r\n if (extractErr) {\r\n return err(new Error(`Failed to extract lock handle: ${extractErr.message}`));\r\n }\r\n debug(`Lock acquired: handle=${lockHandle}`);\r\n\r\n return ok(lockHandle);\r\n}\r\n\r\n/**\r\n * Unlock an object after editing\r\n *\r\n * @param client - ADT client\r\n * @param object - Object reference (name + extension)\r\n * @param lockHandle - Lock handle from lockObject()\r\n * @returns void or error\r\n */\r\nexport async function unlockObject(\r\n client: AdtRequestor,\r\n object: ObjectRef,\r\n lockHandle: string\r\n): AsyncResult<void, Error> {\r\n // Validate object extension is supported.\r\n const [config, configErr] = requireConfig(object.extension);\r\n if (configErr) return err(configErr);\r\n\r\n // Execute unlock request.\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\r\n params: {\r\n '_action': 'UNLOCK',\r\n 'lockHandle': lockHandle,\r\n },\r\n });\r\n\r\n // Validate successful response.\r\n const [_, checkErr] = await checkResponse(\r\n response,\r\n requestErr,\r\n `Failed to unlock ${config.label} ${object.name}`\r\n );\r\n if (checkErr) return err(checkErr);\r\n\r\n return ok(undefined);\r\n}\r\n","/**\n * Create — Create new SAP development object\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectContent } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { escapeXml } from '../utils/xml';\nimport { checkResponse, requireConfig } from './helpers';\n\n/**\n * Create a new object in SAP\n *\n * @param client - ADT client\n * @param object - Object with content (name, extension, content, description)\n * @param packageName - Target package\n * @param transport - Transport request (required for non-$TMP packages)\n * @param username - Creating user\n * @returns void or error\n */\nexport async function createObject(\n client: AdtRequestor,\n object: ObjectContent,\n packageName: string,\n transport: string | undefined,\n username: string\n): AsyncResult<void, Error> {\n // Validate object extension is supported.\n const [config, configErr] = requireConfig(object.extension);\n if (configErr) return err(configErr);\n\n // Default empty description if not provided.\n const description = object.description ?? '';\n\n // Build XML request body with object metadata.\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<${config.rootName} ${config.nameSpace}\n xmlns:adtcore=\"http://www.sap.com/adt/core\"\n adtcore:description=\"${escapeXml(description)}\"\n adtcore:language=\"EN\"\n adtcore:name=\"${object.name.toUpperCase()}\"\n adtcore:type=\"${config.type}\"\n adtcore:responsible=\"${username.toUpperCase()}\">\n\n <adtcore:packageRef adtcore:name=\"${packageName}\"/>\n\n</${config.rootName}>`;\n\n // Add transport parameter if provided.\n const params: Record<string, string> = {};\n if (transport) {\n params['corrNr'] = transport;\n }\n\n // Execute create request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: `/sap/bc/adt/${config.endpoint}`,\n params,\n headers: { 'Content-Type': 'application/*' },\n body: body.trim(),\n });\n\n // Validate successful response.\n const [_, checkErr] = await checkResponse(\n response,\n requestErr,\n `Failed to create ${config.label} ${object.name}`\n );\n if (checkErr) return err(checkErr);\n\n return ok(undefined);\n}\n","/**\r\n * Update — Update existing SAP development object\r\n */\r\n\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { ObjectContent } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport { checkResponse, requireConfig } from './helpers';\r\nimport { debug } from '../utils/logging';\r\n\r\n/**\r\n * Update an existing object's source content\r\n *\r\n * @param client - ADT client\r\n * @param object - Object with new content\r\n * @param lockHandle - Lock handle from lockObject()\r\n * @param transport - Transport request (required for non-$TMP packages)\r\n * @returns void or error\r\n */\r\nexport async function updateObject(\r\n client: AdtRequestor,\r\n object: ObjectContent,\r\n lockHandle: string,\r\n transport: string | undefined\r\n): AsyncResult<void, Error> {\r\n // Validate object extension is supported.\r\n const [config, configErr] = requireConfig(object.extension);\r\n if (configErr) return err(configErr);\r\n\r\n // Build request parameters with lock handle.\r\n const params: Record<string, string> = {\r\n 'lockHandle': lockHandle,\r\n };\r\n if (transport) {\r\n params['corrNr'] = transport;\r\n }\r\n\r\n // Execute update request to ADT server.\r\n debug(`Update ${object.name}: content length=${object.content?.length ?? 0}`);\r\n const [response, requestErr] = await client.request({\r\n method: 'PUT',\r\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\r\n params,\r\n headers: { 'Content-Type': '*/*' },\r\n body: object.content,\r\n });\r\n debug(`Update response: ${response?.status ?? 'no response'}, err=${requestErr?.message ?? 'none'}`);\r\n\r\n // Validate successful response.\r\n const [_, checkErr] = await checkResponse(\r\n response,\r\n requestErr,\r\n `Failed to update ${config.label} ${object.name}`\r\n );\r\n if (checkErr) return err(checkErr);\r\n\r\n return ok(undefined);\r\n}\r\n","/**\n * Delete — Delete SAP development object\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectRef } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { checkResponse, requireConfig } from './helpers';\n\n/**\n * Delete an object from SAP\n *\n * @param client - ADT client\n * @param object - Object reference (name + extension)\n * @param lockHandle - Lock handle from lockObject()\n * @param transport - Transport request (required for non-$TMP packages)\n * @returns void or error\n */\nexport async function deleteObject(\n client: AdtRequestor,\n object: ObjectRef,\n lockHandle: string,\n transport: string | undefined\n): AsyncResult<void, Error> {\n // Validate object extension is supported.\n const [config, configErr] = requireConfig(object.extension);\n if (configErr) return err(configErr);\n\n // Build request parameters with lock handle.\n const params: Record<string, string> = {\n 'lockHandle': lockHandle,\n };\n if (transport) {\n params['corrNr'] = transport;\n }\n\n // Execute delete request.\n const [response, requestErr] = await client.request({\n method: 'DELETE',\n path: `/sap/bc/adt/${config.endpoint}/${object.name}/source/main`,\n params,\n headers: { 'Accept': 'text/plain' },\n });\n\n // Validate successful response.\n const [_, checkErr] = await checkResponse(\n response,\n requestErr,\n `Failed to delete ${config.label} ${object.name}`\n );\n if (checkErr) return err(checkErr);\n\n return ok(undefined);\n}\n","// ADT Activation — activate ADT objects\r\n\r\nimport type { Result, AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { ObjectRef } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport { getConfigByExtension } from './types';\r\nimport { extractError, safeParseXml } from '../utils/xml';\r\nimport { debug } from '../utils/logging';\r\n\r\n/**\r\n * Result of activation operation\r\n */\r\nexport interface ActivationResult {\r\n name: string;\r\n extension: string;\r\n status: 'success' | 'warning' | 'error';\r\n messages: ActivationMessage[];\r\n}\r\n\r\nexport interface ActivationMessage {\r\n severity: 'error' | 'warning' | 'info';\r\n text: string;\r\n line?: number;\r\n column?: number;\r\n}\r\n\r\nexport async function activateObjects(\r\n client: AdtRequestor,\r\n objects: ObjectRef[]\r\n): AsyncResult<ActivationResult[], Error> {\r\n // Handle empty input.\r\n if (objects.length === 0) {\r\n return ok([]);\r\n }\r\n\r\n // Validate object extension is supported.\r\n const extension = objects[0]!.extension;\r\n const config = getConfigByExtension(extension);\r\n if (!config) return err(new Error(`Unsupported extension: ${extension}`));\r\n\r\n // Verify all objects have same extension for batch activation.\r\n for (const obj of objects) {\r\n if (obj.extension !== extension) {\r\n return err(new Error('All objects must have the same extension for batch activation'));\r\n }\r\n }\r\n\r\n // Build XML request body with object references.\r\n const objectRefs = objects.map(obj => `<adtcore:objectReference\r\n adtcore:uri=\"/sap/bc/adt/${config.endpoint}/${obj.name.toLowerCase()}\"\r\n adtcore:type=\"${config.type}\"\r\n adtcore:name=\"${obj.name}\"\r\n adtcore:description=\"*\"/>`).join('\\n ');\r\n\r\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n <adtcore:objectReferences xmlns:adtcore=\"http://www.sap.com/adt/core\">\r\n ${objectRefs}\r\n </adtcore:objectReferences>`;\r\n\r\n // Execute activation request.\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: '/sap/bc/adt/activation',\r\n params: {\r\n 'method': 'activate',\r\n 'preAuditRequested': 'true',\r\n },\r\n headers: {\r\n 'Content-Type': 'application/xml',\r\n 'Accept': 'application/xml',\r\n },\r\n body,\r\n });\r\n\r\n // Validate successful response.\r\n if (requestErr) { return err(requestErr); }\r\n const text = await response.text();\r\n debug(`Activation response status: ${response.status}`);\r\n debug(`Activation response: ${text.substring(0, 500)}`);\r\n if (!response.ok) {\r\n const errorMsg = extractError(text);\r\n return err(new Error(`Activation failed: ${errorMsg}`));\r\n }\r\n\r\n // Parse activation results from response.\r\n const [results, parseErr] = extractActivationErrors(objects, text, extension);\r\n if (parseErr) { return err(parseErr); }\r\n return ok(results);\r\n}\r\n\r\n// Parse activation response XML for errors\r\nfunction extractActivationErrors(\r\n objects: ObjectRef[],\r\n xml: string,\r\n _extension: string\r\n): Result<ActivationResult[], Error> {\r\n // Parse XML response.\r\n const [doc, parseErr] = safeParseXml(xml);\r\n if (parseErr) { return err(parseErr); }\r\n\r\n // Initialize error map with empty arrays for each object.\r\n const errorMap: Map<string, ActivationMessage[]> = new Map();\r\n objects.forEach(obj => errorMap.set(obj.name.toLowerCase(), []));\r\n\r\n // Extract message elements and prepare regex for position parsing.\r\n const msgElements = doc.getElementsByTagName('msg');\r\n const startRegex = /#start=(\\d+),(\\d+)/;\r\n\r\n // Process each message element.\r\n for (let i = 0; i < msgElements.length; i++) {\r\n const msg = msgElements[i];\r\n if (!msg) continue;\r\n\r\n // Skip warning messages (type 'W').\r\n const type = msg.getAttribute('type');\r\n if (type === 'W') continue;\r\n\r\n // Extract object description and href for position info.\r\n const objDescr = msg.getAttribute('objDescr');\r\n const href = msg.getAttribute('href');\r\n if (!objDescr || !href) continue;\r\n\r\n // Parse line and column from href.\r\n let line: number | undefined;\r\n let column: number | undefined;\r\n const match = startRegex.exec(href);\r\n if (match && match[1] && match[2]) {\r\n line = parseInt(match[1], 10);\r\n column = parseInt(match[2], 10);\r\n }\r\n if (!line || !column) continue;\r\n\r\n // Find matching object by name.\r\n const matchingObj = objects.find(obj =>\r\n objDescr.toLowerCase().includes(obj.name.toLowerCase())\r\n );\r\n if (!matchingObj) continue;\r\n\r\n // Extract message text elements.\r\n const shortTextElements = msg.getElementsByTagName('txt');\r\n for (let j = 0; j < shortTextElements.length; j++) {\r\n const txt = shortTextElements[j];\r\n if (!txt) continue;\r\n\r\n const text = txt.textContent;\r\n if (!text) continue;\r\n\r\n // Build activation message with severity and position.\r\n const message: ActivationMessage = {\r\n severity: type === 'E' ? 'error' : 'warning',\r\n text,\r\n line,\r\n column,\r\n };\r\n\r\n // Add message to object's error list.\r\n const messages = errorMap.get(matchingObj.name.toLowerCase()) || [];\r\n messages.push(message);\r\n errorMap.set(matchingObj.name.toLowerCase(), messages);\r\n }\r\n }\r\n\r\n // Build final results with status based on message severity.\r\n const results: ActivationResult[] = objects.map(obj => {\r\n const messages = errorMap.get(obj.name.toLowerCase()) || [];\r\n const hasErrors = messages.some(m => m.severity === 'error');\r\n\r\n return {\r\n name: obj.name,\r\n extension: obj.extension,\r\n status: hasErrors ? 'error' : messages.length > 0 ? 'warning' : 'success',\r\n messages,\r\n };\r\n });\r\n\r\n return ok(results);\r\n}\r\n","/**\n * Tree — Hierarchical tree browsing for packages\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { TreeQuery } from '../../types/requests';\nimport type { AdtRequestor } from './types';\nimport { getConfigByType } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Tree node for hierarchical browsing\n */\nexport interface TreeNode {\n name: string;\n type: 'folder' | 'object';\n objectType?: string;\n extension?: string;\n hasChildren?: boolean;\n children?: TreeNode[];\n}\n\n/**\n * Package info\n */\nexport interface Package {\n name: string;\n description?: string;\n parentPackage?: string;\n}\n\n/**\n * Virtual folder for tree discovery (internal)\n */\ninterface VirtualFolder {\n name: string;\n hasChildrenOfSameFacet: boolean;\n count?: string;\n}\n\n/**\n * Tree discovery internal query (internal)\n */\ninterface TreeDiscoveryQuery {\n PACKAGE?: VirtualFolder;\n TYPE?: VirtualFolder;\n GROUP?: VirtualFolder;\n API?: VirtualFolder;\n}\n\n/**\n * Get hierarchical tree of objects\n *\n * @param client - ADT client\n * @param query - Tree query parameters\n * @returns Tree nodes or error\n */\nexport async function getTree(\n client: AdtRequestor,\n query: TreeQuery\n): AsyncResult<TreeNode[], Error> {\n // Build internal query with package filter.\n const internalQuery: TreeDiscoveryQuery = {};\n if (query.package) {\n internalQuery.PACKAGE = {\n name: query.package.startsWith('..') ? query.package : `..${query.package}`,\n hasChildrenOfSameFacet: false,\n };\n }\n\n // Execute tree discovery and return nodes.\n const [result, resultErr] = await getTreeInternal(client, internalQuery, '*');\n if (resultErr) { return err(resultErr); }\n return ok(result.nodes);\n}\n\n/**\n * Internal tree discovery with full options\n *\n * Exported for use by packages.ts\n */\nexport async function getTreeInternal(\n client: AdtRequestor,\n query: TreeDiscoveryQuery,\n searchPattern: string\n): AsyncResult<{ nodes: TreeNode[]; packages: Package[] }, Error> {\n // Build XML request body.\n const body = constructTreeBody(query, searchPattern);\n\n // Execute virtual folders request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/repository/informationsystem/virtualfolders/contents',\n headers: {\n 'Content-Type': 'application/vnd.sap.adt.repository.virtualfolders.request.v1+xml',\n 'Accept': 'application/vnd.sap.adt.repository.virtualfolders.result.v1+xml',\n },\n body,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Tree discovery failed: ${errorMsg}`));\n }\n\n // Parse tree response.\n const text = await response.text();\n const [result, parseErr] = parseTreeResponse(text);\n if (parseErr) { return err(parseErr); }\n return ok(result);\n}\n\n// Construct tree discovery request body.\nfunction constructTreeBody(query: TreeDiscoveryQuery, searchPattern: string): string {\n // Determine which facets are specified vs requested.\n const facets: string[] = [];\n const specified: Record<string, string> = {};\n const sortedFacets = ['PACKAGE', 'GROUP', 'TYPE', 'API'];\n\n for (const facet of sortedFacets) {\n const value = query[facet as keyof TreeDiscoveryQuery];\n if (value) {\n specified[facet] = value.name;\n if (!value.hasChildrenOfSameFacet) {\n facets.push(facet);\n }\n } else {\n facets.push(facet);\n }\n }\n\n // Build XML elements for specified facets using preselection structure.\n const specifiedXml = Object.entries(specified)\n .map(([facet, name]) => ` <vfs:preselection facet=\"${facet.toLowerCase()}\">\n <vfs:value>${name}</vfs:value>\n </vfs:preselection>`)\n .join('\\n');\n\n // Build XML elements for requested facets (lowercase).\n const facetsXml = facets\n .map(facet => ` <vfs:facet>${facet.toLowerCase()}</vfs:facet>`)\n .join('\\n');\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<vfs:virtualFoldersRequest xmlns:vfs=\"http://www.sap.com/adt/ris/virtualFolders\" objectSearchPattern=\"${searchPattern}\">\n${specifiedXml}\n <vfs:facetorder>\n${facetsXml}\n </vfs:facetorder>\n</vfs:virtualFoldersRequest>`;\n}\n\n// Parse tree discovery response.\nfunction parseTreeResponse(xml: string): Result<{ nodes: TreeNode[]; packages: Package[] }, Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n const nodes: TreeNode[] = [];\n const packages: Package[] = [];\n\n // Process virtual folder elements (packages, groups, etc).\n const virtualFolders = doc.getElementsByTagName('vfs:virtualFolder');\n for (let i = 0; i < virtualFolders.length; i++) {\n const vf = virtualFolders[i];\n if (!vf) continue;\n\n const facet = vf.getAttribute('facet');\n const name = vf.getAttribute('name');\n\n // Extract package metadata if this is a package facet.\n if (facet === 'PACKAGE' && name) {\n const desc = vf.getAttribute('description');\n const pkg: Package = {\n name: name.startsWith('..') ? name.substring(2) : name,\n };\n if (desc) {\n pkg.description = desc;\n }\n packages.push(pkg);\n }\n\n if (!name || !facet) continue;\n\n // Add folder node (strip '..' prefix from name).\n nodes.push({\n name: name.startsWith('..') ? name.substring(2) : name,\n type: 'folder',\n hasChildren: vf.getAttribute('hasChildrenOfSameFacet') === 'true',\n });\n }\n\n // Process object elements (actual ADT objects).\n const objects = doc.getElementsByTagName('vfs:object');\n for (let i = 0; i < objects.length; i++) {\n const obj = objects[i];\n if (!obj) continue;\n\n const name = obj.getAttribute('name');\n const type = obj.getAttribute('type');\n if (!name || !type) continue;\n\n // Look up object type configuration.\n const config = getConfigByType(type);\n if (!config) continue;\n\n nodes.push({\n name,\n type: 'object',\n objectType: config.label,\n extension: config.extension,\n });\n }\n\n return ok({ nodes, packages });\n}\n","/**\n * Packages — List available packages\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport type { Package } from './tree';\nimport { getTreeInternal } from './tree';\n\n/**\n * Get list of available packages\n *\n * @param client - ADT client\n * @returns Array of packages or error\n */\nexport async function getPackages(\n client: AdtRequestor\n): AsyncResult<Package[], Error> {\n // Fetch tree with all packages using wildcard filter.\n const [treeResult, treeErr] = await getTreeInternal(client, {}, '*');\n\n // Validate successful tree retrieval.\n if (treeErr) {\n return err(treeErr);\n }\n\n // Extract packages from tree result.\n return ok(treeResult.packages);\n}\n","/**\n * Transports — List transport requests for a package\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\n\n/**\n * Transport request\n */\nexport interface Transport {\n id: string;\n description: string;\n owner: string;\n status: 'modifiable' | 'released';\n}\n\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Get transports for a package\n *\n * @param client - ADT client\n * @param packageName - Package name\n * @returns Array of transports or error\n */\nexport async function getTransports(\n client: AdtRequestor,\n packageName: string\n): AsyncResult<Transport[], Error> {\n // Build XML request body for transport check.\n const contentType = 'application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.transport.service.checkData';\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <asx:abap version=\"1.0\" xmlns:asx=\"http://www.sap.com/abapxml\">\n <asx:values>\n <DATA>\n <PGMID></PGMID>\n <OBJECT></OBJECT>\n <OBJECTNAME></OBJECTNAME>\n <DEVCLASS>${packageName}</DEVCLASS>\n <SUPER_PACKAGE></SUPER_PACKAGE>\n <OPERATION>I</OPERATION>\n <URI>/sap/bc/adt/ddic/ddl/sources/transport_check</URI>\n </DATA>\n </asx:values>\n </asx:abap>`;\n\n // Execute transport check request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/cts/transportchecks',\n headers: {\n 'Accept': contentType,\n 'Content-Type': contentType,\n },\n body,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Failed to fetch transports for ${packageName}: ${errorMsg}`));\n }\n\n // Parse transports from response.\n const text = await response.text();\n const [transports, parseErr] = extractTransports(text);\n if (parseErr) { return err(parseErr); }\n return ok(transports);\n}\n\n// Extract transports from XML response.\nfunction extractTransports(xml: string): Result<Transport[], Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Extract transport headers from response.\n const transports: Transport[] = [];\n const reqHeaders = doc.getElementsByTagName('REQ_HEADER');\n\n // Process each transport header.\n for (let i = 0; i < reqHeaders.length; i++) {\n const header = reqHeaders[i];\n if (!header) continue;\n\n // Extract transport metadata elements.\n const trkorrElement = header.getElementsByTagName('TRKORR')[0];\n const userElement = header.getElementsByTagName('AS4USER')[0];\n const textElement = header.getElementsByTagName('AS4TEXT')[0];\n if (!trkorrElement || !userElement || !textElement) continue;\n\n // Extract text content from elements.\n const id = trkorrElement.textContent;\n const owner = userElement.textContent;\n const description = textElement.textContent;\n if (!id || !owner || !description) continue;\n\n // Build transport object.\n transports.push({\n id,\n owner,\n description,\n status: 'modifiable',\n });\n }\n\n return ok(transports);\n}\n","/**\r\n * Preview Parser — Parse data preview XML responses\r\n *\r\n * Internal helper used by data.ts, distinct.ts, and count.ts\r\n */\r\n\r\nimport type { Result } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport { safeParseXml } from '../utils/xml';\r\n\r\n/**\r\n * Data preview result (columnar format)\r\n */\r\nexport interface DataFrame {\r\n columns: ColumnInfo[];\r\n rows: unknown[][];\r\n totalRows?: number;\r\n}\r\n\r\nexport interface ColumnInfo {\r\n name: string;\r\n dataType: string;\r\n label?: string;\r\n}\r\n\r\n/**\r\n * Parse data preview XML response\r\n *\r\n * Handles two XML formats:\r\n * 1. Regular queries: Have <metadata> elements with column definitions\r\n * 2. Aggregate queries (COUNT, GROUP BY): No metadata, infer columns from <dataSet> elements\r\n *\r\n * @param xml - XML response from SAP\r\n * @param maxRows - Maximum rows to parse\r\n * @param isTable - Whether source is a table (affects column name attribute)\r\n * @returns DataFrame or error\r\n */\r\nexport function parseDataPreview(\r\n xml: string,\r\n maxRows: number,\r\n isTable: boolean\r\n): Result<DataFrame, Error> {\r\n // Parse XML response.\r\n const [doc, parseErr] = safeParseXml(xml);\r\n if (parseErr) { return err(parseErr); }\r\n\r\n const namespace = 'http://www.sap.com/adt/dataPreview';\r\n\r\n // Extract column metadata from response (if present).\r\n const metadataElements = doc.getElementsByTagNameNS(namespace, 'metadata');\r\n const columns: ColumnInfo[] = [];\r\n\r\n for (let i = 0; i < metadataElements.length; i++) {\r\n const meta = metadataElements[i];\r\n if (!meta) continue;\r\n\r\n // Tables use 'name', views use 'camelCaseName'.\r\n const nameAttr = isTable ? 'name' : 'camelCaseName';\r\n const name = meta.getAttributeNS(namespace, nameAttr) || meta.getAttribute('name');\r\n const dataType = meta.getAttributeNS(namespace, 'colType') || meta.getAttribute('colType');\r\n if (!name || !dataType) continue;\r\n\r\n columns.push({ name, dataType });\r\n }\r\n\r\n // Extract data values organized by column.\r\n const dataSetElements = doc.getElementsByTagNameNS(namespace, 'dataSet');\r\n\r\n // If no metadata, infer columns from dataSet elements (aggregate queries).\r\n if (columns.length === 0 && dataSetElements.length > 0) {\r\n for (let i = 0; i < dataSetElements.length; i++) {\r\n const dataSet = dataSetElements[i];\r\n if (!dataSet) continue;\r\n // Use column index as name for aggregate results.\r\n const name = dataSet.getAttributeNS(namespace, 'columnName')\r\n || dataSet.getAttribute('columnName')\r\n || `column${i}`;\r\n columns.push({ name, dataType: 'unknown' });\r\n }\r\n }\r\n\r\n // Still no columns - return empty DataFrame.\r\n if (columns.length === 0) {\r\n return ok({ columns: [], rows: [], totalRows: 0 });\r\n }\r\n\r\n const columnData: string[][] = Array.from({ length: columns.length }, () => []);\r\n\r\n for (let i = 0; i < dataSetElements.length; i++) {\r\n const dataSet = dataSetElements[i];\r\n if (!dataSet) continue;\r\n\r\n const dataElements = dataSet.getElementsByTagNameNS(namespace, 'data');\r\n for (let j = 0; j < dataElements.length; j++) {\r\n const data = dataElements[j];\r\n if (!data) continue;\r\n\r\n const value = data.textContent?.trim() || '';\r\n columnData[i]!.push(value);\r\n }\r\n }\r\n\r\n // Transform column-oriented data into row-oriented format.\r\n const rows: unknown[][] = [];\r\n const rowCount = columnData[0]?.length || 0;\r\n for (let i = 0; i < Math.min(rowCount, maxRows); i++) {\r\n const row: unknown[] = [];\r\n for (let j = 0; j < columns.length; j++) {\r\n row.push(columnData[j]![i]);\r\n }\r\n rows.push(row);\r\n }\r\n\r\n // Build final DataFrame result.\r\n const dataFrame: DataFrame = {\r\n columns,\r\n rows,\r\n totalRows: rowCount,\r\n };\r\n\r\n return ok(dataFrame);\r\n}\r\n","/**\r\n * Data Preview — Execute SQL queries against table/view data\r\n */\r\n\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { PreviewQuery } from '../../types/requests';\r\nimport type { AdtRequestor } from './types';\r\nimport type { DataFrame } from './previewParser';\r\nimport { getConfigByExtension } from './types';\r\nimport { extractError } from '../utils/xml';\r\nimport { debug } from '../utils/logging';\r\nimport { parseDataPreview } from './previewParser';\r\n\r\n/**\r\n * Execute SQL query against table/view data\r\n *\r\n * @param client - ADT client\r\n * @param query - Preview query with SQL\r\n * @returns DataFrame or error\r\n */\r\nexport async function previewData(\r\n client: AdtRequestor,\r\n query: PreviewQuery\r\n): AsyncResult<DataFrame, Error> {\r\n // Get config by objectType.\r\n const extension = query.objectType === 'table' ? 'astabldt' : 'asddls';\r\n const config = getConfigByExtension(extension);\r\n if (!config?.dpEndpoint || !config?.dpParam) {\r\n return err(new Error(`Data preview not supported for object type: ${query.objectType}`));\r\n }\r\n\r\n // Execute request with caller-provided SQL.\r\n const limit = query.limit ?? 100;\r\n debug(`Data preview: endpoint=${config.dpEndpoint}, param=${config.dpParam}=${query.objectName}`);\r\n debug(`SQL: ${query.sqlQuery}`);\r\n\r\n const [response, requestErr] = await client.request({\r\n method: 'POST',\r\n path: `/sap/bc/adt/datapreview/${config.dpEndpoint}`,\r\n params: {\r\n 'rowNumber': limit,\r\n [config.dpParam]: query.objectName,\r\n },\r\n headers: {\r\n 'Accept': 'application/vnd.sap.adt.datapreview.table.v1+xml',\r\n 'Content-Type': 'text/plain',\r\n },\r\n body: query.sqlQuery,\r\n });\r\n\r\n // Handle errors.\r\n if (requestErr) { return err(requestErr); }\r\n if (!response.ok) {\r\n const text = await response.text();\r\n debug(`Data preview error response: ${text.substring(0, 500)}`);\r\n const errorMsg = extractError(text);\r\n return err(new Error(`Data preview failed: ${errorMsg}`));\r\n }\r\n\r\n // Parse response.\r\n const text = await response.text();\r\n const [dataFrame, parseErr] = parseDataPreview(text, limit, query.objectType === 'table');\r\n if (parseErr) { return err(parseErr); }\r\n return ok(dataFrame);\r\n}\r\n","/**\r\n * Distinct Values — Get distinct column values with counts\r\n */\r\n\r\nimport type { AsyncResult } from '../../types/result';\r\nimport { ok, err } from '../../types/result';\r\nimport type { AdtRequestor } from './types';\r\nimport { previewData } from './dataPreview';\r\n\r\n/**\r\n * Distinct values result\r\n */\r\nexport interface DistinctResult {\r\n column: string;\r\n values: Array<{\r\n value: unknown;\r\n count: number;\r\n }>;\r\n}\r\n\r\nconst MAX_ROW_COUNT = 50000;\r\n\r\n/**\r\n * Get distinct values for a column with counts\r\n *\r\n * @param client - ADT client\r\n * @param objectName - Table or view name\r\n * @param column - Column name\r\n * @param objectType - 'table' or 'view'\r\n * @returns Distinct values with counts or error\r\n */\r\nexport async function getDistinctValues(\r\n client: AdtRequestor,\r\n objectName: string,\r\n column: string,\r\n objectType: 'table' | 'view' = 'view'\r\n): AsyncResult<DistinctResult, Error> {\r\n const columnName = column.toUpperCase();\r\n const sqlQuery = `SELECT ${columnName} AS value, COUNT(*) AS count FROM ${objectName} GROUP BY ${columnName}`;\r\n\r\n const [dataFrame, error] = await previewData(client, {\r\n objectName,\r\n objectType,\r\n sqlQuery,\r\n limit: MAX_ROW_COUNT,\r\n });\r\n\r\n if (error) {\r\n return err(new Error(`Distinct values query failed: ${error.message}`));\r\n }\r\n\r\n // Transform DataFrame to DistinctResult.\r\n const values = dataFrame.rows.map(row => ({\r\n value: row[0],\r\n count: parseInt(String(row[1]), 10),\r\n }));\r\n\r\n return ok({ column, values });\r\n}\r\n","/**\n * Count Rows — Get total row count for table/view\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport { previewData } from './dataPreview';\n\n/**\n * Count total rows in a table or view\n *\n * @param client - ADT client\n * @param objectName - Table or view name\n * @param objectType - 'table' or 'view'\n * @returns Row count or error\n */\nexport async function countRows(\n client: AdtRequestor,\n objectName: string,\n objectType: 'table' | 'view'\n): AsyncResult<number, Error> {\n const sqlQuery = `SELECT COUNT(*) AS count FROM ${objectName}`;\n\n const [dataFrame, error] = await previewData(client, {\n objectName,\n objectType,\n sqlQuery,\n limit: 1,\n });\n\n if (error) {\n return err(new Error(`Row count query failed: ${error.message}`));\n }\n\n // Extract count from first row, first column.\n const countValue = dataFrame.rows[0]?.[0];\n if (countValue === undefined) {\n return err(new Error('No count value returned'));\n }\n\n const count = parseInt(String(countValue), 10);\n if (isNaN(count)) {\n return err(new Error('Invalid count value returned'));\n }\n\n return ok(count);\n}\n","/**\n * Search Objects — Quick search by name pattern\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\n\n/**\n * Search result\n */\nexport interface SearchResult {\n name: string;\n extension: string;\n package: string;\n description?: string;\n objectType: string;\n}\n\nimport { getConfigByType, getAllTypes } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Search for objects by name pattern\n *\n * @param client - ADT client\n * @param query - Search pattern (supports wildcards)\n * @param types - Optional array of object type filters\n * @returns Array of matching objects or error\n */\nexport async function searchObjects(\n client: AdtRequestor,\n query: string,\n types?: string[]\n): AsyncResult<SearchResult[], Error> {\n // Build search parameters.\n const searchPattern = query || '*';\n const objectTypes = types && types.length > 0 ? types : getAllTypes();\n\n // Construct query parameters (matching Python reference exactly).\n const params: Array<[string, string]> = [\n ['operation', 'quickSearch'],\n ['query', searchPattern],\n ['maxResults', '10001'],\n ];\n for (const type of objectTypes) {\n params.push(['objectType', type]);\n }\n\n // Build URL search params.\n const urlParams = new URLSearchParams();\n for (const [key, value] of params) {\n urlParams.append(key, value);\n }\n\n // Execute search request.\n const [response, requestErr] = await client.request({\n method: 'GET',\n path: `/sap/bc/adt/repository/informationsystem/search?${urlParams.toString()}`,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Search failed: ${errorMsg}`));\n }\n\n // Parse search results from response.\n const text = await response.text();\n const [results, parseErr] = parseSearchResults(text);\n if (parseErr) { return err(parseErr); }\n return ok(results);\n}\n\n// Parse search results from XML.\nfunction parseSearchResults(xml: string): Result<SearchResult[], Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Extract object reference elements.\n const results: SearchResult[] = [];\n const objectRefs = doc.getElementsByTagNameNS('http://www.sap.com/adt/core', 'objectReference');\n\n // Process each object reference.\n for (let i = 0; i < objectRefs.length; i++) {\n const obj = objectRefs[i];\n if (!obj) continue;\n\n // Extract object metadata.\n const name = obj.getAttributeNS('http://www.sap.com/adt/core', 'name') || obj.getAttribute('adtcore:name');\n const type = obj.getAttributeNS('http://www.sap.com/adt/core', 'type') || obj.getAttribute('adtcore:type');\n const description = obj.getAttributeNS('http://www.sap.com/adt/core', 'description') || obj.getAttribute('adtcore:description');\n if (!name || !type) continue;\n\n // Look up object type configuration.\n const config = getConfigByType(type);\n if (!config) continue;\n\n // Extract package reference if available.\n const packageRef = obj.getElementsByTagNameNS('http://www.sap.com/adt/core', 'packageRef')[0];\n const packageName = packageRef\n ? (packageRef.getAttributeNS('http://www.sap.com/adt/core', 'name') || packageRef.getAttribute('adtcore:name'))\n : '';\n\n // Build search result object.\n const result: SearchResult = {\n name,\n extension: config.extension,\n package: packageName || '',\n objectType: config.label,\n };\n if (description) {\n result.description = description;\n }\n results.push(result);\n }\n\n return ok(results);\n}\n","/**\n * Where-Used — Find object dependencies\n */\n\nimport type { Result, AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { ObjectRef } from '../../types/requests';\nimport type { AdtRequestor } from './types';\n\n/**\n * Where-used dependency\n */\nexport interface Dependency {\n name: string;\n extension: string;\n package: string;\n usageType: string;\n}\n\nimport { getConfigByType, getConfigByExtension } from './types';\nimport { extractError, safeParseXml } from '../utils/xml';\n\n/**\n * Find where an object is used (dependencies)\n *\n * @param client - ADT client\n * @param object - Object to analyze\n * @returns Array of dependent objects or error\n */\nexport async function findWhereUsed(\n client: AdtRequestor,\n object: ObjectRef\n): AsyncResult<Dependency[], Error> {\n // Validate object extension is supported.\n const config = getConfigByExtension(object.extension);\n if (!config) {\n return err(new Error(`Unsupported extension: ${object.extension}`));\n }\n\n // Build object URI and request body.\n const uri = `/sap/bc/adt/${config.endpoint}/${object.name}`;\n const body = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <usagereferences:usageReferenceRequest xmlns:usagereferences=\"http://www.sap.com/adt/ris/usageReferences\">\n <usagereferences:affectedObjects/>\n </usagereferences:usageReferenceRequest>`;\n\n // Execute where-used query.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/repository/informationsystem/usageReferences',\n params: {\n 'uri': uri,\n 'ris_request_type': 'usageReferences',\n },\n headers: {\n 'Content-Type': 'application/vnd.sap.adt.repository.usagereferences.request.v1+xml',\n 'Accept': 'application/vnd.sap.adt.repository.usagereferences.result.v1+xml',\n },\n body,\n });\n\n // Validate successful response.\n if (requestErr) { return err(requestErr); }\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Where-used query failed: ${errorMsg}`));\n }\n\n // Parse dependencies from response.\n const text = await response.text();\n const [dependencies, parseErr] = parseWhereUsed(text);\n if (parseErr) { return err(parseErr); }\n return ok(dependencies);\n}\n\n// Parse where-used results from XML.\nfunction parseWhereUsed(xml: string): Result<Dependency[], Error> {\n // Parse XML response.\n const [doc, parseErr] = safeParseXml(xml);\n if (parseErr) { return err(parseErr); }\n\n // Extract referenced object elements.\n const dependencies: Dependency[] = [];\n const referencedObjects = doc.getElementsByTagNameNS(\n 'http://www.sap.com/adt/ris/usageReferences',\n 'referencedObject'\n );\n\n // Process each referenced object.\n for (let i = 0; i < referencedObjects.length; i++) {\n const refObj = referencedObjects[i];\n if (!refObj) continue;\n\n // Extract ADT object element.\n const adtObject = refObj.getElementsByTagNameNS(\n 'http://www.sap.com/adt/ris/usageReferences',\n 'adtObject'\n )[0];\n if (!adtObject) continue;\n\n // Extract object name and type.\n const name = adtObject.getAttributeNS('http://www.sap.com/adt/core', 'name') || adtObject.getAttribute('adtcore:name');\n const type = adtObject.getAttributeNS('http://www.sap.com/adt/core', 'type') || adtObject.getAttribute('adtcore:type');\n if (!name || !type) continue;\n\n // Look up object type configuration.\n const config = getConfigByType(type);\n if (!config) continue;\n\n // Extract package reference if available.\n const packageRef = adtObject.getElementsByTagNameNS('http://www.sap.com/adt/core', 'packageRef')[0];\n const packageName = packageRef\n ? (packageRef.getAttributeNS('http://www.sap.com/adt/core', 'name') || packageRef.getAttribute('adtcore:name'))\n : '';\n\n // Build dependency object.\n dependencies.push({\n name,\n extension: config.extension,\n package: packageName || '',\n usageType: 'reference',\n });\n }\n\n return ok(dependencies);\n}\n","/**\n * Create Transport — Create a new transport request for a package\n */\n\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport { dictToAbapXml, extractError } from '../utils/xml';\n\n/**\n * Configuration for creating a transport\n */\nexport interface TransportConfig {\n /** Package name (DEVCLASS) */\n package: string;\n /** Transport description/text */\n description: string;\n}\n\n/**\n * Create a new transport request\n *\n * @param client - ADT client\n * @param config - Transport configuration\n * @returns Transport ID or error\n */\nexport async function createTransport(\n client: AdtRequestor,\n config: TransportConfig\n): AsyncResult<string, Error> {\n // Build XML request body.\n const body = dictToAbapXml({\n DEVCLASS: config.package,\n REQUEST_TEXT: config.description,\n REF: '',\n OPERATION: 'I',\n });\n\n // Execute transport creation request.\n const [response, requestErr] = await client.request({\n method: 'POST',\n path: '/sap/bc/adt/cts/transports',\n headers: {\n 'Content-Type': 'application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.CreateCorrectionRequest',\n 'Accept': 'text/plain',\n },\n body,\n });\n\n // Validate response.\n if (requestErr) return err(requestErr);\n if (!response.ok) {\n const text = await response.text();\n const errorMsg = extractError(text);\n return err(new Error(`Failed to create transport for ${config.package}: ${errorMsg}`));\n }\n\n // Extract transport ID from response.\n const text = await response.text();\n const transportId = text.trim().split('/').pop();\n\n if (!transportId) {\n return err(new Error('Failed to parse transport ID from response'));\n }\n\n return ok(transportId);\n}\n","/**\n * Git Diff — Compare local content with server content\n *\n * Uses Myers diff algorithm to compute line-by-line differences.\n */\n\nimport { diffArrays, type ChangeObject } from 'diff';\nimport type { AsyncResult } from '../../types/result';\nimport { ok, err } from '../../types/result';\nimport type { AdtRequestor } from './types';\nimport type { ObjectContent } from '../../types/requests';\nimport { readObject } from './read';\nimport { getConfigByExtension } from './types';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types (colocated - only used by this function)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Base fields for all diff hunks */\ninterface BaseDiffHunk {\n /** Total number of lines in the hunk */\n length: number;\n /** Starting line in the diff output (0-indexed) */\n diffStart: number;\n /** Starting line in the local file (0-indexed) */\n localStart: number;\n}\n\n/** Addition or deletion hunk */\nexport interface SimpleDiffHunk extends BaseDiffHunk {\n type: 'addition' | 'deletion';\n /** Lines added or removed */\n changes: string[];\n}\n\n/** Modification hunk (deletion immediately followed by addition) */\nexport interface ModifiedDiffHunk extends BaseDiffHunk {\n type: 'modification';\n /** Tuple of [server_lines, local_lines] */\n changes: [string[], string[]];\n}\n\n/** Any diff hunk */\nexport type DiffHunk = SimpleDiffHunk | ModifiedDiffHunk;\n\n/** Result of comparing a single object */\nexport interface DiffResult {\n name: string;\n extension: string;\n label: string;\n diffs: DiffHunk[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Implementation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Compute diff between server and local content\n *\n * Converts jsdiff ChangeObject[] output to the hunk format matching Python behavior.\n */\nfunction computeDiff(serverLines: string[], localLines: string[]): DiffHunk[] {\n const changes = diffArrays(serverLines, localLines);\n const hunks: DiffHunk[] = [];\n\n let diffIndex = 0;\n let localIndex = 0;\n\n for (let i = 0; i < changes.length; i++) {\n const change = changes[i] as ChangeObject<string[]>;\n if (!change) continue;\n\n if (!change.added && !change.removed) {\n // Unchanged lines - advance both indices\n const count = change.count ?? change.value.length;\n diffIndex += count;\n localIndex += count;\n continue;\n }\n\n if (change.removed) {\n // Check if next change is an addition (making this a modification)\n const nextChange = changes[i + 1] as ChangeObject<string[]> | undefined;\n\n if (nextChange?.added) {\n // Modification: deletion followed by addition\n const serverChanges = change.value;\n const localChanges = nextChange.value;\n const modHunk: ModifiedDiffHunk = {\n type: 'modification',\n length: serverChanges.length + localChanges.length,\n diffStart: diffIndex,\n localStart: localIndex,\n changes: [serverChanges, localChanges],\n };\n hunks.push(modHunk);\n\n // Advance indices and skip the next addition\n diffIndex += serverChanges.length + localChanges.length;\n localIndex += localChanges.length;\n i++; // Skip the addition we just processed\n continue;\n }\n\n // Pure deletion\n const deletionHunk: SimpleDiffHunk = {\n type: 'deletion',\n length: change.value.length,\n diffStart: diffIndex,\n localStart: localIndex,\n changes: change.value,\n };\n hunks.push(deletionHunk);\n diffIndex += change.value.length;\n continue;\n }\n\n if (!change.added) continue;\n\n // Pure addition (not preceded by deletion - handled above)\n const additionHunk: SimpleDiffHunk = {\n type: 'addition',\n length: change.value.length,\n diffStart: diffIndex,\n localStart: localIndex,\n changes: change.value,\n };\n hunks.push(additionHunk);\n diffIndex += change.value.length;\n localIndex += change.value.length;\n }\n\n return hunks;\n}\n\n/**\n * Compare local object content with server content\n *\n * @param client - ADT client\n * @param object - Object with local content to compare\n * @returns Diff result or error\n */\nexport async function gitDiff(\n client: AdtRequestor,\n object: ObjectContent\n): AsyncResult<DiffResult, Error> {\n // Read current server content.\n const [serverObj, readErr] = await readObject(client, {\n name: object.name,\n extension: object.extension,\n });\n\n if (readErr) {\n return err(new Error(`${object.name} does not exist on server`));\n }\n\n // Get label from config.\n const config = getConfigByExtension(object.extension);\n const label = config?.label ?? object.extension;\n\n // Split content into lines for comparison.\n const serverLines = serverObj.content.split('\\n');\n const localLines = object.content.split('\\n');\n\n // Compute diff.\n const diffs = computeDiff(serverLines, localLines);\n\n return ok({\n name: serverObj.name,\n extension: serverObj.extension,\n label,\n diffs,\n });\n}\n","/**\r\n * ADT Client Core Implementation\r\n *\r\n * HTTP client for SAP ADT (ABAP Development Tools) with:\r\n * - Session management (login/logout)\r\n * - CSRF token fetching and automatic refresh\r\n * - Basic, SAML, and SSO (Kerberos + mTLS) authentication\r\n * - Automatic retry on 403 CSRF errors\r\n * - Session reset on 500 errors\r\n *\r\n * Uses web standard APIs (fetch, Request, Response) - runtime-agnostic.\r\n */\r\n\r\nimport type { ClientConfig } from '../types/config';\r\nimport type {\r\n ObjectRef,\r\n ObjectContent,\r\n TreeQuery,\r\n PreviewQuery,\r\n} from '../types/requests';\r\nimport type { Session } from './session/types';\r\nimport type {\r\n ObjectWithContent,\r\n UpsertResult,\r\n ActivationResult,\r\n TreeNode,\r\n Transport,\r\n Package,\r\n DataFrame,\r\n DistinctResult,\r\n SearchResult,\r\n Dependency,\r\n TransportConfig,\r\n DiffResult,\r\n ObjectConfig,\r\n} from './adt';\r\nimport type { Result, AsyncResult } from '../types/result';\r\nimport { ok, err } from '../types/result';\r\nimport {\r\n CSRF_TOKEN_HEADER,\r\n BASE_HEADERS,\r\n DEFAULT_TIMEOUT,\r\n buildRequestHeaders,\r\n debug,\r\n debugError,\r\n} from './utils';\r\nimport { clientConfigSchema } from '../types/config';\r\nimport * as sessionOps from './session/login';\r\nimport * as adt from './adt';\r\nimport { Agent, fetch as undiciFetch } from 'undici';\r\nimport type { AuthStrategy } from './auth/types';\r\nimport { createAuthStrategy } from './auth/factory';\r\n\r\n// HTTP request options for internal operations\r\ninterface RequestOptions {\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE';\r\n path: string;\r\n params?: Record<string, string | number>;\r\n headers?: Record<string, string>;\r\n body?: string;\r\n}\r\n\r\n// ADT Client interface - provides all operations for interacting with SAP ADT servers\r\nexport interface ADTClient {\r\n /** Current session info (null if not logged in) */\r\n readonly session: Session | null;\r\n\r\n // Lifecycle\r\n login(): AsyncResult<Session>;\r\n logout(): AsyncResult<void>;\r\n\r\n // CRAUD Operations\r\n read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]>;\r\n create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void>;\r\n update(object: ObjectContent, transport?: string): AsyncResult<void>;\r\n upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;\r\n activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;\r\n delete(objects: ObjectRef[], transport?: string): AsyncResult<void>;\r\n\r\n // Discovery\r\n getPackages(): AsyncResult<Package[]>;\r\n getTree(query: TreeQuery): AsyncResult<TreeNode[]>;\r\n getTransports(packageName: string): AsyncResult<Transport[]>;\r\n\r\n // Data Preview\r\n previewData(query: PreviewQuery): AsyncResult<DataFrame>;\r\n getDistinctValues(objectName: string, column: string, objectType?: 'table' | 'view'): AsyncResult<DistinctResult>;\r\n countRows(objectName: string, objectType: 'table' | 'view'): AsyncResult<number>;\r\n\r\n // Search\r\n search(query: string, types?: string[]): AsyncResult<SearchResult[]>;\r\n whereUsed(object: ObjectRef): AsyncResult<Dependency[]>;\r\n\r\n // Transport Management\r\n createTransport(config: TransportConfig): AsyncResult<string>;\r\n\r\n // Diff Operations\r\n gitDiff(objects: ObjectContent[]): AsyncResult<DiffResult[]>;\r\n\r\n // Configuration\r\n getObjectConfig(): ObjectConfig[];\r\n}\r\n\r\n// Internal client state (implements SessionState interface from session/login)\r\ninterface ClientState extends sessionOps.SessionState {\r\n config: ClientConfig;\r\n cookies: Map<string, string>;\r\n authStrategy: AuthStrategy;\r\n}\r\n\r\n// Build URL search parameters with sap-client\r\nfunction buildParams(\r\n baseParams: Record<string, string | number> | undefined,\r\n clientNum: string\r\n): URLSearchParams {\r\n const params = new URLSearchParams();\r\n\r\n // Add any custom parameters from the request.\r\n if (baseParams) {\r\n for (const [key, value] of Object.entries(baseParams)) {\r\n params.append(key, String(value));\r\n }\r\n }\r\n\r\n // Always append sap-client parameter.\r\n params.append('sap-client', clientNum);\r\n\r\n return params;\r\n}\r\n\r\n// Build full URL from base URL and path\r\nfunction buildUrl(baseUrl: string, path: string, params?: URLSearchParams): string {\r\n // Construct URL from base and path.\r\n const url = new URL(path, baseUrl);\r\n\r\n // Merge query parameters: preserve existing ones from path, add new ones.\r\n if (params) {\r\n for (const [key, value] of params.entries()) {\r\n url.searchParams.append(key, value);\r\n }\r\n }\r\n\r\n return url.toString();\r\n}\r\n\r\n/**\r\n * ADT Client implementation class.\r\n * Methods are defined on the prototype (not recreated per instance).\r\n */\r\nclass ADTClientImpl implements ADTClient {\r\n private state: ClientState;\r\n private requestor: adt.AdtRequestor;\r\n private agent: Agent | undefined;\r\n\r\n constructor(config: ClientConfig) {\r\n // Create auth strategy from config\r\n const authOptions: Parameters<typeof createAuthStrategy>[0] = {\r\n config: config.auth,\r\n baseUrl: config.url,\r\n };\r\n if (config.insecure) {\r\n authOptions.insecure = config.insecure;\r\n }\r\n const authStrategy = createAuthStrategy(authOptions);\r\n\r\n this.state = {\r\n config,\r\n session: null,\r\n csrfToken: null,\r\n cookies: new Map(),\r\n authStrategy,\r\n };\r\n // Bind request method for use as requestor\r\n this.requestor = { request: this.request.bind(this) };\r\n // Create insecure agent if SSL verification should be skipped\r\n if (config.insecure) {\r\n this.agent = new Agent({\r\n connect: {\r\n rejectUnauthorized: false,\r\n checkServerIdentity: () => undefined, // Skip hostname verification\r\n },\r\n });\r\n }\r\n }\r\n\r\n get session(): Session | null {\r\n return this.state.session;\r\n }\r\n\r\n // --- Private helpers ---\r\n\r\n private storeCookies(response: Response): void {\r\n const setCookieHeader = response.headers.get('set-cookie');\r\n if (!setCookieHeader) return;\r\n\r\n // Parse Set-Cookie header(s) - may be multiple cookies\r\n // Format: \"name=value; Path=/; HttpOnly\" or multiple separated\r\n const cookieStrings = setCookieHeader.split(/,(?=\\s*\\w+=)/);\r\n for (const cookieStr of cookieStrings) {\r\n const match = cookieStr.match(/^([^=]+)=([^;]*)/);\r\n if (match && match[1] && match[2]) {\r\n this.state.cookies.set(match[1].trim(), match[2].trim());\r\n }\r\n }\r\n }\r\n\r\n private buildCookieHeader(): string | null {\r\n if (this.state.cookies.size === 0) return null;\r\n return Array.from(this.state.cookies.entries())\r\n .map(([name, value]) => `${name}=${value}`)\r\n .join('; ');\r\n }\r\n\r\n // Core HTTP request function with CSRF token injection and automatic retry on 403 errors\r\n private async request(options: RequestOptions): AsyncResult<Response, Error> {\r\n const { method, path, params, headers: customHeaders, body } = options;\r\n const { config } = this.state;\r\n\r\n // Build headers with auth and CSRF token.\r\n debug(`Request ${method} ${path} - CSRF token in state: ${this.state.csrfToken?.substring(0, 20) || 'null'}...`);\r\n const headers = buildRequestHeaders(\r\n BASE_HEADERS,\r\n customHeaders,\r\n config.auth,\r\n this.state.csrfToken\r\n );\r\n debug(`CSRF header being sent: ${headers['x-csrf-token']?.substring(0, 20) || 'none'}...`);\r\n\r\n // Add stored cookies to request\r\n const cookieHeader = this.buildCookieHeader();\r\n if (cookieHeader) {\r\n headers['Cookie'] = cookieHeader;\r\n debug(`Cookies being sent: ${cookieHeader.substring(0, 50)}...`);\r\n }\r\n\r\n // Build URL with parameters.\r\n const urlParams = buildParams(params, config.client);\r\n const url = buildUrl(config.url, path, urlParams);\r\n\r\n // Build fetch options with timeout and optional insecure agent.\r\n const fetchOptions: RequestInit & { dispatcher?: Agent } = {\r\n method,\r\n headers,\r\n signal: AbortSignal.timeout(config.timeout ?? DEFAULT_TIMEOUT),\r\n };\r\n\r\n // Add insecure agent if configured\r\n if (this.agent) {\r\n fetchOptions.dispatcher = this.agent;\r\n }\r\n\r\n // Add request body if provided.\r\n if (body) {\r\n fetchOptions.body = body;\r\n }\r\n\r\n try {\r\n // Execute HTTP request.\r\n debug(`Fetching URL: ${url}`);\r\n debug(`Insecure mode: ${!!this.agent}`);\r\n // Use undici fetch directly to support dispatcher option for SSL bypass\r\n const response = await undiciFetch(url, fetchOptions as Parameters<typeof undiciFetch>[1]) as unknown as Response;\r\n\r\n // Store any cookies from response\r\n this.storeCookies(response);\r\n\r\n // Handle CSRF token validation failure with automatic refresh.\r\n if (response.status === 403) {\r\n const text = await response.text();\r\n if (text.includes('CSRF token validation failed')) {\r\n // Fetch new CSRF token.\r\n const [newToken, tokenErr] = await sessionOps.fetchCsrfToken(this.state, this.request.bind(this));\r\n if (tokenErr) {\r\n return err(new Error(`CSRF token refresh failed: ${tokenErr.message}`));\r\n }\r\n\r\n // Retry request with new token and cookies.\r\n headers[CSRF_TOKEN_HEADER] = newToken;\r\n const retryCookieHeader = this.buildCookieHeader();\r\n if (retryCookieHeader) {\r\n headers['Cookie'] = retryCookieHeader;\r\n }\r\n debug(`Retrying with new CSRF token: ${newToken.substring(0, 20)}...`);\r\n const retryResponse = await undiciFetch(url, { ...fetchOptions, headers } as Parameters<typeof undiciFetch>[1]) as unknown as Response;\r\n this.storeCookies(retryResponse);\r\n return ok(retryResponse);\r\n }\r\n\r\n // Return 403 response if not CSRF-related.\r\n return ok(new Response(text, {\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n }));\r\n }\r\n\r\n // Handle session expiration with automatic reset.\r\n if (response.status === 500) {\r\n const text = await response.text();\r\n\r\n // Attempt session reset.\r\n const [, resetErr] = await sessionOps.sessionReset(this.state, this.request.bind(this));\r\n if (resetErr) {\r\n return err(new Error(`Session reset failed: ${resetErr.message}`));\r\n }\r\n\r\n // Return original 500 response.\r\n return ok(new Response(text, {\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n }));\r\n }\r\n\r\n return ok(response);\r\n } catch (error) {\r\n // Log detailed error info for debugging\r\n if (error instanceof Error) {\r\n debugError(`Fetch error: ${error.name}: ${error.message}`, error.cause);\r\n if ('code' in error) {\r\n debugError(`Error code: ${(error as NodeJS.ErrnoException).code}`);\r\n }\r\n return err(error);\r\n }\r\n return err(new Error(`Network error: ${String(error)}`));\r\n }\r\n }\r\n\r\n // --- Lifecycle ---\r\n\r\n async login(): AsyncResult<Session> {\r\n const { authStrategy } = this.state;\r\n\r\n // For SSO and SAML, perform initial authentication (certificate enrollment or browser login)\r\n if (authStrategy.performLogin) {\r\n const [, loginErr] = await authStrategy.performLogin(fetch);\r\n if (loginErr) {\r\n return err(loginErr);\r\n }\r\n }\r\n\r\n // For SSO with mTLS, create agent with client certificates\r\n if (authStrategy.type === 'sso' && authStrategy.getCertificates) {\r\n const certs = authStrategy.getCertificates();\r\n if (certs) {\r\n this.agent = new Agent({\r\n connect: {\r\n cert: certs.fullChain,\r\n key: certs.privateKey,\r\n rejectUnauthorized: !this.state.config.insecure,\r\n ...(this.state.config.insecure && {\r\n checkServerIdentity: () => undefined,\r\n }),\r\n },\r\n });\r\n debug('Created mTLS agent with SSO certificates');\r\n }\r\n }\r\n\r\n return sessionOps.login(this.state, this.request.bind(this));\r\n }\r\n\r\n async logout(): AsyncResult<void> {\r\n return sessionOps.logout(this.state, this.request.bind(this));\r\n }\r\n\r\n // --- CRAUD Operations ---\r\n\r\n async read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n const results: ObjectWithContent[] = [];\r\n for (const obj of objects) {\r\n const [result, readErr] = await adt.readObject(this.requestor, obj);\r\n if (readErr) return err(readErr);\r\n results.push(result);\r\n }\r\n return ok(results);\r\n }\r\n\r\n async create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n // Step 1: Create empty object shell\r\n const [, createErr] = await adt.createObject(this.requestor, object, packageName, transport, this.state.session.username);\r\n if (createErr) return err(createErr);\r\n\r\n // Step 2: Populate content via lock → update → unlock\r\n const objRef: ObjectRef = { name: object.name, extension: object.extension };\r\n\r\n const [lockHandle, lockErr] = await adt.lockObject(this.requestor, objRef);\r\n if (lockErr) return err(lockErr);\r\n\r\n const [, updateErr] = await adt.updateObject(this.requestor, object, lockHandle, transport);\r\n\r\n // Always unlock after update attempt\r\n const [, unlockErr] = await adt.unlockObject(this.requestor, objRef, lockHandle);\r\n\r\n if (updateErr) return err(updateErr);\r\n if (unlockErr) return err(unlockErr);\r\n\r\n return ok(undefined);\r\n }\r\n\r\n async update(object: ObjectContent, transport?: string): AsyncResult<void> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n const objRef: ObjectRef = { name: object.name, extension: object.extension };\r\n\r\n // Lock object before update\r\n const [lockHandle, lockErr] = await adt.lockObject(this.requestor, objRef);\r\n if (lockErr) return err(lockErr);\r\n\r\n // Update object content\r\n const [, updateErr] = await adt.updateObject(this.requestor, object, lockHandle, transport);\r\n\r\n // Always unlock after update attempt\r\n const [, unlockErr] = await adt.unlockObject(this.requestor, objRef, lockHandle);\r\n\r\n // Return first error encountered\r\n if (updateErr) return err(updateErr);\r\n if (unlockErr) return err(unlockErr);\r\n\r\n return ok(undefined);\r\n }\r\n\r\n async upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n if (objects.length === 0) return ok([]);\r\n\r\n const results: UpsertResult[] = [];\r\n for (const obj of objects) {\r\n if (!obj.name || !obj.extension) continue;\r\n\r\n const objRef: ObjectRef = { name: obj.name, extension: obj.extension };\r\n\r\n // Try to read existing object\r\n const [existing] = await adt.readObject(this.requestor, objRef);\r\n\r\n // Object doesn't exist - create it\r\n if (!existing) {\r\n const [, createErr] = await this.create(obj, packageName, transport);\r\n if (createErr) return err(createErr);\r\n\r\n const result: UpsertResult = {\r\n name: obj.name,\r\n extension: obj.extension,\r\n status: 'created',\r\n };\r\n if (transport) result.transport = transport;\r\n results.push(result);\r\n continue;\r\n }\r\n\r\n // Object exists - update it\r\n const [, updateErr] = await this.update(obj, transport);\r\n if (updateErr) return err(updateErr);\r\n\r\n const result: UpsertResult = {\r\n name: obj.name,\r\n extension: obj.extension,\r\n status: 'updated',\r\n };\r\n if (transport) result.transport = transport;\r\n results.push(result);\r\n }\r\n return ok(results);\r\n }\r\n\r\n async activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.activateObjects(this.requestor, objects);\r\n }\r\n\r\n async delete(objects: ObjectRef[], transport?: string): AsyncResult<void> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n\r\n for (const obj of objects) {\r\n // Lock object before deletion\r\n const [lockHandle, lockErr] = await adt.lockObject(this.requestor, obj);\r\n if (lockErr) return err(lockErr);\r\n\r\n // Delete object\r\n const [, deleteErr] = await adt.deleteObject(this.requestor, obj, lockHandle, transport);\r\n if (deleteErr) {\r\n // Attempt to unlock on failure\r\n await adt.unlockObject(this.requestor, obj, lockHandle);\r\n return err(deleteErr);\r\n }\r\n }\r\n return ok(undefined);\r\n }\r\n\r\n // --- Discovery ---\r\n\r\n async getPackages(): AsyncResult<Package[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getPackages(this.requestor);\r\n }\r\n\r\n async getTree(query: TreeQuery): AsyncResult<TreeNode[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getTree(this.requestor, query);\r\n }\r\n\r\n async getTransports(packageName: string): AsyncResult<Transport[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getTransports(this.requestor, packageName);\r\n }\r\n\r\n // --- Data Preview ---\r\n\r\n async previewData(query: PreviewQuery): AsyncResult<DataFrame> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.previewData(this.requestor, query);\r\n }\r\n\r\n async getDistinctValues(objectName: string, column: string, objectType: 'table' | 'view' = 'view'): AsyncResult<DistinctResult> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.getDistinctValues(this.requestor, objectName, column, objectType);\r\n }\r\n\r\n async countRows(objectName: string, objectType: 'table' | 'view'): AsyncResult<number> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.countRows(this.requestor, objectName, objectType);\r\n }\r\n\r\n // --- Search ---\r\n\r\n async search(query: string, types?: string[]): AsyncResult<SearchResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.searchObjects(this.requestor, query, types);\r\n }\r\n\r\n async whereUsed(object: ObjectRef): AsyncResult<Dependency[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.findWhereUsed(this.requestor, object);\r\n }\r\n\r\n // --- Transport Management ---\r\n\r\n async createTransport(transportConfig: TransportConfig): AsyncResult<string> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n return adt.createTransport(this.requestor, transportConfig);\r\n }\r\n\r\n // --- Diff Operations ---\r\n\r\n async gitDiff(objects: ObjectContent[]): AsyncResult<DiffResult[]> {\r\n if (!this.state.session) return err(new Error('Not logged in'));\r\n if (objects.length === 0) return ok([]);\r\n\r\n const results: DiffResult[] = [];\r\n for (const obj of objects) {\r\n const [result, diffErr] = await adt.gitDiff(this.requestor, obj);\r\n if (diffErr) return err(diffErr);\r\n results.push(result);\r\n }\r\n return ok(results);\r\n }\r\n\r\n // --- Configuration ---\r\n\r\n getObjectConfig(): ObjectConfig[] {\r\n return Object.values(adt.OBJECT_CONFIG_MAP);\r\n }\r\n}\r\n\r\n// Create a new ADT client - validates config and returns client instance\r\nexport function createClient(config: ClientConfig): Result<ADTClient, Error> {\r\n // Validate config using Zod schema.\r\n const validation = clientConfigSchema.safeParse(config);\r\n if (!validation.success) {\r\n const issues = validation.error.issues.map(i => `${i.path.join('.')}: ${i.message}`).join(', ');\r\n return err(new Error(`Invalid client configuration: ${issues}`));\r\n }\r\n\r\n return ok(new ADTClientImpl(config));\r\n}\r\n","import type { AuthStrategy } from '../types';\r\n\r\n/**\r\n * Basic authentication strategy\r\n *\r\n * Implements HTTP Basic Auth using username/password credentials.\r\n * Credentials are base64-encoded and sent in the Authorization header.\r\n *\r\n * Reference: RFC 7617\r\n */\r\nexport class BasicAuth implements AuthStrategy {\r\n readonly type = 'basic' as const;\r\n private authHeader: string;\r\n\r\n /**\r\n * Create a Basic Auth strategy\r\n * @param username - SAP username\r\n * @param password - SAP password\r\n */\r\n constructor(username: string, password: string) {\r\n if (!username || !password) {\r\n throw new Error('BasicAuth requires both username and password');\r\n }\r\n\r\n const credentials = `${username}:${password}`;\r\n const encoded = btoa(credentials);\r\n this.authHeader = `Basic ${encoded}`;\r\n }\r\n\r\n /**\r\n * Get Authorization header with Basic credentials\r\n * @returns Headers object with Authorization field\r\n */\r\n getAuthHeaders(): Record<string, string> {\r\n return {\r\n Authorization: this.authHeader,\r\n };\r\n }\r\n}\r\n","/**\r\n * SAP Secure Login Server (SLS) client\r\n *\r\n * Handles communication with SLS for certificate enrollment:\r\n * 1. Authenticate using Kerberos SPNEGO\r\n * 2. Submit CSR to get signed certificate\r\n */\r\n\r\nimport { Agent, fetch as undiciFetch } from 'undici';\r\nimport type { AsyncResult } from '../../../types/result';\r\nimport { ok, err } from '../../../types/result';\r\nimport type { SlsConfig, SlsAuthResponse, CertificateMaterial } from './types';\r\nimport { SLS_DEFAULTS } from './types';\r\nimport { getSpnegoToken, extractSpnFromUrl } from './kerberos';\r\nimport { generateKeypair, createCsr, getCurrentUsername } from './certificate';\r\nimport { parsePkcs7Certificates } from './pkcs7';\r\n\r\n/**\r\n * SLS client options\r\n */\r\ninterface SlsClientConfig {\r\n /** SLS configuration */\r\n config: SlsConfig;\r\n /** Skip SSL verification (required for most corporate environments) */\r\n insecure?: boolean;\r\n}\r\n\r\n/**\r\n * Enroll a client certificate from SLS\r\n *\r\n * Performs the full certificate enrollment flow:\r\n * 1. Authenticate to SLS using Kerberos SPNEGO\r\n * 2. Generate RSA keypair\r\n * 3. Create CSR with current username\r\n * 4. Submit CSR to SLS\r\n * 5. Parse PKCS#7 response to extract certificates\r\n *\r\n * @param options - SLS client configuration\r\n * @returns Certificate material (full chain + private key) or error\r\n *\r\n * @example\r\n * ```typescript\r\n * const [certs, error] = await enrollCertificate({\r\n * config: { slsUrl: 'https://sapsso.corp.example.com' },\r\n * insecure: true,\r\n * });\r\n *\r\n * if (error) {\r\n * console.error('Enrollment failed:', error.message);\r\n * return;\r\n * }\r\n *\r\n * // Use certificates for mTLS\r\n * const agent = new Agent({\r\n * connect: {\r\n * cert: certs.fullChain,\r\n * key: certs.privateKey,\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport async function enrollCertificate(\r\n options: SlsClientConfig\r\n): AsyncResult<CertificateMaterial> {\r\n const { config, insecure = false } = options;\r\n const profile = config.profile ?? SLS_DEFAULTS.PROFILE;\r\n\r\n // Create fetch agent (skip SSL verification if insecure)\r\n const agent = insecure\r\n ? new Agent({ connect: { rejectUnauthorized: false } })\r\n : undefined;\r\n\r\n // Step 1: Authenticate with Kerberos\r\n const [authResponse, authErr] = await authenticateToSls(config, profile, agent);\r\n if (authErr) return err(authErr);\r\n\r\n // Step 2: Generate keypair\r\n const keySize = authResponse.clientConfig.keySize ?? SLS_DEFAULTS.KEY_SIZE;\r\n const keypair = generateKeypair(keySize);\r\n\r\n // Step 3: Create CSR\r\n const username = getCurrentUsername();\r\n const csrDer = createCsr(keypair, username);\r\n\r\n // Step 4: Submit CSR and get certificate\r\n const [certData, certErr] = await requestCertificate(config, profile, csrDer, agent);\r\n if (certErr) return err(certErr);\r\n\r\n // Step 5: Parse PKCS#7 response\r\n const [certs, parseErr] = parsePkcs7Certificates(certData);\r\n if (parseErr) return err(parseErr);\r\n\r\n return ok({\r\n fullChain: certs.fullChain,\r\n privateKey: keypair.privateKeyPem,\r\n });\r\n}\r\n\r\n/**\r\n * Authenticate to SLS using Kerberos SPNEGO\r\n */\r\nasync function authenticateToSls(\r\n config: SlsConfig,\r\n profile: string,\r\n agent?: Agent\r\n): AsyncResult<SlsAuthResponse> {\r\n // Get SPNEGO token\r\n const spn = config.servicePrincipalName ?? extractSpnFromUrl(config.slsUrl);\r\n const [token, tokenErr] = await getSpnegoToken(spn);\r\n if (tokenErr) return err(tokenErr);\r\n\r\n // Build auth URL\r\n const authUrl = `${config.slsUrl}${SLS_DEFAULTS.LOGIN_ENDPOINT}?profile=${profile}`;\r\n\r\n try {\r\n const fetchOptions: Parameters<typeof undiciFetch>[1] = {\r\n method: 'POST',\r\n headers: {\r\n 'Authorization': `Negotiate ${token}`,\r\n 'Accept': '*/*',\r\n },\r\n };\r\n if (agent) {\r\n fetchOptions.dispatcher = agent;\r\n }\r\n\r\n const response = await undiciFetch(authUrl, fetchOptions);\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n return err(new Error(`SLS authentication failed: ${response.status} - ${text}`));\r\n }\r\n\r\n const authResponse = await response.json() as SlsAuthResponse;\r\n return ok(authResponse);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(new Error(`SLS authentication request failed: ${message}`));\r\n }\r\n}\r\n\r\n/**\r\n * Request certificate from SLS by submitting CSR\r\n */\r\nasync function requestCertificate(\r\n config: SlsConfig,\r\n profile: string,\r\n csrDer: Buffer,\r\n agent?: Agent\r\n): AsyncResult<Buffer> {\r\n const certUrl = `${config.slsUrl}${SLS_DEFAULTS.CERTIFICATE_ENDPOINT}?profile=${profile}`;\r\n\r\n try {\r\n const fetchOptions: Parameters<typeof undiciFetch>[1] = {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/pkcs10',\r\n 'Content-Length': String(csrDer.length),\r\n 'Accept': '*/*',\r\n },\r\n body: csrDer,\r\n };\r\n if (agent) {\r\n fetchOptions.dispatcher = agent;\r\n }\r\n\r\n const response = await undiciFetch(certUrl, fetchOptions);\r\n\r\n if (!response.ok) {\r\n const text = await response.text();\r\n return err(new Error(`Certificate request failed: ${response.status} - ${text}`));\r\n }\r\n\r\n const buffer = await response.arrayBuffer();\r\n return ok(Buffer.from(buffer));\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(new Error(`Certificate request failed: ${message}`));\r\n }\r\n}\r\n","/**\r\n * SSO authentication types\r\n *\r\n * Types for Kerberos-based SSO authentication with SAP Secure Login Server (SLS).\r\n */\r\n\r\n/**\r\n * Secure Login Server (SLS) configuration\r\n */\r\nexport interface SlsConfig {\r\n /** SLS server URL (e.g., https://sapsso.corp.example.com:443) */\r\n slsUrl: string;\r\n /** SLS profile name (default: SAPSSO_P) */\r\n profile?: string;\r\n /** Service principal name for Kerberos (e.g., HTTP/sapsso.corp.example.com) */\r\n servicePrincipalName?: string;\r\n}\r\n\r\n/**\r\n * Default SLS configuration values\r\n */\r\nexport const SLS_DEFAULTS = {\r\n PROFILE: 'SAPSSO_P',\r\n LOGIN_ENDPOINT: '/SecureLoginServer/slc3/doLogin',\r\n CERTIFICATE_ENDPOINT: '/SecureLoginServer/slc2/getCertificate',\r\n KEY_SIZE: 2048,\r\n} as const;\r\n\r\n/**\r\n * SLS authentication response from doLogin endpoint\r\n */\r\nexport interface SlsAuthResponse {\r\n clientConfig: {\r\n keySize?: number;\r\n };\r\n}\r\n\r\n/**\r\n * mTLS certificate material for use with undici Agent\r\n */\r\nexport interface CertificateMaterial {\r\n /** PEM-encoded client certificate + CA chain */\r\n fullChain: string;\r\n /** PEM-encoded private key */\r\n privateKey: string;\r\n}\r\n\r\n/**\r\n * Certificate file paths on disk\r\n */\r\nexport interface CertificatePaths {\r\n /** Path to client certificate + CA chain PEM file */\r\n fullChainPath: string;\r\n /** Path to private key PEM file */\r\n keyPath: string;\r\n}\r\n\r\n/**\r\n * Result of certificate enrollment - either material or paths\r\n */\r\nexport type CertificateResult = CertificateMaterial | CertificatePaths;\r\n\r\n/**\r\n * Options for SLS client operations\r\n */\r\nexport interface SlsClientOptions {\r\n /** SLS configuration */\r\n config: SlsConfig;\r\n /** Skip SSL verification (dev only) */\r\n insecure?: boolean;\r\n}\r\n\r\n/**\r\n * Certificate storage directory structure\r\n */\r\nexport const CERTIFICATE_STORAGE = {\r\n BASE_DIR: './certificates/sso',\r\n FULL_CHAIN_SUFFIX: '_full_chain.pem',\r\n KEY_SUFFIX: '_key.pem',\r\n} as const;\r\n","/**\r\n * Kerberos SPNEGO token generation\r\n *\r\n * Generates SPNEGO tokens for authenticating to SAP Secure Login Server.\r\n * Uses the kerberos npm package (optional peer dependency).\r\n *\r\n * Platform support:\r\n * - Windows: Uses SSPI (native Windows authentication)\r\n * - Linux/macOS: Uses MIT Kerberos (requires kinit)\r\n */\r\n\r\nimport type { AsyncResult } from '../../../types/result';\r\nimport { ok, err } from '../../../types/result';\r\n\r\n/**\r\n * Kerberos client interface matching the kerberos npm package\r\n */\r\ninterface KerberosClient {\r\n step(token: string): Promise<string | null>;\r\n wrap(message: string, options?: unknown): Promise<string>;\r\n unwrap(message: string): Promise<string>;\r\n}\r\n\r\n/**\r\n * Kerberos module interface\r\n */\r\ninterface KerberosModule {\r\n initializeClient(\r\n service: string,\r\n options?: { mechOID?: string }\r\n ): Promise<KerberosClient>;\r\n}\r\n\r\n/**\r\n * Lazily load kerberos module\r\n *\r\n * @returns Kerberos module or null if not installed\r\n */\r\nasync function loadKerberosModule(): AsyncResult<KerberosModule> {\r\n try {\r\n // Dynamic import to avoid hard dependency\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n const kerberosModule = require('kerberos') as KerberosModule;\r\n return ok(kerberosModule);\r\n } catch {\r\n return err(new Error(\r\n 'kerberos package is not installed. ' +\r\n 'Install it with: npm install kerberos'\r\n ));\r\n }\r\n}\r\n\r\n/**\r\n * Generate SPNEGO token for Kerberos authentication\r\n *\r\n * Creates a base64-encoded SPNEGO token that can be used in\r\n * Authorization: Negotiate headers for authenticating to SLS.\r\n *\r\n * @param servicePrincipalName - SPN to authenticate to (e.g., HTTP/sapsso.corp.example.com)\r\n * @returns Base64-encoded SPNEGO token or error\r\n *\r\n * @example\r\n * ```typescript\r\n * const [token, error] = await getSpnegoToken('HTTP/sapsso.corp.example.com');\r\n * if (error) {\r\n * console.error('Failed to get SPNEGO token:', error.message);\r\n * return;\r\n * }\r\n *\r\n * // Use in Authorization header\r\n * fetch(url, {\r\n * headers: {\r\n * Authorization: `Negotiate ${token}`\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport async function getSpnegoToken(servicePrincipalName: string): AsyncResult<string> {\r\n const [kerberos, loadErr] = await loadKerberosModule();\r\n if (loadErr) return err(loadErr);\r\n\r\n try {\r\n // Initialize Kerberos client for the given SPN\r\n const client = await kerberos.initializeClient(servicePrincipalName);\r\n\r\n // Step with empty token to get initial SPNEGO token\r\n const token = await client.step('');\r\n\r\n if (!token) {\r\n return err(new Error('Failed to generate SPNEGO token: empty response'));\r\n }\r\n\r\n return ok(token);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(new Error(`Kerberos authentication failed: ${message}`));\r\n }\r\n}\r\n\r\n/**\r\n * Extract SPN from SLS URL\r\n *\r\n * Generates HTTP service principal name from the SLS URL hostname.\r\n *\r\n * @param slsUrl - SLS server URL\r\n * @returns Service principal name (e.g., HTTP/hostname.example.com)\r\n *\r\n * @example\r\n * ```typescript\r\n * const spn = extractSpnFromUrl('https://sapsso.corp.example.com:443');\r\n * // Returns: 'HTTP/sapsso.corp.example.com'\r\n * ```\r\n */\r\nexport function extractSpnFromUrl(slsUrl: string): string {\r\n const url = new URL(slsUrl);\r\n return `HTTP/${url.hostname}`;\r\n}\r\n","/**\r\n * Certificate generation for SSO authentication\r\n *\r\n * Generates RSA keypairs and PKCS#10 Certificate Signing Requests (CSR)\r\n * for SAP Secure Login Server certificate enrollment.\r\n */\r\n\r\nimport forge from 'node-forge';\r\nimport { SLS_DEFAULTS } from './types';\r\n\r\n/**\r\n * Generated keypair with private key in PEM format\r\n */\r\nexport interface GeneratedKeypair {\r\n /** Private key in PEM format (PKCS#8) */\r\n privateKeyPem: string;\r\n /** forge private key object for signing */\r\n privateKey: forge.pki.rsa.PrivateKey;\r\n /** forge public key object */\r\n publicKey: forge.pki.rsa.PublicKey;\r\n}\r\n\r\n/**\r\n * Generate an RSA keypair\r\n *\r\n * @param keySize - Key size in bits (default: 2048)\r\n * @returns Generated keypair with PEM-encoded private key\r\n *\r\n * @example\r\n * ```typescript\r\n * const keypair = generateKeypair(2048);\r\n * console.log(keypair.privateKeyPem);\r\n * ```\r\n */\r\nexport function generateKeypair(keySize: number = SLS_DEFAULTS.KEY_SIZE): GeneratedKeypair {\r\n const keypair = forge.pki.rsa.generateKeyPair({ bits: keySize, e: 0x10001 });\r\n\r\n const privateKeyPem = forge.pki.privateKeyToPem(keypair.privateKey);\r\n\r\n return {\r\n privateKeyPem,\r\n privateKey: keypair.privateKey,\r\n publicKey: keypair.publicKey,\r\n };\r\n}\r\n\r\n/**\r\n * Create a Certificate Signing Request (CSR)\r\n *\r\n * Generates a PKCS#10 CSR with:\r\n * - Subject: CN=<username>\r\n * - Key Usage: digitalSignature, keyEncipherment\r\n * - Extended Key Usage: clientAuth (OID 1.3.6.1.5.5.7.3.2)\r\n *\r\n * @param keypair - RSA keypair to use for the CSR\r\n * @param username - Username for the certificate subject (CN)\r\n * @returns DER-encoded CSR as Buffer\r\n *\r\n * @example\r\n * ```typescript\r\n * const keypair = generateKeypair(2048);\r\n * const csrDer = createCsr(keypair, 'JOHNDOE');\r\n * ```\r\n */\r\nexport function createCsr(keypair: GeneratedKeypair, username: string): Buffer {\r\n const csr = forge.pki.createCertificationRequest();\r\n\r\n // Set subject (Common Name = username)\r\n csr.publicKey = keypair.publicKey;\r\n csr.setSubject([{\r\n name: 'commonName',\r\n value: username,\r\n }]);\r\n\r\n // Add Key Usage extension\r\n csr.setAttributes([{\r\n name: 'extensionRequest',\r\n extensions: [\r\n {\r\n name: 'keyUsage',\r\n digitalSignature: true,\r\n keyEncipherment: true,\r\n },\r\n {\r\n name: 'extKeyUsage',\r\n clientAuth: true,\r\n },\r\n ],\r\n }]);\r\n\r\n // Sign the CSR with SHA-256\r\n csr.sign(keypair.privateKey, forge.md.sha256.create());\r\n\r\n // Convert to DER format\r\n const csrAsn1 = forge.pki.certificationRequestToAsn1(csr);\r\n const csrDer = forge.asn1.toDer(csrAsn1);\r\n\r\n return Buffer.from(csrDer.getBytes(), 'binary');\r\n}\r\n\r\n/**\r\n * Get current Windows username\r\n *\r\n * @returns Username from environment or 'unknown'\r\n */\r\nexport function getCurrentUsername(): string {\r\n return process.env['USERNAME'] ?? process.env['USER'] ?? 'unknown';\r\n}\r\n","/**\r\n * PKCS#7 certificate parsing\r\n *\r\n * Parses PKCS#7 SignedData structures returned by SAP Secure Login Server\r\n * to extract client certificates and CA chain.\r\n */\r\n\r\nimport forge from 'node-forge';\r\nimport type { Result } from '../../../types/result';\r\nimport { ok, err } from '../../../types/result';\r\n\r\n/**\r\n * Parsed certificate chain\r\n */\r\nexport interface ParsedCertificates {\r\n /** PEM-encoded client certificate + CA chain */\r\n fullChain: string;\r\n /** PEM-encoded client certificate only */\r\n clientCert: string;\r\n /** PEM-encoded CA chain (intermediate + root) */\r\n caChain: string;\r\n}\r\n\r\n/**\r\n * Parse PKCS#7 certificate data from SLS response\r\n *\r\n * SLS returns a base64-encoded PKCS#7 structure containing:\r\n * - Client certificate (first cert)\r\n * - CA certificate chain (remaining certs)\r\n *\r\n * @param data - Raw response data from SLS (may be base64-encoded)\r\n * @returns Parsed certificates or error\r\n *\r\n * @example\r\n * ```typescript\r\n * const [certs, error] = parsePkcs7Certificates(responseBuffer);\r\n * if (error) {\r\n * console.error('Parse failed:', error.message);\r\n * return;\r\n * }\r\n *\r\n * console.log(certs.clientCert); // PEM client cert\r\n * console.log(certs.caChain); // PEM CA chain\r\n * console.log(certs.fullChain); // Both combined\r\n * ```\r\n */\r\nexport function parsePkcs7Certificates(data: Buffer): Result<ParsedCertificates> {\r\n try {\r\n // Clean and decode the data\r\n // SLS returns base64-encoded PKCS#7 with possible whitespace\r\n const dataString = data.toString('utf-8').replace(/\\r?\\n/g, '').trim();\r\n const derBytes = forge.util.decode64(dataString);\r\n\r\n // Parse PKCS#7 structure\r\n const p7Asn1 = forge.asn1.fromDer(derBytes);\r\n const p7 = forge.pkcs7.messageFromAsn1(p7Asn1);\r\n\r\n // Extract certificates from SignedData\r\n if (!('certificates' in p7) || !p7.certificates || p7.certificates.length === 0) {\r\n return err(new Error('No certificates found in PKCS#7 structure'));\r\n }\r\n\r\n const certificates = p7.certificates as forge.pki.Certificate[];\r\n\r\n // First certificate is the client cert, rest are CA chain\r\n const clientCert = certificates[0];\r\n const caCerts = certificates.slice(1);\r\n\r\n if (!clientCert) {\r\n return err(new Error('No client certificate found in PKCS#7 structure'));\r\n }\r\n\r\n // Convert to PEM format\r\n const clientCertPem = forge.pki.certificateToPem(clientCert);\r\n const caChainPem = caCerts\r\n .map(cert => forge.pki.certificateToPem(cert))\r\n .join('');\r\n\r\n return ok({\r\n clientCert: clientCertPem,\r\n caChain: caChainPem,\r\n fullChain: clientCertPem + caChainPem,\r\n });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(new Error(`Failed to parse PKCS#7 certificates: ${message}`));\r\n }\r\n}\r\n","/**\r\n * Certificate storage\r\n *\r\n * Persists and retrieves mTLS certificates from the filesystem.\r\n */\r\n\r\nimport { readFile, writeFile, mkdir, stat } from 'node:fs/promises';\r\nimport { join } from 'node:path';\r\nimport type { AsyncResult, Result } from '../../../types/result';\r\nimport { ok, err } from '../../../types/result';\r\nimport type { CertificateMaterial, CertificatePaths } from './types';\r\nimport { CERTIFICATE_STORAGE } from './types';\r\nimport { getCurrentUsername } from './certificate';\r\n\r\n/**\r\n * Get certificate file paths for a user\r\n *\r\n * @param username - Username (defaults to current user)\r\n * @returns Certificate file paths\r\n */\r\nexport function getCertificatePaths(username?: string): CertificatePaths {\r\n const user = username ?? getCurrentUsername();\r\n return {\r\n fullChainPath: join(CERTIFICATE_STORAGE.BASE_DIR, `${user}${CERTIFICATE_STORAGE.FULL_CHAIN_SUFFIX}`),\r\n keyPath: join(CERTIFICATE_STORAGE.BASE_DIR, `${user}${CERTIFICATE_STORAGE.KEY_SUFFIX}`),\r\n };\r\n}\r\n\r\n/**\r\n * Save certificates to filesystem\r\n *\r\n * @param material - Certificate material to save\r\n * @param username - Username (defaults to current user)\r\n * @returns File paths or error\r\n *\r\n * @example\r\n * ```typescript\r\n * const [paths, error] = await saveCertificates(material);\r\n * if (error) {\r\n * console.error('Save failed:', error.message);\r\n * return;\r\n * }\r\n *\r\n * console.log('Saved to:', paths.fullChainPath, paths.keyPath);\r\n * ```\r\n */\r\nexport async function saveCertificates(\r\n material: CertificateMaterial,\r\n username?: string\r\n): AsyncResult<CertificatePaths> {\r\n const paths = getCertificatePaths(username);\r\n\r\n try {\r\n // Ensure directory exists\r\n await mkdir(CERTIFICATE_STORAGE.BASE_DIR, { recursive: true });\r\n\r\n // Write certificate files\r\n await writeFile(paths.fullChainPath, material.fullChain, 'utf-8');\r\n await writeFile(paths.keyPath, material.privateKey, { encoding: 'utf-8', mode: 0o600 });\r\n\r\n return ok(paths);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(new Error(`Failed to save certificates: ${message}`));\r\n }\r\n}\r\n\r\n/**\r\n * Load certificates from filesystem\r\n *\r\n * @param username - Username (defaults to current user)\r\n * @returns Certificate material or error\r\n *\r\n * @example\r\n * ```typescript\r\n * const [material, error] = await loadCertificates();\r\n * if (error) {\r\n * // Certificates don't exist, need to enroll\r\n * return;\r\n * }\r\n *\r\n * // Use loaded certificates\r\n * ```\r\n */\r\nexport async function loadCertificates(username?: string): AsyncResult<CertificateMaterial> {\r\n const paths = getCertificatePaths(username);\r\n\r\n try {\r\n const [fullChain, privateKey] = await Promise.all([\r\n readFile(paths.fullChainPath, 'utf-8'),\r\n readFile(paths.keyPath, 'utf-8'),\r\n ]);\r\n\r\n return ok({ fullChain, privateKey });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(new Error(`Failed to load certificates: ${message}`));\r\n }\r\n}\r\n\r\n/**\r\n * Check if certificates exist for a user\r\n *\r\n * @param username - Username (defaults to current user)\r\n * @returns True if certificates exist\r\n */\r\nexport async function certificatesExist(username?: string): Promise<boolean> {\r\n const paths = getCertificatePaths(username);\r\n\r\n try {\r\n await Promise.all([\r\n stat(paths.fullChainPath),\r\n stat(paths.keyPath),\r\n ]);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a certificate is expired or will expire soon\r\n *\r\n * @param certPem - PEM-encoded certificate\r\n * @param bufferDays - Days before expiry to consider as \"expiring soon\" (default: 1)\r\n * @returns True if expired or expiring soon\r\n */\r\nexport function isCertificateExpired(certPem: string, bufferDays: number = 1): Result<boolean> {\r\n try {\r\n // Import forge dynamically to avoid loading it if not needed\r\n // eslint-disable-next-line @typescript-eslint/no-require-imports\r\n const forge = require('node-forge');\r\n\r\n const cert = forge.pki.certificateFromPem(certPem);\r\n const notAfter = cert.validity.notAfter as Date;\r\n const bufferMs = bufferDays * 24 * 60 * 60 * 1000;\r\n const expiryThreshold = new Date(Date.now() + bufferMs);\r\n\r\n return ok(notAfter <= expiryThreshold);\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(new Error(`Failed to check certificate expiry: ${message}`));\r\n }\r\n}\r\n","/**\r\n * SSO (Single Sign-On) authentication strategy\r\n *\r\n * Implements Kerberos-based SSO for SAP systems using mTLS certificates\r\n * obtained from SAP Secure Login Server (SLS).\r\n *\r\n * Authentication flow:\r\n * 1. Check for existing valid certificates\r\n * 2. If missing or expired, enroll new certificate via SLS\r\n * 3. Use mTLS for all subsequent ADT requests\r\n *\r\n * Platform support:\r\n * - Windows: Uses SSPI for Kerberos (requires Active Directory)\r\n * - Linux/macOS: Uses MIT Kerberos (requires kinit)\r\n *\r\n * @example\r\n * ```typescript\r\n * const auth = new SsoAuth({\r\n * slsUrl: 'https://sapsso.corp.example.com',\r\n * });\r\n *\r\n * // Enroll certificate (or load from cache)\r\n * const [, error] = await auth.performLogin(fetch);\r\n * if (error) {\r\n * console.error('SSO failed:', error.message);\r\n * return;\r\n * }\r\n *\r\n * // Get certificates for mTLS\r\n * const certs = auth.getCertificates();\r\n * ```\r\n */\r\n\r\nimport type { AuthStrategy } from '../types';\r\nimport type { AsyncResult } from '../../../types/result';\r\nimport { ok, err } from '../../../types/result';\r\nimport type { SlsConfig, CertificateMaterial } from './types';\r\nimport { enrollCertificate } from './slsClient';\r\nimport { loadCertificates, saveCertificates, certificatesExist, isCertificateExpired } from './storage';\r\n\r\n/**\r\n * SSO authentication configuration\r\n */\r\nexport interface SsoAuthConfig {\r\n /** Secure Login Server URL */\r\n slsUrl: string;\r\n /** SLS profile (default: SAPSSO_P) */\r\n profile?: string;\r\n /** Service principal name override */\r\n servicePrincipalName?: string;\r\n /** Skip SSL verification (required for most corporate environments) */\r\n insecure?: boolean;\r\n /** Force certificate re-enrollment even if valid cert exists */\r\n forceEnroll?: boolean;\r\n /** Return certificate contents instead of saving to files */\r\n returnContents?: boolean;\r\n}\r\n\r\n/**\r\n * SSO authentication strategy using Kerberos and mTLS\r\n */\r\nexport class SsoAuth implements AuthStrategy {\r\n readonly type = 'sso' as const;\r\n private config: SsoAuthConfig;\r\n private certificates: CertificateMaterial | null = null;\r\n\r\n /**\r\n * Create an SSO Auth strategy\r\n *\r\n * @param config - SSO authentication configuration\r\n */\r\n constructor(config: SsoAuthConfig) {\r\n if (!config.slsUrl) {\r\n throw new Error('SsoAuth requires slsUrl');\r\n }\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Get auth headers for SSO\r\n *\r\n * SSO uses mTLS for authentication, not headers.\r\n * Returns empty headers - the mTLS agent handles auth.\r\n */\r\n getAuthHeaders(): Record<string, string> {\r\n return {};\r\n }\r\n\r\n /**\r\n * Get mTLS certificates\r\n *\r\n * Returns the certificate material after successful login.\r\n * Used by ADT client to create an mTLS agent.\r\n *\r\n * @returns Certificate material or null if not enrolled\r\n */\r\n getCertificates(): CertificateMaterial | null {\r\n return this.certificates;\r\n }\r\n\r\n /**\r\n * Perform SSO login via certificate enrollment\r\n *\r\n * Checks for existing valid certificates and enrolls new ones if needed.\r\n *\r\n * @param _fetchFn - Unused, kept for interface compatibility\r\n * @returns Success/error tuple\r\n */\r\n async performLogin(_fetchFn: typeof fetch): AsyncResult<void, Error> {\r\n // Check for existing certificates\r\n if (!this.config.forceEnroll) {\r\n const [loadResult, loadErr] = await this.tryLoadExistingCertificates();\r\n if (!loadErr && loadResult) {\r\n this.certificates = loadResult;\r\n return ok(undefined);\r\n }\r\n }\r\n\r\n // Enroll new certificate\r\n const slsConfig: SlsConfig = {\r\n slsUrl: this.config.slsUrl,\r\n };\r\n if (this.config.profile) {\r\n slsConfig.profile = this.config.profile;\r\n }\r\n if (this.config.servicePrincipalName) {\r\n slsConfig.servicePrincipalName = this.config.servicePrincipalName;\r\n }\r\n\r\n const [material, enrollErr] = await enrollCertificate({\r\n config: slsConfig,\r\n insecure: this.config.insecure ?? false,\r\n });\r\n\r\n if (enrollErr) {\r\n return err(enrollErr);\r\n }\r\n\r\n // Save certificates to filesystem (unless returnContents is true)\r\n if (!this.config.returnContents) {\r\n const [, saveErr] = await saveCertificates(material);\r\n if (saveErr) {\r\n return err(saveErr);\r\n }\r\n }\r\n\r\n this.certificates = material;\r\n return ok(undefined);\r\n }\r\n\r\n /**\r\n * Try to load and validate existing certificates\r\n */\r\n private async tryLoadExistingCertificates(): AsyncResult<CertificateMaterial> {\r\n // Check if files exist\r\n const exists = await certificatesExist();\r\n if (!exists) {\r\n return err(new Error('No existing certificates found'));\r\n }\r\n\r\n // Load certificates\r\n const [material, loadErr] = await loadCertificates();\r\n if (loadErr) {\r\n return err(loadErr);\r\n }\r\n\r\n // Check expiry\r\n const [isExpired, expiryErr] = isCertificateExpired(material.fullChain);\r\n if (expiryErr) {\r\n return err(expiryErr);\r\n }\r\n\r\n if (isExpired) {\r\n return err(new Error('Certificate is expired or expiring soon'));\r\n }\r\n\r\n return ok(material);\r\n }\r\n}\r\n","/**\r\n * SAML authentication types\r\n *\r\n * Defines provider configurations and form selectors for SAML browser automation.\r\n * Configs are loaded from config.json per-system, not hardcoded.\r\n */\r\n\r\n/**\r\n * CSS selectors for login form elements\r\n *\r\n * Used by Playwright to locate and fill login form fields.\r\n */\r\nexport interface FormSelectors {\r\n /** CSS selector for username input field */\r\n username: string;\r\n /** CSS selector for password input field */\r\n password: string;\r\n /** CSS selector for submit button */\r\n submit: string;\r\n}\r\n\r\n/**\r\n * Default SAP IDP form selectors\r\n *\r\n * Used when no custom selectors are configured for a system.\r\n */\r\nexport const DEFAULT_FORM_SELECTORS: FormSelectors = {\r\n username: '#j_username',\r\n password: '#j_password',\r\n submit: '#logOnFormSubmit',\r\n};\r\n\r\n/**\r\n * Configuration for a SAML provider\r\n *\r\n * Defines how to interact with a specific SAP system's login page.\r\n * Configured per-system in config.json.\r\n */\r\nexport interface SamlProviderConfig {\r\n /** Whether to ignore HTTPS certificate errors */\r\n ignoreHttpsErrors: boolean;\r\n /** CSS selectors for login form elements */\r\n formSelectors: FormSelectors;\r\n}\r\n\r\n/**\r\n * Default SAML provider configuration\r\n *\r\n * Used when no SAML config is specified for a system.\r\n */\r\nexport const DEFAULT_PROVIDER_CONFIG: SamlProviderConfig = {\r\n ignoreHttpsErrors: false,\r\n formSelectors: DEFAULT_FORM_SELECTORS,\r\n};\r\n\r\n/**\r\n * Playwright cookie structure\r\n *\r\n * Matches Playwright's Cookie type for interoperability.\r\n */\r\nexport interface PlaywrightCookie {\r\n name: string;\r\n value: string;\r\n domain: string;\r\n path: string;\r\n expires: number;\r\n httpOnly: boolean;\r\n secure: boolean;\r\n sameSite: 'Strict' | 'Lax' | 'None';\r\n}\r\n\r\n/**\r\n * Result of SAML browser login\r\n */\r\nexport interface SamlLoginResult {\r\n /** Session cookies from successful login */\r\n cookies: PlaywrightCookie[];\r\n}\r\n","/**\r\n * SAML browser automation\r\n *\r\n * Implements headless browser login flow using Playwright.\r\n * Dynamically imports Playwright to avoid requiring it when not using SAML.\r\n */\r\n\r\nimport type { AsyncResult } from '../../../types/result';\r\nimport { ok, err } from '../../../types/result';\r\nimport type { PlaywrightCookie, SamlProviderConfig } from './types';\r\nimport { DEFAULT_PROVIDER_CONFIG } from './types';\r\n\r\n/** Timeouts for browser automation */\r\nconst TIMEOUTS = {\r\n PAGE_LOAD: 60_000,\r\n FORM_SELECTOR: 10_000,\r\n} as const;\r\n\r\n/**\r\n * Credentials for SAML login\r\n */\r\nexport interface SamlCredentials {\r\n username: string;\r\n password: string;\r\n}\r\n\r\n/**\r\n * Options for SAML browser login\r\n */\r\nexport interface SamlBrowserLoginOptions {\r\n /** SAP system base URL */\r\n baseUrl: string;\r\n /** Login credentials */\r\n credentials: SamlCredentials;\r\n /** Optional custom provider config (overrides auto-detection) */\r\n providerConfig?: SamlProviderConfig;\r\n /** Whether to run browser in headless mode (default: true) */\r\n headless?: boolean;\r\n}\r\n\r\n/**\r\n * Perform SAML login using headless browser automation\r\n *\r\n * Launches a Chromium browser, navigates to the SAP login page,\r\n * fills in credentials, and extracts session cookies.\r\n *\r\n * @param options - Login options including URL and credentials\r\n * @returns Session cookies on success, error on failure\r\n *\r\n * @example\r\n * ```typescript\r\n * const [cookies, error] = await performBrowserLogin({\r\n * baseUrl: 'https://sap-system.example.com',\r\n * credentials: { username: 'user@example.com', password: 'secret' }\r\n * });\r\n * if (error) {\r\n * console.error('Login failed:', error.message);\r\n * return;\r\n * }\r\n * // Use cookies for authenticated requests\r\n * ```\r\n */\r\nexport async function performBrowserLogin(\r\n options: SamlBrowserLoginOptions\r\n): AsyncResult<PlaywrightCookie[], Error> {\r\n const { baseUrl, credentials, headless = true } = options;\r\n const config = options.providerConfig ?? DEFAULT_PROVIDER_CONFIG;\r\n\r\n // Dynamically import Playwright to avoid requiring it when not using SAML.\r\n let playwright;\r\n try {\r\n playwright = await import('playwright');\r\n } catch {\r\n return err(\r\n new Error(\r\n 'Playwright is required for SAML authentication but is not installed. ' +\r\n 'Install it with: npm install playwright'\r\n )\r\n );\r\n }\r\n\r\n const browserArgs = config.ignoreHttpsErrors\r\n ? ['--ignore-certificate-errors', '--disable-web-security']\r\n : [];\r\n\r\n let browser;\r\n try {\r\n browser = await playwright.chromium.launch({\r\n headless,\r\n args: browserArgs,\r\n });\r\n } catch (launchError) {\r\n return err(\r\n new Error(\r\n `Failed to launch browser: ${launchError instanceof Error ? launchError.message : String(launchError)}`\r\n )\r\n );\r\n }\r\n\r\n try {\r\n const context = await browser.newContext({\r\n ignoreHTTPSErrors: config.ignoreHttpsErrors,\r\n });\r\n const page = await context.newPage();\r\n\r\n // Navigate to SAP login page.\r\n const loginUrl = `${baseUrl}/sap/bc/adt/compatibility/graph`;\r\n try {\r\n await page.goto(loginUrl, {\r\n timeout: TIMEOUTS.PAGE_LOAD,\r\n waitUntil: 'domcontentloaded',\r\n });\r\n } catch {\r\n return err(new Error('Failed to load login page. Please check if the server is online.'));\r\n }\r\n\r\n // Wait for and fill login form.\r\n try {\r\n await page.waitForSelector(config.formSelectors.username, {\r\n timeout: TIMEOUTS.FORM_SELECTOR,\r\n });\r\n } catch {\r\n return err(new Error('Login form not found. The page may have changed or loaded incorrectly.'));\r\n }\r\n\r\n await page.fill(config.formSelectors.username, credentials.username);\r\n await page.fill(config.formSelectors.password, credentials.password);\r\n await page.click(config.formSelectors.submit);\r\n\r\n // Wait for login to complete.\r\n await page.waitForLoadState('networkidle');\r\n\r\n // Extract cookies.\r\n const cookies = await context.cookies();\r\n\r\n return ok(cookies as PlaywrightCookie[]);\r\n } finally {\r\n await browser.close();\r\n }\r\n}\r\n","/**\r\n * Cookie extraction and formatting for SAML authentication\r\n *\r\n * Converts Playwright cookies to AuthCookie format used by the rest of the codebase.\r\n */\r\n\r\nimport type { AuthCookie } from '../types';\r\nimport type { PlaywrightCookie } from './types';\r\n\r\n/**\r\n * Convert Playwright cookies to AuthCookie format\r\n *\r\n * @param playwrightCookies - Cookies from Playwright browser context\r\n * @returns Array of AuthCookie objects\r\n */\r\nexport function toAuthCookies(playwrightCookies: PlaywrightCookie[]): AuthCookie[] {\r\n return playwrightCookies.map((cookie) => ({\r\n name: cookie.name,\r\n value: cookie.value,\r\n domain: cookie.domain,\r\n path: cookie.path,\r\n }));\r\n}\r\n\r\n/**\r\n * Format cookies as Cookie header value\r\n *\r\n * @param cookies - Array of AuthCookie objects\r\n * @returns Cookie header string (e.g., \"name1=value1; name2=value2\")\r\n */\r\nexport function formatCookieHeader(cookies: AuthCookie[]): string {\r\n return cookies.map((c) => `${c.name}=${c.value}`).join('; ');\r\n}\r\n","/**\r\n * SAML authentication strategy\r\n *\r\n * Implements SAML-based SSO for SAP systems using browser automation.\r\n * Requires Playwright for headless browser login.\r\n *\r\n * @example\r\n * ```typescript\r\n * // With default SAP IDP selectors\r\n * const auth = new SamlAuth({\r\n * username: 'user@example.com',\r\n * password: 'secret',\r\n * baseUrl: 'https://sap-system.example.com',\r\n * });\r\n *\r\n * // With custom form selectors\r\n * const auth = new SamlAuth({\r\n * username: 'user@example.com',\r\n * password: 'secret',\r\n * baseUrl: 'https://sap-system.example.com',\r\n * providerConfig: {\r\n * ignoreHttpsErrors: true,\r\n * formSelectors: {\r\n * username: '#custom-user-field',\r\n * password: '#custom-pass-field',\r\n * submit: '#custom-submit-btn',\r\n * },\r\n * },\r\n * });\r\n *\r\n * // Perform login\r\n * const [, error] = await auth.performLogin(fetch);\r\n * if (error) {\r\n * console.error('Login failed:', error.message);\r\n * }\r\n * ```\r\n */\r\n\r\nimport type { AuthStrategy, AuthCookie } from '../types';\r\nimport type { AsyncResult } from '../../../types/result';\r\nimport { ok, err } from '../../../types/result';\r\nimport type { SamlProviderConfig } from './types';\r\nimport { performBrowserLogin } from './browser';\r\nimport { toAuthCookies, formatCookieHeader } from './cookies';\r\n\r\n/**\r\n * Configuration for SAML authentication\r\n */\r\nexport interface SamlAuthConfig {\r\n /** SAML username (often an email address) */\r\n username: string;\r\n /** SAML password */\r\n password: string;\r\n /** SAP system base URL */\r\n baseUrl: string;\r\n /** Optional custom provider configuration */\r\n providerConfig?: SamlProviderConfig;\r\n}\r\n\r\n/**\r\n * SAML authentication strategy\r\n */\r\nexport class SamlAuth implements AuthStrategy {\r\n readonly type = 'saml' as const;\r\n private cookies: AuthCookie[] = [];\r\n private config: SamlAuthConfig;\r\n\r\n /**\r\n * Create a SAML Auth strategy\r\n *\r\n * @param config - SAML authentication configuration\r\n */\r\n constructor(config: SamlAuthConfig) {\r\n if (!config.username || !config.password) {\r\n throw new Error('SamlAuth requires both username and password');\r\n }\r\n if (!config.baseUrl) {\r\n throw new Error('SamlAuth requires baseUrl');\r\n }\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Get auth headers for SAML\r\n *\r\n * After successful login, includes Cookie header with session cookies.\r\n */\r\n getAuthHeaders(): Record<string, string> {\r\n if (this.cookies.length === 0) {\r\n return {};\r\n }\r\n return {\r\n Cookie: formatCookieHeader(this.cookies),\r\n };\r\n }\r\n\r\n /**\r\n * Get authentication cookies\r\n *\r\n * @returns Array of cookies obtained during SAML login\r\n */\r\n getCookies(): AuthCookie[] {\r\n return this.cookies;\r\n }\r\n\r\n /**\r\n * Perform SAML login using headless browser automation\r\n *\r\n * Launches a Chromium browser, navigates to the SAP login page,\r\n * fills in credentials, and extracts session cookies.\r\n *\r\n * @param _fetchFn - Unused, kept for interface compatibility\r\n * @returns Success/error tuple\r\n */\r\n async performLogin(_fetchFn: typeof fetch): AsyncResult<void, Error> {\r\n const [playwrightCookies, loginError] = await performBrowserLogin({\r\n baseUrl: this.config.baseUrl,\r\n credentials: {\r\n username: this.config.username,\r\n password: this.config.password,\r\n },\r\n ...(this.config.providerConfig && { providerConfig: this.config.providerConfig }),\r\n });\r\n\r\n if (loginError) {\r\n return err(loginError);\r\n }\r\n\r\n this.cookies = toAuthCookies(playwrightCookies);\r\n\r\n if (this.cookies.length === 0) {\r\n return err(new Error('SAML login succeeded but no cookies were returned'));\r\n }\r\n\r\n return ok(undefined);\r\n }\r\n}\r\n","import type { AuthConfig } from '../../types/config';\r\nimport type { AuthStrategy } from './types';\r\nimport { BasicAuth } from './basic';\r\nimport { SsoAuth, type SsoAuthConfig } from './sso';\r\nimport { SamlAuth } from './saml';\r\n\r\n/**\r\n * Options for creating an authentication strategy\r\n */\r\nexport interface CreateAuthOptions {\r\n /** Authentication configuration */\r\n config: AuthConfig;\r\n /** Base URL of the SAP system (required for SAML) */\r\n baseUrl?: string;\r\n /** Skip SSL verification (dev only) */\r\n insecure?: boolean;\r\n}\r\n\r\n/**\r\n * Create an authentication strategy based on configuration\r\n *\r\n * Factory function that instantiates the appropriate auth strategy\r\n * based on the auth config type (basic, saml, or sso).\r\n *\r\n * @param options - Authentication options including config and optional baseUrl\r\n * @returns Configured authentication strategy\r\n * @throws Error if config type is invalid or required fields are missing\r\n *\r\n * @example\r\n * ```typescript\r\n * // Basic auth\r\n * const auth = createAuthStrategy({\r\n * config: { type: 'basic', username: 'DEVELOPER', password: 'secret' }\r\n * });\r\n *\r\n * // SAML auth (requires baseUrl)\r\n * const auth = createAuthStrategy({\r\n * config: { type: 'saml', username: 'user@example.com', password: 'secret' },\r\n * baseUrl: 'https://sap-system.example.com'\r\n * });\r\n *\r\n * // SSO auth (Kerberos + mTLS)\r\n * const auth = createAuthStrategy({\r\n * config: {\r\n * type: 'sso',\r\n * slsUrl: 'https://sapsso.corp.example.com'\r\n * },\r\n * insecure: true\r\n * });\r\n * ```\r\n */\r\nexport function createAuthStrategy(options: CreateAuthOptions): AuthStrategy {\r\n const { config, baseUrl, insecure } = options;\r\n\r\n switch (config.type) {\r\n case 'basic':\r\n return new BasicAuth(config.username, config.password);\r\n\r\n case 'saml':\r\n if (!baseUrl) {\r\n throw new Error('SAML authentication requires baseUrl');\r\n }\r\n return new SamlAuth({\r\n username: config.username,\r\n password: config.password,\r\n baseUrl,\r\n ...(config.providerConfig && { providerConfig: config.providerConfig }),\r\n });\r\n\r\n case 'sso': {\r\n const ssoConfig: SsoAuthConfig = {\r\n slsUrl: config.slsUrl,\r\n };\r\n if (config.profile) {\r\n ssoConfig.profile = config.profile;\r\n }\r\n if (config.servicePrincipalName) {\r\n ssoConfig.servicePrincipalName = config.servicePrincipalName;\r\n }\r\n if (config.forceEnroll) {\r\n ssoConfig.forceEnroll = config.forceEnroll;\r\n }\r\n if (insecure) {\r\n ssoConfig.insecure = insecure;\r\n }\r\n return new SsoAuth(ssoConfig);\r\n }\r\n\r\n default: {\r\n const _exhaustive: never = config;\r\n throw new Error(`Unknown auth type: ${(_exhaustive as AuthConfig).type}`);\r\n }\r\n }\r\n}\r\n","/**\n * Configuration loading utilities\n *\n * Matches Python reference behavior:\n * - Load system URLs from config.json\n * - Parse clientId format: \"SystemId-ClientNumber\" (e.g., \"MediaDemo-DM1-200\")\n * - Support RELAY_CONFIG environment variable\n */\n\nimport { readFileSync } from 'node:fs';\nimport { z } from 'zod';\nimport type { Result } from '../types/result';\nimport { ok, err } from '../types/result';\n\n/**\n * System configuration from config.json\n */\nexport interface SystemConfig {\n /** ADT server URL */\n adt: string | undefined;\n /** OData server URL (optional) */\n odata: string | undefined;\n /** Instance number (optional) */\n instanceNum: string | undefined;\n}\n\n/**\n * Loaded configuration map\n * Key: System ID (e.g., \"MediaDemo-DM1\")\n * Value: System configuration\n */\nexport type ConfigMap = Map<string, SystemConfig>;\n\n/**\n * Zod schema for config.json validation\n */\nconst systemConfigSchema = z.record(\n z.string(),\n z.object({\n adt: z.string().url().optional(),\n odata: z.string().url().optional(),\n instance_num: z.string().optional(),\n })\n);\n\n/**\n * Parsed client ID components\n */\nexport interface ParsedClientId {\n /** System ID for config lookup (e.g., \"MediaDemo-DM1\") */\n systemId: string;\n /** SAP client number (e.g., \"200\") */\n clientNumber: string;\n}\n\n/**\n * Global config storage\n */\nlet globalConfig: ConfigMap | null = null;\n\n/**\n * Load configuration from a JSON file\n *\n * @param path - Path to config.json\n * @returns Result with ConfigMap or error\n *\n * @example\n * ```typescript\n * const [config, err] = loadConfig('./config.json');\n * if (err) {\n * console.error('Failed to load config:', err);\n * return;\n * }\n * ```\n */\nexport function loadConfig(path: string): Result<ConfigMap, Error> {\n try {\n // Read and parse the JSON file.\n const content = readFileSync(path, 'utf-8');\n const raw = JSON.parse(content);\n\n // Validate config structure with Zod schema.\n const validation = systemConfigSchema.safeParse(raw);\n if (!validation.success) {\n const issues = validation.error.issues\n .map((i) => `${i.path.join('.')}: ${i.message}`)\n .join(', ');\n return err(new Error(`Invalid config format: ${issues}`));\n }\n\n // Convert validated data to ConfigMap.\n const configMap: ConfigMap = new Map();\n for (const [key, value] of Object.entries(validation.data)) {\n configMap.set(key, {\n adt: value.adt,\n odata: value.odata,\n instanceNum: value.instance_num,\n });\n }\n\n // Store globally for later access.\n globalConfig = configMap;\n\n return ok(configMap);\n } catch (error) {\n // Handle JSON parsing errors.\n if (error instanceof SyntaxError) {\n return err(new Error(`Invalid JSON in config file: ${error.message}`));\n }\n // Handle file not found errors.\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {\n return err(new Error(`Config file not found: ${path}`));\n }\n return err(error instanceof Error ? error : new Error(String(error)));\n }\n}\n\n/**\n * Default config file path\n */\nconst DEFAULT_CONFIG_PATH = './config.json';\n\n/**\n * Load configuration from RELAY_CONFIG environment variable\n *\n * Defaults to './config.json' if RELAY_CONFIG is not set.\n *\n * @returns Result with ConfigMap or error\n *\n * @example\n * ```typescript\n * // Uses RELAY_CONFIG env var, or defaults to './config.json'\n * const [config, err] = loadConfigFromEnv();\n * ```\n */\n\nexport function loadConfigFromEnv(): Result<ConfigMap, Error> {\n // Resolve config path from environment or use default.\n const configPath = process.env['RELAY_CONFIG'] ?? DEFAULT_CONFIG_PATH;\n return loadConfig(configPath);\n}\n\n/**\n * Get the currently loaded config\n *\n * @returns ConfigMap or null if not loaded\n */\nexport function getConfig(): ConfigMap | null {\n return globalConfig;\n}\n\n/**\n * Get system config by ID\n *\n * @param systemId - System ID (e.g., \"MediaDemo-DM1\")\n * @returns SystemConfig or null if not found\n */\nexport function getSystemConfig(systemId: string): SystemConfig | null {\n if (!globalConfig) return null;\n return globalConfig.get(systemId) ?? null;\n}\n\n/**\n * Parse a client ID into system ID and client number\n *\n * Format: \"SystemId-ClientNumber\" where SystemId can contain hyphens\n * Example: \"MediaDemo-DM1-200\" → { systemId: \"MediaDemo-DM1\", clientNumber: \"200\" }\n *\n * @param clientId - Full client ID string\n * @returns Result with parsed components or error\n *\n * @example\n * ```typescript\n * const [parsed, err] = parseClientId('MediaDemo-DM1-200');\n * if (err) return;\n * console.log(parsed.systemId); // \"MediaDemo-DM1\"\n * console.log(parsed.clientNumber); // \"200\"\n * ```\n */\nexport function parseClientId(clientId: string): Result<ParsedClientId, Error> {\n if (!clientId) {\n return err(new Error('Client ID is required'));\n }\n\n // Split by hyphen to extract components.\n const parts = clientId.split('-');\n if (parts.length < 2) {\n return err(new Error(`Invalid client ID format: \"${clientId}\". Expected \"SystemId-ClientNumber\" (e.g., \"MediaDemo-DM1-200\")`));\n }\n\n // Extract client number (last part) and system ID (everything before).\n const clientNumber = parts[parts.length - 1];\n const systemId = parts.slice(0, -1).join('-');\n\n // Validate client number is numeric.\n if (!clientNumber || !/^\\d+$/.test(clientNumber)) {\n return err(new Error(`Invalid client number: \"${clientNumber}\". Must be numeric (e.g., \"100\", \"200\")`));\n }\n\n // Validate system ID is not empty.\n if (!systemId) {\n return err(new Error(`Invalid system ID in client ID: \"${clientId}\"`));\n }\n\n return ok({ systemId, clientNumber });\n}\n\n/**\n * Resolve a client ID to a full URL and client number\n *\n * @param clientId - Full client ID (e.g., \"MediaDemo-DM1-200\")\n * @returns Result with URL and client number or error\n *\n * @example\n * ```typescript\n * loadConfig('./config.json');\n * const [resolved, err] = resolveClientId('MediaDemo-DM1-200');\n * if (err) return;\n * console.log(resolved.url); // \"https://50.19.106.63:443\"\n * console.log(resolved.clientNumber); // \"200\"\n * ```\n */\nexport function resolveClientId(clientId: string): Result<{ url: string; clientNumber: string }, Error> {\n // Parse the client ID into components.\n const [parsed, parseErr] = parseClientId(clientId);\n if (parseErr) {\n return err(parseErr);\n }\n\n // Ensure config is loaded.\n if (!globalConfig) {\n return err(new Error('Config not loaded. Call loadConfig() or loadConfigFromEnv() first.'));\n }\n\n // Lookup system configuration.\n const systemConfig = globalConfig.get(parsed.systemId);\n if (!systemConfig) {\n return err(new Error(`Unknown system ID: \"${parsed.systemId}\". Available: ${Array.from(globalConfig.keys()).join(', ')}`));\n }\n\n // Validate ADT URL is configured.\n if (!systemConfig.adt) {\n return err(new Error(`No ADT URL configured for system: \"${parsed.systemId}\"`));\n }\n\n return ok({\n url: systemConfig.adt,\n clientNumber: parsed.clientNumber,\n });\n}\n\n/**\n * Build a ClientConfig from a client ID and auth config\n *\n * Convenience function that resolves the client ID and builds\n * a complete ClientConfig ready for createClient().\n *\n * @param clientId - Full client ID (e.g., \"MediaDemo-DM1-200\")\n * @param auth - Authentication configuration\n * @returns Result with ClientConfig or error\n *\n * @example\n * ```typescript\n * loadConfig('./config.json');\n *\n * const [config, err] = buildClientConfig('MediaDemo-DM1-200', {\n * type: 'basic',\n * username: 'user',\n * password: 'pass',\n * });\n * if (err) return;\n *\n * const [client, clientErr] = createClient(config);\n * ```\n */\nexport function buildClientConfig(\n clientId: string,\n auth: { type: 'basic'; username: string; password: string } |\n { type: 'saml'; username: string; password: string; provider?: string } |\n { type: 'sso'; certificate?: string }\n): Result<{ url: string; client: string; auth: typeof auth }, Error> {\n // Resolve client ID to URL and client number.\n const [resolved, resolveErr] = resolveClientId(clientId);\n if (resolveErr) {\n return err(resolveErr);\n }\n\n // Build complete client configuration.\n return ok({\n url: resolved.url,\n client: resolved.clientNumber,\n auth,\n });\n}\n"],"mappings":"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","names":["text","text","text","text","text","text","Agent","undiciFetch","forge","forge","forge","buildUrl","Agent","undiciFetch","result","z","z"]}
|