particle-api-js 9.4.1 → 10.1.0

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 (51) hide show
  1. package/.circleci/config.yml +7 -5
  2. package/CHANGELOG.md +11 -0
  3. package/{test/EventStream-e2e-browser.html → EventStream-e2e-browser.html} +0 -1
  4. package/{test/EventStream-e2e-node.js → EventStream-e2e-node.js} +2 -3
  5. package/README.md +2 -2
  6. package/RELEASE.md +1 -1
  7. package/dist/particle.min.js +1 -399
  8. package/dist/particle.min.js.map +1 -1
  9. package/docs/api.md +5223 -115
  10. package/fs.js +2 -0
  11. package/karma.conf.js +18 -6
  12. package/package.json +23 -26
  13. package/src/Agent.js +407 -0
  14. package/src/Client.js +170 -0
  15. package/src/Defaults.js +7 -0
  16. package/src/EventStream.js +263 -0
  17. package/src/Library.js +33 -0
  18. package/src/Particle.js +2644 -0
  19. package/test/Agent.integration.js +5 -4
  20. package/test/Agent.spec.js +174 -291
  21. package/test/Client.spec.js +7 -7
  22. package/test/Defaults.spec.js +2 -2
  23. package/test/EventStream.spec.js +6 -4
  24. package/test/FakeAgent.js +2 -2
  25. package/test/Library.spec.js +2 -2
  26. package/test/Particle.integration.js +7 -7
  27. package/test/Particle.spec.js +332 -18
  28. package/test/fixtures/index.js +4 -18
  29. package/test/support/FixtureHttpServer.js +5 -3
  30. package/test/test-setup.js +5 -5
  31. package/tsconfig.json +14 -0
  32. package/webpack.config.js +45 -0
  33. package/.babelrc +0 -4
  34. package/lib/Agent.js +0 -516
  35. package/lib/Agent.js.map +0 -1
  36. package/lib/Client.js +0 -312
  37. package/lib/Client.js.map +0 -1
  38. package/lib/Defaults.js +0 -14
  39. package/lib/Defaults.js.map +0 -1
  40. package/lib/EventStream.js +0 -335
  41. package/lib/EventStream.js.map +0 -1
  42. package/lib/Library.js +0 -67
  43. package/lib/Library.js.map +0 -1
  44. package/lib/Particle.js +0 -3248
  45. package/lib/Particle.js.map +0 -1
  46. package/lib/superagent-binary-parser.js +0 -20
  47. package/lib/superagent-binary-parser.js.map +0 -1
  48. package/test/Client.integration.js +0 -69
  49. package/test/fixtures/tarball.tar.gz +0 -0
  50. package/test/fixtures/test-library-publish-0.0.1.tar.gz +0 -0
  51. package/test/fixtures/test-library-publish-0.0.2.tar.gz +0 -0
package/fs.js ADDED
@@ -0,0 +1,2 @@
1
+ // In Node, exports the fs module. In the browser, exports undefined due to "./fs": false entry in package.json
2
+ module.exports = require('fs');
package/karma.conf.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // Karma configuration
2
2
  // Generated on Wed Jul 20 2016 12:00:09 GMT-0400 (EDT)
3
+ const webpackConf = require('./webpack.config.js');
4
+ const webpack = require('webpack');
3
5
 
