@algolia/requester-browser-xhr 4.14.2 → 5.0.0-alpha.3

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.
@@ -0,0 +1,3 @@
1
+ export * from './src/createXhrRequester';
2
+ export * from './src/echoRequester';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC"}
@@ -2,60 +2,63 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- function createBrowserXhrRequester() {
6
- return {
7
- send(request) {
8
- return new Promise((resolve) => {
9
- const baseRequester = new XMLHttpRequest();
10
- baseRequester.open(request.method, request.url, true);
11
- Object.keys(request.headers).forEach(key => baseRequester.setRequestHeader(key, request.headers[key]));
12
- const createTimeout = (timeout, content) => {
13
- return setTimeout(() => {
14
- baseRequester.abort();
15
- resolve({
16
- status: 0,
17
- content,
18
- isTimedOut: true,
19
- });
20
- }, timeout * 1000);
21
- };
22
- const connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
23
- // eslint-disable-next-line functional/no-let
24
- let responseTimeout;
25
- // eslint-disable-next-line functional/immutable-data
26
- baseRequester.onreadystatechange = () => {
27
- if (baseRequester.readyState > baseRequester.OPENED && responseTimeout === undefined) {
28
- clearTimeout(connectTimeout);
29
- responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
30
- }
31
- };
32
- // eslint-disable-next-line functional/immutable-data
33
- baseRequester.onerror = () => {
34
- // istanbul ignore next
35
- if (baseRequester.status === 0) {
36
- clearTimeout(connectTimeout);
37
- clearTimeout(responseTimeout);
38
- resolve({
39
- content: baseRequester.responseText || 'Network request failed',
40
- status: baseRequester.status,
41
- isTimedOut: false,
42
- });
43
- }
44
- };
45
- // eslint-disable-next-line functional/immutable-data
46
- baseRequester.onload = () => {
5
+ var clientCommon = require('@algolia/client-common');
6
+
7
+ function createXhrRequester() {
8
+ function send(request) {
9
+ return new Promise((resolve) => {
10
+ const baseRequester = new XMLHttpRequest();
11
+ baseRequester.open(request.method, request.url, true);
12
+ Object.keys(request.headers).forEach((key) => baseRequester.setRequestHeader(key, request.headers[key]));
13
+ const createTimeout = (timeout, content) => {
14
+ return setTimeout(() => {
15
+ baseRequester.abort();
16
+ resolve({
17
+ status: 0,
18
+ content,
19
+ isTimedOut: true,
20
+ });
21
+ }, timeout);
22
+ };
23
+ const connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
24
+ let responseTimeout;
25
+ baseRequester.onreadystatechange = () => {
26
+ if (baseRequester.readyState > baseRequester.OPENED &&
27
+ responseTimeout === undefined) {
28
+ clearTimeout(connectTimeout);
29
+ responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
30
+ }
31
+ };
32
+ baseRequester.onerror = () => {
33
+ // istanbul ignore next
34
+ if (baseRequester.status === 0) {
47
35
  clearTimeout(connectTimeout);
48
36
  clearTimeout(responseTimeout);
49
37
  resolve({
50
- content: baseRequester.responseText,
38
+ content: baseRequester.responseText || 'Network request failed',
51
39
  status: baseRequester.status,
52
40
  isTimedOut: false,
53
41
  });
54
- };
55
- baseRequester.send(request.data);
56
- });
57
- },
58
- };
42
+ }
43
+ };
44
+ baseRequester.onload = () => {
45
+ clearTimeout(connectTimeout);
46
+ clearTimeout(responseTimeout);
47
+ resolve({
48
+ content: baseRequester.responseText,
49
+ status: baseRequester.status,
50
+ isTimedOut: false,
51
+ });
52
+ };
53
+ baseRequester.send(request.data);
54
+ });
55
+ }
56
+ return { send };
57
+ }
58
+
59
+ function echoRequester(status = 200) {
60
+ return clientCommon.createEchoRequester({ getURL: (url) => new URL(url), status });
59
61
  }
60
62
 
61
- exports.createBrowserXhrRequester = createBrowserXhrRequester;
63
+ exports.createXhrRequester = createXhrRequester;
64
+ exports.echoRequester = echoRequester;
@@ -0,0 +1,59 @@
1
+ import { createEchoRequester } from '@algolia/client-common';
2
+
3
+ function createXhrRequester() {
4
+ function send(request) {
5
+ return new Promise((resolve) => {
6
+ const baseRequester = new XMLHttpRequest();
7
+ baseRequester.open(request.method, request.url, true);
8
+ Object.keys(request.headers).forEach((key) => baseRequester.setRequestHeader(key, request.headers[key]));
9
+ const createTimeout = (timeout, content) => {
10
+ return setTimeout(() => {
11
+ baseRequester.abort();
12
+ resolve({
13
+ status: 0,
14
+ content,
15
+ isTimedOut: true,
16
+ });
17
+ }, timeout);
18
+ };
19
+ const connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
20
+ let responseTimeout;
21
+ baseRequester.onreadystatechange = () => {
22
+ if (baseRequester.readyState > baseRequester.OPENED &&
23
+ responseTimeout === undefined) {
24
+ clearTimeout(connectTimeout);
25
+ responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
26
+ }
27
+ };
28
+ baseRequester.onerror = () => {
29
+ // istanbul ignore next
30
+ if (baseRequester.status === 0) {
31
+ clearTimeout(connectTimeout);
32
+ clearTimeout(responseTimeout);
33
+ resolve({
34
+ content: baseRequester.responseText || 'Network request failed',
35
+ status: baseRequester.status,
36
+ isTimedOut: false,
37
+ });
38
+ }
39
+ };
40
+ baseRequester.onload = () => {
41
+ clearTimeout(connectTimeout);
42
+ clearTimeout(responseTimeout);
43
+ resolve({
44
+ content: baseRequester.responseText,
45
+ status: baseRequester.status,
46
+ isTimedOut: false,
47
+ });
48
+ };
49
+ baseRequester.send(request.data);
50
+ });
51
+ }
52
+ return { send };
53
+ }
54
+
55
+ function echoRequester(status = 200) {
56
+ return createEchoRequester({ getURL: (url) => new URL(url), status });
57
+ }
58
+
59
+ export { createXhrRequester, echoRequester };
@@ -0,0 +1,3 @@
1
+ import type { Requester } from '@algolia/client-common';
2
+ export declare function createXhrRequester(): Requester;
3
+ //# sourceMappingURL=createXhrRequester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createXhrRequester.d.ts","sourceRoot":"","sources":["../../../../packages/requester-browser-xhr/src/createXhrRequester.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,SAAS,EAAY,MAAM,wBAAwB,CAAC;AAI9E,wBAAgB,kBAAkB,IAAI,SAAS,CAyE9C"}
@@ -0,0 +1,3 @@
1
+ import type { Requester } from '@algolia/client-common';
2
+ export declare function echoRequester(status?: number): Requester;
3
+ //# sourceMappingURL=echoRequester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"echoRequester.d.ts","sourceRoot":"","sources":["../../../../packages/requester-browser-xhr/src/echoRequester.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,wBAAgB,aAAa,CAAC,MAAM,GAAE,MAAY,GAAG,SAAS,CAE7D"}
package/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './src/createXhrRequester';
2
+ export * from './src/echoRequester';
package/package.json CHANGED
@@ -1,22 +1,35 @@
1
1
  {
2
2
  "name": "@algolia/requester-browser-xhr",
3
- "version": "4.14.2",
4
- "private": false,
3
+ "version": "5.0.0-alpha.3",
5
4
  "description": "Promise-based request library for browser using xhr.",
6
- "repository": {
7
- "type": "git",
8
- "url": "git://github.com/algolia/algoliasearch-client-javascript.git"
9
- },
5
+ "repository": "algolia/algoliasearch-client-javascript",
10
6
  "license": "MIT",
11
- "sideEffects": false,
12
- "main": "index.js",
13
- "module": "dist/requester-browser-xhr.esm.js",
14
- "types": "dist/requester-browser-xhr.d.ts",
7
+ "author": "Algolia",
8
+ "main": "dist/requester-browser-xhr.cjs.js",
9
+ "module": "dist/requester-browser-xhr.esm.node.js",
10
+ "types": "dist/index.d.ts",
15
11
  "files": [
16
- "index.js",
17
- "dist"
12
+ "dist",
13
+ "src",
14
+ "index.ts"
18
15
  ],
16
+ "scripts": {
17
+ "clean": "rm -rf dist/",
18
+ "test": "jest"
19
+ },
19
20
  "dependencies": {
20
- "@algolia/requester-common": "4.14.2"
21
+ "@algolia/client-common": "5.0.0-alpha.3"
22
+ },
23
+ "devDependencies": {
24
+ "@types/jest": "28.1.6",
25
+ "@types/node": "16.11.45",
26
+ "jest": "28.1.3",
27
+ "jest-environment-jsdom": "28.1.3",
28
+ "ts-jest": "28.0.5",
29
+ "typescript": "4.7.4",
30
+ "xhr-mock": "2.5.1"
31
+ },
32
+ "engines": {
33
+ "node": ">= 14.0.0"
21
34
  }
22
35
  }
@@ -0,0 +1,223 @@
1
+ import type http from 'http';
2
+
3
+ import type { EndRequest } from '@algolia/client-common';
4
+ import type { MockRequest, MockResponse } from 'xhr-mock';
5
+ import mock from 'xhr-mock';
6
+
7
+ import { createXhrRequester } from '../..';
8
+ import {
9
+ BASE_URL,
10
+ headers,
11
+ timeoutRequest,
12
+ requestStub,
13
+ getStringifiedBody,
14
+ createTestServer,
15
+ } from '../../../../tests/utils';
16
+
17
+ const requester = createXhrRequester();
18
+
19
+ describe('status code handling', () => {
20
+ beforeEach(() => mock.setup());
21
+ afterEach(() => mock.teardown());
22
+
23
+ it('sends requests', async () => {
24
+ mock.post(BASE_URL, (req: MockRequest, res: MockResponse): MockResponse => {
25
+ expect(req.method()).toEqual('POST');
26
+ expect(req.header('content-type')).toEqual('text/plain');
27
+ expect(req.body()).toEqual(JSON.stringify({ foo: 'bar' }));
28
+
29
+ return res.status(200);
30
+ });
31
+
32
+ await requester.send(requestStub);
33
+ });
34
+
35
+ it('resolves status 200', async () => {
36
+ const body = getStringifiedBody();
37
+
38
+ mock.post(BASE_URL, {
39
+ status: 200,
40
+ body: requestStub.data,
41
+ });
42
+
43
+ const response = await requester.send(requestStub);
44
+
45
+ expect(response.status).toBe(200);
46
+ expect(response.content).toBe(body);
47
+ expect(response.isTimedOut).toBe(false);
48
+ });
49
+
50
+ it('resolves status 300', async () => {
51
+ const reason = 'Multiple Choices';
52
+
53
+ mock.post(BASE_URL, {
54
+ status: 300,
55
+ reason,
56
+ });
57
+
58
+ const response = await requester.send(requestStub);
59
+
60
+ expect(response.status).toBe(300);
61
+ expect(response.content).toBe(''); // No body returned here on xhr
62
+ expect(response.isTimedOut).toBe(false);
63
+ });
64
+
65
+ it('resolves status 400', async () => {
66
+ const body = getStringifiedBody({
67
+ message: 'Invalid Application-Id or API-Key',
68
+ });
69
+
70
+ mock.post(BASE_URL, {
71
+ status: 400,
72
+ body,
73
+ });
74
+
75
+ const response = await requester.send(requestStub);
76
+
77
+ expect(response.status).toBe(400);
78
+ expect(response.content).toBe(body);
79
+ expect(response.isTimedOut).toBe(false);
80
+ });
81
+
82
+ it('handles the protocol', async () => {
83
+ const body = getStringifiedBody();
84
+
85
+ mock.post('http://localhost/', {
86
+ status: 200,
87
+ body,
88
+ });
89
+
90
+ const response = await requester.send({
91
+ ...requestStub,
92
+ url: 'http://localhost',
93
+ });
94
+
95
+ expect(response.status).toBe(200);
96
+ expect(response.content).toBe(body);
97
+ expect(response.isTimedOut).toBe(false);
98
+ });
99
+ });
100
+
101
+ describe('timeout handling', () => {
102
+ let server: http.Server;
103
+ // setup http server to test timeout
104
+ beforeAll(() => {
105
+ server = createTestServer();
106
+
107
+ server.listen('1111');
108
+ });
109
+
110
+ afterAll((done) => {
111
+ server.close(() => done());
112
+ });
113
+
114
+ it('connection timeouts with the given 1 seconds connection timeout', async () => {
115
+ const before = Date.now();
116
+ const response = await requester.send({
117
+ ...timeoutRequest,
118
+ connectTimeout: 1000,
119
+ url: 'http://www.google.com:81',
120
+ });
121
+
122
+ const now = Date.now();
123
+
124
+ expect(response.content).toBe('Connection timeout');
125
+ expect(now - before).toBeGreaterThan(999);
126
+ expect(now - before).toBeLessThan(1200);
127
+ });
128
+
129
+ it('connection timeouts with the given 2 seconds connection timeout', async () => {
130
+ const before = Date.now();
131
+ const response = await requester.send({
132
+ ...timeoutRequest,
133
+ connectTimeout: 2000,
134
+ url: 'http://www.google.com:81',
135
+ });
136
+
137
+ const now = Date.now();
138
+
139
+ expect(response.content).toBe('Connection timeout');
140
+ expect(now - before).toBeGreaterThan(1990);
141
+ expect(now - before).toBeLessThan(2200);
142
+ });
143
+
144
+ it("socket timeouts if response don't appears before the timeout with 2 seconds timeout", async () => {
145
+ const before = Date.now();
146
+
147
+ const response = await requester.send({
148
+ ...timeoutRequest,
149
+ responseTimeout: 2000,
150
+ url: 'http://localhost:1111',
151
+ });
152
+
153
+ const now = Date.now();
154
+
155
+ expect(response.content).toBe('Socket timeout');
156
+ expect(now - before).toBeGreaterThan(1990);
157
+ expect(now - before).toBeLessThan(2200);
158
+ });
159
+
160
+ it("socket timeouts if response don't appears before the timeout with 3 seconds timeout", async () => {
161
+ const before = Date.now();
162
+
163
+ const response = await requester.send({
164
+ ...timeoutRequest,
165
+ responseTimeout: 3000,
166
+ url: 'http://localhost:1111',
167
+ });
168
+
169
+ const now = Date.now();
170
+
171
+ expect(response.content).toBe('Socket timeout');
172
+ expect(now - before).toBeGreaterThan(2999);
173
+ expect(now - before).toBeLessThan(3200);
174
+ });
175
+
176
+ it('do not timeouts if response appears before the timeout', async () => {
177
+ const before = Date.now();
178
+ const response = await requester.send({
179
+ ...requestStub,
180
+ responseTimeout: 6000,
181
+ url: 'http://localhost:1111',
182
+ });
183
+
184
+ const now = Date.now();
185
+
186
+ expect(response.isTimedOut).toBe(false);
187
+ expect(response.status).toBe(200);
188
+ expect(response.content).toBe('{"foo": "bar"}');
189
+ expect(now - before).toBeGreaterThan(4999);
190
+ expect(now - before).toBeLessThan(5200);
191
+ }, 10000); // This is a long-running test, default server timeout is set to 5000ms
192
+ });
193
+
194
+ describe('error handling', () => {
195
+ it('resolves dns not found', async () => {
196
+ const request: EndRequest = {
197
+ url: 'https://this-dont-exist.algolia.com',
198
+ method: 'POST',
199
+ headers,
200
+ data: getStringifiedBody(),
201
+ responseTimeout: 2000,
202
+ connectTimeout: 1000,
203
+ };
204
+
205
+ const response = await requester.send(request);
206
+
207
+ expect(response.status).toBe(0);
208
+ expect(response.content).toBe('Network request failed');
209
+ expect(response.isTimedOut).toBe(false);
210
+ });
211
+
212
+ it('resolves general network errors', async () => {
213
+ mock.post(BASE_URL, () =>
214
+ Promise.reject(new Error('This is a general error'))
215
+ );
216
+
217
+ const response = await requester.send(requestStub);
218
+
219
+ expect(response.status).toBe(0);
220
+ expect(response.content).toBe('Network request failed');
221
+ expect(response.isTimedOut).toBe(false);
222
+ });
223
+ });
@@ -0,0 +1,78 @@
1
+ import type { EndRequest, Requester, Response } from '@algolia/client-common';
2
+
3
+ type Timeout = ReturnType<typeof setTimeout>;
4
+
5
+ export function createXhrRequester(): Requester {
6
+ function send(request: EndRequest): Promise<Response> {
7
+ return new Promise((resolve) => {
8
+ const baseRequester = new XMLHttpRequest();
9
+ baseRequester.open(request.method, request.url, true);
10
+
11
+ Object.keys(request.headers).forEach((key) =>
12
+ baseRequester.setRequestHeader(key, request.headers[key])
13
+ );
14
+
15
+ const createTimeout = (timeout: number, content: string): Timeout => {
16
+ return setTimeout(() => {
17
+ baseRequester.abort();
18
+
19
+ resolve({
20
+ status: 0,
21
+ content,
22
+ isTimedOut: true,
23
+ });
24
+ }, timeout);
25
+ };
26
+
27
+ const connectTimeout = createTimeout(
28
+ request.connectTimeout,
29
+ 'Connection timeout'
30
+ );
31
+
32
+ let responseTimeout: Timeout | undefined;
33
+
34
+ baseRequester.onreadystatechange = (): void => {
35
+ if (
36
+ baseRequester.readyState > baseRequester.OPENED &&
37
+ responseTimeout === undefined
38
+ ) {
39
+ clearTimeout(connectTimeout);
40
+
41
+ responseTimeout = createTimeout(
42
+ request.responseTimeout,
43
+ 'Socket timeout'
44
+ );
45
+ }
46
+ };
47
+
48
+ baseRequester.onerror = (): void => {
49
+ // istanbul ignore next
50
+ if (baseRequester.status === 0) {
51
+ clearTimeout(connectTimeout);
52
+ clearTimeout(responseTimeout!);
53
+
54
+ resolve({
55
+ content: baseRequester.responseText || 'Network request failed',
56
+ status: baseRequester.status,
57
+ isTimedOut: false,
58
+ });
59
+ }
60
+ };
61
+
62
+ baseRequester.onload = (): void => {
63
+ clearTimeout(connectTimeout);
64
+ clearTimeout(responseTimeout!);
65
+
66
+ resolve({
67
+ content: baseRequester.responseText,
68
+ status: baseRequester.status,
69
+ isTimedOut: false,
70
+ });
71
+ };
72
+
73
+ baseRequester.send(request.data);
74
+ });
75
+ }
76
+
77
+ return { send };
78
+ }
@@ -0,0 +1,6 @@
1
+ import { createEchoRequester } from '@algolia/client-common';
2
+ import type { Requester } from '@algolia/client-common';
3
+
4
+ export function echoRequester(status: number = 200): Requester {
5
+ return createEchoRequester({ getURL: (url: string) => new URL(url), status });
6
+ }
@@ -1,5 +0,0 @@
1
- import { Requester } from '@algolia/requester-common';
2
-
3
- export declare function createBrowserXhrRequester(): Requester;
4
-
5
- export { }
@@ -1,57 +0,0 @@
1
- function createBrowserXhrRequester() {
2
- return {
3
- send(request) {
4
- return new Promise((resolve) => {
5
- const baseRequester = new XMLHttpRequest();
6
- baseRequester.open(request.method, request.url, true);
7
- Object.keys(request.headers).forEach(key => baseRequester.setRequestHeader(key, request.headers[key]));
8
- const createTimeout = (timeout, content) => {
9
- return setTimeout(() => {
10
- baseRequester.abort();
11
- resolve({
12
- status: 0,
13
- content,
14
- isTimedOut: true,
15
- });
16
- }, timeout * 1000);
17
- };
18
- const connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
19
- // eslint-disable-next-line functional/no-let
20
- let responseTimeout;
21
- // eslint-disable-next-line functional/immutable-data
22
- baseRequester.onreadystatechange = () => {
23
- if (baseRequester.readyState > baseRequester.OPENED && responseTimeout === undefined) {
24
- clearTimeout(connectTimeout);
25
- responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
26
- }
27
- };
28
- // eslint-disable-next-line functional/immutable-data
29
- baseRequester.onerror = () => {
30
- // istanbul ignore next
31
- if (baseRequester.status === 0) {
32
- clearTimeout(connectTimeout);
33
- clearTimeout(responseTimeout);
34
- resolve({
35
- content: baseRequester.responseText || 'Network request failed',
36
- status: baseRequester.status,
37
- isTimedOut: false,
38
- });
39
- }
40
- };
41
- // eslint-disable-next-line functional/immutable-data
42
- baseRequester.onload = () => {
43
- clearTimeout(connectTimeout);
44
- clearTimeout(responseTimeout);
45
- resolve({
46
- content: baseRequester.responseText,
47
- status: baseRequester.status,
48
- isTimedOut: false,
49
- });
50
- };
51
- baseRequester.send(request.data);
52
- });
53
- },
54
- };
55
- }
56
-
57
- export { createBrowserXhrRequester };
package/index.js DELETED
@@ -1,2 +0,0 @@
1
- // eslint-disable-next-line functional/immutable-data, import/no-commonjs
2
- module.exports = require('./dist/requester-browser-xhr.cjs.js');