soon-fetch 3.0.0-beta.2 → 3.0.0-beta.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/README.md +58 -39
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +46 -13
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
> - ⭐ rapid define a request api
|
|
11
11
|
> - ⌛ timeout disconnect
|
|
12
12
|
> - 🔤 automatic parse or serialization of JSON
|
|
13
|
-
> - 📏 .min size less than **
|
|
13
|
+
> - 📏 .min size less than **5K**, smaller after zip
|
|
14
14
|
> - 💡 smart type tips with Typescript
|
|
15
15
|
|
|
16
16
|
- [Example](#example)
|
|
@@ -18,35 +18,40 @@
|
|
|
18
18
|
- [Shortcut](#shortcut)
|
|
19
19
|
- [Restful Url Params](#restful-url-params)
|
|
20
20
|
- [Timeout](#timeout)
|
|
21
|
+
- [Share pending request](#share-pending-request)
|
|
22
|
+
- [Cache response](#cache-response)
|
|
23
|
+
- [Request race](#request-race)
|
|
21
24
|
- [Rapid Define APIs](#rapid-define-apis)
|
|
22
25
|
- [API](#api)
|
|
23
26
|
|
|
24
|
-
|
|
25
27
|
### Example
|
|
26
28
|
|
|
27
29
|
> [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
|
|
28
30
|
> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
|
|
29
31
|
|
|
30
32
|
```typescript
|
|
31
|
-
import { createSoon
|
|
32
|
-
|
|
33
|
-
const soon = createSoon(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
33
|
+
import { createSoon } from "soon-fetch";
|
|
34
|
+
|
|
35
|
+
const soon = createSoon(
|
|
36
|
+
(url, options) => ({
|
|
37
|
+
url,
|
|
38
|
+
options,
|
|
39
|
+
baseURL: "/api",
|
|
40
|
+
baseOptions: {
|
|
41
|
+
headers: new Headers({
|
|
42
|
+
Authorization: "Bearer " + localStorage.getItem("token"),
|
|
43
|
+
}),
|
|
44
|
+
timeout: 5000,
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
({ parsed }) => {
|
|
48
|
+
return <T>() => {
|
|
49
|
+
return fetch(parsed.url, parsed.options).then((res) =>
|
|
50
|
+
res.json()
|
|
51
|
+
) as Promise<T>;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
);
|
|
50
55
|
|
|
51
56
|
/** GET */
|
|
52
57
|
soon.get("/user?id=123");
|
|
@@ -145,7 +150,8 @@ export default function App() {
|
|
|
145
150
|
|
|
146
151
|
```typescript
|
|
147
152
|
//can be GET POST PATCH PUT DELETE
|
|
148
|
-
|
|
153
|
+
soon.GET(url:string).Query<Query>().Send<Response>()
|
|
154
|
+
soon.POST(url:string).Body<Body>().Send<Response>()
|
|
149
155
|
//define an api
|
|
150
156
|
export const getUserInfo = soon.GET("/user/:id").Send();
|
|
151
157
|
//then use in any where
|
|
@@ -211,7 +217,9 @@ type SoonOptions = Omit<RequestInit, "body"> & {
|
|
|
211
217
|
|
|
212
218
|
- [快捷方法](#快捷方法)
|
|
213
219
|
- [Restful Url 参数自动处理](#restful-url-参数自动处理)
|
|
220
|
+
- [共享未完成的请求](#共享未完成的请求)
|
|
214
221
|
- [超时](#超时)
|
|
222
|
+
- [缓存](#缓存) -[请求竞态](#请求竞态)
|
|
215
223
|
- [快速定义 API](#快速定义-api)
|
|
216
224
|
|
|
217
225
|
- [API](#api-1)
|
|
@@ -222,21 +230,26 @@ type SoonOptions = Omit<RequestInit, "body"> & {
|
|
|
222
230
|
> [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
|
|
223
231
|
|
|
224
232
|
```typescript
|
|
225
|
-
const
|
|
226
|
-
|
|
233
|
+
const soon = createSoon(
|
|
234
|
+
(url, options) => ({
|
|
227
235
|
url,
|
|
228
236
|
options,
|
|
229
237
|
baseURL: "/api",
|
|
230
238
|
baseOptions: {
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
headers: new Headers({
|
|
240
|
+
Authorization: "Bearer " + localStorage.getItem("token"),
|
|
241
|
+
}),
|
|
242
|
+
timeout: 5000,
|
|
233
243
|
},
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
244
|
+
}),
|
|
245
|
+
({ parsed }) => {
|
|
246
|
+
return <T>() => {
|
|
247
|
+
return fetch(parsed.url, parsed.options).then((res) =>
|
|
248
|
+
res.json()
|
|
249
|
+
) as Promise<T>;
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
);
|
|
240
253
|
|
|
241
254
|
/** GET */
|
|
242
255
|
soon.get("/user?id=123");
|
|
@@ -296,7 +309,7 @@ soon.get(url, { timeout: 1000 * 20 });
|
|
|
296
309
|
soon.get(url, { share: true });
|
|
297
310
|
```
|
|
298
311
|
|
|
299
|
-
#####
|
|
312
|
+
##### 缓存
|
|
300
313
|
|
|
301
314
|
如果在指定时间内再次发起相同的请求,则会返回缓存的响应。
|
|
302
315
|
|
|
@@ -304,7 +317,7 @@ soon.get(url, { share: true });
|
|
|
304
317
|
soon.get(url, { staleTime: 1000 * 60 * 5 });
|
|
305
318
|
```
|
|
306
319
|
|
|
307
|
-
#####
|
|
320
|
+
##### 请求竞态
|
|
308
321
|
|
|
309
322
|
如果在第一个请求完成之前发起第二个请求,则会中止第一个请求,以避免因响应顺序错乱导致的问题。
|
|
310
323
|
|
|
@@ -335,19 +348,22 @@ export default function App() {
|
|
|
335
348
|
|
|
336
349
|
##### 快速定义 API
|
|
337
350
|
|
|
338
|
-
```
|
|
351
|
+
```ts
|
|
339
352
|
//可以是 GET POST PATCH PUT DELETE
|
|
340
353
|
//GET 请求数据传递至query,其他方法请求数据传递至body
|
|
341
|
-
soon.
|
|
354
|
+
soon.GET(url:string).Query<Query>().Send<Response>()
|
|
355
|
+
soon.POST(url:string).Body<Body>().Send<Response>()
|
|
342
356
|
|
|
343
357
|
//定义一个api
|
|
344
|
-
export const getUserInfo=soon.
|
|
358
|
+
export const getUserInfo=soon.GET('/user/:id').Send()
|
|
345
359
|
//使用
|
|
346
360
|
getUserInfo({id:2}).then(res=>console.log(res))
|
|
347
361
|
|
|
348
362
|
//用typescript,
|
|
349
|
-
export const login=soon
|
|
350
|
-
|
|
363
|
+
export const login=soon
|
|
364
|
+
.POST('/user/login')
|
|
365
|
+
.Body<{username:string,password:string}>()
|
|
366
|
+
.Send<{token:string}>()
|
|
351
367
|
//开发工具会有请求和响应的智能提醒
|
|
352
368
|
login({username:'admin',password:'123'}).then(res=>{
|
|
353
369
|
localStorage.setItem('token', res.token);
|
|
@@ -376,6 +392,9 @@ type SoonOptions = Omit<RequestInit, "body"> & {
|
|
|
376
392
|
params?: Record<string, string | number>;
|
|
377
393
|
timeout?: number;
|
|
378
394
|
body?: RequestInit["body"] | object;
|
|
395
|
+
aborts?: AbortController[];
|
|
396
|
+
share?: boolean;
|
|
397
|
+
staleTime?: number;
|
|
379
398
|
};
|
|
380
399
|
```
|
|
381
400
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const e=e=>{const t=[],r=e.match(/:([^:/\d]+)\/?/g);return r&&r.forEach((e=>{t.push(e.replace(/\//g,"").replace(/:/g,""))})),t},t=(e="")=>e.endsWith("/")?e.slice(0,-1):e,r=(e="")=>e.startsWith("/")?e:"/"+e,n=(e="")=>e.startsWith("http"),o=e=>{if(!e)return[];if(e instanceof URLSearchParams||"string"==typeof e||Array.isArray(e))return Array.from(new URLSearchParams(e).entries());const t=[];return Object.keys(e).forEach((r=>{const n=e[r];(Array.isArray(n)?n:[n]).forEach((e=>{t.push([r,e??""])}))})),t},s=(s,a)=>{const{query:i,params:c,baseURL:f}=a;let
|
|
1
|
+
"use strict";const e=e=>{const t=[],r=e.match(/:([^:/\d]+)\/?/g);return r&&r.forEach((e=>{t.push(e.replace(/\//g,"").replace(/:/g,""))})),t},t=(e="")=>e.endsWith("/")?e.slice(0,-1):e,r=(e="")=>e.startsWith("/")?e:"/"+e,n=(e="")=>e.startsWith("http"),o=e=>{if(!e)return[];if(e instanceof URLSearchParams||"string"==typeof e||Array.isArray(e))return Array.from(new URLSearchParams(e).entries());const t=[];return Object.keys(e).forEach((r=>{const n=e[r];(Array.isArray(n)?n:[n]).forEach((e=>{t.push([r,e??""])}))})),t},s=(s,a)=>{const{query:i,params:c,baseURL:f}=a;let p=s.trim();e(s).forEach((e=>{c&&(p=p.replace(":"+e,""+c[e]))}));const[u,l]=p.split("?"),h=new URLSearchParams([...o(l),...o(i)]);let y=((e,o)=>{if(n(e))return e;const s=n(o)?o:r(o);return t(s)+t(r(e))})(u,f);return h.size&&(y=y+"?"+h),y},a=(...e)=>{const t=new Headers;return e.forEach((e=>{e&&new Headers(e).forEach(((e,r)=>{t.set(r,e)}))})),t};function i(e,t){const r=(e??[]).filter((e=>!!e));return t&&r.push(AbortSignal.timeout(t)),r.length?AbortSignal.any(r):void 0}function c(e){return!(!e||"object"!=typeof e||(e instanceof Blob||e instanceof ArrayBuffer||e instanceof FormData||e instanceof File||e instanceof DataView||e instanceof URLSearchParams||e instanceof ReadableStream||(t=e,t instanceof Int8Array||t instanceof Uint8Array||t instanceof Uint8ClampedArray||t instanceof Int16Array||t instanceof Uint16Array||t instanceof Int32Array||t instanceof Uint32Array||t instanceof Float32Array||t instanceof Float64Array||t instanceof BigInt64Array||t instanceof BigUint64Array)));var t}function f(...e){const t=Object.assign({},...e),r=a(...e.map((e=>e?.headers)));return t.headers=r,t.signal=i(e.map((e=>e?.signal)),t.timeout),t}function p(e){const{url:t,options:r,baseURL:n,baseOptions:o}=e,a=f(o,r),p=s(t,{...a,baseURL:n}),u=a?.body,l=c(u);a.body=l?JSON.stringify(u):u,l&&a.headers.append("Content-Type","application/json");const h=new AbortController;return a.signal=i([a.signal,h.signal]),{url:p,options:a,is_body_json:l,abortController:h}}const u=["get","post","put","delete","patch"];function l(e,t){const r={};return e.forEach((e=>{r[e]=t(e)})),r}function h(t){const r=(r,n,o)=>{const s=!!e(r).length;return(...e)=>{const a=[...e],{hasBody:i,hasQuery:c}=o||{},f=s?a.shift():void 0,p=c?a.shift():void 0,u=i?a.shift():void 0,l=a.shift();return t(r,n,f,p,u,l,o?.options)}},n={};return u.forEach((e=>{const t=e.toUpperCase();n[t]=t=>({Send:n=>r(t,e,{options:n}),Body:()=>({Send:n=>r(t,e,{hasBody:!0,options:n})}),Query:()=>({Send:n=>r(t,e,{hasQuery:!0,options:n}),Body:()=>({Send:n=>r(t,e,{hasBody:!0,hasQuery:!0,options:n})})})})})),n}function y(e,t){t&&(t.pop()?.abort("race abort"),t.push(e))}function d(e){if(Array.isArray(e))return e.map(d);if("object"==typeof e&&null!==e){const t={};return Object.keys(e).sort().forEach((r=>{t[r]=d(e[r])})),t}return e}function g(e){const{url:t,options:r}=e,{headers:n,method:o,body:s,query:a,params:i}=r??{},c=d(Object.fromEntries(new Headers(n).entries()??[]));return(o??"get").toLowerCase()+t+JSON.stringify(d(a)??"")+JSON.stringify(d(i)??"")+JSON.stringify(c)+("object"==typeof s&&null!=s?JSON.stringify(d(s)):s??"")}function m(){const e={},t=[];setInterval((()=>{const r=Date.now();for(let n=t.length-1;n>=0;n--)t[n].expiredTime<r&&(delete e[t[n].key],t.splice(n,1))}),6e4);const r=e=>e instanceof Response?e.clone():"function"==typeof e||e instanceof Promise?e:structuredClone(e);function n(r){delete e[r];for(let e=t.length-1;e>=0;e--)if(t[e].key===r){t.splice(e,1);break}}return{get:function(t){const o=e[t];if(void 0!==o)return o.expiredTime>Date.now()?r(o.data):void n(t)},set:function(n,o,s){e[n]={data:r(o),expiredTime:s},t.push({key:n,expiredTime:s})},remove:n}}function b(){const e={},t=t=>e[t]=void 0;return{get:t=>e[t],set:(r,n)=>{e[r]=n,n.finally((()=>t(r)))}}}exports.createCache=m,exports.createShare=b,exports.createShortApi=h,exports.createShortMethods=l,exports.createSilentRefresh=function(e){let t=[],r=!1;return(n,o)=>{t.push({success:n,fail:o}),r||(r=!0,e().then((()=>{t.forEach((e=>e.success()))})).catch((e=>{t.forEach((e=>e.fail()))})).finally((()=>{r=!1,t=[]})))}},exports.createSoon=function(e,t){const r=m(),n=b(),o=(o,s)=>new Promise(((a,i)=>{const c=p(e(o,s)),f=g(c),{abortController:u}=c,l=new AbortController;l.signal.addEventListener("abort",(()=>{i(l.signal.reason)}));const h=t({parsed:{...c,requestKey:f}});if(c.options?.share){const e=n.get(f);if(e)return a(e)}if(y(c.options.share?l:u,c.options?.aborts),c.options?.staleTime){const e=r.get(f);if(void 0!==e)return a(e)}const d=h(o,s);c.options?.share&&n.set(f,d),d.then((e=>{a(e),c.options?.staleTime&&r.set(f,e,(new Date).getTime()+c.options.staleTime)})).catch((e=>i(e)))})),s=h(((e,t,r,n,s,a,i)=>o(e,{...i,...a,method:t,params:r,query:n,body:s}))),a=l([...u,"head","options"],(e=>(t,r)=>o(t,{...r,method:e})));return{request:o,...s,...a}},exports.deepSort=d,exports.genRequestKey=g,exports.isBodyJson=c,exports.mergeHeaders=a,exports.mergeOptions=f,exports.mergeSignals=i,exports.mergeUrl=s,exports.parseUrlOptions=function(e){const{url:t,options:r}=p(e);return[t,r]},exports.parseWithBase=p,exports.raceAbort=y;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
type SoonOptions = Omit<RequestInit, "body"> & {
|
|
2
|
+
body?: RequestInit["body"] | object;
|
|
2
3
|
query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
|
|
3
4
|
params?: Record<string, string | number>;
|
|
4
5
|
timeout?: number;
|
|
5
|
-
body?: RequestInit["body"] | object;
|
|
6
6
|
aborts?: AbortController[];
|
|
7
7
|
share?: boolean;
|
|
8
8
|
staleTime?: number;
|
|
@@ -21,17 +21,34 @@ declare const mergeUrl: (url: string, config: {
|
|
|
21
21
|
declare const mergeHeaders: (...headersList: (HeadersInit | undefined)[]) => Headers;
|
|
22
22
|
declare function mergeSignals(signals?: (AbortSignal | null | undefined)[], timeout?: number): AbortSignal | undefined;
|
|
23
23
|
declare function isBodyJson(body: any): boolean;
|
|
24
|
+
declare function mergeOptions<Options extends SoonOptions>(...optionsList: (Options | undefined)[]): Options & {
|
|
25
|
+
headers: Headers;
|
|
26
|
+
};
|
|
27
|
+
declare function parseWithBase<Options extends SoonOptions>(urlOptions: {
|
|
28
|
+
url: string;
|
|
29
|
+
options?: Options;
|
|
30
|
+
baseURL?: string;
|
|
31
|
+
baseOptions?: Options;
|
|
32
|
+
}): {
|
|
33
|
+
url: string;
|
|
34
|
+
options: Options & {
|
|
35
|
+
headers: Headers;
|
|
36
|
+
body?: RequestInit["body"];
|
|
37
|
+
};
|
|
38
|
+
is_body_json: boolean;
|
|
39
|
+
abortController: AbortController;
|
|
40
|
+
};
|
|
24
41
|
declare function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
|
|
25
42
|
url: string;
|
|
26
43
|
options?: Options;
|
|
27
44
|
baseURL?: string;
|
|
28
45
|
baseOptions?: Options;
|
|
29
|
-
}):
|
|
46
|
+
}): [url: string, options: Options & {
|
|
30
47
|
headers: Headers;
|
|
31
48
|
body?: BodyInit | null;
|
|
32
|
-
}
|
|
49
|
+
}];
|
|
33
50
|
declare function createShortMethods<Methods extends readonly string[], Wrapper extends (method: string) => <T>(...args: any) => Promise<T>>(methods: Methods, wrapper: Wrapper): Record<Tuple2Union<Methods>, ReturnType<typeof wrapper>>;
|
|
34
|
-
declare function createShortApi<Wrapper extends <T>(url: string, method: string, params: Record<string, string | number> | undefined, query: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams | undefined, body:
|
|
51
|
+
declare function createShortApi<Wrapper extends <T>(url: string, method: string, params: Record<string, string | number> | undefined, query: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams | undefined, body: RequestInit["body"] | object, options?: any, defineOptions?: any) => Promise<T>>(wrapper: Wrapper): {
|
|
35
52
|
GET: <Url extends string>(url: Url) => {
|
|
36
53
|
Send: <Res>(options?: Parameters<Wrapper>[5]) => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, options?: Parameters<Wrapper>[5] | undefined]) => Promise<Res>;
|
|
37
54
|
Query: <Query>() => unknown extends Query ? never : {
|
|
@@ -55,11 +72,13 @@ declare function raceAbort(abortController: AbortController, controllers?: Abort
|
|
|
55
72
|
declare function deepSort(obj: unknown): unknown;
|
|
56
73
|
declare function genRequestKey(req: {
|
|
57
74
|
url: string;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
options?: {
|
|
76
|
+
method?: string;
|
|
77
|
+
headers?: RequestInit["headers"];
|
|
78
|
+
body?: RequestInit["body"] | object;
|
|
79
|
+
query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
|
|
80
|
+
params?: Record<string, string | number>;
|
|
81
|
+
};
|
|
63
82
|
}): string;
|
|
64
83
|
declare function createCache(): {
|
|
65
84
|
get: (key: string) => unknown;
|
|
@@ -71,8 +90,22 @@ declare function createShare(): {
|
|
|
71
90
|
set: (key: string, value: Promise<any>) => void;
|
|
72
91
|
};
|
|
73
92
|
declare function createSilentRefresh(refresh_token_fn: () => Promise<void>): (success: () => void, fail: () => void) => void;
|
|
74
|
-
declare function createSoon<Options extends SoonOptions>(
|
|
75
|
-
|
|
93
|
+
declare function createSoon<Options extends SoonOptions>(getConfig: (url: string, options?: Options) => {
|
|
94
|
+
url: string;
|
|
95
|
+
options?: Options;
|
|
96
|
+
baseURL?: string;
|
|
97
|
+
baseOptions?: Options;
|
|
98
|
+
}, wrapper: (instance: {
|
|
99
|
+
parsed: {
|
|
100
|
+
url: string;
|
|
101
|
+
options: Options & {
|
|
102
|
+
headers: Headers;
|
|
103
|
+
body?: RequestInit["body"];
|
|
104
|
+
};
|
|
105
|
+
is_body_json: boolean;
|
|
106
|
+
abortController: AbortController;
|
|
107
|
+
requestKey: string;
|
|
108
|
+
};
|
|
76
109
|
}) => <T>(url: string, options?: Options) => Promise<T>): {
|
|
77
110
|
options: <T>(url: string, options?: Options) => Promise<T>;
|
|
78
111
|
get: <T>(url: string, options?: Options) => Promise<T>;
|
|
@@ -135,7 +168,7 @@ declare function createSoon<Options extends SoonOptions>(wrapper: (instance: {
|
|
|
135
168
|
};
|
|
136
169
|
};
|
|
137
170
|
};
|
|
138
|
-
request: <T>(url: string, options
|
|
171
|
+
request: <T>(url: string, options?: Options) => Promise<T>;
|
|
139
172
|
};
|
|
140
173
|
|
|
141
|
-
export { type SoonOptions, createCache, createShare, createShortApi, createShortMethods, createSilentRefresh, createSoon, deepSort, genRequestKey, isBodyJson, mergeHeaders, mergeSignals, mergeUrl, parseUrlOptions, raceAbort };
|
|
174
|
+
export { type SoonOptions, createCache, createShare, createShortApi, createShortMethods, createSilentRefresh, createSoon, deepSort, genRequestKey, isBodyJson, mergeHeaders, mergeOptions, mergeSignals, mergeUrl, parseUrlOptions, parseWithBase, raceAbort };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const t=t=>{const e=[],n=t.match(/:([^:/\d]+)\/?/g);return n&&n.forEach((t=>{e.push(t.replace(/\//g,"").replace(/:/g,""))})),e},e=(t="")=>t.endsWith("/")?t.slice(0,-1):t,n=(t="")=>t.startsWith("/")?t:"/"+t,r=(t="")=>t.startsWith("http"),o=t=>{if(!t)return[];if(t instanceof URLSearchParams||"string"==typeof t||Array.isArray(t))return Array.from(new URLSearchParams(t).entries());const e=[];return Object.keys(t).forEach((n=>{const r=t[n];(Array.isArray(r)?r:[r]).forEach((t=>{e.push([n,t??""])}))})),e},s=(s,a)=>{const{query:i,params:c,baseURL:f}=a;let u=s.trim();t(s).forEach((t=>{c&&(u=u.replace(":"+t,""+c[t]))}));const[l,p]=u.split("?"),h=new URLSearchParams([...o(p),...o(i)]);let y=((t,o)=>{if(r(t))return t;const s=r(o)?o:n(o);return e(s)+e(n(t))})(l,f);return h.size&&(y=y+"?"+h),y},a=(...t)=>{const e=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,n)=>{e.set(n,t)}))})),e};function i(t,e){const n=(t??[]).filter((t=>!!t));return e&&n.push(AbortSignal.timeout(e)),n.length?AbortSignal.any(n):void 0}function c(t){return!(!t||"object"!=typeof t||(t instanceof Blob||t instanceof ArrayBuffer||t instanceof FormData||t instanceof File||t instanceof DataView||t instanceof URLSearchParams||t instanceof ReadableStream||(e=t,e instanceof Int8Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray||e instanceof Int16Array||e instanceof Uint16Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array||e instanceof BigInt64Array||e instanceof BigUint64Array)));var e}function f(...t){const e=Object.assign({},...t),n=a(...t.map((t=>t?.headers)));return e.headers=n,e.signal=i(t.map((t=>t?.signal)),e.timeout),e}function u(t){const{url:e,options:n,baseURL:r,baseOptions:o}=t,a=f(o,n),u=s(e,{...a,baseURL:r}),l=a?.body,p=c(l);a.body=p?JSON.stringify(l):l,p&&a.headers.append("Content-Type","application/json");const h=new AbortController;return a.signal=i([a.signal,h.signal]),{url:u,options:a,is_body_json:p,abortController:h}}function l(t){const{url:e,options:n}=u(t);return[e,n]}const p=["get","post","put","delete","patch"];function h(t,e){const n={};return t.forEach((t=>{n[t]=e(t)})),n}function y(e){const n=(n,r,o)=>{const s=!!t(n).length;return(...t)=>{const a=[...t],{hasBody:i,hasQuery:c}=o||{},f=s?a.shift():void 0,u=c?a.shift():void 0,l=i?a.shift():void 0,p=a.shift();return e(n,r,f,u,l,p,o?.options)}},r={};return p.forEach((t=>{const e=t.toUpperCase();r[e]=e=>({Send:r=>n(e,t,{options:r}),Body:()=>({Send:r=>n(e,t,{hasBody:!0,options:r})}),Query:()=>({Send:r=>n(e,t,{hasQuery:!0,options:r}),Body:()=>({Send:r=>n(e,t,{hasBody:!0,hasQuery:!0,options:r})})})})})),r}function d(t,e){e&&(e.pop()?.abort("race abort"),e.push(t))}function m(t){if(Array.isArray(t))return t.map(m);if("object"==typeof t&&null!==t){const e={};return Object.keys(t).sort().forEach((n=>{e[n]=m(t[n])})),e}return t}function g(t){const{url:e,options:n}=t,{headers:r,method:o,body:s,query:a,params:i}=n??{},c=m(Object.fromEntries(new Headers(r).entries()??[]));return(o??"get").toLowerCase()+e+JSON.stringify(m(a)??"")+JSON.stringify(m(i)??"")+JSON.stringify(c)+("object"==typeof s&&null!=s?JSON.stringify(m(s)):s??"")}function b(){const t={},e=[];setInterval((()=>{const n=Date.now();for(let r=e.length-1;r>=0;r--)e[r].expiredTime<n&&(delete t[e[r].key],e.splice(r,1))}),6e4);const n=t=>t instanceof Response?t.clone():"function"==typeof t||t instanceof Promise?t:structuredClone(t);function r(n){delete t[n];for(let t=e.length-1;t>=0;t--)if(e[t].key===n){e.splice(t,1);break}}return{get:function(e){const o=t[e];if(void 0!==o)return o.expiredTime>Date.now()?n(o.data):void r(e)},set:function(r,o,s){t[r]={data:n(o),expiredTime:s},e.push({key:r,expiredTime:s})},remove:r}}function A(){const t={},e=e=>t[e]=void 0;return{get:e=>t[e],set:(n,r)=>{t[n]=r,r.finally((()=>e(n)))}}}function S(t){let e=[],n=!1;return(r,o)=>{e.push({success:r,fail:o}),n||(n=!0,t().then((()=>{e.forEach((t=>t.success()))})).catch((t=>{e.forEach((t=>t.fail()))})).finally((()=>{n=!1,e=[]})))}}function w(t,e){const n=b(),r=A(),o=(o,s)=>new Promise(((a,i)=>{const c=u(t(o,s)),f=g(c),{abortController:l}=c,p=new AbortController;p.signal.addEventListener("abort",(()=>{i(p.signal.reason)}));const h=e({parsed:{...c,requestKey:f}});if(c.options?.share){const t=r.get(f);if(t)return a(t)}if(d(c.options.share?p:l,c.options?.aborts),c.options?.staleTime){const t=n.get(f);if(void 0!==t)return a(t)}const y=h(o,s);c.options?.share&&r.set(f,y),y.then((t=>{a(t),c.options?.staleTime&&n.set(f,t,(new Date).getTime()+c.options.staleTime)})).catch((t=>i(t)))})),s=y(((t,e,n,r,s,a,i)=>o(t,{...i,...a,method:e,params:n,query:r,body:s}))),a=h([...p,"head","options"],(t=>(e,n)=>o(e,{...n,method:t})));return{request:o,...s,...a}}export{b as createCache,A as createShare,y as createShortApi,h as createShortMethods,S as createSilentRefresh,w as createSoon,m as deepSort,g as genRequestKey,c as isBodyJson,a as mergeHeaders,f as mergeOptions,i as mergeSignals,s as mergeUrl,l as parseUrlOptions,u as parseWithBase,d as raceAbort};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "soon-fetch",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
4
|
-
"description": "a
|
|
3
|
+
"version": "3.0.0-beta.4",
|
|
4
|
+
"description": "a 5Kb request lib alternative to axios with timeout, request reusing ,cache ,race ...",
|
|
5
5
|
"homepage": "https://github.com/leafio/soon-fetch",
|
|
6
6
|
"main": "./dist/index.cjs.js",
|
|
7
7
|
"module": "/dist/index.js",
|