fetchache 0.1.1 → 0.1.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.
package/index.d.ts CHANGED
@@ -1,27 +1,26 @@
1
- /// <reference lib="dom" />
2
- import CachePolicy from 'http-cache-semantics';
3
- export interface FetchacheCacheEntry {
4
- policy: CachePolicy.CachePolicyObject;
5
- body: string;
6
- }
7
- declare type FetchFn = WindowOrWorkerGlobalScope['fetch'];
8
- export interface FetchacheOptions {
9
- fetch: FetchFn;
10
- cache: KeyValueCache<FetchacheCacheEntry>;
11
- Request: typeof Request;
12
- Response: typeof Response;
13
- }
14
- export declare function fetchFactory({ fetch, Request, Response, cache }: FetchacheOptions): FetchFn;
15
- export interface KeyValueCacheSetOptions {
16
- /**
17
- * Specified in **seconds**, the time-to-live (TTL) value limits the lifespan
18
- * of the data being stored in the cache.
19
- */
20
- ttl?: number | null;
21
- }
22
- export interface KeyValueCache<V = any> {
23
- get(key: string): Promise<V | undefined>;
24
- set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;
25
- delete(key: string): Promise<boolean | void>;
26
- }
27
- export {};
1
+ import CachePolicy from 'http-cache-semantics';
2
+ export interface FetchacheCacheEntry {
3
+ policy: CachePolicy.CachePolicyObject;
4
+ body: string;
5
+ }
6
+ declare type FetchFn = WindowOrWorkerGlobalScope['fetch'];
7
+ export interface FetchacheOptions {
8
+ fetch: FetchFn;
9
+ Request: typeof Request;
10
+ Response: typeof Response;
11
+ cache: KeyValueCache<FetchacheCacheEntry>;
12
+ }
13
+ export declare function fetchFactory({ fetch, Response, cache }: FetchacheOptions): FetchFn;
14
+ export interface KeyValueCacheSetOptions {
15
+ /**
16
+ * Specified in **seconds**, the time-to-live (TTL) value limits the lifespan
17
+ * of the data being stored in the cache.
18
+ */
19
+ ttl?: number | null;
20
+ }
21
+ export interface KeyValueCache<V = any> {
22
+ get(key: string): Promise<V | undefined>;
23
+ set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;
24
+ delete(key: string): Promise<boolean | void>;
25
+ }
26
+ export {};
@@ -5,103 +5,120 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
6
 
7
7
  const CachePolicy = _interopDefault(require('http-cache-semantics'));
8
- const flatStr = _interopDefault(require('flatstr'));
9
8
 
