jsforce2 1.11.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.
Files changed (80) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +74 -0
  3. package/bin/jsforce +3 -0
  4. package/bower.json +30 -0
  5. package/build/jsforce-api-analytics.js +393 -0
  6. package/build/jsforce-api-analytics.min.js +2 -0
  7. package/build/jsforce-api-analytics.min.js.map +1 -0
  8. package/build/jsforce-api-apex.js +183 -0
  9. package/build/jsforce-api-apex.min.js +2 -0
  10. package/build/jsforce-api-apex.min.js.map +1 -0
  11. package/build/jsforce-api-bulk.js +1054 -0
  12. package/build/jsforce-api-bulk.min.js +2 -0
  13. package/build/jsforce-api-bulk.min.js.map +1 -0
  14. package/build/jsforce-api-chatter.js +320 -0
  15. package/build/jsforce-api-chatter.min.js +2 -0
  16. package/build/jsforce-api-chatter.min.js.map +1 -0
  17. package/build/jsforce-api-metadata.js +3020 -0
  18. package/build/jsforce-api-metadata.min.js +2 -0
  19. package/build/jsforce-api-metadata.min.js.map +1 -0
  20. package/build/jsforce-api-soap.js +403 -0
  21. package/build/jsforce-api-soap.min.js +2 -0
  22. package/build/jsforce-api-soap.min.js.map +1 -0
  23. package/build/jsforce-api-streaming.js +3479 -0
  24. package/build/jsforce-api-streaming.min.js +2 -0
  25. package/build/jsforce-api-streaming.min.js.map +1 -0
  26. package/build/jsforce-api-tooling.js +319 -0
  27. package/build/jsforce-api-tooling.min.js +2 -0
  28. package/build/jsforce-api-tooling.min.js.map +1 -0
  29. package/build/jsforce-core.js +25250 -0
  30. package/build/jsforce-core.min.js +2 -0
  31. package/build/jsforce-core.min.js.map +1 -0
  32. package/build/jsforce.js +31637 -0
  33. package/build/jsforce.min.js +2 -0
  34. package/build/jsforce.min.js.map +1 -0
  35. package/core.js +1 -0
  36. package/index.js +1 -0
  37. package/lib/VERSION.js +2 -0
  38. package/lib/_required.js +29 -0
  39. package/lib/api/analytics.js +387 -0
  40. package/lib/api/apex.js +177 -0
  41. package/lib/api/bulk.js +862 -0
  42. package/lib/api/chatter.js +314 -0
  43. package/lib/api/index.js +8 -0
  44. package/lib/api/metadata.js +848 -0
  45. package/lib/api/soap.js +397 -0
  46. package/lib/api/streaming-extension.js +136 -0
  47. package/lib/api/streaming.js +270 -0
  48. package/lib/api/tooling.js +313 -0
  49. package/lib/browser/canvas.js +90 -0
  50. package/lib/browser/client.js +241 -0
  51. package/lib/browser/core.js +5 -0
  52. package/lib/browser/jsforce.js +6 -0
  53. package/lib/browser/jsonp.js +52 -0
  54. package/lib/browser/request.js +70 -0
  55. package/lib/cache.js +252 -0
  56. package/lib/cli/cli.js +431 -0
  57. package/lib/cli/repl.js +337 -0
  58. package/lib/connection.js +1881 -0
  59. package/lib/core.js +16 -0
  60. package/lib/csv.js +50 -0
  61. package/lib/date.js +163 -0
  62. package/lib/http-api.js +300 -0
  63. package/lib/jsforce.js +10 -0
  64. package/lib/logger.js +52 -0
  65. package/lib/oauth2.js +206 -0
  66. package/lib/process.js +275 -0
  67. package/lib/promise.js +164 -0
  68. package/lib/query.js +881 -0
  69. package/lib/quick-action.js +90 -0
  70. package/lib/record-stream.js +305 -0
  71. package/lib/record.js +107 -0
  72. package/lib/registry/file-registry.js +48 -0
  73. package/lib/registry/index.js +3 -0
  74. package/lib/registry/registry.js +111 -0
  75. package/lib/require.js +14 -0
  76. package/lib/soap.js +207 -0
  77. package/lib/sobject.js +558 -0
  78. package/lib/soql-builder.js +236 -0
  79. package/lib/transport.js +233 -0
  80. package/package.json +110 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * @file Manages Streaming APIs
