fetchache 0.1.2 → 0.1.4
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/index.d.ts +2 -2
- package/index.js +46 -30
- package/index.mjs +46 -30
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -3,14 +3,14 @@ export interface FetchacheCacheEntry {
|
|
|
3
3
|
policy: CachePolicy.CachePolicyObject;
|
|
4
4
|
body: string;
|
|
5
5
|
}
|
|
6
|
-
declare type FetchFn =
|
|
6
|
+
declare type FetchFn = (input: URL | RequestInfo, init: RequestInit, ...rest: any[]) => Promise<Response>;
|
|
7
7
|
export interface FetchacheOptions {
|
|
8
8
|
fetch: FetchFn;
|
|
9
9
|
Request: typeof Request;
|
|
10
10
|
Response: typeof Response;
|
|
11
11
|
cache: KeyValueCache<FetchacheCacheEntry>;
|
|
12
12
|
}
|
|
13
|
-
export declare function fetchFactory({ fetch,
|
|
13
|
+
export declare function fetchFactory({ fetch, Response, cache }: FetchacheOptions): FetchFn;
|
|
14
14
|
export interface KeyValueCacheSetOptions {
|
|
15
15
|
/**
|
|
16
16
|
* Specified in **seconds**, the time-to-live (TTL) value limits the lifespan
|
package/index.js
CHANGED
|
@@ -6,20 +6,29 @@ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'defau
|
|
|
6
6
|
|
|
7
7
|
const CachePolicy = _interopDefault(require('http-cache-semantics'));
|
|
8
8
|
|
|
9
|
-
function fetchFactory({ fetch,
|
|
10
|
-
return async (input, init) => {
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
function fetchFactory({ fetch, Response, cache }) {
|
|
10
|
+
return async (input, init, ...rest) => {
|
|
11
|
+
let url;
|
|
12
|
+
let method = 'GET';
|
|
13
|
+
let headers = {};
|
|
14
|
+
if (typeof input === 'object' && 'json' in input) {
|
|
15
|
+
url = input.url;
|
|
16
|
+
method = input.method;
|
|
17
|
+
headers = input.headers;
|
|
14
18
|
}
|
|
15
19
|
else {
|
|
16
|
-
|
|
20
|
+
url = input.toString();
|
|
21
|
+
if (init != null) {
|
|
22
|
+
method = init.method || method;
|
|
23
|
+
headers = init.headers || headers;
|
|
24
|
+
}
|
|
17
25
|
}
|
|
18
|
-
const cacheKey =
|
|
26
|
+
const cacheKey = url;
|
|
19
27
|
const entry = await cache.get(cacheKey);
|
|
28
|
+
const policyRequest = policyRequestFrom(url, method, headers);
|
|
20
29
|
if (!entry) {
|
|
21
|
-
const response = await fetch(
|
|
22
|
-
const policy = new CachePolicy(
|
|
30
|
+
const response = await fetch(input, init, ...rest);
|
|
31
|
+
const policy = new CachePolicy(policyRequest, policyResponseFrom(response));
|
|
23
32
|
return storeResponseAndReturnClone(cache, response, policy, cacheKey);
|
|
24
33
|
}
|
|
25
34
|
const { policy: policyRaw, bytes } = typeof entry === 'string' ? JSON.parse(entry) : entry;
|
|
@@ -27,7 +36,7 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
27
36
|
// Remove url from the policy, because otherwise it would never match a request with a custom cache key
|
|
28
37
|
policy._url = undefined;
|
|
29
38
|
const bodyInit = new Uint8Array(bytes);
|
|
30
|
-
if (policy.satisfiesWithoutRevalidation(
|
|
39
|
+
if (policy.satisfiesWithoutRevalidation(policyRequest)) {
|
|
31
40
|
const headers = policy.responseHeaders();
|
|
32
41
|
return new Response(bodyInit, {
|
|
33
42
|
url: policy._url,
|
|
@@ -36,12 +45,17 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
36
45
|
});
|
|
37
46
|
}
|
|
38
47
|
else {
|
|
39
|
-
const revalidationHeaders = policy.revalidationHeaders(
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
const revalidationHeaders = policy.revalidationHeaders(policyRequest);
|
|
49
|
+
const revalidationResponse = await fetch(url, {
|
|
50
|
+
...init,
|
|
51
|
+
method,
|
|
52
|
+
headers: {
|
|
53
|
+
...headers,
|
|
54
|
+
...revalidationHeaders,
|
|
55
|
+
},
|
|
56
|
+
}, ...rest);
|
|
57
|
+
const revalidationPolicyRequest = policyRequestFrom(url, method, revalidationHeaders);
|
|
58
|
+
const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(revalidationPolicyRequest, policyResponseFrom(revalidationResponse));
|
|
45
59
|
const newArrayBuffer = await revalidationResponse.arrayBuffer();
|
|
46
60
|
const newBody = modified ? newArrayBuffer : bodyInit;
|
|
47
61
|
return storeResponseAndReturnClone(cache, new Response(newBody, {
|
|
@@ -64,7 +78,7 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
64
78
|
const uint8array = new Uint8Array(arrayBuffer);
|
|
65
79
|
const entry = {
|
|
66
80
|
policy: policy.toObject(),
|
|
67
|
-
bytes:
|
|
81
|
+
bytes: Array.from(uint8array),
|
|
68
82
|
};
|
|
69
83
|
await cache.set(cacheKey, entry, {
|
|
70
84
|
ttl,
|
|
@@ -73,22 +87,17 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
73
87
|
// body can only be used once.
|
|
74
88
|
// To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
|
|
75
89
|
// response.clone() but create a new response from the consumed body
|
|
76
|
-
return new Response(uint8array,
|
|
77
|
-
url: response.url,
|
|
78
|
-
status: response.status,
|
|
79
|
-
statusText: response.statusText,
|
|
80
|
-
headers: response.headers,
|
|
81
|
-
});
|
|
90
|
+
return new Response(uint8array, response);
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
93
|
function canBeRevalidated(response) {
|
|
85
94
|
return response.headers.has('ETag');
|
|
86
95
|
}
|
|
87
|
-
function policyRequestFrom(
|
|
96
|
+
function policyRequestFrom(url, method, headers) {
|
|
88
97
|
return {
|
|
89
|
-
url
|
|
90
|
-
method
|
|
91
|
-
headers: headersToObject(
|
|
98
|
+
url,
|
|
99
|
+
method,
|
|
100
|
+
headers: headersToObject(headers),
|
|
92
101
|
};
|
|
93
102
|
}
|
|
94
103
|
function policyResponseFrom(response) {
|
|
@@ -99,9 +108,16 @@ function policyResponseFrom(response) {
|
|
|
99
108
|
}
|
|
100
109
|
function headersToObject(headers) {
|
|
101
110
|
const object = Object.create(null);
|
|
102
|
-
headers
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
if (headers != null) {
|
|
112
|
+
if ('forEach' in headers && typeof headers.forEach === 'function') {
|
|
113
|
+
headers === null || headers === void 0 ? void 0 : headers.forEach((val, key) => {
|
|
114
|
+
object[key] = val;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
return headers;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
105
121
|
return object;
|
|
106
122
|
}
|
|
107
123
|
|
package/index.mjs
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
import CachePolicy from 'http-cache-semantics';
|
|
2
2
|
|
|
3
|
-
function fetchFactory({ fetch,
|
|
4
|
-
return async (input, init) => {
|
|
5
|
-
let
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
function fetchFactory({ fetch, Response, cache }) {
|
|
4
|
+
return async (input, init, ...rest) => {
|
|
5
|
+
let url;
|
|
6
|
+
let method = 'GET';
|
|
7
|
+
let headers = {};
|
|
8
|
+
if (typeof input === 'object' && 'json' in input) {
|
|
9
|
+
url = input.url;
|
|
10
|
+
method = input.method;
|
|
11
|
+
headers = input.headers;
|
|
8
12
|
}
|
|
9
13
|
else {
|
|
10
|
-
|
|
14
|
+
url = input.toString();
|
|
15
|
+
if (init != null) {
|
|
16
|
+
method = init.method || method;
|
|
17
|
+
headers = init.headers || headers;
|
|
18
|
+
}
|
|
11
19
|
}
|
|
12
|
-
const cacheKey =
|
|
20
|
+
const cacheKey = url;
|
|
13
21
|
const entry = await cache.get(cacheKey);
|
|
22
|
+
const policyRequest = policyRequestFrom(url, method, headers);
|
|
14
23
|
if (!entry) {
|
|
15
|
-
const response = await fetch(
|
|
16
|
-
const policy = new CachePolicy(
|
|
24
|
+
const response = await fetch(input, init, ...rest);
|
|
25
|
+
const policy = new CachePolicy(policyRequest, policyResponseFrom(response));
|
|
17
26
|
return storeResponseAndReturnClone(cache, response, policy, cacheKey);
|
|
18
27
|
}
|
|
19
28
|
const { policy: policyRaw, bytes } = typeof entry === 'string' ? JSON.parse(entry) : entry;
|
|
@@ -21,7 +30,7 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
21
30
|
// Remove url from the policy, because otherwise it would never match a request with a custom cache key
|
|
22
31
|
policy._url = undefined;
|
|
23
32
|
const bodyInit = new Uint8Array(bytes);
|
|
24
|
-
if (policy.satisfiesWithoutRevalidation(
|
|
33
|
+
if (policy.satisfiesWithoutRevalidation(policyRequest)) {
|
|
25
34
|
const headers = policy.responseHeaders();
|
|
26
35
|
return new Response(bodyInit, {
|
|
27
36
|
url: policy._url,
|
|
@@ -30,12 +39,17 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
30
39
|
});
|
|
31
40
|
}
|
|
32
41
|
else {
|
|
33
|
-
const revalidationHeaders = policy.revalidationHeaders(
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
const revalidationHeaders = policy.revalidationHeaders(policyRequest);
|
|
43
|
+
const revalidationResponse = await fetch(url, {
|
|
44
|
+
...init,
|
|
45
|
+
method,
|
|
46
|
+
headers: {
|
|
47
|
+
...headers,
|
|
48
|
+
...revalidationHeaders,
|
|
49
|
+
},
|
|
50
|
+
}, ...rest);
|
|
51
|
+
const revalidationPolicyRequest = policyRequestFrom(url, method, revalidationHeaders);
|
|
52
|
+
const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(revalidationPolicyRequest, policyResponseFrom(revalidationResponse));
|
|
39
53
|
const newArrayBuffer = await revalidationResponse.arrayBuffer();
|
|
40
54
|
const newBody = modified ? newArrayBuffer : bodyInit;
|
|
41
55
|
return storeResponseAndReturnClone(cache, new Response(newBody, {
|
|
@@ -58,7 +72,7 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
58
72
|
const uint8array = new Uint8Array(arrayBuffer);
|
|
59
73
|
const entry = {
|
|
60
74
|
policy: policy.toObject(),
|
|
61
|
-
bytes:
|
|
75
|
+
bytes: Array.from(uint8array),
|
|
62
76
|
};
|
|
63
77
|
await cache.set(cacheKey, entry, {
|
|
64
78
|
ttl,
|
|
@@ -67,22 +81,17 @@ function fetchFactory({ fetch, Request, Response, cache }) {
|
|
|
67
81
|
// body can only be used once.
|
|
68
82
|
// To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
|
|
69
83
|
// response.clone() but create a new response from the consumed body
|
|
70
|
-
return new Response(uint8array,
|
|
71
|
-
url: response.url,
|
|
72
|
-
status: response.status,
|
|
73
|
-
statusText: response.statusText,
|
|
74
|
-
headers: response.headers,
|
|
75
|
-
});
|
|
84
|
+
return new Response(uint8array, response);
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
87
|
function canBeRevalidated(response) {
|
|
79
88
|
return response.headers.has('ETag');
|
|
80
89
|
}
|
|
81
|
-
function policyRequestFrom(
|
|
90
|
+
function policyRequestFrom(url, method, headers) {
|
|
82
91
|
return {
|
|
83
|
-
url
|
|
84
|
-
method
|
|
85
|
-
headers: headersToObject(
|
|
92
|
+
url,
|
|
93
|
+
method,
|
|
94
|
+
headers: headersToObject(headers),
|
|
86
95
|
};
|
|
87
96
|
}
|
|
88
97
|
function policyResponseFrom(response) {
|
|
@@ -93,9 +102,16 @@ function policyResponseFrom(response) {
|
|
|
93
102
|
}
|
|
94
103
|
function headersToObject(headers) {
|
|
95
104
|
const object = Object.create(null);
|
|
96
|
-
headers
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
if (headers != null) {
|
|
106
|
+
if ('forEach' in headers && typeof headers.forEach === 'function') {
|
|
107
|
+
headers === null || headers === void 0 ? void 0 : headers.forEach((val, key) => {
|
|
108
|
+
object[key] = val;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
return headers;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
99
115
|
return object;
|
|
100
116
|
}
|
|
101
117
|
|