10
- /// <reference lib="dom" />
11
- function fetchFactory({ fetch, Request, Response, cache }) {
12
- return async (input, init) => {
13
- let request;
14
- if (input instanceof Request) {
15
- request = input;
16
- }
17
- else {
18
- request = new Request(input, init);
19
- }
20
- const cacheKey = request.url;
21
- const entry = await cache.get(cacheKey);
22
- if (!entry) {
23
- const response = await fetch(request);
24
- const policy = new CachePolicy(policyRequestFrom(request), policyResponseFrom(response));
25
- return storeResponseAndReturnClone(cache, response, policy, cacheKey);
26
- }
27
- const { policy: policyRaw, body } = typeof entry === 'string' ? JSON.parse(entry) : entry;
28
- const policy = CachePolicy.fromObject(policyRaw);
29
- // Remove url from the policy, because otherwise it would never match a request with a custom cache key
30
- policy._url = undefined;
31
- if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {
32
- const headers = policy.responseHeaders();
33
- return new Response(flatStr(body), {
34
- url: policy._url,
35
- status: policy._status,
36
- headers,
37
- });
38
- }
39
- else {
40
- const revalidationHeaders = policy.revalidationHeaders(policyRequestFrom(request));
41
- const revalidationRequest = new Request(request, {
42
- headers: revalidationHeaders,
43
- });
44
- const revalidationResponse = await fetch(revalidationRequest);
45
- const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(policyRequestFrom(revalidationRequest), policyResponseFrom(revalidationResponse));
46
- return storeResponseAndReturnClone(cache, new Response(flatStr(modified ? await revalidationResponse.text() : body), {
47
- url: revalidatedPolicy._url,
48
- status: revalidatedPolicy._status,
49
- headers: revalidatedPolicy.responseHeaders(),
50
- }), revalidatedPolicy, cacheKey);
51
- }
52
- };
53
- async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
54
- let ttl = Math.round(policy.timeToLive() / 1000);
55
- if (ttl <= 0)
56
- return response;
57
- // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
58
- // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
59
- if (canBeRevalidated(response)) {
60
- ttl *= 2;
61
- }
62
- const body = await response.text();
63
- const entry = {
64
- policy: policy.toObject(),
65
- body,
66
- };
67
- await cache.set(cacheKey, entry, {
68
- ttl,
69
- });
70
- // We have to clone the response before returning it because the
71
- // body can only be used once.
72
- // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
73
- // response.clone() but create a new response from the consumed body
74
- return new Response(flatStr(body), {
75
- url: response.url,
76
- status: response.status,
77
- statusText: response.statusText,
78
- headers: response.headers,
79
- });
80
- }
81
- }
82
- function canBeRevalidated(response) {
83
- return response.headers.has('ETag');
84
- }
85
- function policyRequestFrom(request) {
86
- return {
87
- url: request.url,
88
- method: request.method,
89
- headers: headersToObject(request.headers),
90
- };
91
- }
92
- function policyResponseFrom(response) {
93
- return {
94
- status: response.status,
95
- headers: headersToObject(response.headers),
96
- };
97
- }
98
- function headersToObject(headers) {
99
- const object = Object.create(null);
100
- headers === null || headers === void 0 ? void 0 : headers.forEach((val, key) => {
101
- object[key] = val;
102
- });
103
- return object;
9
+ function fetchFactory({ fetch, Response, cache }) {
10
+ return async (input, init) => {
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;
18
+ }
19
+ else {
20
+ url = input.toString();
21
+ if (init != null) {
22
+ method = init.method || method;
23
+ headers = init.headers || headers;
24
+ }
25
+ }
26
+ const cacheKey = url;
27
+ const entry = await cache.get(cacheKey);
28
+ const policyRequest = policyRequestFrom(url, method, headers);
29
+ if (!entry) {
30
+ const response = await fetch(input, init);
31
+ const policy = new CachePolicy(policyRequest, policyResponseFrom(response));
32
+ return storeResponseAndReturnClone(cache, response, policy, cacheKey);
33
+ }
34
+ const { policy: policyRaw, bytes } = typeof entry === 'string' ? JSON.parse(entry) : entry;
35
+ const policy = CachePolicy.fromObject(policyRaw);
36
+ // Remove url from the policy, because otherwise it would never match a request with a custom cache key
37
+ policy._url = undefined;
38
+ const bodyInit = new Uint8Array(bytes);
39
+ if (policy.satisfiesWithoutRevalidation(policyRequest)) {
40
+ const headers = policy.responseHeaders();
41
+ return new Response(bodyInit, {
42
+ url: policy._url,
43
+ status: policy._status,
44
+ headers,
45
+ });
46
+ }
47
+ else {
48
+ const revalidationHeaders = policy.revalidationHeaders(policyRequest);
49
+ const revalidationResponse = await fetch(url, {
50
+ ...init,
51
+ method,
52
+ headers: {
53
+ ...headers,
54
+ ...revalidationHeaders,
55
+ }
56
+ });
57
+ const revalidationPolicyRequest = policyRequestFrom(url, method, revalidationHeaders);
58
+ const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(revalidationPolicyRequest, policyResponseFrom(revalidationResponse));
59
+ const newArrayBuffer = await revalidationResponse.arrayBuffer();
60
+ const newBody = modified ? newArrayBuffer : bodyInit;
61
+ return storeResponseAndReturnClone(cache, new Response(newBody, {
62
+ url: revalidatedPolicy._url,
63
+ status: revalidatedPolicy._status,
64
+ headers: revalidatedPolicy.responseHeaders(),
65
+ }), revalidatedPolicy, cacheKey);
66
+ }
67
+ };
68
+ async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
69
+ let ttl = Math.round(policy.timeToLive() / 1000);
70
+ if (ttl <= 0)
71
+ return response;
72
+ // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
73
+ // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
74
+ if (canBeRevalidated(response)) {
75
+ ttl *= 2;
76
+ }
77
+ const arrayBuffer = await response.arrayBuffer();
78
+ const uint8array = new Uint8Array(arrayBuffer);
79
+ const entry = {
80
+ policy: policy.toObject(),
81
+ bytes: Array.from(uint8array),
82
+ };
83
+ await cache.set(cacheKey, entry, {
84
+ ttl,
85
+ });
86
+ // We have to clone the response before returning it because the
87
+ // body can only be used once.
88
+ // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
89
+ // response.clone() but create a new response from the consumed body
90
+ return new Response(uint8array, response);
91
+ }
92
+ }
93
+ function canBeRevalidated(response) {
94
+ return response.headers.has('ETag');
95
+ }
96
+ function policyRequestFrom(url, method, headers) {
97
+ return {
98
+ url,
99
+ method,
100
+ headers: headersToObject(headers),
101
+ };
102
+ }
103
+ function policyResponseFrom(response) {
104
+ return {
105
+ status: response.status,
106
+ headers: headersToObject(response.headers),
107
+ };
108
+ }
109
+ function headersToObject(headers) {
110
+ const object = Object.create(null);
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
+ }
121
+ return object;
104
122
  }
