@webex/http-core 3.0.0-bnr.4 → 3.0.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.
- package/.eslintrc.js +6 -0
- package/babel.config.js +3 -0
- package/dist/http-error-subtypes.js.map +1 -1
- package/dist/http-error.js +21 -22
- package/dist/http-error.js.map +1 -1
- package/dist/index.js +58 -13
- package/dist/index.js.map +1 -1
- package/dist/interceptors/http-status.js +4 -3
- package/dist/interceptors/http-status.js.map +1 -1
- package/dist/lib/detect.js.map +1 -1
- package/dist/lib/interceptor.js +6 -4
- package/dist/lib/interceptor.js.map +1 -1
- package/dist/lib/xhr.js +7 -3
- package/dist/lib/xhr.js.map +1 -1
- package/dist/progress-event.js +6 -2
- package/dist/progress-event.js.map +1 -1
- package/dist/request/index.js +3 -30
- package/dist/request/index.js.map +1 -1
- package/dist/request/request.js.map +1 -1
- package/dist/request/request.shim.js +13 -11
- package/dist/request/request.shim.js.map +1 -1
- package/dist/request/utils.js +91 -0
- package/dist/request/utils.js.map +1 -0
- package/jest.config.js +3 -0
- package/package.json +31 -13
- package/process +1 -0
- package/src/index.js +55 -0
- package/src/lib/xhr.js +5 -1
- package/src/request/index.js +4 -36
- package/src/request/request.shim.js +5 -2
- package/src/request/utils.ts +78 -0
- package/test/integration/spec/request.js +2 -1
- package/test/unit/spec/index.js +58 -0
- package/test/unit/spec/request/request.shim.js +28 -0
- package/test/unit/spec/request/utils.js +77 -0
- package/dist/types/http-error-subtypes.d.ts +0 -8
- package/dist/types/http-error.d.ts +0 -41
- package/dist/types/index.d.ts +0 -7
- package/dist/types/interceptors/http-status.d.ts +0 -17
- package/dist/types/lib/detect.d.ts +0 -6
- package/dist/types/lib/interceptor.d.ts +0 -51
- package/dist/types/lib/xhr.d.ts +0 -6
- package/dist/types/progress-event.d.ts +0 -18
- package/dist/types/request/index.d.ts +0 -5
- package/dist/types/request/request.d.ts +0 -6
- package/dist/types/request/request.shim.d.ts +0 -6
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export */
|
|
2
|
+
import {EventEmitter} from 'events';
|
|
3
|
+
import Interceptor from '../lib/interceptor';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {Object} options
|
|
7
|
+
* @param {Array<Object>} interceptors
|
|
8
|
+
* @param {string} key
|
|
9
|
+
* @param {Object | undefined} res
|
|
10
|
+
* @private
|
|
11
|
+
* @returns {Promise}
|
|
12
|
+
*/
|
|
13
|
+
export function intercept(
|
|
14
|
+
options: object,
|
|
15
|
+
interceptors: Array<Interceptor>,
|
|
16
|
+
key: string,
|
|
17
|
+
res: object = undefined
|
|
18
|
+
): Promise<any> {
|
|
19
|
+
const successKey = `on${key}`;
|
|
20
|
+
const errorKey = `on${key}Error`;
|
|
21
|
+
|
|
22
|
+
return interceptors.reduce(
|
|
23
|
+
(promise, interceptor) =>
|
|
24
|
+
promise.then(
|
|
25
|
+
(result) => {
|
|
26
|
+
interceptor.logOptions(options);
|
|
27
|
+
if (interceptor[successKey]) {
|
|
28
|
+
return interceptor[successKey](options, result);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Promise.resolve(result);
|
|
32
|
+
},
|
|
33
|
+
(reason) => {
|
|
34
|
+
interceptor.logOptions(options);
|
|
35
|
+
if (interceptor[errorKey]) {
|
|
36
|
+
return interceptor[errorKey](options, reason);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return Promise.reject(reason);
|
|
40
|
+
}
|
|
41
|
+
),
|
|
42
|
+
Promise.resolve(res)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Prepare options for a fetch.
|
|
48
|
+
* @param {object} options
|
|
49
|
+
* @returns {Promise}
|
|
50
|
+
*/
|
|
51
|
+
export async function prepareFetchOptions(options: any): Promise<any> {
|
|
52
|
+
if (options.url) {
|
|
53
|
+
options.uri = options.url;
|
|
54
|
+
options.url = null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
options.headers = options.headers || {};
|
|
58
|
+
|
|
59
|
+
if (options.json) {
|
|
60
|
+
// don't override existing accept header declared by user
|
|
61
|
+
options.headers.accept = options.headers.accept || options.headers.Accept || 'application/json';
|
|
62
|
+
|
|
63
|
+
// don't override existing content-type header declared by user
|
|
64
|
+
if (options.method !== 'GET' && options.method !== 'HEAD') {
|
|
65
|
+
options.headers['content-type'] =
|
|
66
|
+
options.headers['content-type'] || options.headers['Content-Type'] || 'application/json';
|
|
67
|
+
options.body = JSON.stringify(options.json === true ? options.body : options.json);
|
|
68
|
+
}
|
|
69
|
+
} else if (options.json !== undefined) {
|
|
70
|
+
Reflect.deleteProperty(options, 'json');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
options.download = new EventEmitter();
|
|
74
|
+
options.upload = new EventEmitter();
|
|
75
|
+
options.keepalive = true;
|
|
76
|
+
|
|
77
|
+
return intercept(options, options.interceptors, 'Request').then(() => options);
|
|
78
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
|
|
4
|
+
import * as utils from '@webex/http-core/src/request/utils';
|
|
5
|
+
import WebexTrackingIdInterceptor from '@webex/webex-core/src/interceptors/webex-tracking-id';
|
|
6
|
+
import UserAgentInterceptor from '@webex/webex-core/src/interceptors/webex-user-agent';
|
|
7
|
+
import {protoprepareFetchOptions, setTimingsAndFetch} from '@webex/http-core/src/index';
|
|
8
|
+
|
|
9
|
+
describe('http-core index tests', () => {
|
|
10
|
+
describe('#protoprepareFetchOptions()', () => {
|
|
11
|
+
it('uses default options and adds expected options', async () => {
|
|
12
|
+
const defaultOptions = {
|
|
13
|
+
interceptors: [WebexTrackingIdInterceptor.create(), UserAgentInterceptor.create()],
|
|
14
|
+
};
|
|
15
|
+
const options = {};
|
|
16
|
+
|
|
17
|
+
const prepareFetchOptions = protoprepareFetchOptions(defaultOptions);
|
|
18
|
+
|
|
19
|
+
await prepareFetchOptions(options);
|
|
20
|
+
|
|
21
|
+
assert.deepEqual(options, {
|
|
22
|
+
headers: {
|
|
23
|
+
trackingid: 'undefined_1',
|
|
24
|
+
'spark-user-agent': 'webex-js-sdk/development (node)',
|
|
25
|
+
},
|
|
26
|
+
keepalive: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
assert.equal(typeof options.logger, 'object');
|
|
30
|
+
assert.equal(typeof options.upload, 'object');
|
|
31
|
+
assert.equal(typeof options.download, 'object');
|
|
32
|
+
assert.isArray(options.interceptors);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('#setTimingsAndFetch()', () => {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
let stubbedFetch;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
global.fetch = sinon.stub();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('calls fetch with expected options', async () => {
|
|
45
|
+
sinon.useFakeTimers(now);
|
|
46
|
+
const options = {uri: 'foo'};
|
|
47
|
+
|
|
48
|
+
const newOptions = setTimingsAndFetch(options);
|
|
49
|
+
|
|
50
|
+
sinon.assert.calledOnce(global.fetch);
|
|
51
|
+
sinon.assert.calledWith(global.fetch, 'foo', {
|
|
52
|
+
uri: 'foo',
|
|
53
|
+
$timings: {requestStart: now, networkStart: now},
|
|
54
|
+
});
|
|
55
|
+
sinon.restore();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import window from 'global/window';
|
|
3
|
+
import request from '@webex/http-core/src/request/request.shim';
|
|
4
|
+
import {EventEmitter} from 'events';
|
|
5
|
+
|
|
6
|
+
describe('Request shim', () => {
|
|
7
|
+
describe('#setAuth()', () => {
|
|
8
|
+
beforeAll(() => {
|
|
9
|
+
global.Blob = function (content, options) {
|
|
10
|
+
return { content, options };
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
it('sets auth header', () => {
|
|
14
|
+
|
|
15
|
+
class DummyXMLHttpRequest {
|
|
16
|
+
upload = new EventEmitter();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
window.XMLHttpRequest = DummyXMLHttpRequest;
|
|
20
|
+
|
|
21
|
+
const options = {upload: new EventEmitter(), headers: [], method: 'post', ...options, auth: {user: 'test', pass: 'pw'}, logger: {warn: () => {}}};
|
|
22
|
+
|
|
23
|
+
request(options);
|
|
24
|
+
|
|
25
|
+
assert.equal(options.headers.Authorization, 'Basic dGVzdDpwdw==');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
|
|
4
|
+
import * as utils from '@webex/http-core/src/request/utils';
|
|
5
|
+
import WebexTrackingIdInterceptor from '@webex/webex-core/src/interceptors/webex-tracking-id';
|
|
6
|
+
import UserAgentInterceptor from '@webex/webex-core/src/interceptors/webex-user-agent';
|
|
7
|
+
|
|
8
|
+
describe('Request utils', () => {
|
|
9
|
+
describe('#intercept()', () => {
|
|
10
|
+
it('updates options from interceptors', async () => {
|
|
11
|
+
const options = {};
|
|
12
|
+
const interceptors = [WebexTrackingIdInterceptor.create(), UserAgentInterceptor.create()];
|
|
13
|
+
|
|
14
|
+
return utils.intercept(options, interceptors, 'Request').then(() => {
|
|
15
|
+
assert.equal(Object.keys(options.headers).length, 2);
|
|
16
|
+
assert.equal(options.headers.trackingid, 'undefined_1');
|
|
17
|
+
assert.equal(options.headers['spark-user-agent'], 'webex-js-sdk/development (node)');
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('#prepareFetchOptions()', () => {
|
|
23
|
+
it('updates options as expected', async () => {
|
|
24
|
+
const options = {
|
|
25
|
+
json: true,
|
|
26
|
+
body: {foo: 'bar'},
|
|
27
|
+
headers: {},
|
|
28
|
+
interceptors: [WebexTrackingIdInterceptor.create(), UserAgentInterceptor.create()],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return utils.prepareFetchOptions(options).then(() => {
|
|
32
|
+
assert.deepEqual(options.headers, {
|
|
33
|
+
accept: 'application/json',
|
|
34
|
+
'content-type': 'application/json',
|
|
35
|
+
trackingid: 'undefined_1',
|
|
36
|
+
'spark-user-agent': 'webex-js-sdk/development (node)',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
assert.equal(options.body, '{"foo":"bar"}');
|
|
40
|
+
|
|
41
|
+
assert.equal(options.download != undefined, true);
|
|
42
|
+
assert.equal(options.upload != undefined, true);
|
|
43
|
+
assert.equal(options.keepalive, true);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('updates options as expected when accept and content-type exist', async () => {
|
|
48
|
+
const options = {
|
|
49
|
+
json: true,
|
|
50
|
+
body: {foo: 'bar'},
|
|
51
|
+
headers: {accept: 'foo', 'content-type': 'bar'},
|
|
52
|
+
interceptors: [WebexTrackingIdInterceptor.create(), UserAgentInterceptor.create()],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return utils.prepareFetchOptions(options).then(() => {
|
|
56
|
+
assert.deepEqual(options.headers, {
|
|
57
|
+
accept: 'foo',
|
|
58
|
+
'content-type': 'bar',
|
|
59
|
+
trackingid: 'undefined_1',
|
|
60
|
+
'spark-user-agent': 'webex-js-sdk/development (node)',
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('updates body as expected when json = some object', async () => {
|
|
66
|
+
const options = {
|
|
67
|
+
json: {bar: 'baz'},
|
|
68
|
+
headers: {accept: 'foo', 'content-type': 'bar'},
|
|
69
|
+
interceptors: [WebexTrackingIdInterceptor.create(), UserAgentInterceptor.create()],
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
return utils.prepareFetchOptions(options).then(() => {
|
|
73
|
+
assert.equal(options.body, '{"bar":"baz"}');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base HttpError class. Unlikely to be thrown directly, but handy for general
|
|
3
|
-
* type comparison.
|
|
4
|
-
*/
|
|
5
|
-
declare class HttpError {
|
|
6
|
-
/**
|
|
7
|
-
* @example Extend via
|
|
8
|
-
* MyError extends HttpError {
|
|
9
|
-
* static errorKeys = HttpError.errorKeys.concat([
|
|
10
|
-
* `key1`,
|
|
11
|
-
* `key2`
|
|
12
|
-
* ])
|
|
13
|
-
* }
|
|
14
|
-
*
|
|
15
|
-
* @type {Array}
|
|
16
|
-
*/
|
|
17
|
-
static errorKeys: any[];
|
|
18
|
-
/**
|
|
19
|
-
* Default error string if no error can be extracted from the http response
|
|
20
|
-
* @type {string}
|
|
21
|
-
*/
|
|
22
|
-
static defaultMessage: string;
|
|
23
|
-
/**
|
|
24
|
-
* Parses HttpResponse objects for useful information (status, headers, etc)
|
|
25
|
-
* as well as attempting to extract a useful error message.
|
|
26
|
-
* @param {HttpResponse} res
|
|
27
|
-
* @returns {string}
|
|
28
|
-
*/
|
|
29
|
-
parse(res: HttpResponse): string;
|
|
30
|
-
/**
|
|
31
|
-
* Recursively parses an error body looking for a likely error candidate
|
|
32
|
-
* @param {object} body
|
|
33
|
-
* @returns {string}
|
|
34
|
-
*/
|
|
35
|
-
parseObject(body: object): string;
|
|
36
|
-
}
|
|
37
|
-
declare namespace HttpError {
|
|
38
|
-
export { makeSubTypes };
|
|
39
|
-
}
|
|
40
|
-
export default HttpError;
|
|
41
|
-
import makeSubTypes from "./http-error-subtypes";
|
package/dist/types/index.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export const defaults: import("lodash").CurriedFunction1<any, Promise<any>>;
|
|
2
|
-
export const request: Promise<any>;
|
|
3
|
-
export { default as ProgressEvent } from "./progress-event";
|
|
4
|
-
export { default as Interceptor } from "./lib/interceptor";
|
|
5
|
-
export { default as HttpError } from "./http-error";
|
|
6
|
-
export { default as HttpStatusInterceptor } from "./interceptors/http-status";
|
|
7
|
-
export { default as detect } from "./lib/detect";
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @class
|
|
3
|
-
*/
|
|
4
|
-
export default class HttpStatusInterceptor extends Interceptor {
|
|
5
|
-
/**
|
|
6
|
-
* @param {Object} options
|
|
7
|
-
* @returns {HttpStatusInterceptor}
|
|
8
|
-
*/
|
|
9
|
-
static create(options: any): HttpStatusInterceptor;
|
|
10
|
-
/**
|
|
11
|
-
* @param {Object} webex
|
|
12
|
-
* @param {Object} options
|
|
13
|
-
* @returns {HttpStatusInterceptor}
|
|
14
|
-
*/
|
|
15
|
-
constructor(webex: any, options: any);
|
|
16
|
-
}
|
|
17
|
-
import Interceptor from "../lib/interceptor";
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @class
|
|
3
|
-
*/
|
|
4
|
-
export default class Interceptor {
|
|
5
|
-
/**
|
|
6
|
-
* @abstract
|
|
7
|
-
* @returns {Interceptor}
|
|
8
|
-
*/
|
|
9
|
-
static create(): Interceptor;
|
|
10
|
-
/**
|
|
11
|
-
* @constructor
|
|
12
|
-
* @param {Object} attrs
|
|
13
|
-
* @returns {UrlInterceptor}
|
|
14
|
-
*/
|
|
15
|
-
constructor(attrs: any);
|
|
16
|
-
/**
|
|
17
|
-
* Logs the options of a request. This should be utilized
|
|
18
|
-
* during the intercepting process, but can be used at any
|
|
19
|
-
* time otherwise.
|
|
20
|
-
* @param {object} options
|
|
21
|
-
* @returns {void}
|
|
22
|
-
*/
|
|
23
|
-
logOptions(options?: object): void;
|
|
24
|
-
/**
|
|
25
|
-
* Transform request options before sending them
|
|
26
|
-
* @param {Object} options
|
|
27
|
-
* @returns {Promise<Object>}
|
|
28
|
-
*/
|
|
29
|
-
onRequest(options: any): Promise<any>;
|
|
30
|
-
/**
|
|
31
|
-
* Handle request failures
|
|
32
|
-
* @param {Object} options
|
|
33
|
-
* @param {Error} reason
|
|
34
|
-
* @returns {RejectedPromise<Error>}
|
|
35
|
-
*/
|
|
36
|
-
onRequestError(options: any, reason: Error): RejectedPromise<Error>;
|
|
37
|
-
/**
|
|
38
|
-
* Transform response before returning it
|
|
39
|
-
* @param {Object} options
|
|
40
|
-
* @param {HttpResponse} response
|
|
41
|
-
* @returns {Promise<HttpResponse>}
|
|
42
|
-
*/
|
|
43
|
-
onResponse(options: any, response: HttpResponse): Promise<HttpResponse>;
|
|
44
|
-
/**
|
|
45
|
-
* Handle response errors
|
|
46
|
-
* @param {Object} options
|
|
47
|
-
* @param {WebexHttpError} reason
|
|
48
|
-
* @returns {Promise<WebexHttpError>}
|
|
49
|
-
*/
|
|
50
|
-
onResponseError(options: any, reason: WebexHttpError): Promise<WebexHttpError>;
|
|
51
|
-
}
|
package/dist/types/lib/xhr.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Object of the same shape as web browser ProgressEvents
|
|
3
|
-
* @class ProgressEvent
|
|
4
|
-
* @param {integer} loaded
|
|
5
|
-
* @param {integer} total
|
|
6
|
-
* @returns {ProgressEvent}
|
|
7
|
-
*/
|
|
8
|
-
export default function ProgressEvent(loaded: integer, total: integer): ProgressEvent;
|
|
9
|
-
export default class ProgressEvent {
|
|
10
|
-
/**
|
|
11
|
-
* Object of the same shape as web browser ProgressEvents
|
|
12
|
-
* @class ProgressEvent
|
|
13
|
-
* @param {integer} loaded
|
|
14
|
-
* @param {integer} total
|
|
15
|
-
* @returns {ProgressEvent}
|
|
16
|
-
*/
|
|
17
|
-
constructor(loaded: integer, total: integer);
|
|
18
|
-
}
|