/
fetch.client.browser.ts
89 lines (71 loc) · 2.27 KB
/
fetch.client.browser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { getClientBindings, defaultTimeout, ClientResponseType, ClientType } from "client";
import { parseErrorResponse, parseResponse } from "./fetch.client.utils";
export const browserClient: ClientType = async (command, requestId) => {
const {
fullUrl,
headers,
payload,
config,
createAbortListener,
onBeforeRequest,
onRequestStart,
onRequestProgress,
onRequestEnd,
onResponseStart,
onResponseProgress,
onSuccess,
onError,
onResponseEnd,
onTimeoutError,
} = await getClientBindings(command, requestId);
const { method } = command;
const xhr = new XMLHttpRequest();
xhr.timeout = defaultTimeout;
const abort = () => xhr.abort();
return new Promise<ClientResponseType<unknown, unknown>>((resolve) => {
// Inject xhr options
Object.entries(config).forEach(([name, value]) => {
xhr[name] = value;
});
// Open connection
xhr.open(method, fullUrl, true);
// Set Headers
Object.entries(headers).forEach(([name, value]) => xhr.setRequestHeader(name, value));
// Listen to abort signal
const unmountListener = createAbortListener(abort, resolve);
// Request handlers
xhr.upload.onprogress = onRequestProgress;
// Response handlers
xhr.onloadstart = (): void => {
onRequestEnd();
onResponseStart();
};
xhr.onprogress = onResponseProgress;
xhr.onloadend = () => {
onResponseEnd();
unmountListener();
};
xhr.ontimeout = () => onTimeoutError;
// Data handler
xhr.onreadystatechange = (e: Event) => {
const event = e as unknown as ProgressEvent<XMLHttpRequest>;
const finishedState = 4;
if (event.target && event.target.readyState === finishedState) {
const { status } = event.target;
const isSuccess = String(status).startsWith("2") || String(status).startsWith("3");
if (isSuccess) {
const data = parseResponse(event.target.response);
onSuccess(data, status, resolve);
} else {
// delay to finish after onabort/ontimeout
const data = parseErrorResponse(event.target.response);
onError(data, status, resolve);
}
}
};
// Start request
onBeforeRequest();
onRequestStart();
xhr.send(payload);
});
};