105
123
 
106
124
  exports.fetchFactory = fetchFactory;
107
- //# sourceMappingURL=index.cjs.js.map
@@ -1,101 +1,118 @@
1
1
  import CachePolicy from 'http-cache-semantics';
2
- import flatStr from 'flatstr';
3
2
 
4
- /// <reference lib="dom" />
5
- function fetchFactory({ fetch, Request, Response, cache }) {
6
- return async (input, init) => {
7
- let request;
8
- if (input instanceof Request) {
9
- request = input;
10
- }
11
- else {
12
- request = new Request(input, init);
13
- }
14
- const cacheKey = request.url;
15
- const entry = await cache.get(cacheKey);
16
- if (!entry) {
17
- const response = await fetch(request);
18
- const policy = new CachePolicy(policyRequestFrom(request), policyResponseFrom(response));
19
- return storeResponseAndReturnClone(cache, response, policy, cacheKey);
20
- }
21
- const { policy: policyRaw, body } = typeof entry === 'string' ? JSON.parse(entry) : entry;
22
- const policy = CachePolicy.fromObject(policyRaw);
23
- // Remove url from the policy, because otherwise it would never match a request with a custom cache key
24
- policy._url = undefined;
25
- if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {
26
- const headers = policy.responseHeaders();
27
- return new Response(flatStr(body), {
28
- url: policy._url,
29
- status: policy._status,
30
- headers,
31
- });
32
- }
33
- else {
34
- const revalidationHeaders = policy.revalidationHeaders(policyRequestFrom(request));
35
- const revalidationRequest = new Request(request, {
36
- headers: revalidationHeaders,
37
- });
38
- const revalidationResponse = await fetch(revalidationRequest);
39
- const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(policyRequestFrom(revalidationRequest), policyResponseFrom(revalidationResponse));
40
- return storeResponseAndReturnClone(cache, new Response(flatStr(modified ? await revalidationResponse.text() : body), {
41
- url: revalidatedPolicy._url,
42
- status: revalidatedPolicy._status,
43
- headers: revalidatedPolicy.responseHeaders(),
44
- }), revalidatedPolicy, cacheKey);
45
- }
46
- };
47
- async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
48
- let ttl = Math.round(policy.timeToLive() / 1000);
49
- if (ttl <= 0)
50
- return response;
51
- // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
52
- // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
53
- if (canBeRevalidated(response)) {
54
- ttl *= 2;
55
- }
56
- const body = await response.text();
57
- const entry = {
58
- policy: policy.toObject(),
59
- body,
60
- };
61
- await cache.set(cacheKey, entry, {
62
- ttl,
63
- });
64
- // We have to clone the response before returning it because the
65
- // body can only be used once.
66
- // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
67
- // response.clone() but create a new response from the consumed body
68
- return new Response(flatStr(body), {
69
- url: response.url,
70
- status: response.status,
71
- statusText: response.statusText,
72
- headers: response.headers,
73
- });
74
- }
75
- }
76
- function canBeRevalidated(response) {
77
- return response.headers.has('ETag');
78
- }
79
- function policyRequestFrom(request) {
80
- return {
81
- url: request.url,
82
- method: request.method,
83
- headers: headersToObject(request.headers),
84
- };
85
- }
86
- function policyResponseFrom(response) {
87
- return {
88
- status: response.status,
89
- headers: headersToObject(response.headers),
90
- };
91
- }
92
- function headersToObject(headers) {
93
- const object = Object.create(null);
94
- headers === null || headers === void 0 ? void 0 : headers.forEach((val, key) => {
95
- object[key] = val;
96
- });
97
- return object;
3
+ function fetchFactory({ fetch, Response, cache }) {
4
+ return async (input, init) => {
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;
12
+ }
13
+ else {
14
+ url = input.toString();
15
+ if (init != null) {
16
+ method = init.method || method;
17
+ headers = init.headers || headers;
18
+ }
19
+ }
20
+ const cacheKey = url;
21
+ const entry = await cache.get(cacheKey);
22
+ const policyRequest = policyRequestFrom(url, method, headers);
23
+ if (!entry) {
24
+ const response = await fetch(input, init);
25
+ const policy = new CachePolicy(policyRequest, policyResponseFrom(response));
26
+ return storeResponseAndReturnClone(cache, response, policy, cacheKey);
27
+ }
28
+ const { policy: policyRaw, bytes } = typeof entry === 'string' ? JSON.parse(entry) : entry;
29
+ const policy = CachePolicy.fromObject(policyRaw);
30
+ // Remove url from the policy, because otherwise it would never match a request with a custom cache key
31
+ policy._url = undefined;
32
+ const bodyInit = new Uint8Array(bytes);
33
+ if (policy.satisfiesWithoutRevalidation(policyRequest)) {
34
+ const headers = policy.responseHeaders();
35
+ return new Response(bodyInit, {
36
+ url: policy._url,
37
+ status: policy._status,
38
+ headers,
39
+ });
40
+ }
41
+ else {
42
+ const revalidationHeaders = policy.revalidationHeaders(policyRequest);
43
+ const revalidationResponse = await fetch(url, {
44
+ ...init,
45
+ method,
46
+ headers: {
47
+ ...headers,
48
+ ...revalidationHeaders,
49
+ }
50
+ });
51
+ const revalidationPolicyRequest = policyRequestFrom(url, method, revalidationHeaders);
52
+ const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(revalidationPolicyRequest, policyResponseFrom(revalidationResponse));
53
+ const newArrayBuffer = await revalidationResponse.arrayBuffer();
54
+ const newBody = modified ? newArrayBuffer : bodyInit;
55
+ return storeResponseAndReturnClone(cache, new Response(newBody, {
56
+ url: revalidatedPolicy._url,
57
+ status: revalidatedPolicy._status,
58
+ headers: revalidatedPolicy.responseHeaders(),
59
+ }), revalidatedPolicy, cacheKey);
60
+ }
61
+ };
62
+ async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
63
+ let ttl = Math.round(policy.timeToLive() / 1000);
64
+ if (ttl <= 0)
65
+ return response;
66
+ // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
67
+ // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
68
+ if (canBeRevalidated(response)) {
69
+ ttl *= 2;
70
+ }
71
+ const arrayBuffer = await response.arrayBuffer();
72
+ const uint8array = new Uint8Array(arrayBuffer);
73
+ const entry = {
74
+ policy: policy.toObject(),
75
+ bytes: Array.from(uint8array),
76
+ };
77
+ await cache.set(cacheKey, entry, {
78
+ ttl,
79
+ });
80
+ // We have to clone the response before returning it because the
81
+ // body can only be used once.
82
+ // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
83
+ // response.clone() but create a new response from the consumed body
84
+ return new Response(uint8array, response);
85
+ }
86
+ }
87
+ function canBeRevalidated(response) {
88
+ return response.headers.has('ETag');
89
+ }
90
+ function policyRequestFrom(url, method, headers) {
91
+ return {
92
+ url,
93
+ method,
94
+ headers: headersToObject(headers),
95
+ };
96
+ }
97
+ function policyResponseFrom(response) {
98
+ return {
99
+ status: response.status,
100
+ headers: headersToObject(response.headers),
101
+ };
102
+ }
103
+ function headersToObject(headers) {
104
+ const object = Object.create(null);
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
+ }
115
+ return object;
98
116
  }
