fch 5.0.0 → 5.1.1
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 +142 -0
- package/index.min.js +1 -1
- package/package.json +5 -3
- package/readme.md +6 -7
package/index.d.ts
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
type Store = {
|
|
2
|
+
get: (key: string) => Promise<any>;
|
|
3
|
+
set: (key: string, value: any, options: { EX: number }) => Promise<null>;
|
|
4
|
+
del: (key: string) => Promise<null>;
|
|
5
|
+
keys: () => Promise<string[]>;
|
|
6
|
+
exists: (key: string) => Promise<boolean>;
|
|
7
|
+
flushAll: () => Promise<any>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type Cache =
|
|
11
|
+
| boolean
|
|
12
|
+
| number
|
|
13
|
+
| string
|
|
14
|
+
| {
|
|
15
|
+
expire?: number | string;
|
|
16
|
+
store?: Store;
|
|
17
|
+
shouldCache?: (request) => boolean;
|
|
18
|
+
createKey?: (request) => string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type Headers = { [name: string]: string };
|
|
22
|
+
type Query = { [name: string]: string };
|
|
23
|
+
|
|
24
|
+
type Methods = "get" | "head" | "post" | "patch" | "put" | "delete";
|
|
25
|
+
|
|
26
|
+
type Options = {
|
|
27
|
+
url?: string;
|
|
28
|
+
method?: Methods;
|
|
29
|
+
query?: Query;
|
|
30
|
+
headers?: Headers;
|
|
31
|
+
baseUrl?: string;
|
|
32
|
+
baseURL?: string;
|
|
33
|
+
cache?: Cache;
|
|
34
|
+
output?: string;
|
|
35
|
+
credentials?: string;
|
|
36
|
+
before?: (req: any) => any;
|
|
37
|
+
after?: (res: any) => any;
|
|
38
|
+
error?: (error: Error) => any;
|
|
39
|
+
signal?: AbortSignal;
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type FullOptions = Options & { url: "string" };
|
|
44
|
+
|
|
45
|
+
type Body =
|
|
46
|
+
| string
|
|
47
|
+
| any[]
|
|
48
|
+
| { [key: string]: any }
|
|
49
|
+
| FormData
|
|
50
|
+
| HTMLFormElement
|
|
51
|
+
| SubmitEvent
|
|
52
|
+
| ReadableStream;
|
|
53
|
+
|
|
54
|
+
declare function fch(url: string, options?: Options): Promise<any>;
|
|
55
|
+
|
|
56
|
+
declare module fch {
|
|
57
|
+
var url: string;
|
|
58
|
+
var method: Methods;
|
|
59
|
+
var query: Query;
|
|
60
|
+
var headers: Headers;
|
|
61
|
+
var baseUrl: string;
|
|
62
|
+
var baseURL: string;
|
|
63
|
+
var cache: Cache;
|
|
64
|
+
var output: string;
|
|
65
|
+
var credentials: string;
|
|
66
|
+
var before: (req: any) => any;
|
|
67
|
+
var after: (res: any) => any;
|
|
68
|
+
var error: (error: Error) => any;
|
|
69
|
+
var signal: AbortSignal;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Creates an instance of fch with the given options, perfect for custom APIs:
|
|
73
|
+
*
|
|
74
|
+
* ```js
|
|
75
|
+
* const api = fch.create({
|
|
76
|
+
* baseUrl: 'https://api.myapi.com/',
|
|
77
|
+
* headers: { apiVersion: 2 }
|
|
78
|
+
* })
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
function create(options?: FullOptions): typeof fch;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Make a GET request to the given endpoint:
|
|
85
|
+
*
|
|
86
|
+
* ```js
|
|
87
|
+
* const data = await fch.get('/path')
|
|
88
|
+
* const data = await fch.get('/path', options)
|
|
89
|
+
*/
|
|
90
|
+
function get(url: string, options?: Options): Promise<any>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Make a HEAD request to the given endpoint:
|
|
94
|
+
*
|
|
95
|
+
* ```js
|
|
96
|
+
* const data = await fch.head('/path')
|
|
97
|
+
* const data = await fch.head('/path', options)
|
|
98
|
+
*/
|
|
99
|
+
function head(url: string, options?: Options): Promise<any>;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Make a POST request to the given endpoint:
|
|
103
|
+
*
|
|
104
|
+
* ```js
|
|
105
|
+
* const data = await fch.post('/path', body)
|
|
106
|
+
* const data = await fch.post('/path', body, options)
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
function post(url: string, body?: Body, options?: Options): Promise<any>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Make a PATCH request to the given endpoint:
|
|
113
|
+
*
|
|
114
|
+
* ```js
|
|
115
|
+
* const data = await fch.patch('/path', body)
|
|
116
|
+
* const data = await fch.patch('/path', body, options)
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
function put(url: string, body?: Body, options?: Options): Promise<any>;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Make a PUT request to the given endpoint:
|
|
123
|
+
*
|
|
124
|
+
* ```js
|
|
125
|
+
* const data = await fch.put('/path', body)
|
|
126
|
+
* const data = await fch.put('/path', body, options)
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
function patch(url: string, body?: Body, options?: Options): Promise<any>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Make a DELETE request to the given endpoint:
|
|
133
|
+
*
|
|
134
|
+
* ```js
|
|
135
|
+
* const data = await fch.del('/patd)
|
|
136
|
+
* const data = await fch.del('/patd, options)
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
function del(url: string, body?: Body, options?: Options): Promise<any>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export default fch;
|
package/index.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var d=async e=>(e=await e,Array.isArray(e)?await Promise.all(e.map(d)):e),y=(e,n)=>(...a)=>(r=>r instanceof RegExp?r.test.bind(r):r)(e).call(n,...a),k=(e,n)=>async(a,r,t)=>({value:a,extra:await y(e,n)(a,r,t)}),D=({extra:e})=>e,
|
|
1
|
+
var d=async e=>(e=await e,Array.isArray(e)?await Promise.all(e.map(d)):e),y=(e,n)=>(...a)=>(r=>r instanceof RegExp?r.test.bind(r):r)(e).call(n,...a),k=(e,n)=>async(a,r,t)=>({value:a,extra:await y(e,n)(a,r,t)}),D=({extra:e})=>e,T=({value:e})=>e,j={every:async(e,n,a)=>{for(let r=0;r<e.length;r++)if(!await y(n,a)(e[r],r,e))return!1;return!0},filter:async(e,n,a)=>(await d(e.map(k(n,a)))).filter(D).map(T),find:async(e,n,a)=>{for(let r=0;r<e.length;r++)if(await y(n,a)(e[r],r,e))return e[r]},findIndex:async(e,n,a)=>{for(let r=0;r<e.length;r++)if(await y(n,a)(e[r],r,e))return r;return-1},forEach:async(e,n,a)=>(await d(e.map(k(n,a))),e),reduce:async(e,n,a)=>{let r=a!==void 0;r||(a=e[0]);for(let t=r?0:1;t<e.length;t++)a=await y(n)(a,e[t],t,e);return a},reduceRight:async(e,n,a)=>{let r=a!==void 0;r||(a=e[e.length-1]);for(let t=e.length-(r?1:2);t>=0;t--)a=await y(n)(a,e[t],t,e);return a},some:async(e,n,a)=>{for(let r=0;r<e.length;r++)if(await y(n,a)(e[r],r,e))return!0;return!1}},C=(e,n)=>(a,r)=>r==="then"?(...t)=>d(e).then(...t):r==="catch"?(...t)=>p(d(e).catch(...t)):h(d(e).then(t=>typeof r=="symbol"?t[r]:r in n?h((...o)=>n[r](t,...o),n):typeof t=="number"&&r in n.number?h((...o)=>n.number[r](t,...o),n):typeof t=="string"&&r in n.string?h((...o)=>n.string[r](t,...o),n):Array.isArray(t)&&r in n.array?h((...o)=>n.array[r](t,...o),n):t[r]&&t[r].bind?h(t[r].bind(t),n):h(t[r],n)),n),F=(e,n)=>(a,r,t)=>h(d(e).then(o=>{return typeof o!="function"?(c=`You tried to call "${JSON.stringify(o)}" (${typeof o}) as a function, but it is not.`,Promise.reject(new Error(c))):o(...t);var c}),n),h=(e,n)=>new Proxy(()=>{},{get:C(e,n),apply:F(e,n)});function p(e,{number:n,string:a,array:r,...t}={}){return typeof e=="function"?(...o)=>p(Promise.all(o).then(c=>e(...c)),{number:n,string:a,array:r,...t}):new Proxy({},{get:C(e,{number:{...n},string:{...a},array:{...j,...r},...t})})}function w(e){e.expire||(e.expire=0);let n=new Map,a=async r=>{if(!n.has(r))return!1;let{time:t,expire:o}=n.get(r);return!(!o||new Date().getTime()-t>o*1e3)};return{get:async r=>{if(!await a(r))return null;let{data:o}=n.get(r);return o},set:async(r,t,o={})=>{let c=new Date().getTime(),f=o.EX||o.expire||e.expire;return n.set(r,{time:c,expire:f,data:t})},keys:async()=>[...await n.keys()],del:async r=>n.delete(r),exists:a,flushAll:()=>n.clear()}}var M=/(-?(?:\d+\.?\d*|\d*\.?\d+)(?:e[-+]?\d+)?)\s*([\p{L}]*)/iu;s.millisecond=s.ms=1;s.second=s.sec=s.s=s[""]=s.ms*1e3;s.minute=s.min=s.m=s.s*60;s.hour=s.hr=s.h=s.m*60;s.day=s.d=s.h*24;s.week=s.wk=s.w=s.d*7;s.year=s.yr=s.y=s.d*365.25;s.month=s.b=s.y/12;function s(e=""){if(!e)return 0;if(e===!0)return 60*60*1e3;if(typeof e=="number")return e;e=e.toLowerCase().replace(/[,_]/g,"");let[n,a,r]=M.exec(e)||[];r=s[r]||s[r.replace(/s$/,"")]||1e3;let t=r*parseFloat(a,10);return Math.abs(Math.round(t))}var O=e=>!e||e instanceof FormData||typeof(e.pipe||e.pipeTo)=="function"?!1:typeof e=="object"||Array.isArray(e),b=e=>{if(typeof e!="object")return e;for(let n in e)e[n]===void 0&&delete e[n];return e},g=class extends Error{constructor(n){let a="Error "+n.status;super(a),this.response=n,this.message=a}},B=(e,n,a)=>{let[r,t={}]=e.split("?"),o=new URLSearchParams(Object.fromEntries([...new URLSearchParams(b(n)),...new URLSearchParams(b(t))])).toString();return o&&(r=r+"?"+o),a?new URL(r.replace(/^\//,""),a).href:r},J=e=>{let n={};for(let[a,r]of Object.entries(e))n[a.toLowerCase()]=r;return n},v=async e=>{let n=e.headers.get("content-type"),a=n&&n.includes("application/json"),r=await e.clone().text();return a?JSON.parse(r):r},P=async e=>{let n={status:e.status,statusText:e.statusText,headers:{}};for(let a of e.headers.keys())n.headers[a.toLowerCase()]=e.headers.get(a);if(!e.ok)throw new g(e);return n.body=await v(e),n},L=(e,{ref:n,after:a,error:r,output:t})=>fetch(e.url,e).then(async o=>{if(n.res=o,o.ok&&t==="stream")return o.body;if(o.ok&&o[t]&&typeof o[t]=="function")return o[t]();let c=a(await P(o));if(t==="body")return c.body;if(t==="response")return c;if(t==="raw")return o.clone();throw new Error(`Invalid option output="${t}"`)}).catch(r),$=e=>e.method==="get",q=e=>e.method+":"+e.url,K=({store:e,...n}={},a)=>{let r={store:e?p(e):w({expire:s(n.expire)}),shouldCache:$,createKey:q,...n};return r.clear=()=>Promise.resolve(r.store).then(t=>t?.flushAll()),a&&(r.shouldCache=()=>!1),r};function x(e={}){let n={},a={},t=p(async(o="/",c={})=>{let{output:f,before:S,after:E,error:U,...i}={...t,...c},l={...t.cache},A=u=>["number","string","boolean"].includes(typeof u);if(l.expire=s([c.cache?.expire,c.cache,l?.expire,l].find(A)),i.url=B(o,{...t.query,...c.query},i.baseUrl??i.baseURL),i.method=i.method.toLowerCase()||"GET",i.headers=J({...t.headers,...c.headers}),i.body instanceof SubmitEvent&&(i.body=new FormData(i.body.target)),i.body instanceof HTMLFormElement&&(i.body=new FormData(i.body)),O(i.body)&&(i.body=JSON.stringify(b(i.body)),i.headers["content-type"]="application/json"),i=S(i),l.shouldCache(i)&&l.expire){let u=l.createKey(i);if(l.store?.then){let R=await l.store;l.store=R}if(await l.store.exists(u))return l.store.get(u);if(n[u])return n[u];let m;try{n[u]=L(i,{ref:a,cache:l,output:f,error:U,after:E}),m=await n[u]}finally{delete n[u]}return await l.store.set(u,m,{EX:l.expire}),m}return L(i,{ref:a,output:f,error:U,after:E})},{text:()=>a.res.text(),json:()=>a.res.json(),blob:()=>a.res.blob(),stream:()=>a.res.body,arrayBuffer:()=>a.res.arrayBuffer(),formData:()=>a.res.formData(),body:()=>v(a.res),clone:()=>a.res.clone(),raw:()=>a.res.clone(),response:()=>P(a.res.clone())});return t.url=e.url??"/",t.method=e.method??"get",t.query=e.query??{},t.headers=e.headers??{},t.baseUrl=e.baseUrl??e.baseURL??null,["number","string","boolean"].includes(typeof e.cache)&&(e.cache={expire:e.cache}),t.cache=K(e.cache,e.cache?.expire===!1||e.cache?.expire===0),t.output=e.output??"body",t.credentials=e.credentials??"include",t.before=e.before??(o=>o),t.after=e.after??(o=>o),t.error=e.error??(o=>Promise.reject(o)),t.get=(o,c)=>t(o,{method:"get",...c}),t.head=(o,c)=>t(o,{method:"head",...c}),t.post=(o,c,f)=>t(o,{method:"post",body:c,...f}),t.patch=(o,c,f)=>t(o,{method:"patch",body:c,...f}),t.put=(o,c,f)=>t(o,{method:"put",body:c,...f}),t.delete=(o,c)=>t(o,{method:"delete",...c}),t.del=t.delete,t.create=x,t}typeof window<"u"&&(window.fch=x());var _=x();export{x as create,_ as default,s as parse};
|
|
2
2
|
//# sourceMappingURL=index.min.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fch",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"description": "Fetch interface with better promises, deduplication, defaults, etc.",
|
|
5
5
|
"homepage": "https://github.com/franciscop/fetch",
|
|
6
6
|
"repository": "https://github.com/franciscop/fetch.git",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
],
|
|
25
25
|
"main": "index.min.js",
|
|
26
26
|
"files": [
|
|
27
|
-
"index.min.js"
|
|
27
|
+
"index.min.js",
|
|
28
|
+
"index.d.ts"
|
|
28
29
|
],
|
|
29
30
|
"types": "index.d.ts",
|
|
30
31
|
"type": "module",
|
|
@@ -33,11 +34,12 @@
|
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"check-dts": "^0.7.2",
|
|
37
|
+
"dotenv": "^16.3.1",
|
|
36
38
|
"esbuild": "^0.19.2",
|
|
37
39
|
"jest": "^28.1.0",
|
|
38
40
|
"jest-environment-jsdom": "^28.1.0",
|
|
39
41
|
"jest-fetch-mock": "^3.0.3",
|
|
40
|
-
"redis": "^4.6.
|
|
42
|
+
"redis": "^4.6.10",
|
|
41
43
|
"swear": "^1.1.2"
|
|
42
44
|
},
|
|
43
45
|
"jest": {
|
package/readme.md
CHANGED
|
@@ -354,9 +354,9 @@ Your cache will have a `store`; by default we create an in-memory store, but you
|
|
|
354
354
|
import fch from "fch";
|
|
355
355
|
import { createClient } from "redis";
|
|
356
356
|
|
|
357
|
-
//
|
|
358
|
-
|
|
359
|
-
|
|
357
|
+
// You can either pass the store instance, or a promise that will
|
|
358
|
+
// return the instance. In this case we are doing the latter
|
|
359
|
+
const store = createClient().connect();
|
|
360
360
|
|
|
361
361
|
const api = fch.create({
|
|
362
362
|
cache: {
|
|
@@ -384,14 +384,11 @@ import { createClient } from "redis";
|
|
|
384
384
|
// Initialize it straight away
|
|
385
385
|
const api = fch.create({
|
|
386
386
|
cache: {
|
|
387
|
-
store: createClient(),
|
|
387
|
+
store: createClient().connect(),
|
|
388
388
|
expire: "1h",
|
|
389
389
|
},
|
|
390
390
|
});
|
|
391
391
|
|
|
392
|
-
// Connect it here now
|
|
393
|
-
await api.cache.store.connect();
|
|
394
|
-
|
|
395
392
|
// Later on, maybe in a different place
|
|
396
393
|
await api.cache.store.flushDB();
|
|
397
394
|
```
|
|
@@ -439,6 +436,8 @@ const api = fch.create({
|
|
|
439
436
|
});
|
|
440
437
|
```
|
|
441
438
|
|
|
439
|
+
It is this flexible since you can use fch both in the front-end and back-end, so usually in each of them you might want to follow a slightly different strategy.
|
|
440
|
+
|
|
442
441
|
#### Creating a store.
|
|
443
442
|
|
|
444
443
|
You might want to create a custom store. Please have a look at `src/store.js`, but basically you need an object that implements these methods:
|