@jsforce/jsforce-node 3.1.0 → 3.2.1

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 CHANGED
@@ -24,12 +24,22 @@ Supported Salesforce APIs are the following:
24
24
 
25
25
  ## Documentation
26
26
 
27
- See documentation in <http://jsforce.github.io/> .
27
+ See documentation in https://jsforce.github.io/
28
+
29
+ v3 API reference:
30
+ https://jsforce.github.io/jsforce/
31
+
32
+ v1 API reference:
33
+ https://jsforce.github.io/jsforce/doc/
28
34
 
29
35
  ## Releases
30
36
 
31
37
  See [Releases](https://github.com/jsforce/jsforce/releases).
32
38
 
39
+ ## Node-specific release
40
+
41
+ See [jsforce-node](./JSFORCE-NODE.md).
42
+
33
43
  ## License
34
44
 
35
45
  See [license](LICENSE) (MIT License).
@@ -45,6 +55,7 @@ If you have any questions first file it on [issues](https://github.com/jsforce/j
45
55
  ## How to build/run tests:
46
56
  See [DEVELOPING.md](./DEVELOPING.md)
47
57
 
58
+
48
59
  ## Contributions
49
60
 
50
61
  Your contributions are welcome: both by reporting issues on [GitHub issues](https://github.com/jsforce/jsforce/issues) or pull-requesting patches.
package/lib/VERSION.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const _default: "2.0.0-beta.8";
1
+ declare const _default: "3.2.1";
2
2
  export default _default;
package/lib/VERSION.js CHANGED
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = '2.0.0-beta.8';
3
+ exports.default = '3.2.1';
package/lib/api/bulk.d.ts CHANGED
@@ -17,7 +17,7 @@ export type BulkOptions = {
17
17
  concurrencyMode?: 'Serial' | 'Parallel';
18
18
  assignmentRuleId?: string;
19
19
  };
20
- export type JobState = 'Open' | 'Closed' | 'Aborted' | 'Failed' | 'Unknown';
20
+ export type JobState = 'Open' | 'Closed' | 'Aborted' | 'Failed' | 'Unknown' | 'NotProcessed';
21
21
  export type JobInfo = {
22
22
  id: string;
23
23
  object: string;
@@ -42,6 +42,7 @@ export type BulkQueryBatchResult = Array<{
42
42
  export type BulkIngestBatchResult = Array<{
43
43
  id: string | null;
44
44
  success: boolean;
45
+ created: boolean;
45
46
  errors: string[];
46
47
  }>;
47
48
  export type BatchResult<Opr extends BulkOperation> = Opr extends 'query' | 'queryAll' ? BulkQueryBatchResult : BulkIngestBatchResult;
package/lib/api/bulk.js CHANGED
@@ -472,6 +472,9 @@ class Batch extends stream_1.Writable {
472
472
  else if (res.state === 'Completed') {
473
473
  this.retrieve();
474
474
  }
475
+ else if (res.state === 'NotProcessed') {
476
+ this.emit('error', new Error('Job has been aborted'));
477
+ }
475
478
  else {
476
479
  this.emit('inProgress', res);
477
480
  setTimeout(poll, interval);
@@ -508,6 +511,7 @@ class Batch extends stream_1.Writable {
508
511
  results = res.map((ret) => ({
509
512
  id: ret.Id || null,
510
513
  success: ret.Success === 'true',
514
+ created: ret.Created === 'true',
511
515
  errors: ret.Error ? [ret.Error] : [],
512
516
  }));
513
517
  }
@@ -558,7 +562,7 @@ class BulkApi extends http_api_1.default {
558
562
  }
559
563
  isSessionExpired(response) {
560
564
  return (response.statusCode === 400 &&
561
- /<exceptionCode>InvalidSessionId<\/exceptionCode>/.test(response.body));
565
+ response.body.includes('<exceptionCode>InvalidSessionId</exceptionCode>'));
562
566
  }
563
567
  hasErrorInResponseBody(body) {
564
568
  return !!body.error;
@@ -47,7 +47,7 @@ export type IngestJobV2FailedResults<S extends Schema> = Array<{
47
47
  sf__Error: string;
48
48
  sf__Id: string;
49
49
  } & S>;
50
- export type IngestJobV2UnprocessedRecords<S extends Schema> = Array<S> | string;
50
+ export type IngestJobV2UnprocessedRecords<S extends Schema> = S[] | string;
51
51
  export type IngestJobV2Results<S extends Schema> = {
52
52
  successfulResults: IngestJobV2SuccessfulResults<S>;
53
53
  failedResults: IngestJobV2FailedResults<S>;
@@ -137,7 +137,7 @@ export declare class BulkV2<S extends Schema> {
137
137
  * Default timeout: 10000ms
138
138
  *
139
139
  * @param soql SOQL query
140
- * @param BulkV2PollingOptions options object
140
+ * @param options
141
141
  *
142
142
  * @returns {RecordStream} - Record stream, convertible to a CSV data stream
143
143
  */
@@ -156,8 +156,7 @@ export declare class QueryJobV2<S extends Schema> extends EventEmitter {
156
156
  private error;
157
157
  private jobInfo?;
158
158
  private locator?;
159
- constructor(conn: Connection<S>, options: ExistingQueryJobV2Options);
160
- constructor(conn: Connection<S>, options: CreateQueryJobV2Options);
159
+ constructor(conn: Connection<S>, options: ExistingQueryJobV2Options | CreateQueryJobV2Options);
161
160
  /**
162
161
  * Get the query job ID.
163
162
  *
@@ -228,8 +227,7 @@ export declare class IngestJobV2<S extends Schema> extends EventEmitter {
228
227
  /**
229
228
  *
230
229
  */
231
- constructor(conn: Connection<S>, options: ExistingIngestJobOptions);
232
- constructor(conn: Connection<S>, options: CreateIngestJobV2Options);
230
+ constructor(conn: Connection<S>, options: CreateIngestJobV2Options | ExistingIngestJobOptions);
233
231
  /**
234
232
  * Get the query job ID.
235
233
  *
package/lib/api/bulk2.js CHANGED
@@ -30,7 +30,8 @@ class BulkApiV2 extends http_api_1.default {
30
30
  'errorCode' in body[0]);
31
31
  }
32
32
  isSessionExpired(response) {
33
- return (response.statusCode === 401 && /INVALID_SESSION_ID/.test(response.body));
33
+ return (response.statusCode === 401 &&
34
+ response.body.includes('INVALID_SESSION_ID'));
34
35
  }
35
36
  parseError(body) {
36
37
  return {
@@ -110,20 +111,18 @@ class BulkV2 {
110
111
  options.pollTimeout = this.pollTimeout;
111
112
  if (!options.pollInterval)
112
113
  options.pollInterval = this.pollInterval;
113
- const job = this.createJob({
114
- object: options.object,
115
- operation: options.operation,
116
- });
114
+ const { pollInterval, pollTimeout, input, ...createJobOpts } = options;
115
+ const job = this.createJob(createJobOpts);
117
116
  try {
118
117
  await job.open();
119
- await job.uploadData(options.input);
118
+ await job.uploadData(input);
120
119
  await job.close();
121
- await job.poll(options.pollInterval, options.pollTimeout);
120
+ await job.poll(pollInterval, pollTimeout);
122
121
  return await job.getAllResults();
123
122
  }
124
123
  catch (error) {
125
124
  const err = error;
126
- this.logger.error(`bulk load failed due to: ${err}`);
125
+ this.logger.error(`bulk load failed due to: ${err.message}`);
127
126
  if (err.name !== 'JobPollingTimeoutError') {
128
127
  // fires off one last attempt to clean up and ignores the result | error
129
128
  job.delete().catch((ignored) => ignored);
@@ -137,7 +136,7 @@ class BulkV2 {
137
136
  * Default timeout: 10000ms
138
137
  *
139
138
  * @param soql SOQL query
140
- * @param BulkV2PollingOptions options object
139
+ * @param options
141
140
  *
142
141
  * @returns {RecordStream} - Record stream, convertible to a CSV data stream
143
142
  */
@@ -163,7 +162,7 @@ class BulkV2 {
163
162
  }
164
163
  catch (error) {
165
164
  const err = error;
166
- this.logger.error(`bulk query failed due to: ${err}`);
165
+ this.logger.error(`bulk query failed due to: ${err.message}`);
167
166
  if (err.name !== 'JobPollingTimeoutError') {
168
167
  // fires off one last attempt to clean up and ignores the result | error
169
168
  queryJob.delete().catch((ignored) => ignored);
@@ -280,7 +279,7 @@ class QueryJobV2 extends events_1.EventEmitter {
280
279
  const jobId = this.id;
281
280
  const startTime = Date.now();
282
281
  const endTime = startTime + timeout;
283
- this.logger.debug(`Start polling for job status`);
282
+ this.logger.debug('Start polling for job status');
284
283
  this.logger.debug(`Polling options: timeout:${timeout}ms | interval: ${interval}ms.`);
285
284
  if (timeout === 0) {
286
285
  throw new JobPollingTimeoutError(`Skipping polling because of timeout = 0ms. Job Id = ${jobId}`, jobId);
@@ -401,6 +400,9 @@ class IngestJobV2 extends events_1.EventEmitter {
401
400
  bulkJobUnprocessedRecords;
402
401
  error;
403
402
  jobInfo;
403
+ /**
404
+ *
405
+ */
404
406
  constructor(conn, options) {
405
407
  super();
406
408
  this.connection = conn;
@@ -540,7 +542,7 @@ class IngestJobV2 extends events_1.EventEmitter {
540
542
  if (timeout === 0) {
541
543
  throw new JobPollingTimeoutError(`Skipping polling because of timeout = 0ms. Job Id = ${jobId}`, jobId);
542
544
  }
543
- this.logger.debug(`Start polling for job status`);
545
+ this.logger.debug('Start polling for job status');
544
546
  this.logger.debug(`Polling options: timeout:${timeout}ms | interval: ${interval}ms.`);
545
547
  while (endTime > Date.now()) {
546
548
  try {
@@ -173,13 +173,13 @@ class Chatter {
173
173
  * @private
174
174
  */
175
175
  _normalizeUrl(url) {
176
- if (url.indexOf('/chatter/') === 0 || url.indexOf('/connect/') === 0) {
176
+ if (url.startsWith('/chatter/') || url.startsWith('/connect/')) {
177
177
  return '/services/data/v' + this._conn.version + url;
178
178
  }
179
179
  else if (/^\/v[\d]+\.[\d]+\//.test(url)) {
180
180
  return '/services/data' + url;
181
181
  }
182
- else if (url.indexOf('/services/') !== 0 && url[0] === '/') {
182
+ else if (!url.startsWith('/services/') && url.startsWith('/')) {
183
183
  return '/services/data/v' + this._conn.version + '/chatter' + url;
184
184
  }
185
185
  else {
@@ -17,7 +17,7 @@ export * from './metadata/schema';
17
17
  type MetadataType_<K extends keyof ApiSchemaTypes = keyof ApiSchemaTypes> = K extends keyof ApiSchemaTypes ? ApiSchemaTypes[K] extends Metadata ? K : never : never;
18
18
  export type MetadataType = MetadataType_;
19
19
  export type MetadataDefinition<T extends string, M extends Metadata = Metadata> = Metadata extends M ? T extends keyof ApiSchemaTypes & MetadataType ? ApiSchemaTypes[T] extends Metadata ? ApiSchemaTypes[T] : Metadata : Metadata : M;
20
- type DeepPartial<T> = T extends any[] ? DeepPartial<T[number]>[] : T extends object ? {
20
+ type DeepPartial<T> = T extends any[] ? Array<DeepPartial<T[number]>> : T extends object ? {
21
21
  [K in keyof T]?: DeepPartial<T[K]>;
22
22
  } : T;
23
23
  export type InputMetadataDefinition<T extends string, M extends Metadata = Metadata> = DeepPartial<MetadataDefinition<T, M>>;
@@ -59,9 +59,9 @@ export declare class MetadataApi<S extends Schema> {
59
59
  /**
60
60
  * Update one or more metadata components in the organization.
61
61
  */
62
- update<M extends Metadata = Metadata, T extends string = string, MD extends InputMetadataDefinition<T, M> = InputMetadataDefinition<T, M>>(type: T, metadata: Partial<MD>[]): Promise<SaveResult[]>;
62
+ update<M extends Metadata = Metadata, T extends string = string, MD extends InputMetadataDefinition<T, M> = InputMetadataDefinition<T, M>>(type: T, metadata: Array<Partial<MD>>): Promise<SaveResult[]>;
63
63
  update<M extends Metadata = Metadata, T extends string = string, MD extends InputMetadataDefinition<T, M> = InputMetadataDefinition<T, M>>(type: T, metadata: Partial<MD>): Promise<SaveResult>;
64
- update<M extends Metadata = Metadata, T extends string = string, MD extends InputMetadataDefinition<T, M> = InputMetadataDefinition<T, M>>(type: T, metadata: Partial<MD> | Partial<MD>[]): Promise<SaveResult | SaveResult[]>;
64
+ update<M extends Metadata = Metadata, T extends string = string, MD extends InputMetadataDefinition<T, M> = InputMetadataDefinition<T, M>>(type: T, metadata: Partial<MD> | Array<Partial<MD>>): Promise<SaveResult | SaveResult[]>;
65
65
  /**
66
66
  * Upsert one or more components in your organization's data.
67
67
  */
@@ -295,7 +295,7 @@ class AsyncResultLocator extends events_1.EventEmitter {
295
295
  async check() {
296
296
  const result = await this._promise;
297
297
  this._id = result.id;
298
- return await this._meta.checkStatus(result.id);
298
+ return this._meta.checkStatus(result.id);
299
299
  }
300
300
  /**
301
301
  * Polling until async call status becomes complete or error
package/lib/api/soap.d.ts CHANGED
@@ -15,15 +15,15 @@ export declare class SoapApi<S extends Schema> {
15
15
  /**
16
16
  * Converts a Lead into an Account, Contact, or (optionally) an Opportunity.
17
17
  */
18
- convertLead(leadConverts: Partial<LeadConvert>[]): Promise<LeadConvertResult[]>;
18
+ convertLead(leadConverts: Array<Partial<LeadConvert>>): Promise<LeadConvertResult[]>;
19
19
  convertLead(leadConvert: Partial<LeadConvert>): Promise<LeadConvertResult>;
20
- convertLead(leadConvert: Partial<LeadConvert> | Partial<LeadConvert>[]): Promise<LeadConvertResult | LeadConvertResult[]>;
20
+ convertLead(leadConvert: Partial<LeadConvert> | Array<Partial<LeadConvert>>): Promise<LeadConvertResult | LeadConvertResult[]>;
21
21
  /**
22
22
  * Merge up to three records into one
23
23
  */
24
- merge(mergeRequests: Partial<MergeRequest>[]): Promise<MergeResult[]>;
24
+ merge(mergeRequests: Array<Partial<MergeRequest>>): Promise<MergeResult[]>;
25
25
  merge(mergeRequest: Partial<MergeRequest>): Promise<MergeResult>;
26
- merge(mergeRequest: Partial<MergeRequest> | Partial<MergeRequest>[]): Promise<MergeResult | MergeResult[]>;
26
+ merge(mergeRequest: Partial<MergeRequest> | Array<Partial<MergeRequest>>): Promise<MergeResult | MergeResult[]>;
27
27
  /**
28
28
  * Delete records from the recycle bin immediately
29
29
  */
@@ -125,9 +125,7 @@ class Replay {
125
125
  }
126
126
  }
127
127
  else if (message.channel === this._channel &&
128
- message.data &&
129
- message.data.event &&
130
- message.data.event.replayId) {
128
+ message.data?.event?.replayId) {
131
129
  this._replay = message.data.event.replayId;
132
130
  }
133
131
  callback(message);
@@ -121,13 +121,13 @@ class Streaming extends events_1.EventEmitter {
121
121
  /* @private */
122
122
  _createClient(forChannelName, extensions) {
123
123
  // forChannelName is advisory, for an API workaround. It does not restrict or select the channel.
124
- const needsReplayFix = typeof forChannelName === 'string' && forChannelName.indexOf('/u/') === 0;
124
+ const needsReplayFix = typeof forChannelName === 'string' && forChannelName.startsWith('/u/');
125
125
  const endpointUrl = [
126
126
  this._conn.instanceUrl,
127
127
  // special endpoint "/cometd/replay/xx.x" is only available in 36.0.
128
128
  // See https://releasenotes.docs.salesforce.com/en-us/summer16/release-notes/rn_api_streaming_classic_replay.htm
129
129
  'cometd' +
130
- (needsReplayFix === true && this._conn.version === '36.0'
130
+ (needsReplayFix && this._conn.version === '36.0'
131
131
  ? '/replay'
132
132
  : ''),
133
133
  this._conn.version,
@@ -149,7 +149,7 @@ class Streaming extends events_1.EventEmitter {
149
149
  }
150
150
  /** @private **/
151
151
  _getFayeClient(channelName) {
152
- const isGeneric = channelName.indexOf('/u/') === 0;
152
+ const isGeneric = channelName.startsWith('/u/');
153
153
  const clientType = isGeneric ? 'generic' : 'pushTopic';
154
154
  if (!this._fayeClients[clientType]) {
155
155
  this._fayeClients[clientType] = this._createClient(channelName);
@@ -175,7 +175,7 @@ class Streaming extends events_1.EventEmitter {
175
175
  * Subscribe topic/channel
176
176
  */
177
177
  subscribe(name, listener) {
178
- const channelName = name.indexOf('/') === 0 ? name : '/topic/' + name;
178
+ const channelName = name.startsWith('/') ? name : '/topic/' + name;
179
179
  const fayeClient = this._getFayeClient(channelName);
180
180
  return fayeClient.subscribe(channelName, listener);
181
181
  }
@@ -183,7 +183,7 @@ class Streaming extends events_1.EventEmitter {
183
183
  * Unsubscribe topic
184
184
  */
185
185
  unsubscribe(name, subscription) {
186
- const channelName = name.indexOf('/') === 0 ? name : '/topic/' + name;
186
+ const channelName = name.startsWith('/') ? name : '/topic/' + name;
187
187
  const fayeClient = this._getFayeClient(channelName);
188
188
  fayeClient.unsubscribe(channelName, subscription);
189
189
  return this;
@@ -297,7 +297,7 @@ async function dumpSchema(schemas, outFile) {
297
297
  value = value['?'];
298
298
  }
299
299
  }
300
- if (typeof value === 'string' && value[0] === '?') {
300
+ if (typeof value === 'string' && value.startsWith('?')) {
301
301
  nillable = true;
302
302
  value = value.substring(1);
303
303
  }
@@ -83,7 +83,7 @@ async function startFetchRequest(request, options, input, output, emitter, count
83
83
  ...{ allowHTTP1ForStreamingUpload: true }, // Chrome allows request stream only in HTTP2/QUIC unless this opt-in flag
84
84
  }), options.timeout, () => controller?.abort());
85
85
  const headers = {};
86
- // @ts-expect-error
86
+ // @ts-expect-error no .keys()?
87
87
  for (const headerName of res.headers.keys()) {
88
88
  headers[headerName.toLowerCase()] = res.headers.get(headerName);
89
89
  }
package/lib/cache.js CHANGED
@@ -91,7 +91,7 @@ class Cache {
91
91
  */
92
92
  clear(key) {
93
93
  for (const k of Object.keys(this._entries)) {
94
- if (!key || k.indexOf(key) === 0) {
94
+ if (!key || k.startsWith(key)) {
95
95
  this._entries[k].clear();
96
96
  }
97
97
  }
@@ -306,8 +306,7 @@ export declare class Connection<S extends Schema = Schema> extends EventEmitter
306
306
  /**
307
307
  * Get SObject instance
308
308
  */
309
- sobject<N extends SObjectNames<S>>(type: N): SObject<S, N>;
310
- sobject<N extends SObjectNames<S>>(type: string): SObject<S, N>;
309
+ sobject<N extends SObjectNames<S>>(type: string | N): SObject<S, N>;
311
310
  /**
312
311
  * Get identity information of current user
313
312
  */
@@ -352,5 +351,6 @@ export declare class Connection<S extends Schema = Schema> extends EventEmitter
352
351
  * Module which manages process rules and approval processes
353
352
  */
354
353
  process: Process<S>;
354
+ private isLightningInstance;
355
355
  }
356
356
  export default Connection;
package/lib/connection.js CHANGED
@@ -69,7 +69,7 @@ function esc(str) {
69
69
  */
70
70
  function parseSignedRequest(sr) {
71
71
  if (typeof sr === 'string') {
72
- if (sr[0] === '{') {
72
+ if (sr.startsWith('{')) {
73
73
  // might be JSON
74
74
  return JSON.parse(sr);
75
75
  } // might be original base64-encoded signed request
@@ -224,6 +224,9 @@ class Connection extends events_1.EventEmitter {
224
224
  const { loginUrl, instanceUrl, version, oauth2, maxRequest, logLevel, proxyUrl, httpProxy, } = config;
225
225
  this.loginUrl = loginUrl || defaultConnectionConfig.loginUrl;
226
226
  this.instanceUrl = instanceUrl || defaultConnectionConfig.instanceUrl;
227
+ if (this.isLightningInstance()) {
228
+ throw new Error('lightning URLs are not valid as instance URLs');
229
+ }
227
230
  this.version = version || defaultConnectionConfig.version;
228
231
  this.oauth2 =
229
232
  oauth2 instanceof oauth2_1.default
@@ -360,7 +363,7 @@ class Connection extends events_1.EventEmitter {
360
363
  */
361
364
  async login(username, password) {
362
365
  this._refreshDelegate = new session_refresh_delegate_1.default(this, createUsernamePasswordRefreshFn(username, password));
363
- if (this.oauth2 && this.oauth2.clientId && this.oauth2.clientSecret) {
366
+ if (this.oauth2?.clientId && this.oauth2.clientSecret) {
364
367
  return this.loginByOAuth2(username, password);
365
368
  }
366
369
  return this.loginBySoap(username, password);
@@ -417,6 +420,17 @@ class Connection extends events_1.EventEmitter {
417
420
  const faultstring = m && m[1];
418
421
  throw new Error(faultstring || response.body);
419
422
  }
423
+ // the API will return 200 and a restriced token when using an expired password:
424
+ // https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_login_loginresult.htm
425
+ //
426
+ // we need to throw here to avoid a possible infinite loop with session refresh where:
427
+ // 1. login happens, `this.accessToken` is set to the restricted token
428
+ // 2. requests happen, get back 401
429
+ // 3. trigger session-refresh (username/password login has a default session refresh delegate function)
430
+ // 4. gets stuck refreshing a restricted token
431
+ if (response.body.match(/<passwordExpired>true<\/passwordExpired>/g)) {
432
+ throw new Error('Unable to login because the used password has expired.');
433
+ }
420
434
  this._logger.debug(`SOAP response = ${response.body}`);
421
435
  m = response.body.match(/<serverUrl>([^<]+)<\/serverUrl>/);
422
436
  const serverUrl = m && m[1];
@@ -607,11 +621,11 @@ class Connection extends events_1.EventEmitter {
607
621
  * @private
608
622
  */
609
623
  _normalizeUrl(url) {
610
- if (url[0] === '/') {
611
- if (url.indexOf(this.instanceUrl + '/services/') === 0) {
624
+ if (url.startsWith('/')) {
625
+ if (url.startsWith(this.instanceUrl + '/services/')) {
612
626
  return url;
613
627
  }
614
- if (url.indexOf('/services/') === 0) {
628
+ if (url.startsWith('/services/')) {
615
629
  return this.instanceUrl + url;
616
630
  }
617
631
  return this._baseUrl() + url;
@@ -722,13 +736,13 @@ class Connection extends events_1.EventEmitter {
722
736
  /** @private */
723
737
  async _createSingle(type, record, options) {
724
738
  const { Id, type: rtype, attributes, ...rec } = record;
725
- const sobjectType = type || (attributes && attributes.type) || rtype;
739
+ const sobjectType = type || attributes?.type || rtype;
726
740
  if (!sobjectType) {
727
741
  throw new Error('No SObject Type defined in record');
728
742
  }
729
743
  const url = [this._baseUrl(), 'sobjects', sobjectType].join('/');
730
744
  let contentType, body;
731
- if (options && options.multipartFileFields) {
745
+ if (options?.multipartFileFields) {
732
746
  // Send the record as a multipart/form-data request. Useful for fields containing large binary blobs.
733
747
  const form = new form_data_1.default();
734
748
  // Extract the fields requested to be sent separately from the JSON
@@ -785,7 +799,7 @@ class Connection extends events_1.EventEmitter {
785
799
  }
786
800
  const _records = records.map((record) => {
787
801
  const { Id, type: rtype, attributes, ...rec } = record;
788
- const sobjectType = type || (attributes && attributes.type) || rtype;
802
+ const sobjectType = type || attributes?.type || rtype;
789
803
  if (!sobjectType) {
790
804
  throw new Error('No SObject Type defined in record');
791
805
  }
@@ -828,7 +842,7 @@ class Connection extends events_1.EventEmitter {
828
842
  if (!id) {
829
843
  throw new Error('Record id is not found in record.');
830
844
  }
831
- const sobjectType = type || (attributes && attributes.type) || rtype;
845
+ const sobjectType = type || attributes?.type || rtype;
832
846
  if (!sobjectType) {
833
847
  throw new Error('No SObject Type defined in record');
834
848
  }
@@ -875,7 +889,7 @@ class Connection extends events_1.EventEmitter {
875
889
  if (!id) {
876
890
  throw new Error('Record id is not found in record.');
877
891
  }
878
- const sobjectType = type || (attributes && attributes.type) || rtype;
892
+ const sobjectType = type || attributes?.type || rtype;
879
893
  if (!sobjectType) {
880
894
  throw new Error('No SObject Type defined in record');
881
895
  }
@@ -1018,8 +1032,7 @@ class Connection extends events_1.EventEmitter {
1018
1032
  return body;
1019
1033
  }
1020
1034
  sobject(type) {
1021
- const so = this.sobjects[type] ||
1022
- new sobject_1.default(this, type);
1035
+ const so = this.sobjects[type] || new sobject_1.default(this, type);
1023
1036
  this.sobjects[type] = so;
1024
1037
  return so;
1025
1038
  }
@@ -1027,7 +1040,7 @@ class Connection extends events_1.EventEmitter {
1027
1040
  * Get identity information of current user
1028
1041
  */
1029
1042
  async identity(options = {}) {
1030
- let url = this.userInfo && this.userInfo.url;
1043
+ let url = this.userInfo?.url;
1031
1044
  if (!url) {
1032
1045
  const res = await this.request({
1033
1046
  method: 'GET',
@@ -1148,6 +1161,11 @@ class Connection extends events_1.EventEmitter {
1148
1161
  * Module which manages process rules and approval processes
1149
1162
  */
1150
1163
  process = new process_1.default(this);
1164
+ isLightningInstance() {
1165
+ return (this.instanceUrl.includes('.lightning.force.com') ||
1166
+ this.instanceUrl.includes('.lightning.crmforce.mil') ||
1167
+ this.instanceUrl.includes('.lightning.sfcrmapps.cn'));
1168
+ }
1151
1169
  }
1152
1170
  exports.Connection = Connection;
1153
1171
  exports.default = Connection;
package/lib/http-api.js CHANGED
@@ -178,6 +178,7 @@ class HttpApi extends events_1.EventEmitter {
178
178
  /**
179
179
  * @private
180
180
  */
181
+ // eslint-disable-next-line @typescript-eslint/require-await
181
182
  async parseResponseBody(response) {
182
183
  const contentType = this.getResponseContentType(response) || '';
183
184
  const parseBody = /^(text|application)\/xml(;|$)/.test(contentType)
package/lib/oauth2.js CHANGED
@@ -101,8 +101,7 @@ class OAuth2 {
101
101
  if (this.codeVerifier) {
102
102
  // code verifier must be a base 64 url encoded hash of 128 bytes of random data. Our random data is also
103
103
  // base 64 url encoded. See Connection.create();
104
- const codeChallenge = base64UrlEscape((0, crypto_1.createHash)('sha256').update(this.codeVerifier).digest('base64'));
105
- params.code_challenge = codeChallenge;
104
+ params.code_challenge = base64UrlEscape((0, crypto_1.createHash)('sha256').update(this.codeVerifier).digest('base64'));
106
105
  }
107
106
  const _params = {
108
107
  ...params,
@@ -111,7 +110,7 @@ class OAuth2 {
111
110
  redirect_uri: this.redirectUri,
112
111
  };
113
112
  return (this.authzServiceUrl +
114
- (this.authzServiceUrl.indexOf('?') >= 0 ? '&' : '?') +
113
+ (this.authzServiceUrl.includes('?') ? '&' : '?') +
115
114
  querystring_1.default.stringify(_params));
116
115
  }
117
116
  /**
package/lib/query.d.ts CHANGED
@@ -32,9 +32,9 @@ type ConditionSet<R extends Record> = {
32
32
  [K in keyof R]?: CondValue<R[K]>;
33
33
  };
34
34
  export type QueryCondition<S extends Schema, N extends SObjectNames<S>> = {
35
- $or: QueryCondition<S, N>[];
35
+ $or: Array<QueryCondition<S, N>>;
36
36
  } | {
37
- $and: QueryCondition<S, N>[];
37
+ $and: Array<QueryCondition<S, N>>;
38
38
  } | ConditionSet<SObjectRecord<S, N>>;
39
39
  export type QuerySort<S extends Schema, N extends SObjectNames<S>, R extends SObjectRecord<S, N> = SObjectRecord<S, N>> = {
40
40
  [K in keyof R]?: SortDir;
@@ -110,7 +110,7 @@ export declare class Query<S extends Schema, N extends SObjectNames<S>, R extend
110
110
  _soql: Optional<string>;
111
111
  _locator: Optional<string>;
112
112
  _config: SOQLQueryConfig;
113
- _children: SubQuery<S, N, R, QRT, any, any, any>[];
113
+ _children: Array<SubQuery<S, N, R, QRT, any, any, any>>;
114
114
  _options: QueryOptions;
115
115
  _executed: boolean;
116
116
  _finished: boolean;
@@ -149,10 +149,8 @@ export declare class Query<S extends Schema, N extends SObjectNames<S>, R extend
149
149
  /**
150
150
  * Set query sort with direction
151
151
  */
152
- sort(sort: QuerySort<S, N>): this;
153
- sort(sort: string): this;
154
- sort(sort: SObjectFieldNames<S, N>, dir: SortDir): this;
155
- sort(sort: string, dir: SortDir): this;
152
+ sort(sort: QuerySort<S, N> | string): this;
153
+ sort(sort: SObjectFieldNames<S, N> | string, dir: SortDir): this;
156
154
  /**
157
155
  * Synonym of Query#sort()
158
156
  */
@@ -322,9 +320,7 @@ export declare class SubQuery<S extends Schema, PN extends SObjectNames<S>, PR e
322
320
  * Set query sort with direction
323
321
  */
324
322
  sort(sort: QuerySort<S, CN>): this;
325
- sort(sort: string): this;
326
- sort(sort: SObjectFieldNames<S, CN>, dir: SortDir): this;
327
- sort(sort: string, dir: SortDir): this;
323
+ sort(sort: string | SObjectFieldNames<S, CN>, dir: SortDir): this;
328
324
  /**
329
325
  * Synonym of SubQuery#sort()
330
326
  */
package/lib/query.js CHANGED
@@ -85,7 +85,7 @@ class Query extends events_1.EventEmitter {
85
85
  : locator;
86
86
  }
87
87
  else {
88
- this._logger.debug(`config is QueryConfig: ${config}`);
88
+ this._logger.debug(`config is QueryConfig: ${JSON.stringify(config)}`);
89
89
  const { fields, includes, sort, ..._config } = config;
90
90
  this._config = _config;
91
91
  this.select(fields);
@@ -383,6 +383,7 @@ class Query extends events_1.EventEmitter {
383
383
  this._finished ||
384
384
  data.done ||
385
385
  !autoFetch ||
386
+ this.records.length === maxFetch ||
386
387
  // this is what the response looks like when there are no results
387
388
  (data.records.length === 0 && data.done === undefined);
388
389
  // streaming record instances
@@ -20,6 +20,7 @@ class BaseRegistry {
20
20
  return (this._registryConfig.connections ||
21
21
  (this._registryConfig.connections = {}));
22
22
  }
23
+ // eslint-disable-next-line @typescript-eslint/require-await
23
24
  async getConnectionNames() {
24
25
  return Object.keys(this._getConnections());
25
26
  }
@@ -45,6 +46,7 @@ class BaseRegistry {
45
46
  }
46
47
  return connConfig_;
47
48
  }
49
+ // eslint-disable-next-line @typescript-eslint/require-await
48
50
  async saveConnectionConfig(name, connConfig) {
49
51
  const connections = this._getConnections();
50
52
  const { oauth2, ...connConfig_ } = connConfig;
@@ -70,23 +72,28 @@ class BaseRegistry {
70
72
  }
71
73
  return null;
72
74
  }
75
+ // eslint-disable-next-line @typescript-eslint/require-await
73
76
  async setDefaultConnection(name) {
74
77
  this._registryConfig['default'] = name;
75
78
  this._saveConfig();
76
79
  }
80
+ // eslint-disable-next-line @typescript-eslint/require-await
77
81
  async removeConnectionConfig(name) {
78
82
  const connections = this._getConnections();
79
83
  delete connections[name];
80
84
  this._saveConfig();
81
85
  }
86
+ // eslint-disable-next-line @typescript-eslint/require-await
82
87
  async getClientConfig(name) {
83
88
  const clients = this._getClients();
84
89
  const clientConfig = clients[name];
85
90
  return clientConfig && { ...clientConfig };
86
91
  }
92
+ // eslint-disable-next-line @typescript-eslint/require-await
87
93
  async getClientNames() {
88
94
  return Object.keys(this._getClients());
89
95
  }
96
+ // eslint-disable-next-line @typescript-eslint/require-await
90
97
  async registerClientConfig(name, clientConfig) {
91
98
  const clients = this._getClients();
92
99
  clients[name] = clientConfig;