4
6
  module.exports = function karmaCfg(config){
5
7
  config.set({
@@ -8,7 +10,7 @@ module.exports = function karmaCfg(config){
8
10
 
9
11
  // frameworks to use
10
12
  // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
11
- frameworks: ['browserify', 'mocha', 'chai'],
13
+ frameworks: ['webpack', 'mocha', 'chai'],
12
14
 
13
15
  // list of files / patterns to load in the browser
14
16
  files: [
@@ -24,14 +26,24 @@ module.exports = function karmaCfg(config){
24
26
  // preprocess matching files before serving them to the browser
25
27
  // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
26
28
  preprocessors: {
27
- 'src/**/*.js': ['browserify'],
28
- 'test/**/*.js': ['browserify']
29
+ 'src/**/*.js': ['webpack'],
30
+ 'test/**/*.js': ['webpack']
29
31
  },
30
32
 
31
33
  // Transform test files to a single browser consumable file
32
- browserify: {
33
- debug: true, // generate source maps
34
- transform: ['babelify', 'brfs']
34
+ webpack: {
35
+ mode: 'development',
36
+ target: 'web',
37
+ devtool: 'inline-source-map',
38
+ output: webpackConf.output,
39
+ externals: webpackConf.externals,
40
+ resolve: webpackConf.resolve,
41
+ plugins: [
42
+ new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }),
43
+ new webpack.EnvironmentPlugin({
44
+ SKIP_AGENT_TEST: process.env.SKIP_AGENT_TEST || false
45
+ })
46
+ ]
35
47
  },
36
48
 
37
49
  // test results reporter to use
package/package.json CHANGED
@@ -1,24 +1,23 @@
1
1
  {
2
2
  "name": "particle-api-js",
3
- "version": "9.4.1",
3
+ "version": "10.1.0",
4
4
  "description": "Particle API Client",
5
- "main": "lib/Particle.js",
5
+ "main": "src/Particle.js",
6
6
  "scripts": {
7
- "babel-watch": "babel src -d lib --watch --source-maps",
8
- "prepublish": "npm run lint && npm run compile",
9
- "compile": "babel src -sd lib",
10
- "test": "npm run lint && npm run test:unit",
7
+ "prepublish": "npm run lint && npm run build",
8
+ "test": "npm run lint && npm run typecheck && npm run test:unit",
11
9
  "test:ci": "npm run lint && npm run test:unit -- --forbid-only && npm run coverage",
12
- "test:unit": "mocha test/ -R spec --compilers js:babel-register",
10
+ "test:unit": "mocha test/ -R spec",
13
11
  "test:unit:silent": "npm run test:unit > tmp/test-unit-log.txt 2>&1",
14
12
  "test:browser": "karma start --single-run",
15
13
  "test:watch": "npm run test:unit -- --watch",
14
+ "typecheck": "tsc --noEmit",
16
15
  "coverage": "nyc --reporter=text --include='src/**/*.js' --temp-dir=./tmp/ --check-coverage --lines 91 npm run test:unit:silent",
17
16
  "lint": "eslint . --ext .js --format unix --ignore-path .gitignore --ignore-pattern \"dist/*\"",
18
17
  "lint:fix": "npm run lint -- --fix",
19
18
  "docs": "documentation build src/Particle.js --shallow -g -f md -o docs/api.md",
20
- "build": "browserify lib/Particle.js -s Particle -d -p [minifyify --map particle.min.js.map --output dist/particle.min.js.map] > dist/particle.min.js",
21
- "build-nomin": "browserify lib/Particle.js -s Particle > dist/particle.js",
19
+ "build": "webpack --env mode=production",
20
+ "build-nomin": "webpack --env mode=development",
22
21
  "preversion": "npm run test && npm run prepublish",
23
22
  "reinstall": "rm -rf ./node_modules && npm i",
24
23
  "version": "npm run build && npm run docs && npm run update-changelog && git add dist/* docs/*",
@@ -46,43 +45,41 @@
46
45
  ],
47
46
  "license": "Apache-2.0",
48
47
  "devDependencies": {
49
- "babel-cli": "^6.9.0",
50
- "babel-eslint": "^6.0.4",
51
- "babel-plugin-add-module-exports": "^0.1.2",
52
- "babel-plugin-transform-runtime": "^6.9.0",
53
- "babel-preset-es2015": "^6.6.0",
54
- "babel-register": "^6.5.2",
55
- "babelify": "^7.3.0",
56
- "brfs": "^1.4.3",
57
- "browserify": "^13.0.0",
48
+ "@types/node": "^20.5.9",
49
+ "buffer": "^6.0.3",
58
50
  "chai": "^4.3.6",
59
51
  "chai-as-promised": "^7.1.1",
60
52
  "documentation": "^4.0.0-rc.1",
61
53
  "eslint": "^8.17.0",
62
54
  "eslint-config-particle": "^2.2.1",
55
+ "events": "^3.3.0",
63
56
  "karma": "^1.1.1",
64
- "karma-browserify": "^5.1.0",
65
57
  "karma-chai": "^0.1.0",
66
58
  "karma-cli": "^1.0.1",
67
59
  "karma-coverage": "^1.1.0",
68
60
  "karma-firefox-launcher": "^1.0.0",
69
61
  "karma-mocha": "^1.1.1",
70
- "minifyify": "^7.3.1",
62
+ "karma-webpack": "^5.0.0",
71
63
  "mocha": "^2.5.1",
72
64
  "nyc": "^15.1.0",
65
+ "process": "^0.11.10",
73
66
  "should": "^9.0.0",
74
67
  "sinon": "^7.2.5",
75
68
  "sinon-chai": "^3.7.0",
76
- "watchify": "^3.7.0"
69
+ "terser-webpack-plugin": "^5.3.9",
70
+ "typescript": "^5.2.2",
71
+ "url": "^0.11.3",
72
+ "webpack": "^5.88.2",
73
+ "webpack-cli": "^5.1.4"
77
74
  },
78
75
  "dependencies": {
79
- "babel-runtime": "^6.9.2",
80
- "form-data": ">2.2.0",
81
- "stream-http": "^3.2.0",
82
- "superagent": "^5.1.2",
83
- "superagent-prefix": "0.0.2"
76
+ "form-data": "^4.0.0",
77
+ "node-fetch": "^2.7.0",
78
+ "qs": "^6.11.2",
79
+ "stream-http": "^3.2.0"
84
80
  },
85
81
  "browser": {
82
+ "./fs": false,
86
83
  "http": "stream-http",
87
84
  "https": "stream-http"
88
85
  },
package/src/Agent.js ADDED
@@ -0,0 +1,407 @@
1
+ /*
2
+ ******************************************************************************
3
+ Copyright (c) 2016 Particle Industries, Inc. All rights reserved.
4
+
5
+ This program is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License as published by the Free Software Foundation, either
8
+ version 3 of the License, or (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
17
+ ******************************************************************************
18
+ */
19
+
20
+ const fetch = require('node-fetch');
21
+ const FormData = require('form-data');
22
+ const qs = require('qs');
23
+ const fs = require('../fs');
24
+ const packageJson = require('../package.json');
25
+
26
+ /**
27
+ * The object returned for a basic request
28
+ * @typedef {object} JSONResponse
29
+ * @property {number} statusCode The HTTP response status
30
+ * @property {object} body The endpoint's response parsed as a JSON
31
+ */
32
+
33
+ /**
34
+ * The possible response from an API request
35
+ * @typedef {JSONResponse|Buffer|ArrayBuffer} RequestResponse The type is based on
36
+ * the request config and whether is on browser or node
37
+ */
38
+
39
+ /**
40
+ * The error object generated in case of a failed request
41
+ * @typedef {object} RequestError
42
+ * @property {number} statusCode The HTTP response status
43
+ * @property {string} errorDescription Details on what caused the failed request
44
+ * @property {string} shortErrorDescription Summarized version of the fail reason
45
+ * @property {object} body The response object from the request
46
+ * @property {object} error The error object from the request
47
+ */
48
+
49
+ class Agent {
50
+ constructor(baseUrl){
51
+ this.setBaseUrl(baseUrl);
52
+ }
53
+
54
+ setBaseUrl(baseUrl) {
55
+ this.baseUrl = baseUrl;
56
+ }
57
+
58
+ /**
59
+ * Make a GET request
60
+ * @param {object} params Configurations to customize the request
61
+ * @param {string} params.uri The URI to request
62
+ * @param {string|object} [params.auth] Authorization token to use
63
+ * @param {object} [params.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
64
+ * @param {string|object} [params.query] Key/Value pairs of query params or a correctly formatted string
65
+ * @param {object} [params.context] The invocation context, describing the tool and project
66
+ * @returns {Promise<RequestResponse, RequestError>} A promise that resolves with either the requested data or an error object
67
+ */
68
+ get({ uri, auth, headers, query, context }) {
69
+ return this.request({ uri, method: 'get', auth, headers, query, context });
70
+ }
71
+
72
+ /**
73
+ * Make a HEAD request
74
+ * @param {object} params Configurations to customize the request
75
+ * @param {string} params.uri The URI to request
76
+ * @param {string|object} [params.auth] Authorization token to use
77
+ * @param {object} [params.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
78
+ * @param {string|object} [params.query] Key/Value pairs of query params or a correctly formatted string
79
+ * @param {object} [params.context] The invocation context, describing the tool and project
80
+ * @returns {Promise<RequestResponse, RequestError>} A promise that resolves with either the requested data or an error object
81
+ */
82
+ head({ uri, auth, headers, query, context }) {
83
+ return this.request({ uri, method: 'head', auth, headers, query, context });
84
+ }
85
+
86
+ /**
87
+ * Make a POST request
88
+ * @param {object} params Configurations to customize the request
89
+ * @param {string} params.uri The URI to request
90
+ * @param {string|object} [params.auth] Authorization token to use
91
+ * @param {object} [params.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
92
+ * @param {object} [params.data] Key/Value pairs of query params or a correctly formatted string
93
+ * @param {object} [params.context] The invocation context, describing the tool and project
94
+ * @returns {Promise<RequestResponse, RequestError>} A promise that resolves with either the requested data or an error object
95
+ */
96
+ post({ uri, headers, data, auth, context }) {
97
+ return this.request({ uri, method: 'post', auth, headers, data, context });
98
+ }
99
+
100
+ /**
101
+ * Make a PUT request
102
+ * @param {object} params Configurations to customize the request
103
+ * @param {string} params.uri The URI to request
104
+ * @param {string|object} [params.auth] Authorization token to use
105
+ * @param {object} [params.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
106
+ * @param {object} [params.data] Key/VAlue pairs of query params or a correctly formatted string
107
+ * @param {object} [params.context] The invocation context, describing the tool and project
108
+ * @returns {Promise<RequestResponse, RequestError>} A promise that resolves with either the requested data or an error object
109
+ */
110
+ put({ uri, auth, headers, data, context }) {
111
+ return this.request({ uri, method: 'put', auth, headers, data, context });
112
+ }
113
+
114
+ /**
115
+ * Make a DELETE request
116
+ * @param {object} params Configurations to customize the request
117
+ * @param {string} params.uri The URI to request
118
+ * @param {string|object} [params.auth] Authorization token to use
119
+ * @param {object} [params.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
120
+ * @param {object} [params.data] Key/Value pairs of query params or a correctly formatted string
121
+ * @param {object} [params.context] The invocation context, describing the tool and project
122
+ * @returns {Promise<RequestResponse, RequestError>} A promise that resolves with either the requested data or an error object
123
+ */
124
+ delete({ uri, auth, headers, data, context }) {
125
+ return this.request({ uri, method: 'delete', auth, headers, data, context });
126
+ }
127
+
128
+ /**
129
+ *
130
+ * @param {object} config An obj with all the possible request configurations
131
+ * @param {string} config.uri The URI to request
132
+ * @param {string} config.method The method used to request the URI, should be in uppercase.
133
+ * @param {object} [config.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
134
+ * @param {object} [config.data] Arbitrary data to send as the body.
135
+ * @param {string|object} [config.auth] Authorization
136
+ * @param {string|object} [config.query] Query parameters
137
+ * @param {object} [config.form] Form fields
138
+ * @param {object} [config.files] Array of file names and file content
139
+ * @param {object} [config.context] The invocation context, describing the tool and project.
140
+ * @param {boolean} [config.isBuffer=false] Indicate if the response should be treated as Buffer instead of JSON
141
+ * @returns {Promise<RequestResponse, RequestError>} A promise that resolves with either the requested data or an error object
142
+ */
143
+ request({
144
+ uri,
145
+ method,
146
+ headers = undefined,
147
+ data = undefined,
148
+ auth,
149
+ query = undefined,
150
+ form = undefined,
151
+ files = undefined,
152
+ context = undefined,
153
+ isBuffer = false
154
+ }){
155
+ const requestFiles = this._sanitizeFiles(files);
156
+ const requestParams = this._buildRequest({ uri, method, headers, data, auth, query, form, context, files: requestFiles });
157
+ return this._promiseResponse(requestParams, isBuffer);
158
+ }
159
+
160
+ /**
161
+ * Promises to send the request and retreive the response.
162
+ * @param {[string, object]} requestParams First argument is the URI to request, the second one are the options.
163
+ * @param {boolean} isBuffer Indicate if the response body should be returned as a Buffer (Node) / ArrayBuffer (browser) instead of JSON
164
+ * @param {function} [makerequest=fetch] The fetch function to use. Override for testing.
165
+ * @returns {Promise<RequestResponse, RequestError>} A promise that resolves with either the requested data or an error object
166
+ * @private
167
+ */
168
+ _promiseResponse(requestParams, isBuffer, makerequest = fetch) {
169
+ let status;
170
+ return makerequest(...requestParams)
171
+ .then((resp) => {
172
+ status = resp.status;
173
+ if (!resp.ok) {
174
+ return resp.text().then((err) => {
175
+ const objError = JSON.parse(err);
176
+ // particle-commnds/src/cmd/api expects response.text. to be a string
177
+ const response = Object.assign(resp, { text: err });
178
+ throw Object.assign(objError, { response });
179
+ });
180
+ }
181
+ if (status === 204) { // Can't do resp.json() since there is no body to parse
182
+ return '';
183
+ }
184
+ if (isBuffer) {
185
+ return resp.blob();
186
+ }
187
+ return resp.json();
188
+ }).then((body) => {
189
+ if (isBuffer) {
190
+ return body.arrayBuffer().then((arrayBuffer) => {
191
+ if (!this.isForBrowser()) {
192
+ return Buffer.from(arrayBuffer);
193
+ }
194
+ return arrayBuffer;
195
+ });
196
+ }
197
+ return {
198
+ body,
199
+ statusCode: status
200
+ };
201
+ }).catch((error) => {
202
+ const errorType = status ? `HTTP error ${status}` : 'Network error';
203
+ let errorDescription = `${errorType} from ${requestParams[0]}`;
204
+ let shortErrorDescription;
205
+ if (error.error_description) { // Fetch responded with ok false
206
+ errorDescription = `${errorDescription} - ${error.error_description}`;
207
+ shortErrorDescription = error.error_description;
208
+ }
209
+ const reason = new Error(errorDescription);
210
+ Object.assign(reason, {
211
+ statusCode: status,
212
+ errorDescription,
213
+ shortErrorDescription,
214
+ error,
215
+ body: error
216
+ });
217
+ throw reason;
218
+ });
219
+ }
220
+
221
+ /**
222
+ * Generate the params in a format valid for 'fetch'
223
+ * @returns {[string, object]} The uri to make the request too, and extra configs
224
+ * @private
225
+ */
226
+ _buildRequest({ uri, method, headers, data, auth, query, form, files, context }){
227
+ let actualUri = uri;
228
+ if (this.baseUrl && uri[0] === '/') {
229
+ actualUri = `${this.baseUrl}${uri}`;
230
+ }
231
+ if (query) {
232
+ const queryParams = qs.stringify(query);
233
+ const hasParams = actualUri.includes('?');
234
+ actualUri = `${actualUri}${hasParams ? '&' : '?'}${queryParams}`;
235
+ }
236
+
237
+ const userAgentHeader = { 'User-Agent': `${packageJson.name}/${packageJson.version} (${packageJson.repository.url})` };
238
+ let body;
239
+ let contentTypeHeader;
240
+ if (files){
241
+ // @ts-ignore
242
+ contentTypeHeader = {}; // Needed to allow fetch create its own
243
+ body = this._getFromData(files, form);
244
+ } else if (form){
245
+ contentTypeHeader = { 'Content-Type': 'application/x-www-form-urlencoded' };
246
+ body = qs.stringify(form);
247
+ } else if (data){
248
+ contentTypeHeader = { 'Content-Type': 'application/json' };
249
+ body = JSON.stringify(data);
250
+ }
251
+ const finalHeaders = Object.assign({},
252
+ userAgentHeader,
253
+ contentTypeHeader,
254
+ this._getAuthorizationHeader(auth),
255
+ this._getContextHeaders(context),
256
+ headers
257
+ );
258
+
259
+ return [actualUri, { method, body, headers: finalHeaders }];
260
+ }
261
+
262
+ isForBrowser() {
263
+ return typeof window !== 'undefined';
264
+ }
265
+
266
+ _getFromData(files, form) {
267
+ const formData = new FormData();
268
+ for (let [name, file] of Object.entries(files)){
269
+ let path = file.path;
270
+ let fileData = file.data;
271
+ if (!this.isForBrowser()) {
272
+ const nodeFormData = this._getNodeFormData(file);
273
+ path = nodeFormData.path;
274
+ fileData = nodeFormData.file;
275
+ }
276
+ formData.append(name, fileData, path);
277
+ }
278
+ if (form){
279
+ for (let [name, value] of Object.entries(form)){
280
+ formData.append(name, value);
281
+ }
282
+ }
283
+ return formData;
284
+ }
285
+
286
+ _getNodeFormData(file) {
287
+ let fileData = file.data;
288
+ if (typeof file.data === 'string') {
289
+ fileData = fs.createReadStream(file.data);
290
+ }
291
+ return {
292
+ file: fileData,
293
+ path: { filepath: file.path } // Different API for nodejs
294
+ };
295
+ }
296
+
297
+ _getContextHeaders(context = {}) {
298
+ return Object.assign({},
299
+ this._getToolContext(context.tool),
300
+ this._getProjectContext(context.project)
301
+ );
302
+ }
303
+
304
+ _getToolContext(tool = {}){
305
+ let value = '';
306
+ if (tool.name){
307
+ value += this._toolIdent(tool);
308
+ if (tool.components){
309
+ for (let component of tool.components){
310
+ value += ', '+this._toolIdent(component);
311
+ }
312
+ }
313
+ }
314
+ if (value){
315
+ return { 'X-Particle-Tool': value };
316
+ }
317
+ return {};
318
+ }
319
+
320
+ _toolIdent(tool){
321
+ return this._nameAtVersion(tool.name, tool.version);
322
+ }
323
+
324
+ _nameAtVersion(name, version){
325
+ let value = '';
326
+ if (name){
327
+ value += name;
328
+ if (version){
329
+ value += '@'+version;
330
+ }
331
+ }
332
+ return value;
333
+ }
334
+
335
+ _getProjectContext(project = {}){
336
+ let value = this._buildSemicolonSeparatedProperties(project, 'name');
337
+ if (value){
338
+ return { 'X-Particle-Project': value };
339
+ }
340
+ return {};
341
+ }
342
+
343
+ /**
344
+ * Creates a string like primaryPropertyValue; name=value; name1=value
345
+ * from the properties of an object.
346
+ * @param {object} obj The object to create the string from
347
+ * @param {string} primaryProperty The name of the primary property which is the default value and must be defined.
348
+ * @private
349
+ * @return {string} The formatted string representing the object properties and the default property.
350
+ */
351
+ _buildSemicolonSeparatedProperties(obj, primaryProperty){
352
+ let value = '';
353
+ if (obj[primaryProperty]){
354
+ value += obj[primaryProperty];
355
+ for (let prop in obj){
356
+ if (prop!==primaryProperty && obj.hasOwnProperty(prop)){
357
+ value += '; '+prop+'='+obj[prop];
358
+ }
359
+ }
360
+ }
361
+ return value;
362
+ }
363
+
364
+ /**
365
+ * Adds an authorization header.
366
+ * @param {string|object} auth The authorization bearer token.
367
+ * @returns {object} The original request.
368
+ */
369
+ _getAuthorizationHeader(auth){
370
+ if (!auth) {
371
+ return {};
372
+ }
373
+ if (typeof auth === 'string') {
374
+ return { Authorization: `Bearer ${auth}` };
375
+ }
376
+ let encoded;
377
+ if (this.isForBrowser()) {
378
+ encoded = btoa(`${auth.username}:${auth.password}`);
379
+ } else {
380
+ encoded = Buffer.from(`${auth.username}:${auth.password}`)
381
+ .toString('base64');
382
+ }
383
+ return { Authorization: `Basic ${encoded}` };
384
+ }
385
+
386
+ /**
387
+ *
388
+ * @param {Object} files converts the file names to file, file1, file2.
389
+ * @returns {object} the renamed files.
390
+ */
391
+ _sanitizeFiles(files){
392
+ let requestFiles;
393
+ if (files){
394
+ requestFiles = {};
395
+ Object.keys(files).forEach((k, i) => {
396
+ const name = i ? `file${i + 1}` : 'file';
397
+ requestFiles[name] = {
398
+ data: files[k],
399
+ path: k
400
+ };
401
+ });
402
+ }
403
+ return requestFiles;
404
+ }
405
+ }
406
+
407
+ module.exports = Agent;