3
+ * @author Shinichi Tomita <shinichi.tomita@gmail.com>
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ var events = require('events'),
9
+ inherits = require('inherits'),
10
+ _ = require('lodash/core'),
11
+ Faye = require('faye'),
12
+ StreamingExtension = require('./streaming-extension'),
13
+ jsforce = require('../core');
14
+
15
+ /**
16
+ * Streaming API topic class
17
+ *
18
+ * @class Streaming~Topic
19
+ * @param {Streaming} steaming - Streaming API object
20
+ * @param {String} name - Topic name
21
+ */
22
+ var Topic = function(streaming, name) {
23
+ this._streaming = streaming;
24
+ this.name = name;
25
+ };
26
+
27
+ /**
28
+ * @typedef {Object} Streaming~StreamingMessage
29
+ * @prop {Object} event
30
+ * @prop {Object} event.type - Event type
31
+ * @prop {Record} sobject - Record information
32
+ */
33
+ /**
34
+ * Subscribe listener to topic
35
+ *
36
+ * @method Streaming~Topic#subscribe
37
+ * @param {Callback.<Streaming~StreamingMesasge>} listener - Streaming message listener
38
+ * @returns {Subscription} - Faye subscription object
39
+ */
40
+ Topic.prototype.subscribe = function(listener) {
41
+ return this._streaming.subscribe(this.name, listener);
42
+ };
43
+
44
+ /**
45
+ * Unsubscribe listener from topic
46
+ *
47
+ * @method Streaming~Topic#unsubscribe
48
+ * @param {Callback.<Streaming~StreamingMesasge>} listener - Streaming message listener
49
+ * @returns {Streaming~Topic}
50
+ */
51
+ Topic.prototype.unsubscribe = function(listener) {
52
+ this._streaming.unsubscribe(this.name, listener);
53
+ return this;
54
+ };
55
+
56
+ /*--------------------------------------------*/
57
+
58
+ /**
59
+ * Streaming API Generic Streaming Channel
60
+ *
61
+ * @class Streaming~Channel
62
+ * @param {Streaming} steaming - Streaming API object
63
+ * @param {String} name - Channel name (starts with "/u/")
64
+ */
65
+ var Channel = function(streaming, name) {
66
+ this._streaming = streaming;
67
+ this._name = name;
68
+ };
69
+
70
+ /**
71
+ * Subscribe to channel
72
+ *
73
+ * @param {Callback.<Streaming~StreamingMessage>} listener - Streaming message listener
74
+ * @returns {Subscription} - Faye subscription object
75
+ */
76
+ Channel.prototype.subscribe = function(listener) {
77
+ return this._streaming.subscribe(this._name, listener);
78
+ };
79
+
80
+ Channel.prototype.unsubscribe = function(listener) {
81
+ this._streaming.unsubscribe(this._name, listener);
82
+ return this;
83
+ };
84
+
85
+ Channel.prototype.push = function(events, callback) {
86
+ var isArray = _.isArray(events);
87
+ events = isArray ? events : [ events ];
88
+ var conn = this._streaming._conn;
89
+ if (!this._id) {
90
+ this._id = conn.sobject('StreamingChannel').findOne({ Name: this._name }, 'Id')
91
+ .then(function(rec) { return rec.Id });
92
+ }
93
+ return this._id.then(function(id) {
94
+ var channelUrl = '/sobjects/StreamingChannel/' + id + '/push';
95
+ return conn.requestPost(channelUrl, { pushEvents: events });
96
+ }).then(function(rets) {
97
+ return isArray ? rets : rets[0];
98
+ }).thenCall(callback);
99
+ };
100
+
101
+ /*--------------------------------------------*/
102
+
103
+ /**
104
+ * Streaming API class
105
+ *
106
+ * @class
107
+ * @extends events.EventEmitter
108
+ * @param {Connection} conn - Connection object
109
+ */
110
+ var Streaming = function(conn) {
111
+ this._conn = conn;
112
+ };
113
+
114
+ inherits(Streaming, events.EventEmitter);
115
+
116
+ /** @private **/
117
+ Streaming.prototype._createClient = function(forChannelName, extensions) {
118
+ // forChannelName is advisory, for an API workaround. It does not restrict or select the channel.
119
+ var needsReplayFix = typeof forChannelName === 'string' && forChannelName.indexOf('/u/') === 0;
120
+ var endpointUrl = [
121
+ this._conn.instanceUrl,
122
+ // special endpoint "/cometd/replay/xx.x" is only available in 36.0.
123
+ // See https://releasenotes.docs.salesforce.com/en-us/summer16/release-notes/rn_api_streaming_classic_replay.htm
124
+ "cometd" + (needsReplayFix === true && this._conn.version === "36.0" ? "/replay" : ""),
125
+ this._conn.version
126
+ ].join('/');
127
+ var fayeClient = new Faye.Client(endpointUrl, {});
128
+ fayeClient.setHeader('Authorization', 'OAuth '+this._conn.accessToken);
129
+ if (extensions instanceof Array) {
130
+ extensions.forEach(function(extension) {
131
+ fayeClient.addExtension(extension);
132
+ });
133
+ }
134
+ if (fayeClient._dispatcher.getConnectionTypes().indexOf('callback-polling') === -1) {
135
+ // prevent streaming API server error
136
+ fayeClient._dispatcher.selectTransport('long-polling');
137
+ fayeClient._dispatcher._transport.batching = false;
138
+ }
139
+ return fayeClient;
140
+ };
141
+
142
+ /** @private **/
143
+ Streaming.prototype._getFayeClient = function(channelName) {
144
+ var isGeneric = channelName.indexOf('/u/') === 0;
145
+ var clientType = isGeneric ? 'generic' : 'pushTopic';
146
+ if (!this._fayeClients || !this._fayeClients[clientType]) {
147
+ this._fayeClients = this._fayeClients || {};
148
+ this._fayeClients[clientType] = this._createClient(channelName);
149
+ }
150
+ return this._fayeClients[clientType];
151
+ };
152
+
153
+
154
+ /**
155
+ * Get named topic
156
+ *
157
+ * @param {String} name - Topic name
158
+ * @returns {Streaming~Topic}
159
+ */
160
+ Streaming.prototype.topic = function(name) {
161
+ this._topics = this._topics || {};
162
+ var topic = this._topics[name] =
163
+ this._topics[name] || new Topic(this, name);
164
+ return topic;
165
+ };
166
+
167
+ /**
168
+ * Get Channel for Id
169
+ * @param {String} channelId - Id of StreamingChannel object
170
+ * @returns {Streaming~Channel}
171
+ */
172
+ Streaming.prototype.channel = function(channelId) {
173
+ return new Channel(this, channelId);
174
+ };
175
+
176
+ /**
177
+ * Subscribe topic/channel
178
+ *
179
+ * @param {String} name - Topic name
180
+ * @param {Callback.<Streaming~StreamingMessage>} listener - Streaming message listener
181
+ * @returns {Subscription} - Faye subscription object
182
+ */
183
+ Streaming.prototype.subscribe = function(name, listener) {
184
+ var channelName = name.indexOf('/') === 0 ? name : '/topic/' + name;
185
+ var fayeClient = this._getFayeClient(channelName);
186
+ return fayeClient.subscribe(channelName, listener);
187
+ };
188
+
189
+ /**
190
+ * Unsubscribe topic
191
+ *
192
+ * @param {String} name - Topic name
193
+ * @param {Callback.<Streaming~StreamingMessage>} listener - Streaming message listener
194
+ * @returns {Streaming}
195
+ */
196
+ Streaming.prototype.unsubscribe = function(name, listener) {
197
+ var channelName = name.indexOf('/') === 0 ? name : '/topic/' + name;
198
+ var fayeClient = this._getFayeClient(channelName);
199
+ fayeClient.unsubscribe(channelName, listener);
200
+ return this;
201
+ };
202
+
203
+
204
+ /**
205
+ * Create a Streaming client, optionally with extensions
206
+ *
207
+ * See Faye docs for implementation details: https://faye.jcoglan.com/browser/extensions.html
208
+ *
209
+ * Example usage:
210
+ *
211
+ * ```javascript
212
+ * // Establish a Salesforce connection. (Details elided)
213
+ * const conn = new jsforce.Connection({ … });
214
+ *
215
+ * const fayeClient = conn.streaming.createClient();
216
+ *
217
+ * const subscription = fayeClient.subscribe(channel, data => {
218
+ * console.log('topic received data', data);
219
+ * });
220
+ *
221
+ * subscription.cancel();
222
+ * ```
223
+ *
224
+ * Example with extensions, using Replay & Auth Failure extensions in a server-side Node.js app:
225
+ *
226
+ * ```javascript
227
+ * // Establish a Salesforce connection. (Details elided)
228
+ * const conn = new jsforce.Connection({ … });
229
+ *
230
+ * const channel = "/event/My_Event__e";
231
+ * const replayId = -2; // -2 is all retained events
232
+ *
233
+ * const exitCallback = () => process.exit(1);
234
+ * const authFailureExt = new jsforce.StreamingExtension.AuthFailure(exitCallback);
235
+ *
236
+ * const replayExt = new jsforce.StreamingExtension.Replay(channel, replayId);
237
+ *
238
+ * const fayeClient = conn.streaming.createClient([
239
+ * authFailureExt,
240
+ * replayExt
241
+ * ]);
242
+ *
243
+ * const subscription = fayeClient.subscribe(channel, data => {
244
+ * console.log('topic received data', data);
245
+ * });
246
+ *
247
+ * subscription.cancel();
248
+ * ```
249
+ *
250
+ * @param {Array} Extensions - Optional, extensions to apply to the Faye client
251
+ * @returns {FayeClient} - Faye client object
252
+ */
253
+ Streaming.prototype.createClient = function(extensions) {
254
+ return this._createClient(null, extensions);
255
+ };
256
+
257
+ /*--------------------------------------------*/
258
+ /*
259
+ * Register hook in connection instantiation for dynamically adding this API module features
260
+ */
261
+ jsforce.on('connection:new', function(conn) {
262
+ conn.streaming = new Streaming(conn);
263
+ });
264
+
265
+ /*
266
+ *
267
+ */
268
+ jsforce.StreamingExtension = StreamingExtension;
269
+
270
+ module.exports = Streaming;
@@ -0,0 +1,313 @@
1
+ /**
2
+ * @file Manages Tooling APIs
3
+ * @author Shinichi Tomita <shinichi.tomita@gmail.com>
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ var jsforce = require('../core'),
9
+ _ = require('lodash/core'),
10
+ Cache = require('../cache');
11
+
12
+ /**
13
+ * API class for Tooling API call
14
+ *
15
+ * @class
16
+ * @param {Connection} conn - Connection
17
+ */
18
+ var Tooling = function(conn) {
19
+ this._conn = conn;
20
+ this._logger = conn._logger;
21
+ var delegates = [
22
+ "query",
23
+ "queryMore",
24
+ "_toRecordResult",
25
+ "create",
26
+ "_createSingle",
27
+ "_createParallel",
28
+ "_createMany",
29
+ "insert",
30
+ "retrieve",
31
+ "_retrieveSingle",
32
+ "_retrieveParallel",
33
+ "_retrieveMany",
34
+ "update",
35
+ "_updateSingle",
36
+ "_updateParallel",
37
+ "_updateMany",
38
+ "upsert",
39
+ "del",
40
+ "delete",
41
+ "destroy",
42
+ "_destroySingle",
43
+ "_destroyParallel",
44
+ "_destroyMany",
45
+ "describe",
46
+ "describeGlobal",
47
+ "sobject"
48
+ ];
49
+ delegates.forEach(function(method) {
50
+ this[method] = conn.constructor.prototype[method];
51
+ }, this);
52
+
53
+ this.cache = new Cache();
54
+
55
+ var cacheOptions = {
56
+ key: function(type) { return type ? "describe." + type : "describe"; }
57
+ };
58
+ this.describe$ = this.cache.makeCacheable(this.describe, this, cacheOptions);
59
+ this.describe = this.cache.makeResponseCacheable(this.describe, this, cacheOptions);
60
+ this.describeSObject$ = this.describe$;
61
+ this.describeSObject = this.describe;
62
+
63
+ cacheOptions = { key: 'describeGlobal' };
64
+ this.describeGlobal$ = this.cache.makeCacheable(this.describeGlobal, this, cacheOptions);
65
+ this.describeGlobal = this.cache.makeResponseCacheable(this.describeGlobal, this, cacheOptions);
66
+
67
+ this.initialize();
68
+ };
69
+
70
+ /**
71
+ * Initialize tooling API
72
+ * @protected
73
+ */
74
+ Tooling.prototype.initialize = function() {
75
+ this.sobjects = {};
76
+ this.cache.clear();
77
+ this.cache.get('describeGlobal').removeAllListeners('value');
78
+ this.cache.get('describeGlobal').on('value', _.bind(function(res) {
79
+ if (res.result) {
80
+ var types = _.map(res.result.sobjects, function(so) { return so.name; });
81
+ types.forEach(this.sobject, this);
82
+ }
83
+ }, this));
84
+ };
85
+
86
+ /**
87
+ * @private
88
+ */
89
+ Tooling.prototype._baseUrl = function() {
90
+ return this._conn._baseUrl() + "/tooling";
91
+ };
92
+
93
+ /**
94
+ * @private
95
+ */
96
+ Tooling.prototype._supports = function(feature) {
97
+ // should return false in order not to use compsite collection
98
+ if (feature === 'sobject-collection') {
99
+ return false;
100
+ }
101
+ return this._conn._supports.apply(this._conn, arguments);
102
+ };
103
+
104
+ /**
105
+ * @private
106
+ */
107
+ Tooling.prototype.request = function() {
108
+ return this._conn.request.apply(this._conn, arguments);
109
+ };
110
+
111
+ /**
112
+ * Execute query by using SOQL
113
+ *
114
+ * @param {String} soql - SOQL string
115
+ * @param {Callback.<QueryResult>} [callback] - Callback function
116
+ * @returns {Query.<QueryResult>}
117
+ */
118
+ /**
119
+ * Query next record set by using query locator
120
+ *
121
+ * @method Tooling#query
122
+ * @param {String} locator - Next record set locator
123
+ * @param {Callback.<QueryResult>} [callback] - Callback function
124
+ * @returns {Query.<QueryResult>}
125
+ */
126
+ /**
127
+ * Retrieve specified records
128
+ *
129
+ * @method Tooling#queryMore
130
+ * @param {String} type - SObject Type
131
+ * @param {String|Array.<String>} ids - A record ID or array of record IDs
132
+ * @param {Callback.<Record|Array.<Record>>} [callback] - Callback function
133
+ * @returns {Promise.<Record|Array.<Record>>}
134
+ */
135
+
136
+ /**
137
+ * Synonym of Tooling#create()
138
+ *
139
+ * @method Tooling#insert
140
+ * @param {String} type - SObject Type
141
+ * @param {Object|Array.<Object>} records - A record or array of records to create
142
+ * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
143
+ * @returns {Promise.<RecordResult|Array.<RecordResult>>}
144
+ */
145
+ /**
146
+ * Create records
147
+ *
148
+ * @method Tooling#create
149
+ * @param {String} type - SObject Type
150
+ * @param {Record|Array.<Record>} records - A record or array of records to create
151
+ * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
152
+ * @returns {Promise.<RecordResult|Array.<RecordResult>>}
153
+ */
154
+
155
+ /**
156
+ * Update records
157
+ *
158
+ * @method Tooling#update
159
+ * @param {String} type - SObject Type
160
+ * @param {Record|Array.<Record>} records - A record or array of records to update
161
+ * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
162
+ * @returns {Promise.<RecordResult|Array.<RecordResult>>}
163
+ */
164
+
165
+ /**
166
+ * Upsert records
167
+ *
168
+ * @method Tooling#upsert
169
+ * @param {String} type - SObject Type
170
+ * @param {Record|Array.<Record>} records - Record or array of records to upsert
171
+ * @param {String} extIdField - External ID field name
172
+ * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
173
+ * @returns {Promise.<RecordResult|Array.<RecordResult>>}
174
+ */
175
+
176
+ /**
177
+ * Synonym of Tooling#destroy()
178
+ *
179
+ * @method Tooling#delete
180
+ * @param {String} type - SObject Type
181
+ * @param {String|Array.<String>} ids - A ID or array of IDs to delete
182
+ * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
183
+ * @returns {Promise.<RecordResult|Array.<RecordResult>>}
184
+ */
185
+ /**
186
+ * Synonym of Tooling#destroy()
187
+ *
188
+ * @method Tooling#del
189
+ * @param {String} type - SObject Type
190
+ * @param {String|Array.<String>} ids - A ID or array of IDs to delete
191
+ * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
192
+ * @returns {Promise.<RecordResult|Array.<RecordResult>>}
193
+ */
194
+ /**
195
+ * Delete records
196
+ *
197
+ * @method Tooling#destroy
198
+ * @param {String} type - SObject Type
199
+ * @param {String|Array.<String>} ids - A ID or array of IDs to delete
200
+ * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
201
+ * @returns {Promise.<RecordResult|Array.<RecordResult>>}
202
+ */
203
+
204
+ /**
205
+ * Synonym of Tooling#describe()
206
+ *
207
+ * @method Tooling#describeSObject
208
+ * @param {String} type - SObject Type
209
+ * @param {Callback.<DescribeSObjectResult>} [callback] - Callback function
210
+ * @returns {Promise.<DescribeSObjectResult>}
211
+ */
212
+ /**
213
+ * Describe SObject metadata
214
+ *
215
+ * @method Tooling#describe
216
+ * @param {String} type - SObject Type
217
+ * @param {Callback.<DescribeSObjectResult>} [callback] - Callback function
218
+ * @returns {Promise.<DescribeSObjectResult>}
219
+ */
220
+
221
+ /**
222
+ * Describe global SObjects
223
+ *
224
+ * @method Tooling#describeGlobal
225
+ * @param {Callback.<DescribeGlobalResult>} [callback] - Callback function
226
+ * @returns {Promise.<DescribeGlobalResult>}
227
+ */
228
+
229
+ /**
230
+ * Get SObject instance
231
+ *
232
+ * @method Tooling#sobject
233
+ * @param {String} type - SObject Type
234
+ * @returns {SObject}
235
+ */
236
+
237
+ /**
238
+ * @typedef {Object} Tooling~ExecuteAnonymousResult
239
+ * @prop {Boolean} compiled - Flag if the query is compiled successfully
240
+ * @prop {String} compileProblem - Error reason in compilation
241
+ * @prop {Boolean} success - Flag if the code is executed successfully
242
+ * @prop {Number} line - Line number for the error
243
+ * @prop {Number} column - Column number for the error
244
+ * @prop {String} exceptionMessage - Exception message
245
+ * @prop {String} exceptionStackTrace - Exception stack trace
246
+ */
247
+ /**
248
+ * Executes Apex code anonymously
249
+ *
250
+ * @param {String} body - Anonymous Apex code
251
+ * @param {Callback.<Tooling~ExecuteAnonymousResult>} [callback] - Callback function
252
+ * @returns {Promise.<Tooling~ExecuteAnonymousResult>}
253
+ */
254
+ Tooling.prototype.executeAnonymous = function(body, callback) {
255
+ var url = this._baseUrl() + "/executeAnonymous?anonymousBody=" + encodeURIComponent(body);
256
+ return this.request(url).thenCall(callback);
257
+ };
258
+
259
+ /**
260
+ * Executes Apex tests asynchronously
261
+ *
262
+ * @param {Array.<String>} classids - Comma separated list of class IDs
263
+ * @param {Callback.<Tooling~ExecuteAnonymousResult>} [callback] - Callback function
264
+ * @returns {Promise.<Tooling~ExecuteAnonymousResult>}
265
+ */
266
+ Tooling.prototype.runTestsAsynchronous = function(classids, callback) {
267
+ var url = this._baseUrl() + "/runTestsAsynchronous/";
268
+ return this._conn.requestPost(url, {classids : classids.join(',')}, undefined, callback);
269
+ };
270
+
271
+ /**
272
+ * Executes Apex tests synchronously
273
+ *
274
+ * @param {Array.<String>} classnames - Comma separated list of class Names
275
+ * @param {Callback.<Tooling~ExecuteAnonymousResult>} [callback] - Callback function
276
+ * @returns {Promise.<Tooling~ExecuteAnonymousResult>}
277
+ */
278
+ Tooling.prototype.runTestsSynchronous = function(classnames, callback) {
279
+ var url = this._baseUrl() + "/runTestsSynchronous/";
280
+ return this._conn.requestPost(url, {classnames : classnames.join(',')}, undefined, callback);
281
+ };
282
+
283
+ /**
284
+ * @typedef {Object} Tooling~CompletionsResult
285
+ * @prop {Object} publicDeclarations
286
+ */
287
+ /**
288
+ * Retrieves available code completions of the referenced type
289
+ *
290
+ * @param {String} [type] - completion type (default 'apex')
291
+ * @param {Callback.<Tooling~CompletionsResult>} [callback] - Callback function
292
+ * @returns {Promise.<Tooling~CompletionsResult>}
293
+ */
294
+ Tooling.prototype.completions = function(type, callback) {
295
+ if (!_.isString(type)) {
296
+ callback = type;
297
+ type = 'apex';
298
+ }
299
+ var url = this._baseUrl() + "/completions?type=" + encodeURIComponent(type);
300
+ return this.request(url).thenCall(callback);
301
+ };
302
+
303
+
304
+ /*--------------------------------------------*/
305
+ /*
306
+ * Register hook in connection instantiation for dynamically adding this API module features
307
+ */
308
+ jsforce.on('connection:new', function(conn) {
309
+ conn.tooling = new Tooling(conn);
310
+ });
311
+
312
+
313
+ module.exports = Tooling;
@@ -0,0 +1,90 @@
1
+ /*global Sfdc */
2
+ 'use strict';
3
+
4
+ var Duplex = require('readable-stream').Duplex,
5
+ _ = require('lodash/core');
6
+
7
+ function parseHeaders(hs) {
8
+ var headers = {};
9
+ hs.split(/\n/).forEach(function(line) {
10
+ var pair = line.split(/\s*:\s*/);
11
+ var name = pair[0].toLowerCase();
12
+ var value = pair[1];
13
+ headers[name] = value;
14
+ });
15
+ return headers;
16
+ }
17
+
18
+ module.exports = {
19
+
20
+ supported: typeof Sfdc === 'object' && typeof Sfdc.canvas !== 'undefined',
21
+
22
+ createRequest: function(signedRequest) {
23
+ return function(params, callback) {
24
+ var response;
25
+ var str = new Duplex();
26
+ str._read = function(size) {
27
+ if (response) {
28
+ str.push(response.body);
29
+ }
30
+ };
31
+ var bufs = [];
32
+ var sent = false;
33
+ str._write = function(chunk, encoding, callback) {
34
+ bufs.push(chunk.toString(encoding));
35
+ callback();
36
+ };
37
+ str.on('finish', function() {
38
+ if (!sent) {
39
+ send(bufs.join(''));
40
+ sent = true;
41
+ }
42
+ });
43
+ if (params.body || params.body === "" || !/^(put|post|patch)$/i.test(params.method)) {
44
+ send(params.body);
45
+ sent = true;
46
+ }
47
+
48
+ function send(body) {
49
+ var settings = {
50
+ client: signedRequest.client,
51
+ method: params.method,
52
+ data: body
53
+ };
54
+ if (params.headers) {
55
+ settings.headers = {};
56
+ for (var name in params.headers) {
57
+ if (name.toLowerCase() === 'content-type') {
58
+ settings.contentType = params.headers[name];
59
+ } else {
60
+ settings.headers[name] = params.headers[name];
61
+ }
62
+ }
63
+ }
64
+ settings.success = function(data) {
65
+ var headers = parseHeaders(data.responseHeaders);
66
+ var body = data.payload;
67
+ if (!_.isString(body)) {
68
+ body = JSON.stringify(body);
69
+ }
70
+ response = {
71
+ statusCode : data.status,
72
+ headers: headers,
73
+ body: body
74
+ };
75
+ if (callback) {
76
+ callback(null, response, response.body);
77
+ }
78
+ str.end();
79
+ };
80
+ settings.failure = function(err) {
81
+ if (callback) {
82
+ callback(err);
83
+ }
84
+ };
85
+ Sfdc.canvas.client.ajax(params.url, settings);
86
+ }
87
+ return str;
88
+ };
89
+ }
90
+ };