soon-fetch 0.0.2 → 1.1.0

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 CHANGED
@@ -1,8 +1,10 @@
1
- [English](#soon-fetch-is-a-lightweight-http-request-library-based-on-vanilla-fetch-with-typescript) | [中文](#soon-fetch-是用-ts-对原生-fetch-的轻量封装) | [Installation](#安装-installation)
1
+ [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
2
2
 
3
3
  <!-- omit in toc -->
4
4
 
5
- ##### `soon-fetch` is a lightweight http request library based on vanilla fetch with Typescript
5
+ ### `soon-fetch`
6
+
7
+ **A lightweight http request lib , alternative to axios**
6
8
 
7
9
  > - 🌐 automatic parse restful api url parameters
8
10
  > - ⭐ rapid define a request api
@@ -26,58 +28,28 @@
26
28
 
27
29
  ### Example
28
30
 
29
- > [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
31
+ > [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
32
+ > [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
30
33
 
31
34
  ```typescript
32
- export const soon = createSoon<SoonOptions>({
35
+ export const soon = createSoon({
33
36
  baseURL: "/api",
34
- defaultOptions: () => ({
37
+ baseOptions: () => ({
35
38
  timeout: 20 * 1000,
36
- headers: new Headers({
37
- Authorization: localStorage.getItem("token") ?? "",
38
- }),
39
+ headers: { Authorization: localStorage.getItem("token") ?? "" },
39
40
  }),
40
- afterResponse: async (result, resolve, reject) => {
41
- const res = result.response;
42
- if (res) {
43
- if (res.ok) {
44
- if (res.headers.get("content-type")?.includes("json")) {
45
- const body = await res.json();
46
- if (body.code === 0) {
47
- resolve(body.data);
48
- } else {
49
- toast.error(body.err ?? "Invalid JSON Response");
50
- reject(body.err);
51
- }
52
- } else {
53
- resolve(res);
54
- }
55
- } else if (res.status === 401) {
56
- localStorage.removeItem("token");
57
- location.href = "/login";
58
- } else {
59
- toast.error(res.statusText);
60
- reject(res.statusText);
61
- }
62
- } else if (result.isTimeout) {
63
- toast.error(t("tip.requestTimeout"));
64
- } else if (result.error) {
65
- toast.error(result.error);
66
- }
67
- reject(result.error);
41
+ fetching(url, options) {
42
+ return fetch(url, options).then((res) => res.json());
68
43
  },
69
44
  });
70
45
 
71
46
  /** GET */
72
- soon.get("/user?id=123").then((data) => console.log(data));
73
- soon.get("/user", { query: { id: 123 } }).then((data) => console.log(data));
74
- soon
75
- .get("/user/:id", { params: { id: 123 } })
76
- .then((data) => console.log(data));
47
+ soon.get("/user?id=123");
48
+ soon.get("/user", { query: { id: 123 } });
49
+ soon.get("/user/:id", { params: { id: 123 } });
50
+
77
51
  /** POST */
78
- soon
79
- .post("/login", { body: { username: "admin", password: "123456" } })
80
- .then((data) => console.log(data));
52
+ soon.post("/login", { body: { username: "admin", password: "123456" } });
81
53
 
82
54
  /**Define API */
83
55
  export const login = soon
@@ -131,9 +103,8 @@ soon.get(url, { timeout: 1000 * 20 });
131
103
  //define an api
132
104
  export const getUserInfo=soon.API('/user/:id').GET()
133
105
  //then use in any where
134
- getUserInfo({id:2})
135
- .then(res=>console.log(res))
136
- .catch(err=>console.log(err))
106
+ getUserInfo({id:2}).then(res=>console.log(res))
107
+
137
108
 
138
109
  //with typescript,
139
110
  export const login=soon.API('/user/login')
@@ -152,23 +123,32 @@ soon.get(url, { timeout: 1000 * 20 });
152
123
  import { createSoon } from "soon";
153
124
 
154
125
  declare function createSoon<Options extends SoonOptions = SoonOptions>(
155
- soonInit?: SoonInit<Options>
126
+ soonInit?: NoInfer<SoonInit<Options>>
156
127
  );
157
128
 
158
- // options would overwrite by order : defaultOptions ,request(url,options),beforeRequest(options)
129
+ // options would overwritten by request level options ,but the headers will be merged
159
130
  export type SoonInit<Options> = {
160
131
  //**url prefix */
161
132
  baseURL?: string;
162
133
  /**the fetch http options */
163
- defaultOptions?: () => Options;
164
- /** can modify the fetch options before been handled*/
165
- beforeRequest?: (options: Options & { headers: Headers }) => void;
166
- /** can modify the response after fetched and promise resolved */
167
- afterResponse?: (
168
- result: SoonResult<Options>,
169
- resolve: (value: any) => void,
170
- reject: (reason?: any) => void
171
- ) => Promise<void>;
134
+ baseOptions?: () => Options;
135
+ /** can use return a new fetch request instead*/
136
+ fetching?: (
137
+ //parsed url with query and params
138
+ url: string,
139
+ //parsed options with timeout signal,headers,JSON stringified body
140
+ options: Options & {
141
+ headers: Headers;
142
+ },
143
+ raw: {
144
+ // raw base info defined above
145
+ baseURL?: string;
146
+ baseOptions?: () => Options;
147
+ // raw url,options passed from request
148
+ url: string;
149
+ options?: Options;
150
+ }
151
+ ) => Promise<any>;
172
152
  };
173
153
  ```
174
154
 
@@ -179,8 +159,11 @@ soon.request(url[,options])
179
159
  ```
180
160
 
181
161
  Request data can choose `query` `params` `body` for easy specification
162
+ `body` can pass json without stringified
182
163
 
183
164
  ```typescript
165
+ //fetch(input: RequestInfo | URL, init?: RequestInit)
166
+ //RequestInit is the init params type of fetch
184
167
  type SoonOptions = {
185
168
  /** url search params like `api/info?name=yes` {name:"yes"} passed here*/
186
169
  query?:
@@ -193,65 +176,28 @@ type SoonOptions = {
193
176
  params?: Record<string, string | number>;
194
177
  /** unit ms */
195
178
  timeout?: number;
196
- /***** vanilla fetch props *****/
197
- //body can pass json without stringified
198
- body?: any;
199
- signal?: AbortSignal;
200
- method?:
201
- | "get"
202
- | "GET"
203
- | "delete"
204
- | "DELETE"
205
- | "head"
206
- | "HEAD"
207
- | "options"
208
- | "OPTIONS"
209
- | "post"
210
- | "POST"
211
- | "put"
212
- | "PUT"
213
- | "patch"
214
- | "PATCH"
215
- | "purge"
216
- | "PURGE"
217
- | "link"
218
- | "LINK"
219
- | "unlink"
220
- | "UNLINK";
221
- mode?: "cors" | "no-cors" | "same-origin";
222
- cache?: "default" | "no-cache" | "reload" | "force-cache" | "only-if-cached";
223
- credentials?: "include" | "same-origin" | "omit";
224
- headers?: Headers;
225
- redirect?: "manual" | "follow" | "error";
226
- referrerPolicy?:
227
- | "no-referrer"
228
- | "no-referrer-when-downgrade"
229
- | "origin"
230
- | "origin-when-cross-origin"
231
- | "same-origin"
232
- | "strict-origin"
233
- | "strict-origin-when-cross-origin"
234
- | "unsafe-url";
235
- integrity?: string;
236
179
  };
237
180
  ```
238
181
 
239
182
  ##### Response
240
183
 
241
- Default : return raw fetch Response , you can customize it in afterResponse params of createSoon
184
+ Default : return raw fetch Response , you can customize it in `fetching` params of `createSoon`
242
185
 
243
186
  ### Support Me
244
187
 
245
- If you like this library , you can give a **start** on github.
246
- Email: leafnote@outlook.com
188
+ If you like this library , you can give a **star** on github.
189
+ GitHub: https://github.com/leafio/soon-fetch
247
190
 
248
- > I'm looking for a frontend job in Shanghai , hope someone could find a offer for me.
191
+ > I'm looking for a frontend job , expecting an offer or chance for me .
192
+ > Email: leafnote@outlook.com
249
193
 
250
- [English](#soon-fetch-is-a-lightweight-http-request-library-based-on-vanilla-fetch-with-typescript) | [中文](#soon-fetch-是用-ts-对原生-fetch-的轻量封装) | [Installation](#安装-installation)
194
+ [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
251
195
 
252
196
  <!-- omit in toc -->
253
197
 
254
- ##### soon-fetch 是用 ts 对原生 fetch 的轻量封装
198
+ #### soon-fetch
199
+
200
+ **极轻量的请求库,不到 3K**
255
201
 
256
202
  > - 🌐 自动解析 rest Url 的参数
257
203
  > - ⭐ 快捷定义请求 api
@@ -277,58 +223,28 @@ Email: leafnote@outlook.com
277
223
 
278
224
  ### 示例
279
225
 
280
- > [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
226
+ > [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
227
+ > [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
281
228
 
282
229
  ```typescript
283
- export const soon = createSoon<SoonOptions>({
230
+ export const soon = createSoon({
284
231
  baseURL: "/api",
285
- defaultOptions: () => ({
232
+ baseOptions: () => ({
286
233
  timeout: 20 * 1000,
287
- headers: new Headers({
288
- Authorization: localStorage.getItem("token") ?? "",
289
- }),
234
+ headers: { Authorization: localStorage.getItem("token") ?? "" },
290
235
  }),
291
- afterResponse: async (result, resolve, reject) => {
292
- const res = result.response;
293
- if (res) {
294
- if (res.ok) {
295
- if (res.headers.get("content-type")?.includes("json")) {
296
- const body = await res.json();
297
- if (body.code === 0) {
298
- resolve(body.data);
299
- } else {
300
- toast.error(body.err ?? "Invalid JSON Response");
301
- reject(body.err);
302
- }
303
- } else {
304
- resolve(res);
305
- }
306
- } else if (res.status === 401) {
307
- localStorage.removeItem("token");
308
- location.href = "/login";
309
- } else {
310
- toast.error(res.statusText);
311
- reject(res.statusText);
312
- }
313
- } else if (result.isTimeout) {
314
- toast.error(t("tip.requestTimeout"));
315
- } else if (result.error) {
316
- toast.error(result.error);
317
- }
318
- reject(result.error);
236
+ fetching(url, options) {
237
+ return fetch(url, options).then((res) => res.json());
319
238
  },
320
239
  });
321
240
 
322
241
  /** GET */
323
- soon.get("/user?id=123").then((data) => console.log(data));
324
- soon.get("/user", { query: { id: 123 } }).then((data) => console.log(data));
325
- soon
326
- .get("/user/:id", { params: { id: 123 } })
327
- .then((data) => console.log(data));
242
+ soon.get("/user?id=123");
243
+ soon.get("/user", { query: { id: 123 } });
244
+ soon.get("/user/:id", { params: { id: 123 } });
245
+
328
246
  /** POST */
329
- soon
330
- .post("/login", { body: { username: "admin", password: "123456" } })
331
- .then((data) => console.log(data));
247
+ soon.post("/login", { body: { username: "admin", password: "123456" } });
332
248
 
333
249
  /**定义 API */
334
250
  export const login = soon
@@ -382,9 +298,7 @@ soon.get(url, { timeout: 1000 * 20 });
382
298
  //定义一个api
383
299
  export const getUserInfo=soon.API('/user/:id').GET()
384
300
  //使用
385
- getUserInfo({id:2})
386
- .then(res=>console.log(res))
387
- .catch(err=>console.log(err))
301
+ getUserInfo({id:2}).then(res=>console.log(res))
388
302
 
389
303
  //用typescript,
390
304
  export const login=soon.API('/user/login')
@@ -403,32 +317,31 @@ soon.get(url, { timeout: 1000 * 20 });
403
317
  import { createSoon } from "soon";
404
318
 
405
319
  declare function createSoon<Options extends SoonOptions = SoonOptions>(
406
- soonInit?: SoonInit<Options>
320
+ soonInit?: NoInfer<SoonInit<Options>>
407
321
  );
408
322
 
409
- // options 依次被覆盖 defaultOptions ,request(url,options),beforeRequest(options)
323
+ // 实例级options会被请求级options覆盖,但headers仅同key的被覆盖,其他合并
410
324
  export type SoonInit<Options> = {
411
325
  baseURL?: string;
412
326
  //默认的options
413
- defaultOptions?: () => Options;
414
- //在请求前对options的处理
415
- beforeRequest?: (options: Options & { headers: Headers }) => void;
416
- //在请求后对Response的处理
417
- afterResponse?: (
418
- result: SoonResult<Options>,
419
- resolve: (value: any) => void,
420
- reject: (reason?: any) => void
421
- ) => Promise<void>;
422
- };
423
- ```
424
-
425
- ```typescript
426
- export type SoonResult<Options> = {
427
- isTimeout: boolean;
428
- request: Request; //原生fetch的Request
429
- error?: any;
430
- response?: Response; //原生fetch的Response
431
- options: Options; //请求传递来的options
327
+ baseOptions?: () => Options;
328
+ //可返回自定义的fetch请求
329
+ fetching?: (
330
+ //根据 baseURL query params 解析后的url
331
+ url: string,
332
+ //包含超时signal,传来的JSON类型body已被stringified,并包含content-type json 的 headers
333
+ options: Options & {
334
+ headers: Headers;
335
+ },
336
+ raw: {
337
+ // 上方定义的 baseURL baseOptions
338
+ baseURL?: string;
339
+ baseOptions?: () => Options;
340
+ // 请求时传来的 url  options
341
+ url: string;
342
+ options?: Options;
343
+ }
344
+ ) => Promise<any>;
432
345
  };
433
346
  ```
434
347
 
@@ -439,9 +352,12 @@ soon.request(url[,options])
439
352
  ```
440
353
 
441
354
  请求数据可以选择 _`query`_ _`params`_ _`body`_ ,易于传递。
355
+ `body` 可直接传递 JSON 而不必 stringified
442
356
 
443
357
  ```typescript
444
- type SoonOptions = {
358
+ //fetch(input: RequestInfo | URL, init?: RequestInit)
359
+ //RequestInit 为原生 fetch 的选项类型
360
+ type SoonOptions = RequestInit & {
445
361
  /** url ?后的参数 `api/info?name=yes` 传递 {name:"yes"}*/
446
362
  query?:
447
363
  | Record<
@@ -453,62 +369,22 @@ type SoonOptions = {
453
369
  params?: Record<string, string | number>;
454
370
  /** unit 毫秒 */
455
371
  timeout?: number;
456
-
457
- /*** 原生fetch 参数*/
458
- //可直接传递JSON而不必stringified
459
- body?: any;
460
- signal?: AbortSignal;
461
- method?:
462
- | "get"
463
- | "GET"
464
- | "delete"
465
- | "DELETE"
466
- | "head"
467
- | "HEAD"
468
- | "options"
469
- | "OPTIONS"
470
- | "post"
471
- | "POST"
472
- | "put"
473
- | "PUT"
474
- | "patch"
475
- | "PATCH"
476
- | "purge"
477
- | "PURGE"
478
- | "link"
479
- | "LINK"
480
- | "unlink"
481
- | "UNLINK";
482
- mode?: "cors" | "no-cors" | "same-origin";
483
- cache?: "default" | "no-cache" | "reload" | "force-cache" | "only-if-cached";
484
- credentials?: "include" | "same-origin" | "omit";
485
- headers?: Headers;
486
- redirect?: "manual" | "follow" | "error";
487
- referrerPolicy?:
488
- | "no-referrer"
489
- | "no-referrer-when-downgrade"
490
- | "origin"
491
- | "origin-when-cross-origin"
492
- | "same-origin"
493
- | "strict-origin"
494
- | "strict-origin-when-cross-origin"
495
- | "unsafe-url";
496
- integrity?: string;
497
372
  };
498
373
  ```
499
374
 
500
375
  ##### 响应
501
376
 
502
- 默认为原生 fetch 的 Response ,可在 createSoon 的 afterResponse 里自定义处理 Response
377
+ 默认为原生 fetch 的 Response ,可在 `createSoon``fetching` 里自定义返回结果
503
378
 
504
379
  ### 支持一下
505
380
 
506
381
  喜欢 soon-fetch 的话 , 在 github 上给个 **star** 吧.
507
- Email: leafnote@outlook.com
382
+ GitHub: https://github.com/leafio/soon-fetch
508
383
 
509
- > 我目前在找前端的工作,位置上海。有岗位机会的话,可以联系我。
384
+ > 我目前在找前端的工作,有岗位机会的话,可以联系我。
385
+ > Email: leafnote@outlook.com
510
386
 
511
- [English](#soon-fetch-is-a-lightweight-http-request-library-based-on-vanilla-fetch-with-typescript) | [中文](#soon-fetch-是用-ts-对原生-fetch-的轻量封装)
387
+ [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
512
388
 
513
389
  <!-- omit in toc -->
514
390
 
package/dist/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";function e(e,t,n,s){return new(n||(n=Promise))((function(o,r){function a(e){try{c(s.next(e))}catch(e){r(e)}}function i(e){try{c(s.throw(e))}catch(e){r(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,i)}c((s=s.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const t=e=>{var t;const n=[];return null===(t=e.match(/\:([^:\/\d]+)\/?/g))||void 0===t||t.forEach((e=>{n.push(e.replace(/\//g,"").replace(/:/g,""))})),n},n=(e,n)=>{const{query:s,params:o,baseURL:r}=n;let a=e.trim();let i,c;t(e).forEach((e=>{o&&(a=a.replace(":"+e,""+o[e]))}));const u="http",l=e=>(null==e?void 0:e.endsWith("/"))?e.slice(0,-1):null!=e?e:"",d=e=>{let t=null!=e?e:"";return e&&(t=l(t),e.startsWith("/")||(t="/"+t)),t};let f,h=a;if(0!==a.indexOf(u)){let e=l(r);0!==(null==r?void 0:r.indexOf(u))&&(c=!0,e=`${u}://t.c`+d(r)),h=e+d(a)}i=new URL(h);const p=[];s&&Object.keys(s).forEach((e=>{const t=s[e];(Array.isArray(t)?t:[t]).forEach((t=>{p.push([e,null!=t?t:""])}))})),f=new URLSearchParams([...Array.from(i.searchParams.entries()),...p]);let b=(c?"":i.origin)+i.pathname;return f.size&&(b=b+"?"+f),b},s=(...e)=>{const t=new Headers;return e.forEach((e=>{e&&e.forEach(((e,n)=>{t.set(n,e)}))})),t};exports.createSoon=function(o={}){const r={};r.baseInit=o;const a=(t,o)=>function(t,o,r){const a=null==r?void 0:r.defaultOptions,i=a?a():void 0;let c=s(null==i?void 0:i.headers,null==o?void 0:o.headers),u=Object.assign({},i,o,{headers:c});const{beforeRequest:l,afterResponse:d}=r||{};l&&l(u);let f=u.timeout;const h=[];f&&h.push(AbortSignal.timeout(f));const p=u.signal;p&&h.push(p),u.signal=AbortSignal.any(h);const b=(t,n,s)=>e(this,void 0,void 0,(function*(){d&&(yield d(t,n,s));const e=t.response;e&&n(e),s(t)}));return new Promise(((s,o)=>e(this,void 0,void 0,(function*(){let e=n(t,Object.assign(Object.assign({},u),{baseURL:null==r?void 0:r.baseURL})),a=!1;const i=u.body;i&&(i instanceof Blob||i instanceof ArrayBuffer||i instanceof FormData||"string"==typeof i||(a=!0,u.body=JSON.stringify(i))),a&&u.headers.set("Content-Type","application/json");const c=new Request(e,u);let l={request:c,options:u};try{const e=yield fetch(c);l.response=e,b(l,s,o)}catch(e){"TimeoutError"===(null==e?void 0:e.name)&&(l.isTimeout=!0),b(Object.assign(Object.assign({},l),{error:e}),s,o)}}))))}(t,o,r.baseInit),i=["get","post","put","delete","patch"];return[...i,"head","options"].forEach((e=>{r[e]=(t,n)=>a(t,Object.assign({method:e},n))})),r.request=a,r.API=(e,n)=>{const s={},o=!!t(e).length;return i.forEach((t=>{const r=t.toUpperCase();s[r]=()=>(...s)=>{let[r,i]=s;const c="get"===t?"query":"body";return a(e,Object.assign(Object.assign({method:t},n),{params:o?r:void 0,[c]:o?i:r}))}})),s},r};
1
+ "use strict";const t=t=>{const e=[],s=t.match(/\:([^:\/\d]+)\/?/g);return s&&s.forEach((t=>{e.push(t.replace(/\//g,"").replace(/:/g,""))})),e},e=(t="")=>t.startsWith("http"),s=(t="")=>e(t)?t:((t="")=>{let e=t;return t&&(e=((t="")=>t.endsWith("/")?t.slice(0,-1):t)(e),t.startsWith("/")||(e="/"+e)),e})(t),r=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((s=>{const r=t[s];(Array.isArray(r)?r:[r]).forEach((t=>{e.push([s,null!=t?t:""])}))})),e},n=(n,a)=>{const{query:o,params:c,baseURL:i}=a;let h=n.trim();t(n).forEach((t=>{c&&(h=h.replace(":"+t,""+c[t]))}));const[u,p]=h.split("?");let f=new URLSearchParams([...r(p),...r(o)]),l=((t,r)=>{let n=s(t);return e(n)||(n=s(r)+n),n})(u,i);return f.size&&(l=l+"?"+f),l},a=(...t)=>{const e=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,s)=>{e.set(s,t)}))})),e};function o(t,e,s){const{baseURL:r,fetching:o}=s||{};let c;s&&(c=s.baseOptions?s.baseOptions:s.options);const i={url:t,options:e,baseURL:r,baseOptions:c},[h,u]=function(t){const{url:e,options:s,baseURL:r,baseOptions:o}=t,c=o?o():{},{headers:i}=c,h=s||{},{headers:u}=h;let p=a(i,u),f=Object.assign({},c,s,{headers:p}),l=f.timeout;const b=[];l&&b.push(AbortSignal.timeout(l));const g=f.signal;g&&b.push(g),f.signal=AbortSignal.any(b);let y=n(e,Object.assign({},f,{baseURL:r})),d=!1;const m=f.body;return m&&(m instanceof Blob||m instanceof ArrayBuffer||m instanceof FormData||"string"==typeof m||(d=!0,f.body=JSON.stringify(m))),d&&f.headers.set("Content-Type","application/json"),[y,f]}(i);return o?o(h,u,i):fetch(h,u)}exports.createSoon=function(e={}){const s={};s.baseInit=e;const r=(t,e)=>o(t,e,s.baseInit),n=["get","post","put","delete","patch"];return[...n,"head","options"].forEach((t=>{s[t]=(e,s)=>r(e,Object.assign({},s,{method:t}))})),s.request=r,s.API=(e,s)=>{const a={},o=!!t(e).length;return n.forEach((t=>{const n=t.toUpperCase();a[n]=()=>(...n)=>{let[a,c]=n;const i="get"===t?"query":"body";return r(e,Object.assign({},s,{method:t,params:o?a:void 0,[i]:o?c:a}))}})),a},s};
package/dist/index.d.ts CHANGED
@@ -1,34 +1,22 @@
1
- type SoonOptions = {
2
- query?: Record<string, string | number | boolean | string[] | number[] | null | undefined> | URLSearchParams;
1
+ type SoonOptions = RequestInit & {
2
+ query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
3
3
  params?: Record<string, string | number>;
4
4
  timeout?: number;
5
- signal?: AbortSignal;
6
- method?: "get" | "GET" | "delete" | "DELETE" | "head" | "HEAD" | "options" | "OPTIONS" | "post" | "POST" | "put" | "PUT" | "patch" | "PATCH" | "purge" | "PURGE" | "link" | "LINK" | "unlink" | "UNLINK";
7
- mode?: "cors" | "no-cors" | "same-origin";
8
- cache?: "default" | "no-cache" | "reload" | "force-cache" | "only-if-cached";
9
- credentials?: "include" | "same-origin" | "omit";
10
- headers?: Headers;
11
- redirect?: "manual" | "follow" | "error";
12
- referrerPolicy?: "no-referrer" | "no-referrer-when-downgrade" | "origin" | "origin-when-cross-origin" | "same-origin" | "strict-origin" | "strict-origin-when-cross-origin" | "unsafe-url";
13
- body?: any;
14
- integrity?: string;
15
- };
16
- type SoonResult<Options> = {
17
- isTimeout?: boolean;
18
- request: Request;
19
- error?: any;
20
- response?: Response;
21
- options: Options;
22
5
  };
23
6
  type SoonInit<Options> = {
24
7
  baseURL?: string;
25
- defaultOptions?: () => Options;
26
- beforeRequest?: (options: Options & {
8
+ options?: () => Options;
9
+ baseOptions?: () => Options;
10
+ fetching?: (url: string, options: Options & {
27
11
  headers: Headers;
28
- }) => void;
29
- afterResponse?: (result: SoonResult<Options>, resolve: (value: any) => void, reject: (reason?: any) => void) => Promise<void>;
12
+ }, raw: {
13
+ url: string;
14
+ baseURL?: string;
15
+ options?: Options;
16
+ baseOptions?: () => Options;
17
+ }) => Promise<any>;
30
18
  };
31
- declare function createSoon<Options extends SoonOptions = SoonOptions>(soonInit?: SoonInit<Options>): {
19
+ declare function createSoon<Options extends SoonOptions = SoonOptions>(soonInit?: NoInfer<SoonInit<Options>>): {
32
20
  request: <T = any>(url: string, options?: Options) => Promise<T>;
33
21
  get: <T = any>(url: string, options?: Options) => Promise<T>;
34
22
  post: <T = any>(url: string, options?: Options) => Promise<T>;
@@ -50,4 +38,4 @@ type OptionParams<Args> = Args extends undefined ? [] : keyof Args extends never
50
38
  type OptionQuery<Args> = Args extends undefined ? [] : keyof Args extends never ? [] : Partial<Args> extends Args ? [query?: Args] : NonNullable<Args> | undefined extends Args ? [query?: Args] : [query: Args];
51
39
  type OptionBody<Args> = Args extends undefined ? [] : keyof Args extends never ? [] : Partial<Args> extends Args ? [body?: Args] : NonNullable<Args> | undefined extends Args ? [body?: Args] : [body: Args];
52
40
 
53
- export { SoonInit, SoonOptions, SoonResult, createSoon };
41
+ export { type SoonInit, type SoonOptions, createSoon };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- function e(e,t,n,s){return new(n||(n=Promise))((function(o,r){function a(e){try{c(s.next(e))}catch(e){r(e)}}function i(e){try{c(s.throw(e))}catch(e){r(e)}}function c(e){var t;e.done?o(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,i)}c((s=s.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;const t=e=>{var t;const n=[];return null===(t=e.match(/\:([^:\/\d]+)\/?/g))||void 0===t||t.forEach((e=>{n.push(e.replace(/\//g,"").replace(/:/g,""))})),n},n=(e,n)=>{const{query:s,params:o,baseURL:r}=n;let a=e.trim();let i,c;t(e).forEach((e=>{o&&(a=a.replace(":"+e,""+o[e]))}));const u="http",l=e=>(null==e?void 0:e.endsWith("/"))?e.slice(0,-1):null!=e?e:"",d=e=>{let t=null!=e?e:"";return e&&(t=l(t),e.startsWith("/")||(t="/"+t)),t};let f,h=a;if(0!==a.indexOf(u)){let e=l(r);0!==(null==r?void 0:r.indexOf(u))&&(c=!0,e=`${u}://t.c`+d(r)),h=e+d(a)}i=new URL(h);const p=[];s&&Object.keys(s).forEach((e=>{const t=s[e];(Array.isArray(t)?t:[t]).forEach((t=>{p.push([e,null!=t?t:""])}))})),f=new URLSearchParams([...Array.from(i.searchParams.entries()),...p]);let b=(c?"":i.origin)+i.pathname;return f.size&&(b=b+"?"+f),b},s=(...e)=>{const t=new Headers;return e.forEach((e=>{e&&e.forEach(((e,n)=>{t.set(n,e)}))})),t};function o(o={}){const r={};r.baseInit=o;const a=(t,o)=>function(t,o,r){const a=null==r?void 0:r.defaultOptions,i=a?a():void 0;let c=s(null==i?void 0:i.headers,null==o?void 0:o.headers),u=Object.assign({},i,o,{headers:c});const{beforeRequest:l,afterResponse:d}=r||{};l&&l(u);let f=u.timeout;const h=[];f&&h.push(AbortSignal.timeout(f));const p=u.signal;p&&h.push(p),u.signal=AbortSignal.any(h);const b=(t,n,s)=>e(this,void 0,void 0,(function*(){d&&(yield d(t,n,s));const e=t.response;e&&n(e),s(t)}));return new Promise(((s,o)=>e(this,void 0,void 0,(function*(){let e=n(t,Object.assign(Object.assign({},u),{baseURL:null==r?void 0:r.baseURL})),a=!1;const i=u.body;i&&(i instanceof Blob||i instanceof ArrayBuffer||i instanceof FormData||"string"==typeof i||(a=!0,u.body=JSON.stringify(i))),a&&u.headers.set("Content-Type","application/json");const c=new Request(e,u);let l={request:c,options:u};try{const e=yield fetch(c);l.response=e,b(l,s,o)}catch(e){"TimeoutError"===(null==e?void 0:e.name)&&(l.isTimeout=!0),b(Object.assign(Object.assign({},l),{error:e}),s,o)}}))))}(t,o,r.baseInit),i=["get","post","put","delete","patch"];return[...i,"head","options"].forEach((e=>{r[e]=(t,n)=>a(t,Object.assign({method:e},n))})),r.request=a,r.API=(e,n)=>{const s={},o=!!t(e).length;return i.forEach((t=>{const r=t.toUpperCase();s[r]=()=>(...s)=>{let[r,i]=s;const c="get"===t?"query":"body";return a(e,Object.assign(Object.assign({method:t},n),{params:o?r:void 0,[c]:o?i:r}))}})),s},r}export{o as createSoon};
1
+ const t=t=>{const e=[],s=t.match(/\:([^:\/\d]+)\/?/g);return s&&s.forEach((t=>{e.push(t.replace(/\//g,"").replace(/:/g,""))})),e},e=(t="")=>t.startsWith("http"),s=(t="")=>e(t)?t:((t="")=>{let e=t;return t&&(e=((t="")=>t.endsWith("/")?t.slice(0,-1):t)(e),t.startsWith("/")||(e="/"+e)),e})(t),r=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((s=>{const r=t[s];(Array.isArray(r)?r:[r]).forEach((t=>{e.push([s,null!=t?t:""])}))})),e},n=(n,a)=>{const{query:o,params:c,baseURL:i}=a;let h=n.trim();t(n).forEach((t=>{c&&(h=h.replace(":"+t,""+c[t]))}));const[p,u]=h.split("?");let f=new URLSearchParams([...r(u),...r(o)]),l=((t,r)=>{let n=s(t);return e(n)||(n=s(r)+n),n})(p,i);return f.size&&(l=l+"?"+f),l},a=(...t)=>{const e=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,s)=>{e.set(s,t)}))})),e};function o(t,e,s){const{baseURL:r,fetching:o}=s||{};let c;s&&(c=s.baseOptions?s.baseOptions:s.options);const i={url:t,options:e,baseURL:r,baseOptions:c},[h,p]=function(t){const{url:e,options:s,baseURL:r,baseOptions:o}=t,c=o?o():{},{headers:i}=c,h=s||{},{headers:p}=h;let u=a(i,p),f=Object.assign({},c,s,{headers:u}),l=f.timeout;const b=[];l&&b.push(AbortSignal.timeout(l));const g=f.signal;g&&b.push(g),f.signal=AbortSignal.any(b);let y=n(e,Object.assign({},f,{baseURL:r})),d=!1;const m=f.body;return m&&(m instanceof Blob||m instanceof ArrayBuffer||m instanceof FormData||"string"==typeof m||(d=!0,f.body=JSON.stringify(m))),d&&f.headers.set("Content-Type","application/json"),[y,f]}(i);return o?o(h,p,i):fetch(h,p)}function c(e={}){const s={};s.baseInit=e;const r=(t,e)=>o(t,e,s.baseInit),n=["get","post","put","delete","patch"];return[...n,"head","options"].forEach((t=>{s[t]=(e,s)=>r(e,Object.assign({},s,{method:t}))})),s.request=r,s.API=(e,s)=>{const a={},o=!!t(e).length;return n.forEach((t=>{const n=t.toUpperCase();a[n]=()=>(...n)=>{let[a,c]=n;const i="get"===t?"query":"body";return r(e,Object.assign({},s,{method:t,params:o?a:void 0,[i]:o?c:a}))}})),a},s}export{c as createSoon};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "soon-fetch",
3
- "version": "0.0.2",
4
- "description": "a lightweight request library based on fetch with TS prompt",
3
+ "version": "1.1.0",
4
+ "description": "a 3Kb request lib alternative to axios",
5
5
  "homepage": "https://github.com/leafio/soon-fetch",
6
6
  "main": "./dist/index.cjs.js",
7
7
  "module": "/dist/index.js",
@@ -25,17 +25,17 @@
25
25
  "author": "",
26
26
  "license": "MIT",
27
27
  "devDependencies": {
28
- "@babel/core": "^7.22.9",
29
- "@babel/preset-env": "^7.22.9",
28
+ "@babel/core": "^7.25.2",
29
+ "@babel/preset-env": "^7.25.4",
30
30
  "@rollup/plugin-babel": "^6.0.3",
31
31
  "@rollup/plugin-node-resolve": "^15.1.0",
32
32
  "@rollup/plugin-terser": "^0.4.3",
33
- "rollup": "^3.26.3",
33
+ "rollup": "^4.22.0",
34
34
  "rollup-plugin-commonjs": "^10.1.0",
35
- "rollup-plugin-dts": "^5.3.0",
35
+ "rollup-plugin-dts": "^6.1.1",
36
36
  "rollup-plugin-typescript": "^1.0.1",
37
- "tslib": "^2.6.0",
38
- "typescript": "^5.1.6"
37
+ "tslib": "^2.7.0",
38
+ "typescript": "^5.6.2"
39
39
  },
40
40
  "dependencies": {}
41
- }
41
+ }