UNPKG

@contiva/sap-integration-suite-client

Version:
523 lines (522 loc) 20 kB
/** * SAP Cloud Platform Integration API Client * * This module provides a client for interacting with the SAP Cloud Platform Integration API. * It handles authentication, request management, and provides type-safe access to all SAP API endpoints. * * @module sap-integration-suite-client * @packageDocumentation */ import { IntegrationContentClient } from '../wrapper/integration-content-client'; import { IntegrationContentAdvancedClient } from '../wrapper/custom/integration-content-advanced-client'; import { MessageProcessingLogsClient } from '../wrapper/message-processing-logs-client'; import { LogFilesClient } from '../wrapper/log-files-client'; import { MessageStoreClient } from '../wrapper/message-store-client'; import { SecurityContentClient } from '../wrapper/security-content-client'; import { B2BScenariosClient } from '../wrapper/b2b-scenarios-client'; import { PartnerDirectoryClient } from '../wrapper/partner-directory-client'; import { BaseCustomClient, CustomClientFactory } from '../wrapper/custom/base-custom-client'; import { CacheManager } from '../core/cache-manager'; /** * Configuration interface for SapClient * * @interface SapClientConfig * @example * // Create a client with explicit configuration * const client = new SapClient({ * baseUrl: 'https://my-tenant.sap-api.com/api/v1', * oauthClientId: 'my-client-id', * oauthClientSecret: 'my-client-secret', * oauthTokenUrl: 'https://my-tenant.authentication.sap.hana.ondemand.com/oauth/token' * }); */ export interface SapClientConfig { /** * Base URL of the SAP API (e.g. https://tenant.sap-api.com/api/v1) * If not provided, the SAP_BASE_URL environment variable will be used */ baseUrl?: string; /** * OAuth client ID for authentication * If not provided, the SAP_OAUTH_CLIENT_ID environment variable will be used */ oauthClientId?: string; /** * OAuth client secret for authentication * If not provided, the SAP_OAUTH_CLIENT_SECRET environment variable will be used */ oauthClientSecret?: string; /** * OAuth token URL for retrieving tokens * If not provided, the SAP_OAUTH_TOKEN_URL environment variable will be used */ oauthTokenUrl?: string; /** * Enable response format normalization * If true, the client will attempt to normalize different SAP API response formats * Default: true */ normalizeResponses?: boolean; /** * Maximum number of retries for failed requests * Default: 0 (no retries) */ maxRetries?: number; /** * Delay between retries in milliseconds * Default: 1000 (1 second) */ retryDelay?: number; /** * Aktiviere oder deaktiviere benutzerdefinierte Client-Erweiterungen * Default: true */ enableCustomClients?: boolean; /** * Redis connection string for caching * Format: host:port,password=xxx,ssl=True,abortConnect=False * If not provided, the REDIS_CONNECTION_STRING environment variable will be used */ redisConnectionString?: string; /** * Enable Redis caching * Default: false (or REDIS_ENABLED environment variable) */ redisEnabled?: boolean; /** * Force cache revalidation on every request * Uses stale-while-revalidate pattern (returns cached data while updating in background) * Default: false */ forceRefreshCache?: boolean; /** * Disable caching completely for this client instance * No cache reads or writes will be performed * Default: false */ noCache?: boolean; /** * Custom logger function for cache events * If provided, cache status logs will be sent to this function instead of console.log */ cacheLogger?: (message: string) => void; /** * External CacheManager instance (optional) * If provided, this instance will be used instead of creating a new one * Useful for sharing a single Redis connection across multiple SapClient instances */ cacheManager?: CacheManager; } /** * Main SAP Client class that provides access to all SAP API endpoints * * This client handles: * - Authentication via OAuth 2.0 client credentials flow * - Token management (expiration and renewal) * - CSRF token handling for write operations * - Type-safe API access through generated API clients * - Error handling * - Response format normalization * * @example * // Basic usage with environment variables * import SapClient from 'sap-integration-suite-client'; * const client = new SapClient(); * * // With explicit configuration * const client = new SapClient({ * baseUrl: 'https://tenant.sap-api.com/api/v1', * oauthClientId: 'client-id', * oauthClientSecret: 'client-secret', * oauthTokenUrl: 'https://tenant.authentication.sap.hana.ondemand.com/oauth/token' * }); * * // Making API calls * async function getPackages() { * const response = await client.integrationContent.integrationPackages.integrationPackagesList(); * return response.data; * } */ declare class SapClient { /** Axios instance used for HTTP requests */ private axiosInstance; /** Base URL of the SAP API */ private baseUrl; /** CSRF token for write operations */ private csrfToken; /** Promise for ongoing CSRF token fetch to prevent race conditions */ private csrfTokenPromise; /** OAuth token with expiration information */ private oauthToken; /** Promise for ongoing token refresh to prevent race conditions */ private tokenRefreshPromise; /** OAuth client ID */ private oauthClientId; /** OAuth client secret */ private oauthClientSecret; /** OAuth token URL */ private oauthTokenUrl; /** Whether to normalize API responses */ private normalizeResponses; /** Maximum number of retries for failed requests */ private maxRetries; /** Delay between retries in milliseconds */ private retryDelay; /** Minimum delay between consecutive requests (rate limiting prevention) */ private minRequestDelay; /** Timestamp of last request */ private lastRequestTime; /** Whether to enable custom client extensions */ private enableCustomClients; /** Registry für benutzerdefinierte Client-Erweiterungen */ private customClientRegistry; /** Map der erstellten benutzerdefinierten Clients */ private customClients; /** Cache manager for Redis-based caching */ private _cacheManager; /** Flag to track if cache manager is externally provided (don't disconnect on cleanup) */ private isExternalCacheManager; /** Hostname for cache key generation */ private hostname; /** Force cache revalidation on every request */ private forceRefreshCache; /** Disable caching completely */ private noCache; /** Custom logger for cache events */ private cacheLogger?; /** Cached debug mode flag for performance */ private readonly debugMode; /** * Integration Content API client * Provides access to integration packages, artifacts, and related operations */ integrationContent: IntegrationContentClient; /** * Integration Content Advanced API client * Provides extended functionality for integration content operations */ integrationContentAdvanced: IntegrationContentAdvancedClient; /** * Log Files API client * Access system logs and log archives */ logFiles: LogFilesClient; /** * Message Processing Logs API client * Access and query message processing logs */ messageProcessingLogs: MessageProcessingLogsClient; /** * Message Store API client * Access stored messages and attachments */ messageStore: MessageStoreClient; /** * Security Content API client * Manage security artifacts like credentials and certificates */ securityContent: SecurityContentClient; /** * B2B Scenarios API client * Access business documents, orphaned interchanges, and acknowledgements */ b2bScenarios: B2BScenariosClient; /** * Partner Directory API client * Manage partner information, parameters, and authorized users */ partnerDirectory: PartnerDirectoryClient; /** * Gets the cache manager instance * Returns null if caching is disabled or not configured * * @returns The CacheManager instance or null */ get cacheManager(): CacheManager | null; /** * Creates a new SAP Client instance * * @param {SapClientConfig} [config] - Configuration options for the client * @throws {Error} If required configuration is missing * * @example * // Using environment variables * const client = new SapClient(); * * @example * // Using explicit configuration * const client = new SapClient({ * baseUrl: 'https://tenant.sap-api.com/api/v1', * oauthClientId: 'client-id', * oauthClientSecret: 'client-secret', * oauthTokenUrl: 'https://tenant.authentication.sap.hana.ondemand.com/oauth/token' * }); */ constructor(config?: SapClientConfig); /** * Validates that the required configuration is provided * * @private * @throws {Error} If baseUrl is missing * @throws {Error} If any OAuth configuration is incomplete */ private validateConfig; /** * Gets or refreshes the OAuth token * - Returns existing token if it's still valid * - Fetches a new token if the current one is expired or doesn't exist * - Adds expiration timestamp to the token * * @private * @returns {Promise<OAuthToken>} Promise resolving to the OAuth token * @throws {Error} If token cannot be obtained */ private getOAuthToken; /** * Normalizes different SAP API response formats into a consistent structure * * @private * @param {any} data - The response data to normalize * @returns {any} Normalized response data */ private normalizeResponseFormat; /** * Enhances error objects with more detailed information * * @private * @param {any} error - The error object * @param {string} [message] - Optional message to prefix the error * @returns {any} Enhanced error object */ private enhanceError; /** * Performs an HTTP request with retry logic for transient errors * * @private * @param {Function} requestFn - Function that performs the request * @param {number} retries - Number of retries left * @returns {Promise<any>} Promise resolving to the response */ private requestWithRetry; /** * Checks if a URL represents a collection endpoint (without specific ID) * Collection endpoints return arrays of items and are candidates for differential updates * * @private * @param url - The URL to check * @returns true if URL is a collection endpoint, false otherwise * * @example * isCollectionEndpoint('https://api.com/IntegrationRuntimeArtifacts') // true * isCollectionEndpoint('https://api.com/IntegrationRuntimeArtifacts(\'id\')') // false * isCollectionEndpoint('https://api.com/IntegrationPackages') // true */ private isCollectionEndpoint; /** * Extracts the base endpoint pattern for cache invalidation * * This method determines which cache pattern should be invalidated based on the endpoint. * For example: * - /IntegrationPackages('MyPackage')/IntegrationDesigntimeArtifacts → /IntegrationPackages * - /IntegrationRuntimeArtifacts('MyArtifact') → /IntegrationRuntimeArtifacts * - /MessageMappingDesigntimeArtifacts → /MessageMappingDesigntimeArtifacts * * @private * @param endpoint - The full endpoint path (without base URL) * @returns The base endpoint pattern for invalidation */ private extractBaseEndpointForInvalidation; /** * Custom fetch implementation that uses axios to make HTTP requests * - Handles CSRF token for write operations * - Adds OAuth token to requests * - Transforms axios responses to fetch API Response objects * - Implements retry logic * - Normalizes response formats * - Implements Redis-based caching with stale-while-revalidate pattern * * @private * @param {string | URL | Request} input - URL or Request object * @param {RequestInit} [init] - Request initialization options * @returns {Promise<Response>} Promise resolving to a Response object * @throws {Error} If the request fails */ private customFetch; /** * Performs the actual HTTP request to SAP * * @private * @param url - The URL to request * @param method - HTTP method * @param headers - Request headers * @param body - Request body * @returns The response data */ private performRequest; /** * Ensures a CSRF token is available for write operations * - Fetches a new token if one doesn't exist * - Uses OAuth token for authentication * - Prevents race conditions with csrfTokenPromise * * @private * @param {boolean} forceRefresh - Force fetching a new token even if one exists * @returns {Promise<void>} * @throws {Error} If the CSRF token cannot be fetched */ private ensureCsrfToken; /** * Initialisiert alle benutzerdefinierten Client-Erweiterungen */ private initializeCustomClients; /** * Gibt einen vorhandenen benutzerdefinierten Client zurück oder erstellt einen neuen * * @param type - Der Typ des benutzerdefinierten Clients * @param baseClient - Der zugrundeliegende Standard-Client * @returns Eine Instanz des benutzerdefinierten Clients */ private getOrCreateCustomClient; /** * Gibt einen benutzerdefinierten Client nach Typ zurück * * @param type - Der Typ des benutzerdefinierten Clients * @returns Der benutzerdefinierte Client oder undefined, wenn nicht gefunden */ getCustomClient<C extends BaseCustomClient<any>>(type: string): C | undefined; /** * Registriert einen benutzerdefinierten Client-Factory * * Diese Methode erlaubt es, zur Laufzeit neue benutzerdefinierte Client-Factories * zu registrieren, was die dynamische Erweiterung des Clients ermöglicht. * * @param type - Der Typ des benutzerdefinierten Clients * @param factory - Die Factory für die Erstellung des Clients */ registerCustomClientFactory<T, C extends BaseCustomClient<T>>(type: string, factory: CustomClientFactory<T, C>): void; /** * Invalidates cache entries matching a pattern * * This is a convenience wrapper around CacheManager.deleteByPattern that * automatically generates the hostname prefix for the cache key pattern. * * @param pattern - The pattern to match (without hostname prefix, e.g. 'GET:/IntegrationRuntimeArtifacts*') * @returns The number of cache keys deleted * * @example * // Invalidate all cache entries for a specific artifact * const deleted = await client.invalidateCache(`GET:/IntegrationRuntimeArtifacts('artifactId')*`); * * // Invalidate all runtime artifacts * const deleted = await client.invalidateCache('GET:/IntegrationRuntimeArtifacts*'); */ invalidateCache(pattern: string): Promise<number>; /** * Invalidates all cache entries for a specific artifact * * This is a convenience method that invalidates both the runtime artifact cache * and optionally the package cache containing the artifact. * * **Important**: This method also invalidates the corresponding collection caches * (e.g., `GET:/IntegrationRuntimeArtifacts*` and `GET:/IntegrationPackages*`) to ensure * consistency between single-item and collection caches. * * @param artifactId - The ID of the artifact to invalidate * @param packageId - Optional package ID to also invalidate the package cache * @returns The total number of cache keys deleted * * @example * // Invalidate cache for an artifact (includes collection cache) * const deleted = await client.invalidateArtifactCache('MyArtifact'); * * // Invalidate cache for an artifact and its package (includes all collection caches) * const deleted = await client.invalidateArtifactCache('MyArtifact', 'MyPackage'); */ invalidateArtifactCache(artifactId: string, packageId?: string): Promise<number>; /** * Invalidates ALL designtime-related cache entries for this client's hostname * * This method clears all caches related to designtime artifacts, which includes: * - /IntegrationPackages (collection and individual packages) * - /IntegrationDesigntimeArtifacts (all designtime artifacts) * - /MessageMappingDesigntimeArtifacts (all message mappings) * - /ValueMappingDesigntimeArtifacts (all value mappings) * - /ScriptCollectionDesigntimeArtifacts (all script collections) * * Use this method before fetching fresh designtime data to ensure * deleted artifacts are properly removed from the cache. * * @returns The total number of cache keys deleted * * @example * // Clear all designtime caches before refresh * const deleted = await client.invalidateDesigntimeCache(); * console.log(`Cleared ${deleted} cache entries`); * * // Then fetch fresh data * const packages = await client.integrationContent.getIntegrationPackages(); */ invalidateDesigntimeCache(): Promise<number>; /** * Invalidates ALL runtime-related cache entries for this client's hostname * * This method clears all caches related to runtime/deployed artifacts: * - /IntegrationRuntimeArtifacts (collection and individual deployed artifacts) * * Use this method before fetching fresh runtime data to ensure * undeployed artifacts are properly removed from the cache. * * @returns The total number of cache keys deleted * * @example * // Clear all runtime caches before refresh * const deleted = await client.invalidateRuntimeCache(); * console.log(`Cleared ${deleted} cache entries`); * * // Then fetch fresh data * const deployedArtifacts = await client.integrationContent.getDeployedArtifacts(); */ invalidateRuntimeCache(): Promise<number>; /** * Invalidates ALL cache entries for this client's hostname * * This method clears the entire cache for the current SAP system, * including both designtime and runtime data. * * **Warning**: This is a destructive operation that will clear ALL cached data * for this hostname. Use with caution as it will cause increased load on SAP * while the cache is repopulated. * * @returns The total number of cache keys deleted * * @example * // Clear ALL caches for this system * const deleted = await client.invalidateAllCache(); */ invalidateAllCache(): Promise<number>; /** * Gets the hostname used for cache key generation * * @returns The hostname extracted from the base URL */ getHostname(): string; /** * Closes all connections and cleans up resources * * This method should be called when the SapClient is no longer needed * to prevent memory leaks and ensure proper cleanup of resources like * Redis connections. * * @returns Promise that resolves when cleanup is complete * * @example * const client = new SapClient(); * // ... use client ... * await client.disconnect(); */ disconnect(): Promise<void>; } /** * Export the SapClient class as default export */ export default SapClient;