99
117
 
100
118
  export { fetchFactory };
101
- //# sourceMappingURL=index.esm.js.map
package/package.json CHANGED
@@ -1,22 +1,34 @@
1
1
  {
2
2
  "name": "fetchache",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Cross Platform Fetch Wrapper with Key Value Cache support",
5
5
  "sideEffects": false,
6
6
  "dependencies": {
7
- "flatstr": "1.0.12",
8
- "http-cache-semantics": "4.1.0"
7
+ "http-cache-semantics": "^4.1.0",
8
+ "tslib": "^2.3.1"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "ardatan/whatwg-node",
13
+ "directory": "packages/fetchache"
9
14
  },
10
- "repository": "git@github.com:ardatan/fetch-with-cache.git",
11
15
  "author": "Arda TANRIKULU <ardatanrikulu@gmail.com>",
12
16
  "license": "MIT",
13
- "engines": {
14
- "node": ">=10"
15
- },
16
- "main": "index.cjs.js",
17
- "module": "index.esm.js",
17
+ "main": "index.js",
18
+ "module": "index.mjs",
18
19
  "typings": "index.d.ts",
19
20
  "typescript": {
20
21
  "definition": "index.d.ts"
22
+ },
23
+ "exports": {
24
+ ".": {
25
+ "require": "./index.js",
26
+ "import": "./index.mjs"
27
+ },
28
+ "./*": {
29
+ "require": "./*.js",
30
+ "import": "./*.mjs"
31
+ },
32
+ "./package.json": "./package.json"
21
33
  }
22
34
  }
