@jsforce/jsforce-node 0.0.1 → 3.0.0-next.2

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.
Files changed (131) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +54 -0
  3. package/index.d.ts +4 -0
  4. package/index.js +1 -0
  5. package/lib/VERSION.d.ts +2 -0
  6. package/lib/VERSION.js +3 -0
  7. package/lib/api/analytics/types.d.ts +509 -0
  8. package/lib/api/analytics/types.js +2 -0
  9. package/lib/api/analytics.d.ts +163 -0
  10. package/lib/api/analytics.js +342 -0
  11. package/lib/api/apex.d.ts +44 -0
  12. package/lib/api/apex.js +86 -0
  13. package/lib/api/bulk.d.ts +253 -0
  14. package/lib/api/bulk.js +678 -0
  15. package/lib/api/bulk2.d.ts +324 -0
  16. package/lib/api/bulk2.js +800 -0
  17. package/lib/api/chatter.d.ts +133 -0
  18. package/lib/api/chatter.js +248 -0
  19. package/lib/api/metadata/schema.d.ts +16117 -0
  20. package/lib/api/metadata/schema.js +9094 -0
  21. package/lib/api/metadata.d.ts +189 -0
  22. package/lib/api/metadata.js +406 -0
  23. package/lib/api/soap/schema.d.ts +3167 -0
  24. package/lib/api/soap/schema.js +1787 -0
  25. package/lib/api/soap.d.ts +76 -0
  26. package/lib/api/soap.js +155 -0
  27. package/lib/api/streaming/extension.d.ts +94 -0
  28. package/lib/api/streaming/extension.js +151 -0
  29. package/lib/api/streaming.d.ts +160 -0
  30. package/lib/api/streaming.js +252 -0
  31. package/lib/api/tooling.d.ts +284 -0
  32. package/lib/api/tooling.js +202 -0
  33. package/lib/api/wsdl/wsdl2schema.d.ts +1 -0
  34. package/lib/api/wsdl/wsdl2schema.js +354 -0
  35. package/lib/browser/canvas.d.ts +12 -0
  36. package/lib/browser/canvas.js +77 -0
  37. package/lib/browser/client.d.ts +82 -0
  38. package/lib/browser/client.js +244 -0
  39. package/lib/browser/jsonp.d.ts +12 -0
  40. package/lib/browser/jsonp.js +69 -0
  41. package/lib/browser/registry.d.ts +3 -0
  42. package/lib/browser/registry.js +5 -0
  43. package/lib/browser/request.d.ts +10 -0
  44. package/lib/browser/request.js +202 -0
  45. package/lib/cache.d.ts +74 -0
  46. package/lib/cache.js +159 -0
  47. package/lib/connection.d.ts +356 -0
  48. package/lib/connection.js +1153 -0
  49. package/lib/core.d.ts +17 -0
  50. package/lib/core.js +55 -0
  51. package/lib/csv.d.ts +23 -0
  52. package/lib/csv.js +35 -0
  53. package/lib/date.d.ts +82 -0
  54. package/lib/date.js +201 -0
  55. package/lib/http-api.d.ts +75 -0
  56. package/lib/http-api.js +295 -0
  57. package/lib/index.d.ts +13 -0
  58. package/lib/index.js +32 -0
  59. package/lib/jsforce.d.ts +26 -0
  60. package/lib/jsforce.js +67 -0
  61. package/lib/jwtOAuth2.d.ts +8 -0
  62. package/lib/jwtOAuth2.js +23 -0
  63. package/lib/oauth2.d.ts +92 -0
  64. package/lib/oauth2.js +245 -0
  65. package/lib/process.d.ts +157 -0
  66. package/lib/process.js +143 -0
  67. package/lib/query.d.ts +341 -0
  68. package/lib/query.js +817 -0
  69. package/lib/quick-action.d.ts +44 -0
  70. package/lib/quick-action.js +46 -0
  71. package/lib/record-reference.d.ts +46 -0
  72. package/lib/record-reference.js +65 -0
  73. package/lib/record-stream.d.ts +83 -0
  74. package/lib/record-stream.js +233 -0
  75. package/lib/registry/base.d.ts +43 -0
  76. package/lib/registry/base.js +96 -0
  77. package/lib/registry/empty.d.ts +7 -0
  78. package/lib/registry/empty.js +13 -0
  79. package/lib/registry/file.d.ts +11 -0
  80. package/lib/registry/file.js +51 -0
  81. package/lib/registry/index.d.ts +8 -0
  82. package/lib/registry/index.js +21 -0
  83. package/lib/registry/sfdx.d.ts +56 -0
  84. package/lib/registry/sfdx.js +133 -0
  85. package/lib/registry/types.d.ts +47 -0
  86. package/lib/registry/types.js +2 -0
  87. package/lib/request-helper.d.ts +23 -0
  88. package/lib/request-helper.js +102 -0
  89. package/lib/request.d.ts +11 -0
  90. package/lib/request.js +75 -0
  91. package/lib/session-refresh-delegate.d.ts +31 -0
  92. package/lib/session-refresh-delegate.js +69 -0
  93. package/lib/soap.d.ts +60 -0
  94. package/lib/soap.js +257 -0
  95. package/lib/sobject.d.ts +258 -0
  96. package/lib/sobject.js +376 -0
  97. package/lib/soql-builder.d.ts +25 -0
  98. package/lib/soql-builder.js +226 -0
  99. package/lib/transport.d.ts +63 -0
  100. package/lib/transport.js +175 -0
  101. package/lib/types/common.d.ts +560 -0
  102. package/lib/types/common.js +2 -0
  103. package/lib/types/index.d.ts +7 -0
  104. package/lib/types/index.js +23 -0
  105. package/lib/types/projection.d.ts +26 -0
  106. package/lib/types/projection.js +2 -0
  107. package/lib/types/record.d.ts +44 -0
  108. package/lib/types/record.js +2 -0
  109. package/lib/types/schema.d.ts +50 -0
  110. package/lib/types/schema.js +2 -0
  111. package/lib/types/soap.d.ts +43 -0
  112. package/lib/types/soap.js +2 -0
  113. package/lib/types/standard-schema.d.ts +16199 -0
  114. package/lib/types/standard-schema.js +2 -0
  115. package/lib/types/util.d.ts +7 -0
  116. package/lib/types/util.js +2 -0
  117. package/lib/util/formatter.d.ts +8 -0
  118. package/lib/util/formatter.js +24 -0
  119. package/lib/util/function.d.ts +32 -0
  120. package/lib/util/function.js +52 -0
  121. package/lib/util/get-body-size.d.ts +4 -0
  122. package/lib/util/get-body-size.js +39 -0
  123. package/lib/util/logger.d.ts +29 -0
  124. package/lib/util/logger.js +102 -0
  125. package/lib/util/promise.d.ts +19 -0
  126. package/lib/util/promise.js +25 -0
  127. package/lib/util/stream.d.ts +12 -0
  128. package/lib/util/stream.js +88 -0
  129. package/package.json +262 -6
  130. package/typings/faye/index.d.ts +16 -0
  131. package/typings/index.d.ts +1 -0
