-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
136 lines (129 loc) · 3.42 KB
/
index.js
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/**
* The FetchInterceptor class
*/
class FetchInterceptor {
/**
* Recognize global environment and attach fetch
*/
constructor() {
const ENVIRONMENT_IS_REACT_NATIVE
= typeof navigator === 'object' && navigator.product === 'ReactNative';
const ENVIRONMENT_IS_NODE
= typeof process === 'object' && typeof require === 'function';
const ENVIRONMENT_IS_WEB = typeof window === 'object';
const ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
if (ENVIRONMENT_IS_REACT_NATIVE) {
this.env = global;
} else if (ENVIRONMENT_IS_WORKER) {
this.env = self;
} else if (ENVIRONMENT_IS_WEB) {
this.env = window;
} else if (ENVIRONMENT_IS_NODE) {
this.env = global;
} else {
throw new Error('Unsupported environment for fetch-intercept');
}
this.fetch = this.env.fetch;
}
/**
* Whitelist hooks
*/
static hooks = [
'onBeforeRequest',
'onRequestSuccess',
'onRequestFailure',
];
/**
* Register intercept hooks & return an interceptor instance
* @param {object} hooks - The intercept hooks
* @return {FetchInterceptor} An interceptor object
*/
static register(hooks = {}) {
if (this._instance) {
return this._instance;
}
const interceptor = new this();
for (let i = 0; i < this.hooks.length; i++) {
const hook = this.hooks[i];
if (typeof hooks[hook] === 'function') {
interceptor[hook] = hooks[hook];
}
}
interceptor.hijack();
this._instance = interceptor;
return interceptor;
}
/**
* Reset fetch and unregister intercept hooks
*/
unregister() {
this.env.fetch = this.fetch;
delete this.constructor._instance;
}
/**
* Hijack global fetch and insert registered hooks if present
*/
hijack() {
const controller = new AbortController();
const signal = controller.signal;
this.env.fetch = (...a) => {
let request;
if (a[0] instanceof Request) {
let object = {};
[
'cache',
'context',
'credentials',
'destination',
'headers',
'integrity',
'method',
'mode',
'redirect',
'referrer',
'referrerPolicy',
'url',
'body',
'bodyUsed',
].forEach((prop) => {
if (prop in a[0]) {
object[prop] = a[0][prop];
}
});
object.signal = signal;
const {
url,
...options
} = object;
request = new Request(url, options);
} else {
const url = a[0];
const options = {
...a[1],
signal,
};
request = new Request(url, options);
}
if (typeof this.onBeforeRequest === 'function') {
this.onBeforeRequest(request, controller);
}
const promise = this.fetch.call(this.env, request);
if (typeof this.onAfterRequest === 'function') {
this.onAfterRequest(request, controller);
}
return promise.then((response) => {
if (response.ok) {
if (typeof this.onRequestSuccess === 'function') {
this.onRequestSuccess(response, request, controller);
}
} else {
if (typeof this.onRequestFailure === 'function') {
this.onRequestFailure(response, request, controller);
}
}
return response;
});
};
}
}
module.exports = FetchInterceptor;