package/index.cjs.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/index.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\nimport CachePolicy from 'http-cache-semantics';\nimport flatStr from 'flatstr';\n\nexport interface FetchacheCacheEntry {\n policy: CachePolicy.CachePolicyObject;\n body: string;\n}\n\ntype FetchFn = WindowOrWorkerGlobalScope['fetch'];\n\nexport interface FetchacheOptions {\n fetch: FetchFn;\n cache: KeyValueCache<FetchacheCacheEntry>;\n Request: typeof Request;\n Response: typeof Response;\n}\n\nexport function fetchFactory({\n fetch,\n Request,\n Response,\n cache\n}: FetchacheOptions): FetchFn {\n return async (input, init) => {\n let request: Request;\n if (input instanceof Request) {\n request = input;\n } else {\n request = new Request(input, init);\n }\n const cacheKey = request.url;\n const entry = await cache.get(cacheKey);\n if (!entry) {\n const response = await fetch(request);\n\n const policy = new CachePolicy(\n policyRequestFrom(request),\n policyResponseFrom(response),\n );\n\n return storeResponseAndReturnClone(\n cache,\n response,\n policy,\n cacheKey,\n );\n }\n\n const { policy: policyRaw, body } = typeof entry === 'string' ? JSON.parse(entry) : entry;\n\n const policy = CachePolicy.fromObject(policyRaw);\n // Remove url from the policy, because otherwise it would never match a request with a custom cache key\n (policy as any)._url = undefined;\n\n if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {\n const headers = policy.responseHeaders() as HeadersInit;\n return new Response(flatStr(body), {\n url: (policy as any)._url,\n status: (policy as any)._status,\n headers,\n } as ResponseInit);\n } else {\n const revalidationHeaders = policy.revalidationHeaders(\n policyRequestFrom(request),\n );\n const revalidationRequest = new Request(request, {\n headers: revalidationHeaders as HeadersInit,\n });\n const revalidationResponse = await fetch(revalidationRequest);\n\n const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(\n policyRequestFrom(revalidationRequest),\n policyResponseFrom(revalidationResponse),\n );\n\n return storeResponseAndReturnClone(\n cache,\n new Response(flatStr(modified ? await revalidationResponse.text() : body), {\n url: (revalidatedPolicy as any)._url,\n status: (revalidatedPolicy as any)._status,\n headers: (revalidatedPolicy as any).responseHeaders(),\n } as ResponseInit),\n revalidatedPolicy,\n cacheKey,\n );\n }\n }\n\n async function storeResponseAndReturnClone(\n cache: KeyValueCache,\n response: Response,\n policy: CachePolicy,\n cacheKey: string,\n ): Promise<Response> {\n\n let ttl = Math.round(policy.timeToLive() / 1000);\n if (ttl <= 0) return response;\n\n // If a response can be revalidated, we don't want to remove it from the cache right after it expires.\n // We may be able to use better heuristics here, but for now we'll take the max-age times 2.\n if (canBeRevalidated(response)) {\n ttl *= 2;\n }\n\n const body = await response.text();\n const entry = {\n policy: policy.toObject(),\n body,\n };\n\n await cache.set(cacheKey, entry, {\n ttl,\n });\n\n // We have to clone the response before returning it because the\n // body can only be used once.\n // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use\n // response.clone() but create a new response from the consumed body\n return new Response(flatStr(body), {\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n } as ResponseInit);\n }\n};\n\n\nfunction canBeRevalidated(response: Response): boolean {\n return response.headers.has('ETag');\n}\n\nfunction policyRequestFrom(request: Request) {\n return {\n url: request.url,\n method: request.method,\n headers: headersToObject(request.headers),\n };\n}\n\nfunction policyResponseFrom(response: Response) {\n return {\n status: response.status,\n headers: headersToObject(response.headers),\n };\n}\n\nfunction headersToObject(headers: Headers) {\n const object = Object.create(null);\n headers?.forEach((val, key) => {\n object[key] = val;\n });\n return object;\n}\n\nexport interface KeyValueCacheSetOptions {\n /**\n * Specified in **seconds**, the time-to-live (TTL) value limits the lifespan\n * of the data being stored in the cache.\n */\n ttl?: number | null\n};\n\nexport interface KeyValueCache<V = any> {\n get(key: string): Promise<V | undefined>;\n set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;\n delete(key: string): Promise<boolean | void>;\n}\n"],"names":[],"mappings":"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"}
package/index.esm.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/index.ts"],"sourcesContent":["/// <reference lib=\"dom\" />\nimport CachePolicy from 'http-cache-semantics';\nimport flatStr from 'flatstr';\n\nexport interface FetchacheCacheEntry {\n policy: CachePolicy.CachePolicyObject;\n body: string;\n}\n\ntype FetchFn = WindowOrWorkerGlobalScope['fetch'];\n\nexport interface FetchacheOptions {\n fetch: FetchFn;\n cache: KeyValueCache<FetchacheCacheEntry>;\n Request: typeof Request;\n Response: typeof Response;\n}\n\nexport function fetchFactory({\n fetch,\n Request,\n Response,\n cache\n}: FetchacheOptions): FetchFn {\n return async (input, init) => {\n let request: Request;\n if (input instanceof Request) {\n request = input;\n } else {\n request = new Request(input, init);\n }\n const cacheKey = request.url;\n const entry = await cache.get(cacheKey);\n if (!entry) {\n const response = await fetch(request);\n\n const policy = new CachePolicy(\n policyRequestFrom(request),\n policyResponseFrom(response),\n );\n\n return storeResponseAndReturnClone(\n cache,\n response,\n policy,\n cacheKey,\n );\n }\n\n const { policy: policyRaw, body } = typeof entry === 'string' ? JSON.parse(entry) : entry;\n\n const policy = CachePolicy.fromObject(policyRaw);\n // Remove url from the policy, because otherwise it would never match a request with a custom cache key\n (policy as any)._url = undefined;\n\n if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {\n const headers = policy.responseHeaders() as HeadersInit;\n return new Response(flatStr(body), {\n url: (policy as any)._url,\n status: (policy as any)._status,\n headers,\n } as ResponseInit);\n } else {\n const revalidationHeaders = policy.revalidationHeaders(\n policyRequestFrom(request),\n );\n const revalidationRequest = new Request(request, {\n headers: revalidationHeaders as HeadersInit,\n });\n const revalidationResponse = await fetch(revalidationRequest);\n\n const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(\n policyRequestFrom(revalidationRequest),\n policyResponseFrom(revalidationResponse),\n );\n\n return storeResponseAndReturnClone(\n cache,\n new Response(flatStr(modified ? await revalidationResponse.text() : body), {\n url: (revalidatedPolicy as any)._url,\n status: (revalidatedPolicy as any)._status,\n headers: (revalidatedPolicy as any).responseHeaders(),\n } as ResponseInit),\n revalidatedPolicy,\n cacheKey,\n );\n }\n }\n\n async function storeResponseAndReturnClone(\n cache: KeyValueCache,\n response: Response,\n policy: CachePolicy,\n cacheKey: string,\n ): Promise<Response> {\n\n let ttl = Math.round(policy.timeToLive() / 1000);\n if (ttl <= 0) return response;\n\n // If a response can be revalidated, we don't want to remove it from the cache right after it expires.\n // We may be able to use better heuristics here, but for now we'll take the max-age times 2.\n if (canBeRevalidated(response)) {\n ttl *= 2;\n }\n\n const body = await response.text();\n const entry = {\n policy: policy.toObject(),\n body,\n };\n\n await cache.set(cacheKey, entry, {\n ttl,\n });\n\n // We have to clone the response before returning it because the\n // body can only be used once.\n // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use\n // response.clone() but create a new response from the consumed body\n return new Response(flatStr(body), {\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n } as ResponseInit);\n }\n};\n\n\nfunction canBeRevalidated(response: Response): boolean {\n return response.headers.has('ETag');\n}\n\nfunction policyRequestFrom(request: Request) {\n return {\n url: request.url,\n method: request.method,\n headers: headersToObject(request.headers),\n };\n}\n\nfunction policyResponseFrom(response: Response) {\n return {\n status: response.status,\n headers: headersToObject(response.headers),\n };\n}\n\nfunction headersToObject(headers: Headers) {\n const object = Object.create(null);\n headers?.forEach((val, key) => {\n object[key] = val;\n });\n return object;\n}\n\nexport interface KeyValueCacheSetOptions {\n /**\n * Specified in **seconds**, the time-to-live (TTL) value limits the lifespan\n * of the data being stored in the cache.\n */\n ttl?: number | null\n};\n\nexport interface KeyValueCache<V = any> {\n get(key: string): Promise<V | undefined>;\n set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;\n delete(key: string): Promise<boolean | void>;\n}\n"],"names":[],"mappings":"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"}