UNPKG

@ibm-cloud/watsonx-ai

Version:
407 lines 20.2 kB
/** * (C) Copyright IBM Corp. 2025-2026. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { BaseService, readExternalSources } from 'ibm-cloud-sdk-core'; import { Agent } from 'https'; import { readFileSync } from 'fs'; import { getAuthenticatorFromEnvironment } from "../authentication/utils/get-authenticator-from-environment.mjs"; import { VERSION_DATE } from "../version.mjs"; import { getSdkHeaders, transformStreamToObjectStream, transformStreamToStringStream, } from "../lib/common.mjs"; import { PLATFORM_URL_MAPPINGS } from "../config/index.mjs"; import { validateRequiredOneOf } from "../helpers/validators.mjs"; /** * WatsonxBaseService class extends BaseService and provides common functionalities for Watsonx * services. * * @category BaseService */ export class WatsonxBaseService extends BaseService { /** * Constructs an instance of WatsonxBaseService with passed in options and external configuration. * * @category Constructor * @param {UserOptions} [options] - The parameters to send to the service. * @param {string} [options.version] - The version date for the API of the form `YYYY-MM-DD` * @param {string} [options.serviceUrl] - The base URL for the service * @param {string} [options.serviceName] - The name of the service to configure * @param {Authenticator} [options.authenticator] - The Authenticator object used to authenticate * requests to the service * @param {Certificates['caCert']} [options.caCert] - Certificate configuration for HTTPS * connections * @param {string} [options.projectId] - The project ID to use for API requests * @param {string} [options.spaceId] - The space ID to use for API requests */ constructor(options = {}) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; // If version is not provided, use the VERSION_DATE from version.ts if (!options.version) { options.version = VERSION_DATE; } // version is now guaranteed to be set (either provided or from VERSION_DATE) options.version = options.version; (_a = options.serviceName) !== null && _a !== void 0 ? _a : (options.serviceName = WatsonxBaseService.DEFAULT_SERVICE_NAME); let httpsAgentAuth; if (typeof options.caCert === 'string') { const certFile = readFileSync(options.caCert); httpsAgentAuth = new Agent({ ca: certFile, }); options.httpsAgent = httpsAgentAuth; } else if ((_c = (_b = options.caCert) === null || _b === void 0 ? void 0 : _b.auth) === null || _c === void 0 ? void 0 : _c.path) { const certFile = readFileSync(options.caCert.auth.path); httpsAgentAuth = new Agent({ ca: certFile, }); } // Create authenticator with user given params and environment variables if (!options.authenticator) { const { serviceName, requestToken, serviceUrl } = options; options.authenticator = getAuthenticatorFromEnvironment({ serviceName, requestToken, serviceUrl, httpsAgent: httpsAgentAuth, }); } (_d = options.url) !== null && _d !== void 0 ? _d : (options.url = options.serviceUrl); super(options); this.httpsAgentMap = { service: undefined, dataplatform: undefined }; this.version = options.version; validateRequiredOneOf(options, ['projectId', 'spaceId'], false); this.projectId = options.projectId; this.spaceId = options.spaceId; this.configureService(options.serviceName); // Using build-in method to ensure user-given URL is correct ex. trimming slashes if (options.serviceUrl) { this.setServiceUrl(options.serviceUrl); } else { this.setServiceUrl(WatsonxBaseService.DEFAULT_SERVICE_URL); } if (typeof options.caCert !== 'string') { if ((_f = (_e = options.caCert) === null || _e === void 0 ? void 0 : _e.service) === null || _f === void 0 ? void 0 : _f.path) { const certFile = readFileSync(options.caCert.service.path); this.httpsAgentMap.service = new Agent({ ca: certFile, }); } if ((_h = (_g = options.caCert) === null || _g === void 0 ? void 0 : _g.dataplatform) === null || _h === void 0 ? void 0 : _h.path) { const certFile = readFileSync(options.caCert.dataplatform.path); this.httpsAgentMap.dataplatform = new Agent({ ca: certFile, }); } } if (!this.baseOptions.serviceUrl) throw new Error('Something went wrong with setting up serviceUrl'); // Read platformUrl from environment variables (_j = options.platformUrl) !== null && _j !== void 0 ? _j : (options.platformUrl = readExternalSources(options.serviceName).platformUrl); // Set platformUrl depending on user given urls if (options.platformUrl) { this.wxServiceUrl = options.platformUrl.concat('/wx'); this.serviceUrl = options.platformUrl; } else if (Object.keys(WatsonxBaseService.PLATFORM_URLS_MAP).includes(this.baseOptions.serviceUrl)) { const platformUrl = WatsonxBaseService.PLATFORM_URLS_MAP[this.baseOptions.serviceUrl]; this.wxServiceUrl = platformUrl.concat('/wx'); this.serviceUrl = platformUrl; } else { this.wxServiceUrl = this.baseOptions.serviceUrl.concat('/wx'); this.serviceUrl = this.baseOptions.serviceUrl; } } /** * Resolves projectId and spaceId with fallback to instance values. * * This method implements a priority-based resolution strategy: * * 1. If both instance values (this.projectId/this.spaceId) AND parameter values exist, parameter * values take absolute precedence and instance values are ignored * 2. Otherwise, parameter values are used if provided, falling back to instance values * * This ensures that explicitly passed parameters always override instance configuration when both * are present, preventing unintended mixing of project and space contexts. * * @private * @param {Object} params - Object containing optional projectId and spaceId * @param {string} [params.projectId] - The project ID to use for the request * @param {string} [params.spaceId] - The space ID to use for the request * @returns {Object} Resolved projectId and spaceId values * @returns {string | undefined} Return.projectId - The resolved project ID (from params or * instance) * @returns {string | undefined} Return.spaceId - The resolved space ID (from params or instance) */ resolveContextId(params) { if (params.projectId !== undefined || params.spaceId !== undefined) return { projectId: params.projectId, spaceId: params.spaceId, }; return { projectId: this.projectId, spaceId: this.spaceId, }; } } /** @ignore */ WatsonxBaseService.DEFAULT_SERVICE_URL = 'https://us-south.ml.cloud.ibm.com'; /** @ignore */ WatsonxBaseService.DEFAULT_SERVICE_NAME = 'watsonx_ai'; WatsonxBaseService.PLATFORM_URLS_MAP = PLATFORM_URL_MAPPINGS; /** * APIBaseService class extends WatsonxBaseService and provides common API request functionalities. * * @category APIBaseService */ export class APIBaseService extends WatsonxBaseService { /** * Forms container ID headers based on project ID or space ID. * * This method creates the appropriate IBM-specific headers for identifying the container (project * or space) that the API request should operate within. It prioritizes parameters passed in the * request over instance-level defaults. * * @param {ContextIdentifiers} [params={}] - Container identifiers (projectId or spaceId). Default * is `{}` * @returns {{ 'X-IBM-PROJECT-ID': string } | { 'X-IBM-SPACE-ID': string } | {}} An object * containing either the project ID header, space ID header, or an empty object if neither is * provided * @protected */ _formContainerIdHeaders(params = {}, requireContainerId = false) { const { projectId, spaceId } = this.resolveContextId(params); if (requireContainerId) validateRequiredOneOf({ projectId, spaceId }, ['projectId', 'spaceId']); return Object.assign(Object.assign({}, (projectId ? { 'X-IBM-PROJECT-ID': projectId, } : {})), (spaceId ? { 'X-IBM-SPACE-ID': spaceId, } : {})); } /** * Appends additional data to request headers. * * This utility method merges override headers with existing headers in the parameters object, * ensuring that custom headers are properly combined without losing existing header data. * * @template T - The type of parameters, constrained to request parameter types with container * identifiers * @param {T} params - The request parameters containing existing headers * @param {Record<string, any>} overrides - Additional headers to merge into the request * @returns {T} A new parameters object with merged headers * @protected */ appendDataToHeaders(params, overrides) { return Object.assign(Object.assign({}, params), { headers: Object.assign(Object.assign({}, params.headers), overrides) }); } /** * Performs a POST request to the specified URL. * * @template T * @param {PostParameters} params - The parameters for the POST request. * @param {string} params.url - The parameters for the POST request. * @param {Record<string, any>} [params.body] - Body parameters to be passed to an endpoint * @param {Record<string, any>} [params.query] - Query parameters to be passed with url. * @param {Record<string, any>} [params.path] - Path parameters to be used to create url. * @param {OutgoingHttpHeaders} [params.headers] - Custom request headers. * @param {AbortSignal} [params.signal] - Signal from AbortController * @returns {Promise<Response<T>>} - A promise that resolves to the response from the POST * request. */ _post(params) { return __awaiter(this, void 0, void 0, function* () { if (!params) throw new Error('Input is required'); const { url, signal = null, path, body = {}, query = {}, headers = {} } = params; const qs = Object.assign({ 'version': this.version }, query); const sdkHeaders = getSdkHeaders(); const parameters = { options: { url, method: 'POST', body, qs, path, }, defaultOptions: Object.assign(Object.assign({}, this.baseOptions), { headers: Object.assign(Object.assign(Object.assign({}, sdkHeaders), { 'Accept': 'application/json', 'Content-Type': 'application/json' }), headers), axiosOptions: { signal, } }), }; return this.createRequest(parameters); }); } /** * Performs a GET request to the specified URL. * * @template T * @param {GetParameters} params - The parameters for the GET request. * @param {string} [params.url] - The parameters for the GET request. * @param {Record<string, any>} [params.query] - Query parameters to be passed with url. * @param {Record<string, any>} [params.path] - Path parameters to be used to create url. * @param {OutgoingHttpHeaders} [params.headers] - Custom request headers. * @param {AbortSignal} [params.signal] - Signal from AbortController * @returns {Promise<Response<T>>} - A promise that resolves to the response from the GET request. */ _get(params) { return __awaiter(this, void 0, void 0, function* () { if (!params) throw new Error('Input is required'); const { url, signal = null, query = {}, path, headers = {} } = params; const qs = Object.assign({ 'version': this.version }, query); const sdkHeaders = getSdkHeaders(); const parameters = { options: { url, method: 'GET', qs, path, }, defaultOptions: Object.assign(Object.assign({}, this.baseOptions), { headers: Object.assign(Object.assign(Object.assign({}, sdkHeaders), { 'Accept': 'application/json' }), headers), axiosOptions: { signal, } }), }; return this.createRequest(parameters); }); } /** * Performs a DELETE request to the specified URL. * * @template T * @param {DeleteParameters} params - The parameters for the DELETE request. * @param {string} params.url - The parameters for the DELETE request. * @param {Record<string, any>} [params.body] - Body parameters to be passed to an endpoint * @param {Record<string, any>} [params.query] - Query parameters to be passed with url. * @param {Record<string, any>} [params.path] - Path parameters to be used to create url. * @param {OutgoingHttpHeaders} [params.headers] - Custom request headers. * @param {AbortSignal} [params.signal] - Signal from AbortController * @returns {Promise<Response<T>>} - A promise that resolves to the response from the DELETE * request. */ _delete(params) { return __awaiter(this, void 0, void 0, function* () { if (!params) throw new Error('Input is required'); const { url, signal = null, path, body, query = {}, headers = {} } = params; const qs = Object.assign({ 'version': this.version }, query); const sdkHeaders = getSdkHeaders(); const deleteHeaders = body ? { 'Content-Type': 'application/json' } : {}; const parameters = { options: { url, method: 'DELETE', qs, body, path, }, defaultOptions: Object.assign(Object.assign({}, this.baseOptions), { headers: Object.assign(Object.assign(Object.assign({}, sdkHeaders), deleteHeaders), headers), axiosOptions: { signal, } }), }; return this.createRequest(parameters); }); } /** * Performs a PUT request to the specified URL. * * @template T * @param {PutParameters} params - The parameters for the PUT request. * @param {string} params.url - The parameters for the PUT request. * @param {Record<string, any>} [params.body] - Body parameters to be passed to an endpoint * @param {Record<string, any>} [params.query] - Query parameters to be passed with url. * @param {Record<string, any>} [params.path] - Path parameters to be used to create url. * @param {OutgoingHttpHeaders} [params.headers] - Custom request headers. * @param {AbortSignal} [params.signal] - Signal from AbortController * @returns {Promise<Response<T>>} - A promise that resolves to the response from the PUT request. */ _put(params) { return __awaiter(this, void 0, void 0, function* () { if (!params) throw new Error('Input is required'); const { url, signal = null, path, body = {}, query = {}, headers = {} } = params; const qs = Object.assign({ 'version': this.version }, query); const sdkHeaders = getSdkHeaders(); const parameters = { options: { url, method: 'PUT', body, qs, path, }, defaultOptions: Object.assign(Object.assign({}, this.baseOptions), { headers: Object.assign(Object.assign(Object.assign({}, sdkHeaders), { 'Accept': 'application/json', 'Content-Type': 'application/json' }), headers), axiosOptions: { signal, } }), }; return this.createRequest(parameters); }); } /** * Performs a POST request to the specified URL and returns a stream. * * @template T * @param {CreateStreamParameters} params - The parameters for the POST request. * @param {string} params.url - The parameters for the POST request. * @param {Record<string, any>} [params.body] - Body parameters to be passed to an endpoint * @param {Record<string, any>} [params.query] - Query parameters to be passed with url. * @param {Record<string, any>} [params.path] - Path parameters to be used to create url. * @param {Record<string, any>} [params.returnObject] - Flag that indicates return type. Set * 'true' to return objects, 'false' to return SSE * @param {OutgoingHttpHeaders} [params.headers] - Custom request headers. * @param {AbortSignal} [params.signal] - Signal from AbortController * @returns {Promise<Stream<T | string>>} - A promise that resolves to a stream from the POST * request. */ _postStream(params) { return __awaiter(this, void 0, void 0, function* () { if (!params) throw new Error('Input is required'); const { url, returnObject = true, signal = null, body = {}, query = {}, headers = {} } = params; const qs = Object.assign({ 'version': this.version }, query); const sdkHeaders = getSdkHeaders(); const parameters = { options: { url, method: 'POST', body, qs, responseType: 'stream', adapter: 'fetch', }, defaultOptions: Object.assign(Object.assign({}, this.baseOptions), { headers: Object.assign(Object.assign(Object.assign({}, sdkHeaders), { 'Accept': 'text/event-stream', 'Connection': 'keep-alive', 'Content-Type': 'application/json' }), headers), axiosOptions: { signal, } }), }; const apiResponse = yield this.createRequest(parameters); const stream = returnObject ? transformStreamToObjectStream(apiResponse) : transformStreamToStringStream(apiResponse); return stream; }); } } //# sourceMappingURL=base.mjs.map