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.
- package/LICENSE +22 -0
- package/README.md +74 -0
- package/bin/jsforce +3 -0
- package/bower.json +30 -0
- package/build/jsforce-api-analytics.js +393 -0
- package/build/jsforce-api-analytics.min.js +2 -0
- package/build/jsforce-api-analytics.min.js.map +1 -0
- package/build/jsforce-api-apex.js +183 -0
- package/build/jsforce-api-apex.min.js +2 -0
- package/build/jsforce-api-apex.min.js.map +1 -0
- package/build/jsforce-api-bulk.js +1054 -0
- package/build/jsforce-api-bulk.min.js +2 -0
- package/build/jsforce-api-bulk.min.js.map +1 -0
- package/build/jsforce-api-chatter.js +320 -0
- package/build/jsforce-api-chatter.min.js +2 -0
- package/build/jsforce-api-chatter.min.js.map +1 -0
- package/build/jsforce-api-metadata.js +3020 -0
- package/build/jsforce-api-metadata.min.js +2 -0
- package/build/jsforce-api-metadata.min.js.map +1 -0
- package/build/jsforce-api-soap.js +403 -0
- package/build/jsforce-api-soap.min.js +2 -0
- package/build/jsforce-api-soap.min.js.map +1 -0
- package/build/jsforce-api-streaming.js +3479 -0
- package/build/jsforce-api-streaming.min.js +2 -0
- package/build/jsforce-api-streaming.min.js.map +1 -0
- package/build/jsforce-api-tooling.js +319 -0
- package/build/jsforce-api-tooling.min.js +2 -0
- package/build/jsforce-api-tooling.min.js.map +1 -0
- package/build/jsforce-core.js +25250 -0
- package/build/jsforce-core.min.js +2 -0
- package/build/jsforce-core.min.js.map +1 -0
- package/build/jsforce.js +31637 -0
- package/build/jsforce.min.js +2 -0
- package/build/jsforce.min.js.map +1 -0
- package/core.js +1 -0
- package/index.js +1 -0
- package/lib/VERSION.js +2 -0
- package/lib/_required.js +29 -0
- package/lib/api/analytics.js +387 -0
- package/lib/api/apex.js +177 -0
- package/lib/api/bulk.js +862 -0
- package/lib/api/chatter.js +314 -0
- package/lib/api/index.js +8 -0
- package/lib/api/metadata.js +848 -0
- package/lib/api/soap.js +397 -0
- package/lib/api/streaming-extension.js +136 -0
- package/lib/api/streaming.js +270 -0
- package/lib/api/tooling.js +313 -0
- package/lib/browser/canvas.js +90 -0
- package/lib/browser/client.js +241 -0
- package/lib/browser/core.js +5 -0
- package/lib/browser/jsforce.js +6 -0
- package/lib/browser/jsonp.js +52 -0
- package/lib/browser/request.js +70 -0
- package/lib/cache.js +252 -0
- package/lib/cli/cli.js +431 -0
- package/lib/cli/repl.js +337 -0
- package/lib/connection.js +1881 -0
- package/lib/core.js +16 -0
- package/lib/csv.js +50 -0
- package/lib/date.js +163 -0
- package/lib/http-api.js +300 -0
- package/lib/jsforce.js +10 -0
- package/lib/logger.js +52 -0
- package/lib/oauth2.js +206 -0
- package/lib/process.js +275 -0
- package/lib/promise.js +164 -0
- package/lib/query.js +881 -0
- package/lib/quick-action.js +90 -0
- package/lib/record-stream.js +305 -0
- package/lib/record.js +107 -0
- package/lib/registry/file-registry.js +48 -0
- package/lib/registry/index.js +3 -0
- package/lib/registry/registry.js +111 -0
- package/lib/require.js +14 -0
- package/lib/soap.js +207 -0
- package/lib/sobject.js +558 -0
- package/lib/soql-builder.js +236 -0
- package/lib/transport.js +233 -0
- package/package.json +110 -0
package/lib/cli/cli.js
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/*global process */
|
|
2
|
+
/**
|
|
3
|
+
* @file Command line interface for JSforce
|
|
4
|
+
* @author Shinichi Tomita <shinichi.tomita@gmail.com>
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
var http = require('http'),
|
|
10
|
+
url = require('url'),
|
|
11
|
+
crypto = require('crypto'),
|
|
12
|
+
openUrl = require('opn'),
|
|
13
|
+
commander = require('commander'),
|
|
14
|
+
coprompt = require('co-prompt'),
|
|
15
|
+
request = require('request'),
|
|
16
|
+
base64url = require('base64-url'),
|
|
17
|
+
Repl = require('./repl'),
|
|
18
|
+
jsforce = require('../jsforce'),
|
|
19
|
+
registry = jsforce.registry,
|
|
20
|
+
Promise = require('../promise'),
|
|
21
|
+
pkg = require('../../package.json');
|
|
22
|
+
|
|
23
|
+
var repl;
|
|
24
|
+
var conn = null;
|
|
25
|
+
var connName = null;
|
|
26
|
+
var outputEnabled = true;
|
|
27
|
+
var defaultLoginUrl = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
function start() {
|
|
33
|
+
var program = new commander.Command();
|
|
34
|
+
program.option('-u, --username [username]', 'Salesforce username')
|
|
35
|
+
.option('-p, --password [password]', 'Salesforce password (and security token, if available)')
|
|
36
|
+
.option('-c, --connection [connection]', 'Connection name stored in connection registry')
|
|
37
|
+
.option('-e, --evalScript [evalScript]', 'Script to evaluate')
|
|
38
|
+
.option('-l, --loginUrl [loginUrl]', 'Salesforce login url')
|
|
39
|
+
.option('--sandbox', 'Login to Salesforce sandbox')
|
|
40
|
+
.option('--coffee', 'Using CoffeeScript')
|
|
41
|
+
.version(pkg.version)
|
|
42
|
+
.parse(process.argv);
|
|
43
|
+
var replModule = program.coffee ? require('coffee-script/lib/coffee-script/repl') : require('repl');
|
|
44
|
+
repl = new Repl(cli, replModule);
|
|
45
|
+
outputEnabled = !program.evalScript;
|
|
46
|
+
var options = { username: program.username, password: program.password };
|
|
47
|
+
var loginUrl = program.loginUrl ? program.loginUrl :
|
|
48
|
+
program.sandbox ? 'sandbox' :
|
|
49
|
+
null;
|
|
50
|
+
setLoginServer(loginUrl);
|
|
51
|
+
connect(program.connection, options, function(err, res) {
|
|
52
|
+
if (err) {
|
|
53
|
+
console.error(err.message);
|
|
54
|
+
process.exit();
|
|
55
|
+
} else {
|
|
56
|
+
if (program.evalScript) {
|
|
57
|
+
repl.start({
|
|
58
|
+
interactive: false,
|
|
59
|
+
evalScript: program.evalScript
|
|
60
|
+
});
|
|
61
|
+
} else {
|
|
62
|
+
repl.start();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @private
|
|
70
|
+
*/
|
|
71
|
+
function getCurrentConnection() {
|
|
72
|
+
return conn;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function print(message) {
|
|
76
|
+
if (outputEnabled) { console.log(message); }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
function saveCurrentConnection() {
|
|
83
|
+
if (conn && connName) {
|
|
84
|
+
var connConfig = {
|
|
85
|
+
oauth2: conn.oauth2 && {
|
|
86
|
+
clientId: conn.oauth2.clientId,
|
|
87
|
+
clientSecret: conn.oauth2.clientSecret,
|
|
88
|
+
redirectUri: conn.oauth2.redirectUri,
|
|
89
|
+
loginUrl: conn.oauth2.loginUrl
|
|
90
|
+
},
|
|
91
|
+
accessToken: conn.accessToken,
|
|
92
|
+
instanceUrl: conn.instanceUrl,
|
|
93
|
+
refreshToken: conn.refreshToken
|
|
94
|
+
};
|
|
95
|
+
registry.saveConnectionConfig(connName, connConfig);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @private
|
|
101
|
+
*/
|
|
102
|
+
function setLoginServer(loginServer) {
|
|
103
|
+
if (!loginServer) { return; }
|
|
104
|
+
if (loginServer === 'production') {
|
|
105
|
+
defaultLoginUrl = 'https://login.salesforce.com';
|
|
106
|
+
} else if (loginServer === 'sandbox') {
|
|
107
|
+
defaultLoginUrl = 'https://test.salesforce.com';
|
|
108
|
+
} else if (loginServer.indexOf('https://') !== 0) {
|
|
109
|
+
defaultLoginUrl = 'https://' + loginServer;
|
|
110
|
+
} else {
|
|
111
|
+
defaultLoginUrl = loginServer;
|
|
112
|
+
}
|
|
113
|
+
print('Using "' + defaultLoginUrl + '" as default login URL.');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
function connect(name, options, callback) {
|
|
120
|
+
connName = name;
|
|
121
|
+
options = options || {};
|
|
122
|
+
var connConfig = registry.getConnectionConfig(name);
|
|
123
|
+
var username, password;
|
|
124
|
+
if (!connConfig) {
|
|
125
|
+
connConfig = {};
|
|
126
|
+
if (defaultLoginUrl) {
|
|
127
|
+
connConfig.loginUrl = defaultLoginUrl;
|
|
128
|
+
}
|
|
129
|
+
username = name;
|
|
130
|
+
}
|
|
131
|
+
conn = new jsforce.Connection(connConfig);
|
|
132
|
+
username = username || options.username;
|
|
133
|
+
password = options.password;
|
|
134
|
+
var handleLogin = function(err) {
|
|
135
|
+
if (err) { return callback(err); }
|
|
136
|
+
saveCurrentConnection();
|
|
137
|
+
callback();
|
|
138
|
+
};
|
|
139
|
+
if (username) {
|
|
140
|
+
loginByPassword(username, password, 2, handleLogin);
|
|
141
|
+
} else {
|
|
142
|
+
if (connName && conn.accessToken) {
|
|
143
|
+
conn.on('refresh', function(accessToken) {
|
|
144
|
+
print('Refreshing access token ... ');
|
|
145
|
+
saveCurrentConnection();
|
|
146
|
+
});
|
|
147
|
+
conn.identity(function(err, identity) {
|
|
148
|
+
if (err) {
|
|
149
|
+
print(err.message);
|
|
150
|
+
if (conn.oauth2) {
|
|
151
|
+
callback(new Error('Please re-authorize connection.'));
|
|
152
|
+
} else {
|
|
153
|
+
loginByPassword(connName, null, 2, handleLogin);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
print('Logged in as : ' + identity.username);
|
|
157
|
+
callback();
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
} else {
|
|
161
|
+
callback();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
function loginByPassword(username, password, retry, callback) {
|
|
170
|
+
if (!password) {
|
|
171
|
+
promptPassword('Password: ', function(err, pass) {
|
|
172
|
+
if (err) { return callback(err); }
|
|
173
|
+
loginByPassword(username, pass, retry, callback);
|
|
174
|
+
});
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
conn.login(username, password, function(err, result) {
|
|
178
|
+
if (err) {
|
|
179
|
+
console.error(err.message);
|
|
180
|
+
if (retry > 0) {
|
|
181
|
+
loginByPassword(username, null, --retry, callback);
|
|
182
|
+
} else {
|
|
183
|
+
callback(new Error());
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
print("Logged in as : " + username);
|
|
187
|
+
callback(null, result);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @private
|
|
194
|
+
*/
|
|
195
|
+
function disconnect(name) {
|
|
196
|
+
name = name || connName;
|
|
197
|
+
if (registry.getConnectionConfig(name)) {
|
|
198
|
+
registry.removeConnectionConfig(name);
|
|
199
|
+
print("Disconnect connection '" + name + "'");
|
|
200
|
+
}
|
|
201
|
+
connName = null;
|
|
202
|
+
conn = new jsforce.Connection();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @private
|
|
207
|
+
*/
|
|
208
|
+
function authorize(clientName, callback) {
|
|
209
|
+
clientName = clientName || 'default';
|
|
210
|
+
var oauth2Config = registry.getClient(clientName);
|
|
211
|
+
if (!oauth2Config || !oauth2Config.clientId) {
|
|
212
|
+
if (clientName === 'default' || clientName === 'sandbox') {
|
|
213
|
+
print('No client information registered. Downloading JSforce default client information...');
|
|
214
|
+
return downloadDefaultClientInfo(clientName, callback);
|
|
215
|
+
}
|
|
216
|
+
return callback(new Error("No OAuth2 client information registered : '"+clientName+"'. Please register client info first."));
|
|
217
|
+
}
|
|
218
|
+
var oauth2 = new jsforce.OAuth2(oauth2Config);
|
|
219
|
+
var verifier = base64url.encode(crypto.randomBytes(32));
|
|
220
|
+
var challenge = base64url.encode(crypto.createHash('sha256').update(verifier).digest());
|
|
221
|
+
var state = base64url.encode(crypto.randomBytes(32));
|
|
222
|
+
var authzUrl = oauth2.getAuthorizationUrl({ code_challenge: challenge, state: state });
|
|
223
|
+
print('Opening authorization page in browser...');
|
|
224
|
+
print('URL: ' + authzUrl);
|
|
225
|
+
openUrl(authzUrl);
|
|
226
|
+
waitCallback(oauth2Config.redirectUri, state, function(err, params) {
|
|
227
|
+
if (err) { return callback(err); }
|
|
228
|
+
conn = new jsforce.Connection({ oauth2: oauth2 });
|
|
229
|
+
if (!params.code) {
|
|
230
|
+
return callback(new Error('No authorization code returned.'));
|
|
231
|
+
}
|
|
232
|
+
if (params.state !== state) {
|
|
233
|
+
return callback(new Error('Invalid state parameter returned.'));
|
|
234
|
+
}
|
|
235
|
+
print('Received authorization code. Please close the opened browser window.');
|
|
236
|
+
conn.authorize(params.code, { code_verifier: verifier }).then(function(res) {
|
|
237
|
+
print('Authorized. Fetching user info...');
|
|
238
|
+
return conn.identity();
|
|
239
|
+
}).then(function(identity) {
|
|
240
|
+
print('Logged in as : ' + identity.username);
|
|
241
|
+
connName = identity.username;
|
|
242
|
+
saveCurrentConnection();
|
|
243
|
+
}).thenCall(callback);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* @private
|
|
249
|
+
*/
|
|
250
|
+
function downloadDefaultClientInfo(clientName, callback) {
|
|
251
|
+
var configUrl = 'https://jsforce.github.io/client-config/default.json';
|
|
252
|
+
request(configUrl, function(err, res) {
|
|
253
|
+
if (err) { return callback(err); }
|
|
254
|
+
var clientConfig = JSON.parse(res.body);
|
|
255
|
+
if (clientName === 'sandbox') {
|
|
256
|
+
clientConfig.loginUrl = 'https://test.salesforce.com';
|
|
257
|
+
}
|
|
258
|
+
registry.registerClient(clientName, clientConfig);
|
|
259
|
+
print("Client information downloaded successfully.");
|
|
260
|
+
authorize(clientName, callback);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @private
|
|
267
|
+
*/
|
|
268
|
+
function waitCallback(serverUrl, state, callback) {
|
|
269
|
+
if (serverUrl.indexOf('http://localhost:') === 0) {
|
|
270
|
+
var server = http.createServer(function(req, res) {
|
|
271
|
+
var qparams = url.parse(req.url, true).query;
|
|
272
|
+
res.writeHead(200, {'Content-Type': 'text/html'});
|
|
273
|
+
res.write('<html><script>location.href="about:blank";</script></html>');
|
|
274
|
+
res.end();
|
|
275
|
+
callback(null, qparams);
|
|
276
|
+
server.close();
|
|
277
|
+
req.connection.end();
|
|
278
|
+
req.connection.destroy();
|
|
279
|
+
});
|
|
280
|
+
var port = url.parse(serverUrl).port;
|
|
281
|
+
server.listen(port, "localhost");
|
|
282
|
+
} else {
|
|
283
|
+
var msg = 'Copy & paste authz code passed in redirected URL: ';
|
|
284
|
+
promptMessage(msg, function(err, code) {
|
|
285
|
+
if (err) {
|
|
286
|
+
callback(err);
|
|
287
|
+
} else {
|
|
288
|
+
callback(null, { code: decodeURIComponent(code), state: state });
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* @private
|
|
296
|
+
*/
|
|
297
|
+
function register(clientName, clientConfig, callback) {
|
|
298
|
+
if (!clientName) {
|
|
299
|
+
clientName = "default";
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
var prompts = {
|
|
303
|
+
"clientId": "Input client ID : ",
|
|
304
|
+
"clientSecret": "Input client secret (optional) : ",
|
|
305
|
+
"redirectUri": "Input redirect URI : ",
|
|
306
|
+
"loginUrl": "Input login URL (default is https://login.salesforce.com) : "
|
|
307
|
+
};
|
|
308
|
+
new Promise(function(resolve, reject) {
|
|
309
|
+
if (registry.getClient(clientName)) {
|
|
310
|
+
var msg = "Client '"+clientName+"' is already registered. Are you sure you want to override ? [yN] : ";
|
|
311
|
+
promptConfirm(msg, function(err, ok) {
|
|
312
|
+
if (ok) {
|
|
313
|
+
resolve();
|
|
314
|
+
} else {
|
|
315
|
+
reject(new Error('Registration canceled.'));
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
} else {
|
|
319
|
+
resolve();
|
|
320
|
+
}
|
|
321
|
+
})
|
|
322
|
+
.then(function() {
|
|
323
|
+
return Object.keys(prompts).reduce(function(promise, name) {
|
|
324
|
+
return promise.then(function() {
|
|
325
|
+
var message = prompts[name];
|
|
326
|
+
return new Promise(function(resolve, reject) {
|
|
327
|
+
if (!clientConfig[name]) {
|
|
328
|
+
promptMessage(message, function(err, value) {
|
|
329
|
+
if (err) { return reject(err); }
|
|
330
|
+
if (value) { clientConfig[name] = value; }
|
|
331
|
+
resolve();
|
|
332
|
+
});
|
|
333
|
+
} else {
|
|
334
|
+
resolve();
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
}, Promise.resolve());
|
|
339
|
+
}).then(function() {
|
|
340
|
+
registry.registerClient(clientName, clientConfig);
|
|
341
|
+
print("Client registered successfully.");
|
|
342
|
+
}).thenCall(callback);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* @private
|
|
347
|
+
*/
|
|
348
|
+
function listConnections() {
|
|
349
|
+
var names = registry.getConnectionNames();
|
|
350
|
+
for (var i=0; i<names.length; i++) {
|
|
351
|
+
var name = names[i];
|
|
352
|
+
print((name === connName ? '* ' : ' ') + name);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* @private
|
|
358
|
+
*/
|
|
359
|
+
function getConnectionNames() {
|
|
360
|
+
return registry.getConnectionNames();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @private
|
|
365
|
+
*/
|
|
366
|
+
function getClientNames() {
|
|
367
|
+
return registry.getClientNames();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* @private
|
|
372
|
+
*/
|
|
373
|
+
function promptMessage(message, callback) {
|
|
374
|
+
repl.pause();
|
|
375
|
+
coprompt(message)(function(err, res) {
|
|
376
|
+
repl.resume();
|
|
377
|
+
callback(err, res);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @private
|
|
383
|
+
*/
|
|
384
|
+
function promptPassword(message, callback) {
|
|
385
|
+
repl.pause();
|
|
386
|
+
coprompt.password(message)(function(err, res) {
|
|
387
|
+
repl.resume();
|
|
388
|
+
callback(err, res);
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @private
|
|
394
|
+
*/
|
|
395
|
+
function promptConfirm(message, callback) {
|
|
396
|
+
repl.pause();
|
|
397
|
+
coprompt.confirm(message)(function(err, res) {
|
|
398
|
+
repl.resume();
|
|
399
|
+
callback(err, res);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @private
|
|
405
|
+
*/
|
|
406
|
+
function openUrlUsingSession(url) {
|
|
407
|
+
var frontdoorUrl = conn.instanceUrl + '/secur/frontdoor.jsp?sid=' + conn.accessToken;
|
|
408
|
+
if (url) {
|
|
409
|
+
frontdoorUrl += "&retURL=" + encodeURIComponent(url);
|
|
410
|
+
}
|
|
411
|
+
openUrl(frontdoorUrl);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/* ------------------------------------------------------------------------- */
|
|
415
|
+
|
|
416
|
+
var cli = {
|
|
417
|
+
start: start,
|
|
418
|
+
getCurrentConnection: getCurrentConnection,
|
|
419
|
+
saveCurrentConnection: saveCurrentConnection,
|
|
420
|
+
listConnections: listConnections,
|
|
421
|
+
setLoginServer: setLoginServer,
|
|
422
|
+
getConnectionNames: getConnectionNames,
|
|
423
|
+
getClientNames: getClientNames,
|
|
424
|
+
connect: connect,
|
|
425
|
+
disconnect: disconnect,
|
|
426
|
+
authorize: authorize,
|
|
427
|
+
register: register,
|
|
428
|
+
openUrl: openUrlUsingSession
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
module.exports = cli;
|