fetchache 0.0.4 → 0.1.2

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,15 +1,26 @@
1
- export declare function fetchache(request: Request, cache: KeyValueCache): Promise<Response>;
2
- export * from 'cross-fetch';
3
- export default fetchache;
4
- export interface KeyValueCacheSetOptions {
5
- /**
6
- * Specified in **seconds**, the time-to-live (TTL) value limits the lifespan
7
- * of the data being stored in the cache.
8
- */
9
- ttl?: number | null;
10
- }
11
- export interface KeyValueCache<V = string> {
12
- get(key: string): Promise<V | undefined>;
13
- set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;
14
- delete(key: string): Promise<boolean | void>;
15
- }
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, Request, 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 {};
package/index.js ADDED
@@ -0,0 +1,108 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
7
+ const CachePolicy = _interopDefault(require('http-cache-semantics'));
8
+
9
+ function fetchFactory({ fetch, Request, Response, cache }) {
10
+ return async (input, init) => {
11
+ let request;
12
+ if (input instanceof Request) {
13
+ request = input;
14
+ }
15
+ else {
16
+ request = new Request(input, init);
17
+ }
18
+ const cacheKey = request.url;
19
+ const entry = await cache.get(cacheKey);
20
+ if (!entry) {
21
+ const response = await fetch(request);
22
+ const policy = new CachePolicy(policyRequestFrom(request), policyResponseFrom(response));
23
+ return storeResponseAndReturnClone(cache, response, policy, cacheKey);
24
+ }
25
+ const { policy: policyRaw, bytes } = typeof entry === 'string' ? JSON.parse(entry) : entry;
26
+ const policy = CachePolicy.fromObject(policyRaw);
27
+ // Remove url from the policy, because otherwise it would never match a request with a custom cache key
28
+ policy._url = undefined;
29
+ const bodyInit = new Uint8Array(bytes);
30
+ if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {
31
+ const headers = policy.responseHeaders();
32
+ return new Response(bodyInit, {
33
+ url: policy._url,
34
+ status: policy._status,
35
+ headers,
36
+ });
37
+ }
38
+ else {
39
+ const revalidationHeaders = policy.revalidationHeaders(policyRequestFrom(request));
40
+ const revalidationRequest = new Request(request, {
41
+ headers: revalidationHeaders,
42
+ });
43
+ const revalidationResponse = await fetch(revalidationRequest);
44
+ const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(policyRequestFrom(revalidationRequest), policyResponseFrom(revalidationResponse));
45
+ const newArrayBuffer = await revalidationResponse.arrayBuffer();
46
+ const newBody = modified ? newArrayBuffer : bodyInit;
47
+ return storeResponseAndReturnClone(cache, new Response(newBody, {
48
+ url: revalidatedPolicy._url,
49
+ status: revalidatedPolicy._status,
50
+ headers: revalidatedPolicy.responseHeaders(),
51
+ }), revalidatedPolicy, cacheKey);
52
+ }
53
+ };
54
+ async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
55
+ let ttl = Math.round(policy.timeToLive() / 1000);
56
+ if (ttl <= 0)
57
+ return response;
58
+ // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
59
+ // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
60
+ if (canBeRevalidated(response)) {
61
+ ttl *= 2;
62
+ }
63
+ const arrayBuffer = await response.arrayBuffer();
64
+ const uint8array = new Uint8Array(arrayBuffer);
65
+ const entry = {
66
+ policy: policy.toObject(),
67
+ bytes: [...uint8array],
68
+ };
69
+ await cache.set(cacheKey, entry, {
70
+ ttl,
71
+ });
72
+ // We have to clone the response before returning it because the
73
+ // body can only be used once.
74
+ // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
75
+ // 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
+ });
82
+ }
83
+ }
84
+ function canBeRevalidated(response) {
85
+ return response.headers.has('ETag');
86
+ }
87
+ function policyRequestFrom(request) {
88
+ return {
89
+ url: request.url,
90
+ method: request.method,
91
+ headers: headersToObject(request.headers),
92
+ };
93
+ }
94
+ function policyResponseFrom(response) {
95
+ return {
96
+ status: response.status,
97
+ headers: headersToObject(response.headers),
98
+ };
99
+ }
100
+ function headersToObject(headers) {
101
+ const object = Object.create(null);
102
+ headers === null || headers === void 0 ? void 0 : headers.forEach((val, key) => {
103
+ object[key] = val;
104
+ });
105
+ return object;
106
+ }
107
+
108
+ exports.fetchFactory = fetchFactory;
package/index.mjs ADDED
@@ -0,0 +1,102 @@
1
+ import CachePolicy from 'http-cache-semantics';
2
+
3
+ function fetchFactory({ fetch, Request, Response, cache }) {
4
+ return async (input, init) => {
5
+ let request;
6
+ if (input instanceof Request) {
7
+ request = input;
8
+ }
9
+ else {
10
+ request = new Request(input, init);
11
+ }
12
+ const cacheKey = request.url;
13
+ const entry = await cache.get(cacheKey);
14
+ if (!entry) {
15
+ const response = await fetch(request);
16
+ const policy = new CachePolicy(policyRequestFrom(request), policyResponseFrom(response));
17
+ return storeResponseAndReturnClone(cache, response, policy, cacheKey);
18
+ }
19
+ const { policy: policyRaw, bytes } = typeof entry === 'string' ? JSON.parse(entry) : entry;
20
+ const policy = CachePolicy.fromObject(policyRaw);
21
+ // Remove url from the policy, because otherwise it would never match a request with a custom cache key
22
+ policy._url = undefined;
23
+ const bodyInit = new Uint8Array(bytes);
24
+ if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {
25
+ const headers = policy.responseHeaders();
26
+ return new Response(bodyInit, {
27
+ url: policy._url,
28
+ status: policy._status,
29
+ headers,
30
+ });
31
+ }
32
+ else {
33
+ const revalidationHeaders = policy.revalidationHeaders(policyRequestFrom(request));
34
+ const revalidationRequest = new Request(request, {
35
+ headers: revalidationHeaders,
36
+ });
37
+ const revalidationResponse = await fetch(revalidationRequest);
38
+ const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(policyRequestFrom(revalidationRequest), policyResponseFrom(revalidationResponse));
39
+ const newArrayBuffer = await revalidationResponse.arrayBuffer();
40
+ const newBody = modified ? newArrayBuffer : bodyInit;
41
+ return storeResponseAndReturnClone(cache, new Response(newBody, {
42
+ url: revalidatedPolicy._url,
43
+ status: revalidatedPolicy._status,
44
+ headers: revalidatedPolicy.responseHeaders(),
45
+ }), revalidatedPolicy, cacheKey);
46
+ }
47
+ };
48
+ async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
49
+ let ttl = Math.round(policy.timeToLive() / 1000);
50
+ if (ttl <= 0)
51
+ return response;
52
+ // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
53
+ // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
54
+ if (canBeRevalidated(response)) {
55
+ ttl *= 2;
56
+ }
57
+ const arrayBuffer = await response.arrayBuffer();
58
+ const uint8array = new Uint8Array(arrayBuffer);
59
+ const entry = {
60
+ policy: policy.toObject(),
61
+ bytes: [...uint8array],
62
+ };
63
+ await cache.set(cacheKey, entry, {
64
+ ttl,
65
+ });
66
+ // We have to clone the response before returning it because the
67
+ // body can only be used once.
68
+ // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
69
+ // 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
+ });
76
+ }
77
+ }
78
+ function canBeRevalidated(response) {
79
+ return response.headers.has('ETag');
80
+ }
81
+ function policyRequestFrom(request) {
82
+ return {
83
+ url: request.url,
84
+ method: request.method,
85
+ headers: headersToObject(request.headers),
86
+ };
87
+ }
88
+ function policyResponseFrom(response) {
89
+ return {
90
+ status: response.status,
91
+ headers: headersToObject(response.headers),
92
+ };
93
+ }
94
+ function headersToObject(headers) {
95
+ const object = Object.create(null);
96
+ headers === null || headers === void 0 ? void 0 : headers.forEach((val, key) => {
97
+ object[key] = val;
98
+ });
99
+ return object;
100
+ }
101
+
102
+ export { fetchFactory };
package/package.json CHANGED
@@ -1,22 +1,34 @@
1
1
  {
2
2
  "name": "fetchache",
3
- "version": "0.0.4",
4
- "description": "Cross Platform Fetch with Key Value Cache support",
3
+ "version": "0.1.2",
4
+ "description": "Cross Platform Fetch Wrapper with Key Value Cache support",
5
5
  "sideEffects": false,
6
6
  "dependencies": {
7
- "http-cache-semantics": "4.1.0",
8
- "cross-fetch": "3.0.6"
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 DELETED
@@ -1,106 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
-
7
- const CachePolicy = _interopDefault(require('http-cache-semantics'));
8
- const crossFetch = require('cross-fetch');
9
-
10
- async function fetchache(request, cache) {
11
- const cacheKey = request.url;
12
- const entry = await cache.get(cacheKey);
13
- if (!entry) {
14
- const response = await crossFetch.fetch(request);
15
- const policy = new CachePolicy(policyRequestFrom(request), policyResponseFrom(response));
16
- return storeResponseAndReturnClone(cache, response, policy, cacheKey);
17
- }
18
- const { policy: policyRaw, body } = JSON.parse(entry);
19
- const policy = CachePolicy.fromObject(policyRaw);
20
- // Remove url from the policy, because otherwise it would never match a request with a custom cache key
21
- policy._url = undefined;
22
- if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {
23
- const headers = policy.responseHeaders();
24
- return new crossFetch.Response(body, {
25
- url: policy._url,
26
- status: policy._status,
27
- headers,
28
- });
29
- }
30
- else {
31
- const revalidationHeaders = policy.revalidationHeaders(policyRequestFrom(request));
32
- const revalidationRequest = new crossFetch.Request(request, {
33
- headers: revalidationHeaders,
34
- });
35
- const revalidationResponse = await crossFetch.fetch(revalidationRequest);
36
- const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(policyRequestFrom(revalidationRequest), policyResponseFrom(revalidationResponse));
37
- return storeResponseAndReturnClone(cache, new crossFetch.Response(modified ? await revalidationResponse.text() : body, {
38
- url: revalidatedPolicy._url,
39
- status: revalidatedPolicy._status,
40
- headers: revalidatedPolicy.responseHeaders(),
41
- }), revalidatedPolicy, cacheKey);
42
- }
43
- }
44
- async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
45
- let ttl = Math.round(policy.timeToLive() / 1000);
46
- if (ttl <= 0)
47
- return response;
48
- // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
49
- // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
50
- if (canBeRevalidated(response)) {
51
- ttl *= 2;
52
- }
53
- const body = await response.text();
54
- const entry = JSON.stringify({
55
- policy: policy.toObject(),
56
- body,
57
- });
58
- await cache.set(cacheKey, entry, {
59
- ttl,
60
- });
61
- // We have to clone the response before returning it because the
62
- // body can only be used once.
63
- // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
64
- // response.clone() but create a new response from the consumed body
65
- return new crossFetch.Response(body, {
66
- url: response.url,
67
- status: response.status,
68
- statusText: response.statusText,
69
- headers: response.headers,
70
- });
71
- }
72
- function canBeRevalidated(response) {
73
- return response.headers.has('ETag');
74
- }
75
- function policyRequestFrom(request) {
76
- return {
77
- url: request.url,
78
- method: request.method,
79
- headers: headersToObject(request.headers),
80
- };
81
- }
82
- function policyResponseFrom(response) {
83
- return {
84
- status: response.status,
85
- headers: headersToObject(response.headers),
86
- };
87
- }
88
- function headersToObject(headers) {
89
- const object = Object.create(null);
90
- headers.forEach((val, key) => {
91
- object[key] = val;
92
- });
93
- return object;
94
- }
95
-
96
- Object.keys(crossFetch).forEach(function (k) {
97
- if (k !== 'default') Object.defineProperty(exports, k, {
98
- enumerable: true,
99
- get: function () {
100
- return crossFetch[k];
101
- }
102
- });
103
- });
104
- exports.default = fetchache;
105
- exports.fetchache = fetchache;
106
- //# sourceMappingURL=index.cjs.js.map
package/index.cjs.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/index.ts"],"sourcesContent":["import CachePolicy from 'http-cache-semantics';\r\nimport { fetch, Request, Response } from 'cross-fetch';\r\n\r\nexport async function fetchache(request: Request, cache: KeyValueCache) {\r\n const cacheKey = request.url;\r\n const entry = await cache.get(cacheKey);\r\n if (!entry) {\r\n const response = await fetch(request);\r\n\r\n const policy = new CachePolicy(\r\n policyRequestFrom(request),\r\n policyResponseFrom(response),\r\n );\r\n\r\n return storeResponseAndReturnClone(\r\n cache,\r\n response,\r\n policy,\r\n cacheKey,\r\n );\r\n }\r\n\r\n const { policy: policyRaw, body } = JSON.parse(entry);\r\n\r\n const policy = CachePolicy.fromObject(policyRaw);\r\n // Remove url from the policy, because otherwise it would never match a request with a custom cache key\r\n (policy as any)._url = undefined;\r\n\r\n if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {\r\n const headers = policy.responseHeaders() as HeadersInit;\r\n return new Response(body, {\r\n url: (policy as any)._url,\r\n status: (policy as any)._status,\r\n headers,\r\n } as ResponseInit);\r\n } else {\r\n const revalidationHeaders = policy.revalidationHeaders(\r\n policyRequestFrom(request),\r\n );\r\n const revalidationRequest = new Request(request, {\r\n headers: revalidationHeaders as HeadersInit,\r\n });\r\n const revalidationResponse = await fetch(revalidationRequest);\r\n\r\n const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(\r\n policyRequestFrom(revalidationRequest),\r\n policyResponseFrom(revalidationResponse),\r\n );\r\n\r\n return storeResponseAndReturnClone(\r\n cache,\r\n new Response(modified ? await revalidationResponse.text() : body, {\r\n url: (revalidatedPolicy as any)._url,\r\n status: (revalidatedPolicy as any)._status,\r\n headers: (revalidatedPolicy as any).responseHeaders(),\r\n } as ResponseInit),\r\n revalidatedPolicy,\r\n cacheKey,\r\n );\r\n }\r\n}\r\n\r\nexport * from 'cross-fetch';\r\n\r\nexport default fetchache;\r\n\r\nasync function storeResponseAndReturnClone(\r\n cache: KeyValueCache,\r\n response: Response,\r\n policy: CachePolicy,\r\n cacheKey: string,\r\n): Promise<Response> {\r\n\r\n let ttl = Math.round(policy.timeToLive() / 1000);\r\n if (ttl <= 0) return response;\r\n\r\n // If a response can be revalidated, we don't want to remove it from the cache right after it expires.\r\n // We may be able to use better heuristics here, but for now we'll take the max-age times 2.\r\n if (canBeRevalidated(response)) {\r\n ttl *= 2;\r\n }\r\n\r\n const body = await response.text();\r\n const entry = JSON.stringify({\r\n policy: policy.toObject(),\r\n body,\r\n });\r\n\r\n await cache.set(cacheKey, entry, {\r\n ttl,\r\n });\r\n\r\n // We have to clone the response before returning it because the\r\n // body can only be used once.\r\n // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use\r\n // response.clone() but create a new response from the consumed body\r\n return new Response(body, {\r\n url: response.url,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n } as ResponseInit);\r\n}\r\n\r\nfunction canBeRevalidated(response: Response): boolean {\r\n return response.headers.has('ETag');\r\n}\r\n\r\nfunction policyRequestFrom(request: Request) {\r\n return {\r\n url: request.url,\r\n method: request.method,\r\n headers: headersToObject(request.headers),\r\n };\r\n}\r\n\r\nfunction policyResponseFrom(response: Response) {\r\n return {\r\n status: response.status,\r\n headers: headersToObject(response.headers),\r\n };\r\n}\r\n\r\nfunction headersToObject(headers: Headers) {\r\n const object = Object.create(null);\r\n headers.forEach((val, key) => {\r\n object[key] = val;\r\n });\r\n return object;\r\n}\r\n\r\nexport interface KeyValueCacheSetOptions {\r\n /**\r\n * Specified in **seconds**, the time-to-live (TTL) value limits the lifespan\r\n * of the data being stored in the cache.\r\n */\r\n ttl?: number | null\r\n};\r\n\r\nexport interface KeyValueCache<V = string> {\r\n get(key: string): Promise<V | undefined>;\r\n set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;\r\n delete(key: string): Promise<boolean | void>;\r\n}\r\n"],"names":["fetch","Response","Request"],"mappings":";;;;;;;;;AAGO,eAAe,SAAS,CAAC,OAAgB,EAAE,KAAoB;IAClE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC;IAC7B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,EAAE;QACR,MAAM,QAAQ,GAAG,MAAMA,gBAAK,CAAC,OAAO,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,IAAI,WAAW,CAC1B,iBAAiB,CAAC,OAAO,CAAC,EAC1B,kBAAkB,CAAC,QAAQ,CAAC,CAC/B,CAAC;QAEF,OAAO,2BAA2B,CAC9B,KAAK,EACL,QAAQ,EACR,MAAM,EACN,QAAQ,CACX,CAAC;KACL;IAED,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAEtD,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;;IAEhD,MAAc,CAAC,IAAI,GAAG,SAAS,CAAC;IAEjC,IAAI,MAAM,CAAC,4BAA4B,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,EAAE;QACjE,MAAM,OAAO,GAAG,MAAM,CAAC,eAAe,EAAiB,CAAC;QACxD,OAAO,IAAIC,mBAAQ,CAAC,IAAI,EAAE;YACtB,GAAG,EAAG,MAAc,CAAC,IAAI;YACzB,MAAM,EAAG,MAAc,CAAC,OAAO;YAC/B,OAAO;SACM,CAAC,CAAC;KACtB;SAAM;QACH,MAAM,mBAAmB,GAAG,MAAM,CAAC,mBAAmB,CAClD,iBAAiB,CAAC,OAAO,CAAC,CAC7B,CAAC;QACF,MAAM,mBAAmB,GAAG,IAAIC,kBAAO,CAAC,OAAO,EAAE;YAC7C,OAAO,EAAE,mBAAkC;SAC9C,CAAC,CAAC;QACH,MAAM,oBAAoB,GAAG,MAAMF,gBAAK,CAAC,mBAAmB,CAAC,CAAC;QAE9D,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,iBAAiB,CACpE,iBAAiB,CAAC,mBAAmB,CAAC,EACtC,kBAAkB,CAAC,oBAAoB,CAAC,CAC3C,CAAC;QAEF,OAAO,2BAA2B,CAC9B,KAAK,EACL,IAAIC,mBAAQ,CAAC,QAAQ,GAAG,MAAM,oBAAoB,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE;YAC9D,GAAG,EAAG,iBAAyB,CAAC,IAAI;YACpC,MAAM,EAAG,iBAAyB,CAAC,OAAO;YAC1C,OAAO,EAAG,iBAAyB,CAAC,eAAe,EAAE;SACxC,CAAC,EAClB,iBAAiB,EACjB,QAAQ,CACX,CAAC;KACL;AACL,CAAC;AAMD,eAAe,2BAA2B,CACtC,KAAoB,EACpB,QAAkB,EAClB,MAAmB,EACnB,QAAgB;IAGhB,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;IACjD,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,QAAQ,CAAC;;;IAI9B,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE;QAC5B,GAAG,IAAI,CAAC,CAAC;KACZ;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC;QACzB,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;QACzB,IAAI;KACP,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE;QAC7B,GAAG;KACN,CAAC,CAAC;;;;;IAMH,OAAO,IAAIA,mBAAQ,CAAC,IAAI,EAAE;QACtB,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,OAAO,EAAE,QAAQ,CAAC,OAAO;KACZ,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAkB;IACxC,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAgB;IACvC,OAAO;QACH,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;KAC5C,CAAC;AACN,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAkB;IAC1C,OAAO;QACH,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC;KAC7C,CAAC;AACN,CAAC;AAED,SAAS,eAAe,CAAC,OAAgB;IACrC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG;QACrB,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;KACrB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAClB;;;;;;;;;;;;;"}
package/index.esm.js DELETED
@@ -1,93 +0,0 @@
1
- import CachePolicy from 'http-cache-semantics';
2
- import { fetch, Response, Request } from 'cross-fetch';
3
- export * from 'cross-fetch';
4
-
5
- async function fetchache(request, cache) {
6
- const cacheKey = request.url;
7
- const entry = await cache.get(cacheKey);
8
- if (!entry) {
9
- const response = await fetch(request);
10
- const policy = new CachePolicy(policyRequestFrom(request), policyResponseFrom(response));
11
- return storeResponseAndReturnClone(cache, response, policy, cacheKey);
12
- }
13
- const { policy: policyRaw, body } = JSON.parse(entry);
14
- const policy = CachePolicy.fromObject(policyRaw);
15
- // Remove url from the policy, because otherwise it would never match a request with a custom cache key
16
- policy._url = undefined;
17
- if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {
18
- const headers = policy.responseHeaders();
19
- return new Response(body, {
20
- url: policy._url,
21
- status: policy._status,
22
- headers,
23
- });
24
- }
25
- else {
26
- const revalidationHeaders = policy.revalidationHeaders(policyRequestFrom(request));
27
- const revalidationRequest = new Request(request, {
28
- headers: revalidationHeaders,
29
- });
30
- const revalidationResponse = await fetch(revalidationRequest);
31
- const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(policyRequestFrom(revalidationRequest), policyResponseFrom(revalidationResponse));
32
- return storeResponseAndReturnClone(cache, new Response(modified ? await revalidationResponse.text() : body, {
33
- url: revalidatedPolicy._url,
34
- status: revalidatedPolicy._status,
35
- headers: revalidatedPolicy.responseHeaders(),
36
- }), revalidatedPolicy, cacheKey);
37
- }
38
- }
39
- async function storeResponseAndReturnClone(cache, response, policy, cacheKey) {
40
- let ttl = Math.round(policy.timeToLive() / 1000);
41
- if (ttl <= 0)
42
- return response;
43
- // If a response can be revalidated, we don't want to remove it from the cache right after it expires.
44
- // We may be able to use better heuristics here, but for now we'll take the max-age times 2.
45
- if (canBeRevalidated(response)) {
46
- ttl *= 2;
47
- }
48
- const body = await response.text();
49
- const entry = JSON.stringify({
50
- policy: policy.toObject(),
51
- body,
52
- });
53
- await cache.set(cacheKey, entry, {
54
- ttl,
55
- });
56
- // We have to clone the response before returning it because the
57
- // body can only be used once.
58
- // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use
59
- // response.clone() but create a new response from the consumed body
60
- return new Response(body, {
61
- url: response.url,
62
- status: response.status,
63
- statusText: response.statusText,
64
- headers: response.headers,
65
- });
66
- }
67
- function canBeRevalidated(response) {
68
- return response.headers.has('ETag');
69
- }
70
- function policyRequestFrom(request) {
71
- return {
72
- url: request.url,
73
- method: request.method,
74
- headers: headersToObject(request.headers),
75
- };
76
- }
77
- function policyResponseFrom(response) {
78
- return {
79
- status: response.status,
80
- headers: headersToObject(response.headers),
81
- };
82
- }
83
- function headersToObject(headers) {
84
- const object = Object.create(null);
85
- headers.forEach((val, key) => {
86
- object[key] = val;
87
- });
88
- return object;
89
- }
90
-
91
- export default fetchache;
92
- export { fetchache };
93
- //# sourceMappingURL=index.esm.js.map
package/index.esm.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/index.ts"],"sourcesContent":["import CachePolicy from 'http-cache-semantics';\r\nimport { fetch, Request, Response } from 'cross-fetch';\r\n\r\nexport async function fetchache(request: Request, cache: KeyValueCache) {\r\n const cacheKey = request.url;\r\n const entry = await cache.get(cacheKey);\r\n if (!entry) {\r\n const response = await fetch(request);\r\n\r\n const policy = new CachePolicy(\r\n policyRequestFrom(request),\r\n policyResponseFrom(response),\r\n );\r\n\r\n return storeResponseAndReturnClone(\r\n cache,\r\n response,\r\n policy,\r\n cacheKey,\r\n );\r\n }\r\n\r\n const { policy: policyRaw, body } = JSON.parse(entry);\r\n\r\n const policy = CachePolicy.fromObject(policyRaw);\r\n // Remove url from the policy, because otherwise it would never match a request with a custom cache key\r\n (policy as any)._url = undefined;\r\n\r\n if (policy.satisfiesWithoutRevalidation(policyRequestFrom(request))) {\r\n const headers = policy.responseHeaders() as HeadersInit;\r\n return new Response(body, {\r\n url: (policy as any)._url,\r\n status: (policy as any)._status,\r\n headers,\r\n } as ResponseInit);\r\n } else {\r\n const revalidationHeaders = policy.revalidationHeaders(\r\n policyRequestFrom(request),\r\n );\r\n const revalidationRequest = new Request(request, {\r\n headers: revalidationHeaders as HeadersInit,\r\n });\r\n const revalidationResponse = await fetch(revalidationRequest);\r\n\r\n const { policy: revalidatedPolicy, modified } = policy.revalidatedPolicy(\r\n policyRequestFrom(revalidationRequest),\r\n policyResponseFrom(revalidationResponse),\r\n );\r\n\r\n return storeResponseAndReturnClone(\r\n cache,\r\n new Response(modified ? await revalidationResponse.text() : body, {\r\n url: (revalidatedPolicy as any)._url,\r\n status: (revalidatedPolicy as any)._status,\r\n headers: (revalidatedPolicy as any).responseHeaders(),\r\n } as ResponseInit),\r\n revalidatedPolicy,\r\n cacheKey,\r\n );\r\n }\r\n}\r\n\r\nexport * from 'cross-fetch';\r\n\r\nexport default fetchache;\r\n\r\nasync function storeResponseAndReturnClone(\r\n cache: KeyValueCache,\r\n response: Response,\r\n policy: CachePolicy,\r\n cacheKey: string,\r\n): Promise<Response> {\r\n\r\n let ttl = Math.round(policy.timeToLive() / 1000);\r\n if (ttl <= 0) return response;\r\n\r\n // If a response can be revalidated, we don't want to remove it from the cache right after it expires.\r\n // We may be able to use better heuristics here, but for now we'll take the max-age times 2.\r\n if (canBeRevalidated(response)) {\r\n ttl *= 2;\r\n }\r\n\r\n const body = await response.text();\r\n const entry = JSON.stringify({\r\n policy: policy.toObject(),\r\n body,\r\n });\r\n\r\n await cache.set(cacheKey, entry, {\r\n ttl,\r\n });\r\n\r\n // We have to clone the response before returning it because the\r\n // body can only be used once.\r\n // To avoid https://github.com/bitinn/node-fetch/issues/151, we don't use\r\n // response.clone() but create a new response from the consumed body\r\n return new Response(body, {\r\n url: response.url,\r\n status: response.status,\r\n statusText: response.statusText,\r\n headers: response.headers,\r\n } as ResponseInit);\r\n}\r\n\r\nfunction canBeRevalidated(response: Response): boolean {\r\n return response.headers.has('ETag');\r\n}\r\n\r\nfunction policyRequestFrom(request: Request) {\r\n return {\r\n url: request.url,\r\n method: request.method,\r\n headers: headersToObject(request.headers),\r\n };\r\n}\r\n\r\nfunction policyResponseFrom(response: Response) {\r\n return {\r\n status: response.status,\r\n headers: headersToObject(response.headers),\r\n };\r\n}\r\n\r\nfunction headersToObject(headers: Headers) {\r\n const object = Object.create(null);\r\n headers.forEach((val, key) => {\r\n object[key] = val;\r\n });\r\n return object;\r\n}\r\n\r\nexport interface KeyValueCacheSetOptions {\r\n /**\r\n * Specified in **seconds**, the time-to-live (TTL) value limits the lifespan\r\n * of the data being stored in the cache.\r\n */\r\n ttl?: number | null\r\n};\r\n\r\nexport interface KeyValueCache<V = string> {\r\n get(key: string): Promise<V | undefined>;\r\n set(key: string, value: V, options?: KeyValueCacheSetOptions): Promise<void>;\r\n delete(key: string): Promise<boolean | void>;\r\n}\r\n"],"names":[],"mappings":"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"}