soon-fetch 0.0.2 → 1.0.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,14 +1,16 @@
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
9
11
  > - ⌛ timeout disconnect
10
12
  > - 🔤 automatic parse or serialization of JSON
11
- > - 📏 .min size less than **3K**, smaller after zip
13
+ > - 📏 .min size less than **2K**, smaller after zip
12
14
  > - 💡 smart type tips with Typescript
13
15
 
14
16
  - [Example](#example)
@@ -26,58 +28,30 @@
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>({
33
- baseURL: "/api",
34
- defaultOptions: () => ({
35
+ export const soon = createSoon({
36
+ baseURL: "/",
37
+ options: () => ({
35
38
  timeout: 20 * 1000,
36
39
  headers: new Headers({
37
40
  Authorization: localStorage.getItem("token") ?? "",
38
41
  }),
39
42
  }),
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);
43
+ fetching(url, options) {
44
+ return fetch(url, options).then((res) => res.json());
68
45
  },
69
46
  });
70
47
 
71
48
  /** 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));
49
+ soon.get("/user?id=123");
50
+ soon.get("/user", { query: { id: 123 } });
51
+ soon.get("/user/:id", { params: { id: 123 } });
52
+
77
53
  /** POST */
78
- soon
79
- .post("/login", { body: { username: "admin", password: "123456" } })
80
- .then((data) => console.log(data));
54
+ soon.post("/login", { body: { username: "admin", password: "123456" } });
81
55
 
82
56
  /**Define API */
83
57
  export const login = soon
@@ -131,9 +105,8 @@ soon.get(url, { timeout: 1000 * 20 });
131
105
  //define an api
132
106
  export const getUserInfo=soon.API('/user/:id').GET()
133
107
  //then use in any where
134
- getUserInfo({id:2})
135
- .then(res=>console.log(res))
136
- .catch(err=>console.log(err))
108
+ getUserInfo({id:2}).then(res=>console.log(res))
109
+
137
110
 
138
111
  //with typescript,
139
112
  export const login=soon.API('/user/login')
@@ -155,20 +128,17 @@ declare function createSoon<Options extends SoonOptions = SoonOptions>(
155
128
  soonInit?: SoonInit<Options>
156
129
  );
157
130
 
158
- // options would overwrite by order : defaultOptions ,request(url,options),beforeRequest(options)
131
+ // options would overwritten by request level options ,but the headers will be merged
159
132
  export type SoonInit<Options> = {
160
133
  //**url prefix */
161
134
  baseURL?: string;
162
135
  /**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>;
136
+ options?: () => Options;
137
+ /** can use return a new fetch request instead*/
138
+ fetching?: (
139
+ url: string,
140
+ options: Options & { headers: Headers }
141
+ ) => Promise<any>;
172
142
  };
173
143
  ```
174
144
 
@@ -238,26 +208,29 @@ type SoonOptions = {
238
208
 
239
209
  ##### Response
240
210
 
241
- Default : return raw fetch Response , you can customize it in afterResponse params of createSoon
211
+ Default : return raw fetch Response , you can customize it in `fetching` params of `createSoon`
242
212
 
243
213
  ### Support Me
244
214
 
245
- If you like this library , you can give a **start** on github.
246
- Email: leafnote@outlook.com
215
+ If you like this library , you can give a **star** on github.
216
+ GitHub: https://github.com/leafio/soon-fetch
247
217
 
248
- > I'm looking for a frontend job in Shanghai , hope someone could find a offer for me.
218
+ > I'm looking for a frontend job in Shanghai , hope someone could find a offer for me.
219
+ Email: leafnote@outlook.com
249
220
 
250
- [English](#soon-fetch-is-a-lightweight-http-request-library-based-on-vanilla-fetch-with-typescript) | [中文](#soon-fetch-是用-ts-对原生-fetch-的轻量封装) | [Installation](#安装-installation)
221
+ [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
251
222
 
252
223
  <!-- omit in toc -->
253
224
 
254
- ##### soon-fetch 是用 ts 对原生 fetch 的轻量封装
225
+ #### soon-fetch
226
+
227
+ **极轻量的请求库,不到 2K**
255
228
 
256
229
  > - 🌐 自动解析 rest Url 的参数
257
230
  > - ⭐ 快捷定义请求 api
258
231
  > - ⌛ 超时断开
259
232
  > - 🔤 自动处理 JSON
260
- > - 📏 不到 **3K** , zip 后会更小
233
+ > - 📏 不到 **2K** , zip 后会更小
261
234
  > - 💡 用 typescript 有智能类型提醒
262
235
 
263
236
  - [示例](#示例)
@@ -277,58 +250,30 @@ Email: leafnote@outlook.com
277
250
 
278
251
  ### 示例
279
252
 
280
- > [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
253
+ > [github: soon-admin-vue3 ](https://github.com/leafio/soon-admin-vue3)
254
+ > [github: soon-admin-react-nextjs ](https://github.com/leafio/soon-admin-react-nextjs)
281
255
 
282
256
  ```typescript
283
257
  export const soon = createSoon<SoonOptions>({
284
- baseURL: "/api",
285
- defaultOptions: () => ({
258
+ baseURL: "/",
259
+ options: () => ({
286
260
  timeout: 20 * 1000,
287
261
  headers: new Headers({
288
262
  Authorization: localStorage.getItem("token") ?? "",
289
263
  }),
290
264
  }),
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);
265
+ fetching(url, options) {
266
+ return fetch(url, options).then((res) => res.json());
319
267
  },
320
268
  });
321
269
 
322
270
  /** 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));
271
+ soon.get("/user?id=123");
272
+ soon.get("/user", { query: { id: 123 } });
273
+ soon.get("/user/:id", { params: { id: 123 } });
274
+
328
275
  /** POST */
329
- soon
330
- .post("/login", { body: { username: "admin", password: "123456" } })
331
- .then((data) => console.log(data));
276
+ soon.post("/login", { body: { username: "admin", password: "123456" } });
332
277
 
333
278
  /**定义 API */
334
279
  export const login = soon
@@ -382,9 +327,7 @@ soon.get(url, { timeout: 1000 * 20 });
382
327
  //定义一个api
383
328
  export const getUserInfo=soon.API('/user/:id').GET()
384
329
  //使用
385
- getUserInfo({id:2})
386
- .then(res=>console.log(res))
387
- .catch(err=>console.log(err))
330
+ getUserInfo({id:2}).then(res=>console.log(res))
388
331
 
389
332
  //用typescript,
390
333
  export const login=soon.API('/user/login')
@@ -406,29 +349,16 @@ declare function createSoon<Options extends SoonOptions = SoonOptions>(
406
349
  soonInit?: SoonInit<Options>
407
350
  );
408
351
 
409
- // options 依次被覆盖 defaultOptions ,request(url,options),beforeRequest(options)
352
+ // 实例级options会被请求级options覆盖,但headers仅同key的被覆盖,其他合并
410
353
  export type SoonInit<Options> = {
411
354
  baseURL?: string;
412
355
  //默认的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
356
+ options?: () => Options;
357
+ //可返回自定义的fetch请求
358
+ fetching?: (
359
+ url: string,
360
+ options: Options & { headers: Headers }
361
+ ) => Promise<any>;
432
362
  };
433
363
  ```
434
364
 
@@ -499,16 +429,17 @@ type SoonOptions = {
499
429
 
500
430
  ##### 响应
501
431
 
502
- 默认为原生 fetch 的 Response ,可在 createSoon 的 afterResponse 里自定义处理 Response
432
+ 默认为原生 fetch 的 Response ,可在 `createSoon``fetching` 里自定义返回结果
503
433
 
504
434
  ### 支持一下
505
435
 
506
436
  喜欢 soon-fetch 的话 , 在 github 上给个 **star** 吧.
507
- Email: leafnote@outlook.com
437
+ GitHub: https://github.com/leafio/soon-fetch
508
438
 
509
439
  > 我目前在找前端的工作,位置上海。有岗位机会的话,可以联系我。
440
+ > Email: leafnote@outlook.com
510
441
 
511
- [English](#soon-fetch-is-a-lightweight-http-request-library-based-on-vanilla-fetch-with-typescript) | [中文](#soon-fetch-是用-ts-对原生-fetch-的轻量封装)
442
+ [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
512
443
 
513
444
  <!-- omit in toc -->
514
445
 
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=>{var e;const s=[];return null===(e=t.match(/\:([^:\/\d]+)\/?/g))||void 0===e||e.forEach((t=>{s.push(t.replace(/\//g,"").replace(/:/g,""))})),s},e=(e,s)=>{const{query:n,params:r,baseURL:a}=s;let o=e.trim();t(e).forEach((t=>{r&&(o=o.replace(":"+t,""+r[t]))}));const c="http",i=t=>(null==t?void 0:t.endsWith("/"))?t.slice(0,-1):null!=t?t:"",h=t=>{let e=null!=t?t:"";return t&&(e=i(e),t.startsWith("/")||(e="/"+e)),e},[l,u]=o.split("?"),p=new URLSearchParams(u);let f;const d=[];n&&Object.keys(n).forEach((t=>{const e=n[t];(Array.isArray(e)?e:[e]).forEach((e=>{d.push([t,null!=e?e:""])}))})),f=new URLSearchParams([...Array.from(p.entries()),...d]);let g=l;return o.startsWith(c)||(g=i(a)+h(l),g.startsWith(c)||(g=h(g))),f.size&&(g=g+"?"+f),g},s=(...t)=>{const e=new Headers;return t.forEach((t=>{t&&t.forEach(((t,s)=>{e.set(s,t)}))})),e};exports.createSoon=function(n={}){const r={};r.baseInit=n;const a=(t,n)=>function(t,n,r){const{options:a,fetching:o,baseURL:c}=r||{},i=a?a():{},{headers:h}=i,{headers:l}=n||{};let u=s(h,l),p=Object.assign({},i,n,{headers:u}),f=p.timeout;const d=[];f&&d.push(AbortSignal.timeout(f));const g=p.signal;g&&d.push(g),p.signal=AbortSignal.any(d);let b=e(t,Object.assign({},p,{baseURL:c})),y=!1;const m=p.body;return m&&(m instanceof Blob||m instanceof ArrayBuffer||m instanceof FormData||"string"==typeof m||(y=!0,p.body=JSON.stringify(m))),y&&p.headers.set("Content-Type","application/json"),o?o(b,p):fetch(b,p)}(t,n,r.baseInit),o=["get","post","put","delete","patch"];return[...o,"head","options"].forEach((t=>{r[t]=(e,s)=>a(e,Object.assign({},s,{method:t}))})),r.request=a,r.API=(e,s)=>{const n={},r=!!t(e).length;return o.forEach((t=>{const o=t.toUpperCase();n[o]=()=>(...n)=>{let[o,c]=n;const i="get"===t?"query":"body";return a(e,Object.assign({},s,{method:t,params:r?o:void 0,[i]:r?c:o}))}})),n},r};
package/dist/index.d.ts CHANGED
@@ -1,53 +1,45 @@
1
- type SoonOptions = {
2
- query?: Record<string, string | number | boolean | string[] | number[] | null | undefined> | URLSearchParams;
3
- params?: Record<string, string | number>;
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
- };
23
- type SoonInit<Options> = {
24
- baseURL?: string;
25
- defaultOptions?: () => Options;
26
- beforeRequest?: (options: Options & {
27
- headers: Headers;
28
- }) => void;
29
- afterResponse?: (result: SoonResult<Options>, resolve: (value: any) => void, reject: (reason?: any) => void) => Promise<void>;
30
- };
31
- declare function createSoon<Options extends SoonOptions = SoonOptions>(soonInit?: SoonInit<Options>): {
32
- request: <T = any>(url: string, options?: Options) => Promise<T>;
33
- get: <T = any>(url: string, options?: Options) => Promise<T>;
34
- post: <T = any>(url: string, options?: Options) => Promise<T>;
35
- put: <T = any>(url: string, options?: Options) => Promise<T>;
36
- patch: <T = any>(url: string, options?: Options) => Promise<T>;
37
- delete: <T = any>(url: string, options?: Options) => Promise<T>;
38
- head: <T = any>(url: string, options?: Options) => Promise<T>;
39
- options: <T = any>(url: string, options?: Options) => Promise<T>;
40
- API: <Url extends string>(url: Url, options?: Options) => {
41
- GET: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionQuery<Req>]) => Promise<Res>;
42
- POST: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
43
- PATCH: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
44
- DELETE: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
45
- PUT: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
46
- };
47
- };
48
- type GetUrlKey<Url> = Url extends `${string}/:${infer Key}/${infer Right}` ? `${Key}` | GetUrlKey<`/${Right}`> : Url extends `${string}/:${infer Key}` ? `${Key}` : never;
49
- type OptionParams<Args> = Args extends undefined ? [] : keyof Args extends never ? [] : Partial<Args> extends Args ? [params?: Args] : NonNullable<Args> | undefined extends Args ? [params?: Args] : [params: Args];
50
- 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
- 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
-
53
- export { SoonInit, SoonOptions, SoonResult, createSoon };
1
+ type SoonOptions = {
2
+ query?: Record<string, string | number | boolean | string[] | number[] | null | undefined> | URLSearchParams;
3
+ params?: Record<string, string | number>;
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 SoonInit<Options> = {
17
+ baseURL?: string;
18
+ options?: () => Options;
19
+ fetching?: (url: string, options: Options & {
20
+ headers: Headers;
21
+ }) => Promise<any>;
22
+ };
23
+ declare function createSoon<Options extends SoonOptions = SoonOptions>(soonInit?: SoonInit<Options>): {
24
+ request: <T = any>(url: string, options?: Options) => Promise<T>;
25
+ get: <T = any>(url: string, options?: Options) => Promise<T>;
26
+ post: <T = any>(url: string, options?: Options) => Promise<T>;
27
+ put: <T = any>(url: string, options?: Options) => Promise<T>;
28
+ patch: <T = any>(url: string, options?: Options) => Promise<T>;
29
+ delete: <T = any>(url: string, options?: Options) => Promise<T>;
30
+ head: <T = any>(url: string, options?: Options) => Promise<T>;
31
+ options: <T = any>(url: string, options?: Options) => Promise<T>;
32
+ API: <Url extends string>(url: Url, options?: Options) => {
33
+ GET: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionQuery<Req>]) => Promise<Res>;
34
+ POST: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
35
+ PATCH: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
36
+ DELETE: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
37
+ PUT: <Req = undefined, Res = any>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>;
38
+ };
39
+ };
40
+ type GetUrlKey<Url> = Url extends `${string}/:${infer Key}/${infer Right}` ? `${Key}` | GetUrlKey<`/${Right}`> : Url extends `${string}/:${infer Key}` ? `${Key}` : never;
41
+ type OptionParams<Args> = Args extends undefined ? [] : keyof Args extends never ? [] : Partial<Args> extends Args ? [params?: Args] : NonNullable<Args> | undefined extends Args ? [params?: Args] : [params: Args];
42
+ 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];
43
+ 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];
44
+
45
+ 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=>{var e;const s=[];return null===(e=t.match(/\:([^:\/\d]+)\/?/g))||void 0===e||e.forEach((t=>{s.push(t.replace(/\//g,"").replace(/:/g,""))})),s},e=(e,s)=>{const{query:n,params:r,baseURL:a}=s;let o=e.trim();t(e).forEach((t=>{r&&(o=o.replace(":"+t,""+r[t]))}));const c="http",i=t=>(null==t?void 0:t.endsWith("/"))?t.slice(0,-1):null!=t?t:"",h=t=>{let e=null!=t?t:"";return t&&(e=i(e),t.startsWith("/")||(e="/"+e)),e},[l,u]=o.split("?"),p=new URLSearchParams(u);let f;const d=[];n&&Object.keys(n).forEach((t=>{const e=n[t];(Array.isArray(e)?e:[e]).forEach((e=>{d.push([t,null!=e?e:""])}))})),f=new URLSearchParams([...Array.from(p.entries()),...d]);let g=l;return o.startsWith(c)||(g=i(a)+h(l),g.startsWith(c)||(g=h(g))),f.size&&(g=g+"?"+f),g},s=(...t)=>{const e=new Headers;return t.forEach((t=>{t&&t.forEach(((t,s)=>{e.set(s,t)}))})),e};function n(n={}){const r={};r.baseInit=n;const a=(t,n)=>function(t,n,r){const{options:a,fetching:o,baseURL:c}=r||{},i=a?a():{},{headers:h}=i,{headers:l}=n||{};let u=s(h,l),p=Object.assign({},i,n,{headers:u}),f=p.timeout;const d=[];f&&d.push(AbortSignal.timeout(f));const g=p.signal;g&&d.push(g),p.signal=AbortSignal.any(d);let b=e(t,Object.assign({},p,{baseURL:c})),y=!1;const m=p.body;return m&&(m instanceof Blob||m instanceof ArrayBuffer||m instanceof FormData||"string"==typeof m||(y=!0,p.body=JSON.stringify(m))),y&&p.headers.set("Content-Type","application/json"),o?o(b,p):fetch(b,p)}(t,n,r.baseInit),o=["get","post","put","delete","patch"];return[...o,"head","options"].forEach((t=>{r[t]=(e,s)=>a(e,Object.assign({},s,{method:t}))})),r.request=a,r.API=(e,s)=>{const n={},r=!!t(e).length;return o.forEach((t=>{const o=t.toUpperCase();n[o]=()=>(...n)=>{let[o,c]=n;const i="get"===t?"query":"body";return a(e,Object.assign({},s,{method:t,params:r?o:void 0,[i]:r?c:o}))}})),n},r}export{n 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.0.0",
4
+ "description": "a 2Kb 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
+ }