1 | ;
|
2 | /*
|
3 | * Copyright (c) 2018, salesforce.com, inc.
|
4 | * All rights reserved.
|
5 | * SPDX-License-Identifier: BSD-3-Clause
|
6 | * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
7 | */
|
8 | Object.defineProperty(exports, "__esModule", { value: true });
|
9 | const kit_1 = require("@salesforce/kit");
|
10 | const ts_types_1 = require("@salesforce/ts-types");
|
11 | const jsforce_1 = require("jsforce");
|
12 | const jsforce_2 = require("jsforce");
|
13 | const configAggregator_1 = require("./config/configAggregator");
|
14 | const logger_1 = require("./logger");
|
15 | const sfdxError_1 = require("./sfdxError");
|
16 | const sfdc_1 = require("./util/sfdc");
|
17 | /**
|
18 | * The 'async' in our request override replaces the jsforce promise with the node promise, then returns it back to
|
19 | * jsforce which expects .thenCall. Add .thenCall to the node promise to prevent breakage.
|
20 | */
|
21 | // @ts-ignore
|
22 | Promise.prototype.thenCall = jsforce_2.Promise.prototype.thenCall;
|
23 | const clientId = `sfdx toolbelt:${process.env.SFDX_SET_CLIENT_IDS || ''}`;
|
24 | exports.SFDX_HTTP_HEADERS = {
|
25 | 'content-type': 'application/json',
|
26 | 'user-agent': clientId
|
27 | };
|
28 | /**
|
29 | * Handles connections and requests to Salesforce Orgs.
|
30 | *
|
31 | * ```
|
32 | * // Uses latest API version
|
33 | * const connection = await Connection.create({
|
34 | * authInfo: await AuthInfo.create({ username: 'myAdminUsername' })
|
35 | * });
|
36 | * connection.query('SELECT Name from Account');
|
37 | *
|
38 | * // Use different API version
|
39 | * connection.setApiVersion("42.0");
|
40 | * connection.query('SELECT Name from Account');
|
41 | * ```
|
42 | */
|
43 | class Connection extends jsforce_1.Connection {
|
44 | /**
|
45 | * Creates an instance of a Connection. Performs additional async initializations.
|
46 | * @param options Constructor options.
|
47 | */
|
48 | static async create(options) {
|
49 | const _aggregator = options.configAggregator || (await configAggregator_1.ConfigAggregator.create());
|
50 | const versionFromConfig = ts_types_1.asString(_aggregator.getInfo('apiVersion').value);
|
51 | const baseOptions = {
|
52 | // Set the API version obtained from the config aggregator.
|
53 | // Will use jsforce default if undefined.
|
54 | version: versionFromConfig,
|
55 | callOptions: {
|
56 | client: clientId
|
57 | }
|
58 | };
|
59 | // Get connection options from auth info and create a new jsForce connection
|
60 | options.connectionOptions = Object.assign(baseOptions, options.authInfo.getConnectionOptions());
|
61 | const conn = new this(options);
|
62 | await conn.init();
|
63 | if (!versionFromConfig) {
|
64 | await conn.useLatestApiVersion();
|
65 | }
|
66 | return conn;
|
67 | }
|
68 | /**
|
69 | * Constructor
|
70 | * **Do not directly construct instances of this class -- use {@link Connection.create} instead.**
|
71 | * @param options The options for the class instance.
|
72 | * @ignore
|
73 | */
|
74 | constructor(options) {
|
75 | super(options.connectionOptions || {});
|
76 | this.tooling.autoFetchQuery = Connection.prototype.autoFetchQuery;
|
77 | this.options = options;
|
78 | }
|
79 | /**
|
80 | * Async initializer.
|
81 | */
|
82 | async init() {
|
83 | this.logger = this._logger = this.tooling._logger = await logger_1.Logger.child('connection');
|
84 | }
|
85 | /**
|
86 | * Send REST API request with given HTTP request info, with connected session information
|
87 | * and SFDX headers.
|
88 | *
|
89 | * @param request HTTP request object or URL to GET request.
|
90 | * @param options HTTP API request options.
|
91 | */
|
92 | async request(request, options) {
|
93 | const _request = ts_types_1.isString(request) ? { method: 'GET', url: request } : request;
|
94 | _request.headers = Object.assign({}, exports.SFDX_HTTP_HEADERS, _request.headers);
|
95 | this.logger.debug(`request: ${JSON.stringify(_request)}`);
|
96 | // The "as" is a workaround for the jsforce typings.
|
97 | return super.request(_request, options);
|
98 | }
|
99 | /**
|
100 | * Send REST API request with given HTTP request info, with connected session information
|
101 | * and SFDX headers. This method returns a raw http response which includes a response body and statusCode.
|
102 | *
|
103 | * @param request HTTP request object or URL to GET request.
|
104 | */
|
105 | async requestRaw(request) {
|
106 | const _headers = this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {};
|
107 | kit_1.merge(_headers, exports.SFDX_HTTP_HEADERS, request.headers);
|
108 | return this._transport.httpRequest({
|
109 | method: request.method,
|
110 | url: request.url,
|
111 | headers: _headers,
|
112 | body: request.body
|
113 | });
|
114 | }
|
115 | /**
|
116 | * The Force API base url for the instance.
|
117 | */
|
118 | baseUrl() {
|
119 | // essentially the same as pathJoin(super.instanceUrl, 'services', 'data', `v${super.version}`);
|
120 | return super._baseUrl();
|
121 | }
|
122 | /**
|
123 | * Retrieves the highest api version that is supported by the target server instance.
|
124 | */
|
125 | async retrieveMaxApiVersion() {
|
126 | const versions = (await this.request(`${this.instanceUrl}/services/data`));
|
127 | this.logger.debug(`response for org versions: ${versions}`);
|
128 | const max = ts_types_1.ensure(kit_1.maxBy(versions, (version) => version.version));
|
129 | return max.version;
|
130 | }
|
131 | /**
|
132 | * Use the latest API version available on `this.instanceUrl`.
|
133 | */
|
134 | async useLatestApiVersion() {
|
135 | try {
|
136 | this.setApiVersion(await this.retrieveMaxApiVersion());
|
137 | }
|
138 | catch (err) {
|
139 | // Don't fail if we can't use the latest, just use the default
|
140 | this.logger.warn('Failed to set the latest API version:', err);
|
141 | }
|
142 | }
|
143 | /**
|
144 | * Get the API version used for all connection requests.
|
145 | */
|
146 | getApiVersion() {
|
147 | return this.version;
|
148 | }
|
149 | /**
|
150 | * Set the API version for all connection requests.
|
151 | *
|
152 | * **Throws** *{@link SfdxError}{ name: 'IncorrectAPIVersion' }* Incorrect API version.
|
153 | * @param version The API version.
|
154 | */
|
155 | setApiVersion(version) {
|
156 | if (!sfdc_1.sfdc.validateApiVersion(version)) {
|
157 | throw new sfdxError_1.SfdxError(`Invalid API version ${version}. Expecting format "[1-9][0-9].0", i.e. 42.0`, 'IncorrectAPIVersion');
|
158 | }
|
159 | this.version = version;
|
160 | }
|
161 | /**
|
162 | * Getter for the AuthInfo.
|
163 | */
|
164 | getAuthInfoFields() {
|
165 | return this.options.authInfo.getFields();
|
166 | }
|
167 | /**
|
168 | * Getter for the auth fields.
|
169 | */
|
170 | getConnectionOptions() {
|
171 | return this.options.authInfo.getConnectionOptions();
|
172 | }
|
173 | /**
|
174 | * Getter for the username of the Salesforce Org.
|
175 | */
|
176 | getUsername() {
|
177 | return this.getAuthInfoFields().username;
|
178 | }
|
179 | /**
|
180 | * Returns true if this connection is using access token auth.
|
181 | */
|
182 | isUsingAccessToken() {
|
183 | return this.options.authInfo.isUsingAccessToken();
|
184 | }
|
185 | /**
|
186 | * Normalize a Salesforce url to include a instance information.
|
187 | * @param url Partial url.
|
188 | */
|
189 | normalizeUrl(url) {
|
190 | return this._normalizeUrl(url);
|
191 | }
|
192 | /**
|
193 | * Executes a query and auto-fetches (i.e., "queryMore") all results. This is especially
|
194 | * useful with large query result sizes, such as over 2000 records. The default maximum
|
195 | * fetch size is 10,000 records. Modify this via the options argument.
|
196 | * @param soql The SOQL string.
|
197 | * @param options The query options. NOTE: the autoFetch option will always be true.
|
198 | */
|
199 | async autoFetchQuery(soql, options = {}) {
|
200 | const _options = Object.assign(options, {
|
201 | autoFetch: true
|
202 | });
|
203 | const records = [];
|
204 | this._logger.debug(`Auto-fetching query: ${soql}`);
|
205 | return new Promise((resolve, reject) => this.query(soql, _options)
|
206 | .on('record', rec => records.push(rec))
|
207 | .on('error', err => reject(err))
|
208 | .on('end', () => resolve({
|
209 | done: true,
|
210 | totalSize: records.length,
|
211 | records
|
212 | })));
|
213 | }
|
214 | }
|
215 | exports.Connection = Connection;
|
216 | //# sourceMappingURL=connection.js.map |
\ | No newline at end of file |