@@ -0,0 +1,1153 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.Connection = void 0;
30
+ /**
31
+ *
32
+ */
33
+ const events_1 = require("events");
34
+ const jsforce_1 = __importDefault(require("./jsforce"));
35
+ const transport_1 = __importStar(require("./transport"));
36
+ const logger_1 = require("./util/logger");
37
+ const oauth2_1 = __importDefault(require("./oauth2"));
38
+ const cache_1 = __importDefault(require("./cache"));
39
+ const http_api_1 = __importDefault(require("./http-api"));
40
+ const session_refresh_delegate_1 = __importDefault(require("./session-refresh-delegate"));
41
+ const query_1 = __importDefault(require("./query"));
42
+ const sobject_1 = __importDefault(require("./sobject"));
43
+ const quick_action_1 = __importDefault(require("./quick-action"));
44
+ const process_1 = __importDefault(require("./process"));
45
+ const formatter_1 = require("./util/formatter");
46
+ const form_data_1 = __importDefault(require("form-data"));
47
+ /**
48
+ *
49
+ */
50
+ const defaultConnectionConfig = {
51
+ loginUrl: 'https://login.salesforce.com',
52
+ instanceUrl: '',
53
+ version: '50.0',
54
+ logLevel: 'NONE',
55
+ maxRequest: 10,
56
+ };
57
+ /**
58
+ *
59
+ */
60
+ function esc(str) {
61
+ return String(str || '')
62
+ .replace(/&/g, '&')
63
+ .replace(/</g, '&lt;')
64
+ .replace(/>/g, '&gt;')
65
+ .replace(/"/g, '&quot;');
66
+ }
67
+ /**
68
+ *
69
+ */
70
+ function parseSignedRequest(sr) {
71
+ if (typeof sr === 'string') {
72
+ if (sr[0] === '{') {
73
+ // might be JSON
74
+ return JSON.parse(sr);
75
+ } // might be original base64-encoded signed request
76
+ const msg = sr.split('.').pop(); // retrieve latter part
77
+ if (!msg) {
78
+ throw new Error('Invalid signed request');
79
+ }
80
+ const json = Buffer.from(msg, 'base64').toString('utf-8');
81
+ return JSON.parse(json);
82
+ }
83
+ return sr;
84
+ }
85
+ /** @private **/
86
+ function parseIdUrl(url) {
87
+ const [organizationId, id] = url.split('/').slice(-2);
88
+ return { id, organizationId, url };
89
+ }
90
+ /**
91
+ * Session Refresh delegate function for OAuth2 authz code flow
92
+ * @private
93
+ */
94
+ async function oauthRefreshFn(conn, callback) {
95
+ try {
96
+ if (!conn.refreshToken) {
97
+ throw new Error('No refresh token found in the connection');
98
+ }
99
+ const res = await conn.oauth2.refreshToken(conn.refreshToken);
100
+ const userInfo = parseIdUrl(res.id);
101
+ conn._establish({
102
+ instanceUrl: res.instance_url,
103
+ accessToken: res.access_token,
104
+ userInfo,
105
+ });
106
+ callback(undefined, res.access_token, res);
107
+ }
108
+ catch (err) {
109
+ if (err instanceof Error) {
110
+ callback(err);
111
+ }
112
+ else {
113
+ throw err;
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Session Refresh delegate function for username/password login
119
+ * @private
120
+ */
121
+ function createUsernamePasswordRefreshFn(username, password) {
122
+ return async (conn, callback) => {
123
+ try {
124
+ await conn.login(username, password);
125
+ if (!conn.accessToken) {
126
+ throw new Error('Access token not found after login');
127
+ }
128
+ callback(null, conn.accessToken);
129
+ }
130
+ catch (err) {
131
+ if (err instanceof Error) {
132
+ callback(err);
133
+ }
134
+ else {
135
+ throw err;
136
+ }
137
+ }
138
+ };
139
+ }
140
+ /**
141
+ * @private
142
+ */
143
+ function toSaveResult(err) {
144
+ return {
145
+ success: false,
146
+ errors: [err],
147
+ };
148
+ }
149
+ /**
150
+ *
151
+ */
152
+ function raiseNoModuleError(name) {
153
+ throw new Error(`API module '${name}' is not loaded, load 'jsforce/api/${name}' explicitly`);
154
+ }
155
+ /*
156
+ * Constant of maximum records num in DML operation (update/delete)
157
+ */
158
+ const MAX_DML_COUNT = 200;
159
+ /**
160
+ *
161
+ */
162
+ class Connection extends events_1.EventEmitter {
163
+ static _logger = (0, logger_1.getLogger)('connection');
164
+ version;
165
+ loginUrl;
166
+ instanceUrl;
167
+ accessToken;
168
+ refreshToken;
169
+ userInfo;
170
+ limitInfo = {};
171
+ oauth2;
172
+ sobjects = {};
173
+ cache;
174
+ _callOptions;
175
+ _maxRequest;
176
+ _logger;
177
+ _logLevel;
178
+ _transport;
179
+ _sessionType;
180
+ _refreshDelegate;
181
+ // describe: (name: string) => Promise<DescribeSObjectResult>;
182
+ describe$;
183
+ describe$$;
184
+ describeSObject;
185
+ describeSObject$;
186
+ describeSObject$$;
187
+ // describeGlobal: () => Promise<DescribeGlobalResult>;
188
+ describeGlobal$;
189
+ describeGlobal$$;
190
+ // API libs are not instantiated here so that core module to remain without dependencies to them
191
+ // It is responsible for developers to import api libs explicitly if they are using 'jsforce/core' instead of 'jsforce'.
192
+ get analytics() {
193
+ return raiseNoModuleError('analytics');
194
+ }
195
+ get apex() {
196
+ return raiseNoModuleError('apex');
197
+ }
198
+ get bulk() {
199
+ return raiseNoModuleError('bulk');
200
+ }
201
+ get bulk2() {
202
+ return raiseNoModuleError('bulk2');
203
+ }
204
+ get chatter() {
205
+ return raiseNoModuleError('chatter');
206
+ }
207
+ get metadata() {
208
+ return raiseNoModuleError('metadata');
209
+ }
210
+ get soap() {
211
+ return raiseNoModuleError('soap');
212
+ }
213
+ get streaming() {
214
+ return raiseNoModuleError('streaming');
215
+ }
216
+ get tooling() {
217
+ return raiseNoModuleError('tooling');
218
+ }
219
+ /**
220
+ *
221
+ */
222
+ constructor(config = {}) {
223
+ super();
224
+ const { loginUrl, instanceUrl, version, oauth2, maxRequest, logLevel, proxyUrl, httpProxy, } = config;
225
+ this.loginUrl = loginUrl || defaultConnectionConfig.loginUrl;
226
+ this.instanceUrl = instanceUrl || defaultConnectionConfig.instanceUrl;
227
+ this.version = version || defaultConnectionConfig.version;
228
+ this.oauth2 =
229
+ oauth2 instanceof oauth2_1.default
230
+ ? oauth2
231
+ : new oauth2_1.default({
232
+ loginUrl: this.loginUrl,
233
+ proxyUrl,
234
+ httpProxy,
235
+ ...oauth2,
236
+ });
237
+ let refreshFn = config.refreshFn;
238
+ if (!refreshFn && this.oauth2.clientId) {
239
+ refreshFn = oauthRefreshFn;
240
+ }
241
+ if (refreshFn) {
242
+ this._refreshDelegate = new session_refresh_delegate_1.default(this, refreshFn);
243
+ }
244
+ this._maxRequest = maxRequest || defaultConnectionConfig.maxRequest;
245
+ this._logger = logLevel
246
+ ? Connection._logger.createInstance(logLevel)
247
+ : Connection._logger;
248
+ this._logLevel = logLevel;
249
+ this._transport = proxyUrl
250
+ ? new transport_1.XdProxyTransport(proxyUrl)
251
+ : httpProxy
252
+ ? new transport_1.HttpProxyTransport(httpProxy)
253
+ : new transport_1.default();
254
+ this._callOptions = config.callOptions;
255
+ this.cache = new cache_1.default();
256
+ const describeCacheKey = (type) => type ? `describe.${type}` : 'describe';
257
+ const describe = Connection.prototype.describe;
258
+ this.describe = this.cache.createCachedFunction(describe, this, {
259
+ key: describeCacheKey,
260
+ strategy: 'NOCACHE',
261
+ });
262
+ this.describe$ = this.cache.createCachedFunction(describe, this, {
263
+ key: describeCacheKey,
264
+ strategy: 'HIT',
265
+ });
266
+ this.describe$$ = this.cache.createCachedFunction(describe, this, {
267
+ key: describeCacheKey,
268
+ strategy: 'IMMEDIATE',
269
+ });
270
+ this.describeSObject = this.describe;
271
+ this.describeSObject$ = this.describe$;
272
+ this.describeSObject$$ = this.describe$$;
273
+ const describeGlobal = Connection.prototype.describeGlobal;
274
+ this.describeGlobal = this.cache.createCachedFunction(describeGlobal, this, { key: 'describeGlobal', strategy: 'NOCACHE' });
275
+ this.describeGlobal$ = this.cache.createCachedFunction(describeGlobal, this, { key: 'describeGlobal', strategy: 'HIT' });
276
+ this.describeGlobal$$ = this.cache.createCachedFunction(describeGlobal, this, { key: 'describeGlobal', strategy: 'IMMEDIATE' });
277
+ const { accessToken, refreshToken, sessionId, serverUrl, signedRequest, } = config;
278
+ this._establish({
279
+ accessToken,
280
+ refreshToken,
281
+ instanceUrl,
282
+ sessionId,
283
+ serverUrl,
284
+ signedRequest,
285
+ });
286
+ jsforce_1.default.emit('connection:new', this);
287
+ }
288
+ /* @private */
289
+ _establish(options) {
290
+ const { accessToken, refreshToken, instanceUrl, sessionId, serverUrl, signedRequest, userInfo, } = options;
291
+ this.instanceUrl = serverUrl
292
+ ? serverUrl.split('/').slice(0, 3).join('/')
293
+ : instanceUrl || this.instanceUrl;
294
+ this.accessToken = sessionId || accessToken || this.accessToken;
295
+ this.refreshToken = refreshToken || this.refreshToken;
296
+ if (this.refreshToken && !this._refreshDelegate) {
297
+ throw new Error('Refresh token is specified without oauth2 client information or refresh function');
298
+ }
299
+ const signedRequestObject = signedRequest && parseSignedRequest(signedRequest);
300
+ if (signedRequestObject) {
301
+ this.accessToken = signedRequestObject.client.oauthToken;
302
+ if (transport_1.CanvasTransport.supported) {
303
+ this._transport = new transport_1.CanvasTransport(signedRequestObject);
304
+ }
305
+ }
306
+ this.userInfo = userInfo || this.userInfo;
307
+ this._sessionType = sessionId ? 'soap' : 'oauth2';
308
+ this._resetInstance();
309
+ }
310
+ /* @priveate */
311
+ _clearSession() {
312
+ this.accessToken = null;
313
+ this.refreshToken = null;
314
+ this.instanceUrl = defaultConnectionConfig.instanceUrl;
315
+ this.userInfo = null;
316
+ this._sessionType = null;
317
+ }
318
+ /* @priveate */
319
+ _resetInstance() {
320
+ this.limitInfo = {};
321
+ this.sobjects = {};
322
+ // TODO impl cache
323
+ this.cache.clear();
324
+ this.cache.get('describeGlobal').removeAllListeners('value');
325
+ this.cache.get('describeGlobal').on('value', ({ result }) => {
326
+ if (result) {
327
+ for (const so of result.sobjects) {
328
+ this.sobject(so.name);
329
+ }
330
+ }
331
+ });
332
+ /*
333
+ if (this.tooling) {
334
+ this.tooling._resetInstance();
335
+ }
336
+ */
337
+ }
338
+ /**
339
+ * Authorize the connection using OAuth2 flow.
340
+ * Typically, just pass the code returned from authorization server in the first argument to complete authorization.
341
+ * If you want to authorize with grant types other than `authorization_code`, you can also pass params object with the grant type.
342
+ *
343
+ * @returns {Promise<UserInfo>} An object that contains the user ID, org ID and identity URL.
344
+ *
345
+ */
346
+ async authorize(codeOrParams, params = {}) {
347
+ const res = await this.oauth2.requestToken(codeOrParams, params);
348
+ const userInfo = parseIdUrl(res.id);
349
+ this._establish({
350
+ instanceUrl: res.instance_url,
351
+ accessToken: res.access_token,
352
+ refreshToken: res.refresh_token,
353
+ userInfo,
354
+ });
355
+ this._logger.debug(`<login> completed. user id = ${userInfo.id}, org id = ${userInfo.organizationId}`);
356
+ return userInfo;
357
+ }
358
+ /**
359
+ *
360
+ */
361
+ async login(username, password) {
362
+ this._refreshDelegate = new session_refresh_delegate_1.default(this, createUsernamePasswordRefreshFn(username, password));
363
+ if (this.oauth2 && this.oauth2.clientId && this.oauth2.clientSecret) {
364
+ return this.loginByOAuth2(username, password);
365
+ }
366
+ return this.loginBySoap(username, password);
367
+ }
368
+ /**
369
+ * Login by OAuth2 username & password flow
370
+ */
371
+ async loginByOAuth2(username, password) {
372
+ const res = await this.oauth2.authenticate(username, password);
373
+ const userInfo = parseIdUrl(res.id);
374
+ this._establish({
375
+ instanceUrl: res.instance_url,
376
+ accessToken: res.access_token,
377
+ userInfo,
378
+ });
379
+ this._logger.info(`<login> completed. user id = ${userInfo.id}, org id = ${userInfo.organizationId}`);
380
+ return userInfo;
381
+ }
382
+ /**
383
+ *
384
+ */
385
+ async loginBySoap(username, password) {
386
+ if (!username || !password) {
387
+ return Promise.reject(new Error('no username password given'));
388
+ }
389
+ const body = [
390
+ '<se:Envelope xmlns:se="http://schemas.xmlsoap.org/soap/envelope/">',
391
+ '<se:Header/>',
392
+ '<se:Body>',
393
+ '<login xmlns="urn:partner.soap.sforce.com">',
394
+ `<username>${esc(username)}</username>`,
395
+ `<password>${esc(password)}</password>`,
396
+ '</login>',
397
+ '</se:Body>',
398
+ '</se:Envelope>',
399
+ ].join('');
400
+ const soapLoginEndpoint = [
401
+ this.loginUrl,
402
+ 'services/Soap/u',
403
+ this.version,
404
+ ].join('/');
405
+ const response = await this._transport.httpRequest({
406
+ method: 'POST',
407
+ url: soapLoginEndpoint,
408
+ body,
409
+ headers: {
410
+ 'Content-Type': 'text/xml',
411
+ SOAPAction: '""',
412
+ },
413
+ });
414
+ let m;
415
+ if (response.statusCode >= 400) {
416
+ m = response.body.match(/<faultstring>([^<]+)<\/faultstring>/);
417
+ const faultstring = m && m[1];
418
+ throw new Error(faultstring || response.body);
419
+ }
420
+ this._logger.debug(`SOAP response = ${response.body}`);
421
+ m = response.body.match(/<serverUrl>([^<]+)<\/serverUrl>/);
422
+ const serverUrl = m && m[1];
423
+ m = response.body.match(/<sessionId>([^<]+)<\/sessionId>/);
424
+ const sessionId = m && m[1];
425
+ m = response.body.match(/<userId>([^<]+)<\/userId>/);
426
+ const userId = m && m[1];
427
+ m = response.body.match(/<organizationId>([^<]+)<\/organizationId>/);
428
+ const organizationId = m && m[1];
429
+ if (!serverUrl || !sessionId || !userId || !organizationId) {
430
+ throw new Error('could not extract session information from login response');
431
+ }
432
+ const idUrl = [this.loginUrl, 'id', organizationId, userId].join('/');
433
+ const userInfo = { id: userId, organizationId, url: idUrl };
434
+ this._establish({
435
+ serverUrl: serverUrl.split('/').slice(0, 3).join('/'),
436
+ sessionId,
437
+ userInfo,
438
+ });
439
+ this._logger.info(`<login> completed. user id = ${userId}, org id = ${organizationId}`);
440
+ return userInfo;
441
+ }
442
+ /**
443
+ * Logout the current session
444
+ */
445
+ async logout(revoke) {
446
+ this._refreshDelegate = undefined;
447
+ if (this._sessionType === 'oauth2') {
448
+ return this.logoutByOAuth2(revoke);
449
+ }
450
+ return this.logoutBySoap(revoke);
451
+ }
452
+ /**
453
+ * Logout the current session by revoking access token via OAuth2 session revoke
454
+ */
455
+ async logoutByOAuth2(revoke) {
456
+ const token = revoke ? this.refreshToken : this.accessToken;
457
+ if (token) {
458
+ await this.oauth2.revokeToken(token);
459
+ }
460
+ // Destroy the session bound to this connection
461
+ this._clearSession();
462
+ this._resetInstance();
463
+ }
464
+ /**
465
+ * Logout the session by using SOAP web service API
466
+ */
467
+ async logoutBySoap(revoke) {
468
+ const body = [
469
+ '<se:Envelope xmlns:se="http://schemas.xmlsoap.org/soap/envelope/">',
470
+ '<se:Header>',
471
+ '<SessionHeader xmlns="urn:partner.soap.sforce.com">',
472
+ `<sessionId>${esc(revoke ? this.refreshToken : this.accessToken)}</sessionId>`,
473
+ '</SessionHeader>',
474
+ '</se:Header>',
475
+ '<se:Body>',
476
+ '<logout xmlns="urn:partner.soap.sforce.com"/>',
477
+ '</se:Body>',
478
+ '</se:Envelope>',
479
+ ].join('');
480
+ const response = await this._transport.httpRequest({
481
+ method: 'POST',
482
+ url: [this.instanceUrl, 'services/Soap/u', this.version].join('/'),
483
+ body,
484
+ headers: {
485
+ 'Content-Type': 'text/xml',
486
+ SOAPAction: '""',
487
+ },
488
+ });
489
+ this._logger.debug(`SOAP statusCode = ${response.statusCode}, response = ${response.body}`);
490
+ if (response.statusCode >= 400) {
491
+ const m = response.body.match(/<faultstring>([^<]+)<\/faultstring>/);
492
+ const faultstring = m && m[1];
493
+ throw new Error(faultstring || response.body);
494
+ }
495
+ // Destroy the session bound to this connection
496
+ this._clearSession();
497
+ this._resetInstance();
498
+ }
499
+ /**
500
+ * Send REST API request with given HTTP request info, with connected session information.
501
+ *
502
+ * Endpoint URL can be absolute URL ('https://na1.salesforce.com/services/data/v32.0/sobjects/Account/describe')
503
+ * , relative path from root ('/services/data/v32.0/sobjects/Account/describe')
504
+ * , or relative path from version root ('/sobjects/Account/describe').
505
+ */
506
+ request(request, options = {}) {
507
+ // if request is simple string, regard it as url in GET method
508
+ let request_ = typeof request === 'string' ? { method: 'GET', url: request } : request;
509
+ // if url is given in relative path, prepend base url or instance url before.
510
+ request_ = {
511
+ ...request_,
512
+ url: this._normalizeUrl(request_.url),
513
+ };
514
+ const httpApi = new http_api_1.default(this, options);
515
+ // log api usage and its quota
516
+ httpApi.on('response', (response) => {
517
+ if (response.headers && response.headers['sforce-limit-info']) {
518
+ const apiUsage = response.headers['sforce-limit-info'].match(/api-usage=(\d+)\/(\d+)/);
519
+ if (apiUsage) {
520
+ this.limitInfo = {
521
+ apiUsage: {
522
+ used: parseInt(apiUsage[1], 10),
523
+ limit: parseInt(apiUsage[2], 10),
524
+ },
525
+ };
526
+ }
527
+ }
528
+ });
529
+ return httpApi.request(request_);
530
+ }
531
+ /**
532
+ * Send HTTP GET request
533
+ *
534
+ * Endpoint URL can be absolute URL ('https://na1.salesforce.com/services/data/v32.0/sobjects/Account/describe')
535
+ * , relative path from root ('/services/data/v32.0/sobjects/Account/describe')
536
+ * , or relative path from version root ('/sobjects/Account/describe').
537
+ */
538
+ requestGet(url, options) {
539
+ const request = { method: 'GET', url };
540
+ return this.request(request, options);
541
+ }
542
+ /**
543
+ * Send HTTP POST request with JSON body, with connected session information
544
+ *
545
+ * Endpoint URL can be absolute URL ('https://na1.salesforce.com/services/data/v32.0/sobjects/Account/describe')
546
+ * , relative path from root ('/services/data/v32.0/sobjects/Account/describe')
547
+ * , or relative path from version root ('/sobjects/Account/describe').
548
+ */
549
+ requestPost(url, body, options) {
550
+ const request = {
551
+ method: 'POST',
552
+ url,
553
+ body: JSON.stringify(body),
554
+ headers: { 'content-type': 'application/json' },
555
+ };
556
+ return this.request(request, options);
557
+ }
558
+ /**
559
+ * Send HTTP PUT request with JSON body, with connected session information
560
+ *
561
+ * Endpoint URL can be absolute URL ('https://na1.salesforce.com/services/data/v32.0/sobjects/Account/describe')
562
+ * , relative path from root ('/services/data/v32.0/sobjects/Account/describe')
563
+ * , or relative path from version root ('/sobjects/Account/describe').
564
+ */
565
+ requestPut(url, body, options) {
566
+ const request = {
567
+ method: 'PUT',
568
+ url,
569
+ body: JSON.stringify(body),
570
+ headers: { 'content-type': 'application/json' },
571
+ };
572
+ return this.request(request, options);
573
+ }
574
+ /**
575
+ * Send HTTP PATCH request with JSON body
576
+ *
577
+ * Endpoint URL can be absolute URL ('https://na1.salesforce.com/services/data/v32.0/sobjects/Account/describe')
578
+ * , relative path from root ('/services/data/v32.0/sobjects/Account/describe')
579
+ * , or relative path from version root ('/sobjects/Account/describe').
580
+ */
581
+ requestPatch(url, body, options) {
582
+ const request = {
583
+ method: 'PATCH',
584
+ url,
585
+ body: JSON.stringify(body),
586
+ headers: { 'content-type': 'application/json' },
587
+ };
588
+ return this.request(request, options);
589
+ }
590
+ /**
591
+ * Send HTTP DELETE request
592
+ *
593
+ * Endpoint URL can be absolute URL ('https://na1.salesforce.com/services/data/v32.0/sobjects/Account/describe')
594
+ * , relative path from root ('/services/data/v32.0/sobjects/Account/describe')
595
+ * , or relative path from version root ('/sobjects/Account/describe').
596
+ */
597
+ requestDelete(url, options) {
598
+ const request = { method: 'DELETE', url };
599
+ return this.request(request, options);
600
+ }
601
+ /** @private **/
602
+ _baseUrl() {
603
+ return [this.instanceUrl, 'services/data', `v${this.version}`].join('/');
604
+ }
605
+ /**
606
+ * Convert path to absolute url
607
+ * @private
608
+ */
609
+ _normalizeUrl(url) {
610
+ if (url[0] === '/') {
611
+ if (url.indexOf(this.instanceUrl + '/services/') === 0) {
612
+ return url;
613
+ }
614
+ if (url.indexOf('/services/') === 0) {
615
+ return this.instanceUrl + url;
616
+ }
617
+ return this._baseUrl() + url;
618
+ }
619
+ return url;
620
+ }
621
+ /**
622
+ *
623
+ */
624
+ query(soql, options) {
625
+ return new query_1.default(this, soql, options);
626
+ }
627
+ /**
628
+ * Execute search by SOSL
629
+ *
630
+ * @param {String} sosl - SOSL string
631
+ * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
632
+ * @returns {Promise.<Array.<RecordResult>>}
633
+ */
634
+ search(sosl) {
635
+ const url = this._baseUrl() + '/search?q=' + encodeURIComponent(sosl);
636
+ return this.request(url);
637
+ }
638
+ /**
639
+ *
640
+ */
641
+ queryMore(locator, options) {
642
+ return new query_1.default(this, { locator }, options);
643
+ }
644
+ /* */
645
+ _ensureVersion(majorVersion) {
646
+ const versions = this.version.split('.');
647
+ return parseInt(versions[0], 10) >= majorVersion;
648
+ }
649
+ /* */
650
+ _supports(feature) {
651
+ switch (feature) {
652
+ case 'sobject-collection': // sobject collection is available only in API ver 42.0+
653
+ return this._ensureVersion(42);
654
+ default:
655
+ return false;
656
+ }
657
+ }
658
+ async retrieve(type, ids, options = {}) {
659
+ return Array.isArray(ids)
660
+ ? // check the version whether SObject collection API is supported (42.0)
661
+ this._ensureVersion(42)
662
+ ? this._retrieveMany(type, ids, options)
663
+ : this._retrieveParallel(type, ids, options)
664
+ : this._retrieveSingle(type, ids, options);
665
+ }
666
+ /** @private */
667
+ async _retrieveSingle(type, id, options) {
668
+ if (!id) {
669
+ throw new Error('Invalid record ID. Specify valid record ID value');
670
+ }
671
+ let url = [this._baseUrl(), 'sobjects', type, id].join('/');
672
+ const { fields, headers } = options;
673
+ if (fields) {
674
+ url += `?fields=${fields.join(',')}`;
675
+ }
676
+ return this.request({ method: 'GET', url, headers });
677
+ }
678
+ /** @private */
679
+ async _retrieveParallel(type, ids, options) {
680
+ if (ids.length > this._maxRequest) {
681
+ throw new Error('Exceeded max limit of concurrent call');
682
+ }
683
+ return Promise.all(ids.map((id) => this._retrieveSingle(type, id, options).catch((err) => {
684
+ if (options.allOrNone || err.errorCode !== 'NOT_FOUND') {
685
+ throw err;
686
+ }
687
+ return null;
688
+ })));
689
+ }
690
+ /** @private */
691
+ async _retrieveMany(type, ids, options) {
692
+ if (ids.length === 0) {
693
+ return [];
694
+ }
695
+ const url = [this._baseUrl(), 'composite', 'sobjects', type].join('/');
696
+ const fields = options.fields ||
697
+ (await this.describe$(type)).fields.map((field) => field.name);
698
+ return this.request({
699
+ method: 'POST',
700
+ url,
701
+ body: JSON.stringify({ ids, fields }),
702
+ headers: {
703
+ ...(options.headers || {}),
704
+ 'content-type': 'application/json',
705
+ },
706
+ });
707
+ }
708
+ /**
709
+ * @param type
710
+ * @param records
711
+ * @param options
712
+ */
713
+ async create(type, records, options = {}) {
714
+ const ret = Array.isArray(records)
715
+ ? // check the version whether SObject collection API is supported (42.0)
716
+ this._ensureVersion(42)
717
+ ? await this._createMany(type, records, options)
718
+ : await this._createParallel(type, records, options)
719
+ : await this._createSingle(type, records, options);
720
+ return ret;
721
+ }
722
+ /** @private */
723
+ async _createSingle(type, record, options) {
724
+ const { Id, type: rtype, attributes, ...rec } = record;
725
+ const sobjectType = type || (attributes && attributes.type) || rtype;
726
+ if (!sobjectType) {
727
+ throw new Error('No SObject Type defined in record');
728
+ }
729
+ const url = [this._baseUrl(), 'sobjects', sobjectType].join('/');
730
+ let contentType, body;
731
+ if (options && options.multipartFileFields) {
732
+ // Send the record as a multipart/form-data request. Useful for fields containing large binary blobs.
733
+ const form = new form_data_1.default();
734
+ // Extract the fields requested to be sent separately from the JSON
735
+ Object.entries(options.multipartFileFields).forEach(([fieldName, fileDetails]) => {
736
+ form.append(fieldName, Buffer.from(rec[fieldName], 'base64'), fileDetails);
737
+ delete rec[fieldName];
738
+ });
739
+ // Serialize the remaining fields as JSON
740
+ form.append(type, JSON.stringify(rec), {
741
+ contentType: 'application/json',
742
+ });
743
+ contentType = form.getHeaders()['content-type']; // This is necessary to ensure the 'boundary' is present
744
+ body = form;
745
+ }
746
+ else {
747
+ // Default behavior: send the request as JSON
748
+ contentType = 'application/json';
749
+ body = JSON.stringify(rec);
750
+ }
751
+ return this.request({
752
+ method: 'POST',
753
+ url,
754
+ body: body,
755
+ headers: {
756
+ ...(options.headers || {}),
757
+ 'content-type': contentType,
758
+ },
759
+ });
760
+ }
761
+ /** @private */
762
+ async _createParallel(type, records, options) {
763
+ if (records.length > this._maxRequest) {
764
+ throw new Error('Exceeded max limit of concurrent call');
765
+ }
766
+ return Promise.all(records.map((record) => this._createSingle(type, record, options).catch((err) => {
767
+ // be aware that allOrNone in parallel mode will not revert the other successful requests
768
+ // it only raises error when met at least one failed request.
769
+ if (options.allOrNone || !err.errorCode) {
770
+ throw err;
771
+ }
772
+ return toSaveResult(err);
773
+ })));
774
+ }
775
+ /** @private */
776
+ async _createMany(type, records, options) {
777
+ if (records.length === 0) {
778
+ return Promise.resolve([]);
779
+ }
780
+ if (records.length > MAX_DML_COUNT && options.allowRecursive) {
781
+ return [
782
+ ...(await this._createMany(type, records.slice(0, MAX_DML_COUNT), options)),
783
+ ...(await this._createMany(type, records.slice(MAX_DML_COUNT), options)),
784
+ ];
785
+ }
786
+ const _records = records.map((record) => {
787
+ const { Id, type: rtype, attributes, ...rec } = record;
788
+ const sobjectType = type || (attributes && attributes.type) || rtype;
789
+ if (!sobjectType) {
790
+ throw new Error('No SObject Type defined in record');
791
+ }
792
+ return { attributes: { type: sobjectType }, ...rec };
793
+ });
794
+ const url = [this._baseUrl(), 'composite', 'sobjects'].join('/');
795
+ return this.request({
796
+ method: 'POST',
797
+ url,
798
+ body: JSON.stringify({
799
+ allOrNone: options.allOrNone || false,
800
+ records: _records,
801
+ }),
802
+ headers: {
803
+ ...(options.headers || {}),
804
+ 'content-type': 'application/json',
805
+ },
806
+ });
807
+ }
808
+ /**
809
+ * Synonym of Connection#create()
810
+ */
811
+ insert = this.create;
812
+ /**
813
+ * @param type
814
+ * @param records
815
+ * @param options
816
+ */
817
+ update(type, records, options = {}) {
818
+ return Array.isArray(records)
819
+ ? // check the version whether SObject collection API is supported (42.0)
820
+ this._ensureVersion(42)
821
+ ? this._updateMany(type, records, options)
822
+ : this._updateParallel(type, records, options)
823
+ : this._updateSingle(type, records, options);
824
+ }
825
+ /** @private */
826
+ async _updateSingle(type, record, options) {
827
+ const { Id: id, type: rtype, attributes, ...rec } = record;
828
+ if (!id) {
829
+ throw new Error('Record id is not found in record.');
830
+ }
831
+ const sobjectType = type || (attributes && attributes.type) || rtype;
832
+ if (!sobjectType) {
833
+ throw new Error('No SObject Type defined in record');
834
+ }
835
+ const url = [this._baseUrl(), 'sobjects', sobjectType, id].join('/');
836
+ return this.request({
837
+ method: 'PATCH',
838
+ url,
839
+ body: JSON.stringify(rec),
840
+ headers: {
841
+ ...(options.headers || {}),
842
+ 'content-type': 'application/json',
843
+ },
844
+ }, {
845
+ noContentResponse: { id, success: true, errors: [] },
846
+ });
847
+ }
848
+ /** @private */
849
+ async _updateParallel(type, records, options) {
850
+ if (records.length > this._maxRequest) {
851
+ throw new Error('Exceeded max limit of concurrent call');
852
+ }
853
+ return Promise.all(records.map((record) => this._updateSingle(type, record, options).catch((err) => {
854
+ // be aware that allOrNone in parallel mode will not revert the other successful requests
855
+ // it only raises error when met at least one failed request.
856
+ if (options.allOrNone || !err.errorCode) {
857
+ throw err;
858
+ }
859
+ return toSaveResult(err);
860
+ })));
861
+ }
862
+ /** @private */
863
+ async _updateMany(type, records, options) {
864
+ if (records.length === 0) {
865
+ return [];
866
+ }
867
+ if (records.length > MAX_DML_COUNT && options.allowRecursive) {
868
+ return [
869
+ ...(await this._updateMany(type, records.slice(0, MAX_DML_COUNT), options)),
870
+ ...(await this._updateMany(type, records.slice(MAX_DML_COUNT), options)),
871
+ ];
872
+ }
873
+ const _records = records.map((record) => {
874
+ const { Id: id, type: rtype, attributes, ...rec } = record;
875
+ if (!id) {
876
+ throw new Error('Record id is not found in record.');
877
+ }
878
+ const sobjectType = type || (attributes && attributes.type) || rtype;
879
+ if (!sobjectType) {
880
+ throw new Error('No SObject Type defined in record');
881
+ }
882
+ return { id, attributes: { type: sobjectType }, ...rec };
883
+ });
884
+ const url = [this._baseUrl(), 'composite', 'sobjects'].join('/');
885
+ return this.request({
886
+ method: 'PATCH',
887
+ url,
888
+ body: JSON.stringify({
889
+ allOrNone: options.allOrNone || false,
890
+ records: _records,
891
+ }),
892
+ headers: {
893
+ ...(options.headers || {}),
894
+ 'content-type': 'application/json',
895
+ },
896
+ });
897
+ }
898
+ /**
899
+ *
900
+ * @param type
901
+ * @param records
902
+ * @param extIdField
903
+ * @param options
904
+ */
905
+ async upsert(type, records, extIdField, options = {}) {
906
+ const isArray = Array.isArray(records);
907
+ const _records = Array.isArray(records) ? records : [records];
908
+ if (_records.length > this._maxRequest) {
909
+ throw new Error('Exceeded max limit of concurrent call');
910
+ }
911
+ const results = await Promise.all(_records.map((record) => {
912
+ const { [extIdField]: extId, type: rtype, attributes, ...rec } = record;
913
+ const url = [this._baseUrl(), 'sobjects', type, extIdField, extId].join('/');
914
+ return this.request({
915
+ method: 'PATCH',
916
+ url,
917
+ body: JSON.stringify(rec),
918
+ headers: {
919
+ ...(options.headers || {}),
920
+ 'content-type': 'application/json',
921
+ },
922
+ }, {
923
+ noContentResponse: { success: true, errors: [] },
924
+ }).catch((err) => {
925
+ // Be aware that `allOrNone` option in upsert method
926
+ // will not revert the other successful requests.
927
+ // It only raises error when met at least one failed request.
928
+ if (!isArray || options.allOrNone || !err.errorCode) {
929
+ throw err;
930
+ }
931
+ return toSaveResult(err);
932
+ });
933
+ }));
934
+ return isArray ? results : results[0];
935
+ }
936
+ /**
937
+ * @param type
938
+ * @param ids
939
+ * @param options
940
+ */
941
+ async destroy(type, ids, options = {}) {
942
+ return Array.isArray(ids)
943
+ ? // check the version whether SObject collection API is supported (42.0)
944
+ this._ensureVersion(42)
945
+ ? this._destroyMany(type, ids, options)
946
+ : this._destroyParallel(type, ids, options)
947
+ : this._destroySingle(type, ids, options);
948
+ }
949
+ /** @private */
950
+ async _destroySingle(type, id, options) {
951
+ const url = [this._baseUrl(), 'sobjects', type, id].join('/');
952
+ return this.request({
953
+ method: 'DELETE',
954
+ url,
955
+ headers: options.headers || {},
956
+ }, {
957
+ noContentResponse: { id, success: true, errors: [] },
958
+ });
959
+ }
960
+ /** @private */
961
+ async _destroyParallel(type, ids, options) {
962
+ if (ids.length > this._maxRequest) {
963
+ throw new Error('Exceeded max limit of concurrent call');
964
+ }
965
+ return Promise.all(ids.map((id) => this._destroySingle(type, id, options).catch((err) => {
966
+ // Be aware that `allOrNone` option in parallel mode
967
+ // will not revert the other successful requests.
968
+ // It only raises error when met at least one failed request.
969
+ if (options.allOrNone || !err.errorCode) {
970
+ throw err;
971
+ }
972
+ return toSaveResult(err);
973
+ })));
974
+ }
975
+ /** @private */
976
+ async _destroyMany(type, ids, options) {
977
+ if (ids.length === 0) {
978
+ return [];
979
+ }
980
+ if (ids.length > MAX_DML_COUNT && options.allowRecursive) {
981
+ return [
982
+ ...(await this._destroyMany(type, ids.slice(0, MAX_DML_COUNT), options)),
983
+ ...(await this._destroyMany(type, ids.slice(MAX_DML_COUNT), options)),
984
+ ];
985
+ }
986
+ let url = [this._baseUrl(), 'composite', 'sobjects?ids='].join('/') + ids.join(',');
987
+ if (options.allOrNone) {
988
+ url += '&allOrNone=true';
989
+ }
990
+ return this.request({
991
+ method: 'DELETE',
992
+ url,
993
+ headers: options.headers || {},
994
+ });
995
+ }
996
+ /**
997
+ * Synonym of Connection#destroy()
998
+ */
999
+ delete = this.destroy;
1000
+ /**
1001
+ * Synonym of Connection#destroy()
1002
+ */
1003
+ del = this.destroy;
1004
+ /**
1005
+ * Describe SObject metadata
1006
+ */
1007
+ async describe(type) {
1008
+ const url = [this._baseUrl(), 'sobjects', type, 'describe'].join('/');
1009
+ const body = await this.request(url);
1010
+ return body;
1011
+ }
1012
+ /**
1013
+ * Describe global SObjects
1014
+ */
1015
+ async describeGlobal() {
1016
+ const url = `${this._baseUrl()}/sobjects`;
1017
+ const body = await this.request(url);
1018
+ return body;
1019
+ }
1020
+ sobject(type) {
1021
+ const so = this.sobjects[type] ||
1022
+ new sobject_1.default(this, type);
1023
+ this.sobjects[type] = so;
1024
+ return so;
1025
+ }
1026
+ /**
1027
+ * Get identity information of current user
1028
+ */
1029
+ async identity(options = {}) {
1030
+ let url = this.userInfo && this.userInfo.url;
1031
+ if (!url) {
1032
+ const res = await this.request({
1033
+ method: 'GET',
1034
+ url: this._baseUrl(),
1035
+ headers: options.headers,
1036
+ });
1037
+ url = res.identity;
1038
+ }
1039
+ url += '?format=json';
1040
+ if (this.accessToken) {
1041
+ url += `&oauth_token=${encodeURIComponent(this.accessToken)}`;
1042
+ }
1043
+ const res = await this.request({ method: 'GET', url });
1044
+ this.userInfo = {
1045
+ id: res.user_id,
1046
+ organizationId: res.organization_id,
1047
+ url: res.id,
1048
+ };
1049
+ return res;
1050
+ }
1051
+ /**
1052
+ * List recently viewed records
1053
+ */
1054
+ async recent(type, limit) {
1055
+ /* eslint-disable no-param-reassign */
1056
+ if (typeof type === 'number') {
1057
+ limit = type;
1058
+ type = undefined;
1059
+ }
1060
+ let url;
1061
+ if (type) {
1062
+ url = [this._baseUrl(), 'sobjects', type].join('/');
1063
+ const { recentItems } = await this.request(url);
1064
+ return limit ? recentItems.slice(0, limit) : recentItems;
1065
+ }
1066
+ url = `${this._baseUrl()}/recent`;
1067
+ if (limit) {
1068
+ url += `?limit=${limit}`;
1069
+ }
1070
+ return this.request(url);
1071
+ }
1072
+ /**
1073
+ * Retrieve updated records
1074
+ */
1075
+ async updated(type, start, end) {
1076
+ /* eslint-disable no-param-reassign */
1077
+ let url = [this._baseUrl(), 'sobjects', type, 'updated'].join('/');
1078
+ if (typeof start === 'string') {
1079
+ start = new Date(start);
1080
+ }
1081
+ start = (0, formatter_1.formatDate)(start);
1082
+ url += `?start=${encodeURIComponent(start)}`;
1083
+ if (typeof end === 'string') {
1084
+ end = new Date(end);
1085
+ }
1086
+ end = (0, formatter_1.formatDate)(end);
1087
+ url += `&end=${encodeURIComponent(end)}`;
1088
+ const body = await this.request(url);
1089
+ return body;
1090
+ }
1091
+ /**
1092
+ * Retrieve deleted records
1093
+ */
1094
+ async deleted(type, start, end) {
1095
+ /* eslint-disable no-param-reassign */
1096
+ let url = [this._baseUrl(), 'sobjects', type, 'deleted'].join('/');
1097
+ if (typeof start === 'string') {
1098
+ start = new Date(start);
1099
+ }
1100
+ start = (0, formatter_1.formatDate)(start);
1101
+ url += `?start=${encodeURIComponent(start)}`;
1102
+ if (typeof end === 'string') {
1103
+ end = new Date(end);
1104
+ }
1105
+ end = (0, formatter_1.formatDate)(end);
1106
+ url += `&end=${encodeURIComponent(end)}`;
1107
+ const body = await this.request(url);
1108
+ return body;
1109
+ }
1110
+ /**
1111
+ * Returns a list of all tabs
1112
+ */
1113
+ async tabs() {
1114
+ const url = [this._baseUrl(), 'tabs'].join('/');
1115
+ const body = await this.request(url);
1116
+ return body;
1117
+ }
1118
+ /**
1119
+ * Returns current system limit in the organization
1120
+ */
1121
+ async limits() {
1122
+ const url = [this._baseUrl(), 'limits'].join('/');
1123
+ const body = await this.request(url);
1124
+ return body;
1125
+ }
1126
+ /**
1127
+ * Returns a theme info
1128
+ */
1129
+ async theme() {
1130
+ const url = [this._baseUrl(), 'theme'].join('/');
1131
+ const body = await this.request(url);
1132
+ return body;
1133
+ }
1134
+ /**
1135
+ * Returns all registered global quick actions
1136
+ */
1137
+ async quickActions() {
1138
+ const body = await this.request('/quickActions');
1139
+ return body;
1140
+ }
1141
+ /**
1142
+ * Get reference for specified global quick action
1143
+ */
1144
+ quickAction(actionName) {
1145
+ return new quick_action_1.default(this, `/quickActions/${actionName}`);
1146
+ }
1147
+ /**
1148
+ * Module which manages process rules and approval processes
1149
+ */
1150
+ process = new process_1.default(this);
1151
+ }
1152
+ exports.Connection = Connection;
1153
+ exports.default = Connection;