UNPKG

@salesforce/core

Version:

Core libraries to interact with SFDX projects, orgs, and APIs.

235 lines 9.09 kB
"use strict"; /* * Copyright (c) 2020, salesforce.com, inc. * All rights reserved. * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Connection = exports.SFDX_HTTP_HEADERS = void 0; const kit_1 = require("@salesforce/kit"); const ts_types_1 = require("@salesforce/ts-types"); const jsforce_1 = require("jsforce"); const configAggregator_1 = require("./config/configAggregator"); const logger_1 = require("./logger"); const sfdxError_1 = require("./sfdxError"); const sfdc_1 = require("./util/sfdc"); /** * The 'async' in our request override replaces the jsforce promise with the node promise, then returns it back to * jsforce which expects .thenCall. Add .thenCall to the node promise to prevent breakage. */ // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore Promise.prototype.thenCall = jsforce_1.Promise.prototype.thenCall; const clientId = `sfdx toolbelt:${process.env.SFDX_SET_CLIENT_IDS || ''}`; exports.SFDX_HTTP_HEADERS = { 'content-type': 'application/json', 'user-agent': clientId, }; /** * Handles connections and requests to Salesforce Orgs. * * ``` * // Uses latest API version * const connection = await Connection.create({ * authInfo: await AuthInfo.create({ username: 'myAdminUsername' }) * }); * connection.query('SELECT Name from Account'); * * // Use different API version * connection.setApiVersion("42.0"); * connection.query('SELECT Name from Account'); * ``` */ class Connection extends jsforce_1.Connection { /** * Constructor * **Do not directly construct instances of this class -- use {@link Connection.create} instead.** * * @param options The options for the class instance. * @ignore */ constructor(options) { super(options.connectionOptions || {}); // eslint-disable-next-line @typescript-eslint/unbound-method this.tooling.autoFetchQuery = Connection.prototype.autoFetchQuery; this.options = options; } /** * Creates an instance of a Connection. Performs additional async initializations. * * @param options Constructor options. */ static async create(options) { const configAggregator = options.configAggregator || (await configAggregator_1.ConfigAggregator.create()); const versionFromConfig = ts_types_1.asString(configAggregator.getInfo('apiVersion').value); const baseOptions = { // Set the API version obtained from the config aggregator. // Will use jsforce default if undefined. version: versionFromConfig, callOptions: { client: clientId, }, }; // Get connection options from auth info and create a new jsForce connection options.connectionOptions = Object.assign(baseOptions, options.authInfo.getConnectionOptions()); const conn = new this(options); await conn.init(); if (!versionFromConfig) { await conn.useLatestApiVersion(); } return conn; } /** * Async initializer. */ async init() { // eslint-disable-next-line no-underscore-dangle this.logger = this.tooling._logger = await logger_1.Logger.child('connection'); } /** * Send REST API request with given HTTP request info, with connected session information * and SFDX headers. * * @param request HTTP request object or URL to GET request. * @param options HTTP API request options. */ async request(request, options) { const requestInfo = ts_types_1.isString(request) ? { method: 'GET', url: request } : request; requestInfo.headers = Object.assign({}, exports.SFDX_HTTP_HEADERS, requestInfo.headers); this.logger.debug(`request: ${JSON.stringify(requestInfo)}`); // The "as" is a workaround for the jsforce typings. return super.request(requestInfo, options); } /** * Send REST API request with given HTTP request info, with connected session information * and SFDX headers. This method returns a raw http response which includes a response body and statusCode. * * @param request HTTP request object or URL to GET request. */ async requestRaw(request) { const headers = this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}; kit_1.merge(headers, exports.SFDX_HTTP_HEADERS, request.headers); return this.transport.httpRequest({ method: request.method, url: request.url, headers, body: request.body, }); } /** * The Force API base url for the instance. */ baseUrl() { // essentially the same as pathJoin(super.instanceUrl, 'services', 'data', `v${super.version}`); return super._baseUrl(); } /** * Retrieves the highest api version that is supported by the target server instance. */ async retrieveMaxApiVersion() { const versions = (await this.request(`${this.instanceUrl}/services/data`)); this.logger.debug(`response for org versions: ${versions}`); const max = ts_types_1.ensure(kit_1.maxBy(versions, (version) => version.version)); return max.version; } /** * Use the latest API version available on `this.instanceUrl`. */ async useLatestApiVersion() { try { this.setApiVersion(await this.retrieveMaxApiVersion()); } catch (err) { // Don't fail if we can't use the latest, just use the default this.logger.warn('Failed to set the latest API version:', err); } } /** * Get the API version used for all connection requests. */ getApiVersion() { return this.version; } /** * Set the API version for all connection requests. * * **Throws** *{@link SfdxError}{ name: 'IncorrectAPIVersion' }* Incorrect API version. * * @param version The API version. */ setApiVersion(version) { if (!sfdc_1.sfdc.validateApiVersion(version)) { throw new sfdxError_1.SfdxError(`Invalid API version ${version}. Expecting format "[1-9][0-9].0", i.e. 42.0`, 'IncorrectAPIVersion'); } this.version = version; } /** * Getter for the AuthInfo. */ getAuthInfoFields() { return this.options.authInfo.getFields(); } /** * Getter for the auth fields. */ getConnectionOptions() { return this.options.authInfo.getConnectionOptions(); } /** * Getter for the username of the Salesforce Org. */ getUsername() { return this.getAuthInfoFields().username; } /** * Returns true if this connection is using access token auth. */ isUsingAccessToken() { return this.options.authInfo.isUsingAccessToken(); } /** * Normalize a Salesforce url to include a instance information. * * @param url Partial url. */ normalizeUrl(url) { return this._normalizeUrl(url); } /** * Executes a query and auto-fetches (i.e., "queryMore") all results. This is especially * useful with large query result sizes, such as over 2000 records. The default maximum * fetch size is 10,000 records. Modify this via the options argument. * * @param soql The SOQL string. * @param executeOptions The query options. NOTE: the autoFetch option will always be true. */ async autoFetchQuery(soql, executeOptions = {}) { const config = await configAggregator_1.ConfigAggregator.create(); // take the limit from the calling function, then the config, then default 10,000 const maxFetch = config.getInfo('maxQueryLimit').value || executeOptions.maxFetch || 10000; const options = Object.assign(executeOptions, { autoFetch: true, maxFetch, }); const records = []; return new Promise((resolve, reject) => { const query = this.query(soql, options) .on('record', (rec) => records.push(rec)) .on('error', (err) => reject(err)) .on('end', () => { const totalSize = ts_types_1.getNumber(query, 'totalSize') || 0; if (totalSize > records.length) { process.emitWarning(`The query result is missing ${totalSize - records.length} records due to a ${maxFetch} record limit. Increase the number of records returned by setting the config value "maxQueryLimit" or the environment variable "SFDX_MAX_QUERY_LIMIT" to ${totalSize} or greater than ${maxFetch}.`); } resolve({ done: true, totalSize, records, }); }); }); } } exports.Connection = Connection; //# sourceMappingURL=connection.js.map