@koine/api 2.0.0-beta.132 → 2.0.0-beta.134

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/ApiError.cjs.js CHANGED
@@ -2,13 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- /**
6
- * Custom `ApiError` class extending `Error` to throw in failed response.
7
- *
8
- * @see https://eslint.org/docs/rules/no-throw-literal
9
- * @see https://github.com/sindresorhus/ky/blob/main/source/errors/HTTPError.ts
10
- *
11
- */class ApiError extends Error{constructor(r){super(`Request failed with ${r.status} ${r.msg}`),this.name="ApiError",Object.assign(this,r);}}
5
+ class ApiError extends Error{constructor(r){super(`Request failed with ${r.status} ${r.msg}`),this.name="ApiError",Object.assign(this,r);}}
12
6
 
13
7
  exports.ApiError = ApiError;
14
8
  exports.default = ApiError;
package/ApiError.d.ts CHANGED
@@ -1,4 +1,11 @@
1
1
  import type { Api } from "./types";
2
+ /**
3
+ * Custom `ApiError` class extending `Error` to throw in failed response.
4
+ *
5
+ * @see https://eslint.org/docs/rules/no-throw-literal
6
+ * @see https://github.com/sindresorhus/ky/blob/main/source/errors/HTTPError.ts
7
+ *
8
+ */
2
9
  export declare class ApiError<TResponseFail extends Api.ResponseFail = unknown> extends Error {
3
10
  constructor(result: Api.ResultFail<TResponseFail>);
4
11
  }
package/ApiError.esm.js CHANGED
@@ -1,9 +1,3 @@
1
- /**
2
- * Custom `ApiError` class extending `Error` to throw in failed response.
3
- *
4
- * @see https://eslint.org/docs/rules/no-throw-literal
5
- * @see https://github.com/sindresorhus/ky/blob/main/source/errors/HTTPError.ts
6
- *
7
- */class ApiError extends Error{constructor(r){super(`Request failed with ${r.status} ${r.msg}`),this.name="ApiError",Object.assign(this,r);}}
1
+ class ApiError extends Error{constructor(r){super(`Request failed with ${r.status} ${r.msg}`),this.name="ApiError",Object.assign(this,r);}}
8
2
 
9
3
  export { ApiError, ApiError as default };
package/createApi.cjs.js CHANGED
@@ -4,24 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var utils = require('@koine/utils');
6
6
 
7
- let o=["get","post","put","patch","delete"];/**
8
- * Create api client
9
- *
10
- * @param apiName Short name to use in debug logs
11
- * @param baseUrl Either relativ eor absolute, it must end without trailing slash
12
- */let createApi=(l,a,i)=>{let{headers:s={},request:n={},throwErr:p,timeout:c=1e4,processReq:u,processRes:f,processErr:d}=i||{};return o.reduce((o,i)=>(// @ts-expect-error FIXME: type
13
- o[i]=async(o,h)=>{let $,m;let{request:w=n,headers:y=s,timeout:b=c,processReq:g,processRes:E=f,processErr:N=d,throwErr:k=p}=h||{},{params:A,json:C,query:j}=h||{},q=`${a}/${o+"".replace(/^\/*/,"")}`,v={method:i.toUpperCase(),...w,headers:{"content-type":"application/json",...y}};if(u){let e=u(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(g){let e=g(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(utils.isFullObject(A))for(let e in A)// TODO: not the greatest assertion...
14
- q=q.replace(`{${e}}`,A[e]);let x=Number(b);C&&(v.body=JSON.stringify(C)),x>0&&(// TODO: combine multiple abort signals
15
- // @see https://dev.to/rashidshamloo/adding-timeout-and-multiple-abort-signals-to-fetch-typescriptreact-33bb
16
- $=new AbortController,m=setTimeout(()=>$.abort(),x),v.signal=$.signal),j&&// FIXME: ts-expect-error this assertion is not the best, but nevermind for now
17
- (q+=utils.buildUrlQueryString(j));let O=null,R=null,T="";try{O=await fetch(q,v);}catch(e){T=utils.errorToString(e);}if(m&&clearTimeout(m),O)try{R=E?await E(O,h||{}):await O.json();}catch(e){T=utils.errorToString(e);}if(null===R&&(R=N?await N(T,h||{}):// this error should only happen on network errors or wrong API urls
18
- // there is no specific HTTP error for this, we can consider these
19
- // two statuses though:
20
- // - [100 Continue](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/100)
21
- // - [501 Not Implemented](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501)
22
- {data:null,msg:T,status:100,fail:!0,ok:!1}),k&&R?.fail)// throw new ApiError<Failed>(result);
23
- // I prefer to throw an object literal despite what eslint says
24
- throw R;if("development"===process.env.NODE_ENV){let e=`${R?.status}: api[${l}] ${i.toUpperCase()} ${q}`;R?.ok?console.info(`🟢 ${e}`):console.info(`🔴 ${e}`);}return R},o),{})};
7
+ let o=["get","post","put","patch","delete"];let createApi=(l,a,i)=>{let{headers:s={},request:n={},throwErr:p,timeout:c=1e4,processReq:u,processRes:f,processErr:d}=i||{};return o.reduce((o,i)=>(o[i]=async(o,h)=>{let $,m;let{request:w=n,headers:y=s,timeout:b=c,processReq:g,processRes:E=f,processErr:N=d,throwErr:k=p}=h||{},{params:A,json:C,query:j}=h||{},q=`${a}/${o+"".replace(/^\/*/,"")}`,v={method:i.toUpperCase(),...w,headers:{"content-type":"application/json",...y}};if(u){let e=u(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(g){let e=g(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(utils.isFullObject(A))for(let e in A)q=q.replace(`{${e}}`,A[e]);let x=Number(b);C&&(v.body=JSON.stringify(C)),x>0&&($=new AbortController,m=setTimeout(()=>$.abort(),x),v.signal=$.signal),j&&(q+=utils.buildUrlQueryString(j));let O=null,R=null,T="";try{O=await fetch(q,v);}catch(e){T=utils.errorToString(e);}if(m&&clearTimeout(m),O)try{R=E?await E(O,h||{}):await O.json();}catch(e){T=utils.errorToString(e);}if(null===R&&(R=N?await N(T,h||{}):{data:null,msg:T,status:100,fail:!0,ok:!1}),k&&R?.fail)throw R;if("development"===process.env.NODE_ENV){let e=`${R?.status}: api[${l}] ${i.toUpperCase()} ${q}`;R?.ok?console.info(`🟢 ${e}`):console.info(`🔴 ${e}`);}return R},o),{})};
25
8
 
26
9
  exports.createApi = createApi;
27
10
  exports.default = createApi;
package/createApi.d.ts CHANGED
@@ -1,3 +1,9 @@
1
1
  import type { Api } from "./types";
2
+ /**
3
+ * Create api client
4
+ *
5
+ * @param apiName Short name to use in debug logs
6
+ * @param baseUrl Either relativ eor absolute, it must end without trailing slash
7
+ */
2
8
  export declare let createApi: <TEndpoints extends Api.Endpoints>(apiName: string, baseUrl: string, options?: Api.ClientOptions) => Api.Client<TEndpoints>;
3
9
  export default createApi;
package/createApi.esm.js CHANGED
@@ -1,22 +1,5 @@
1
1
  import { isFullObject, buildUrlQueryString, errorToString } from '@koine/utils';
2
2
 
3
- let o=["get","post","put","patch","delete"];/**
4
- * Create api client
5
- *
6
- * @param apiName Short name to use in debug logs
7
- * @param baseUrl Either relativ eor absolute, it must end without trailing slash
8
- */let createApi=(l,a,i)=>{let{headers:s={},request:n={},throwErr:p,timeout:c=1e4,processReq:u,processRes:f,processErr:d}=i||{};return o.reduce((o,i)=>(// @ts-expect-error FIXME: type
9
- o[i]=async(o,h)=>{let $,m;let{request:w=n,headers:y=s,timeout:b=c,processReq:g,processRes:E=f,processErr:N=d,throwErr:k=p}=h||{},{params:A,json:C,query:j}=h||{},q=`${a}/${o+"".replace(/^\/*/,"")}`,v={method:i.toUpperCase(),...w,headers:{"content-type":"application/json",...y}};if(u){let e=u(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(g){let e=g(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(isFullObject(A))for(let e in A)// TODO: not the greatest assertion...
10
- q=q.replace(`{${e}}`,A[e]);let x=Number(b);C&&(v.body=JSON.stringify(C)),x>0&&(// TODO: combine multiple abort signals
11
- // @see https://dev.to/rashidshamloo/adding-timeout-and-multiple-abort-signals-to-fetch-typescriptreact-33bb
12
- $=new AbortController,m=setTimeout(()=>$.abort(),x),v.signal=$.signal),j&&// FIXME: ts-expect-error this assertion is not the best, but nevermind for now
13
- (q+=buildUrlQueryString(j));let O=null,R=null,T="";try{O=await fetch(q,v);}catch(e){T=errorToString(e);}if(m&&clearTimeout(m),O)try{R=E?await E(O,h||{}):await O.json();}catch(e){T=errorToString(e);}if(null===R&&(R=N?await N(T,h||{}):// this error should only happen on network errors or wrong API urls
14
- // there is no specific HTTP error for this, we can consider these
15
- // two statuses though:
16
- // - [100 Continue](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/100)
17
- // - [501 Not Implemented](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501)
18
- {data:null,msg:T,status:100,fail:!0,ok:!1}),k&&R?.fail)// throw new ApiError<Failed>(result);
19
- // I prefer to throw an object literal despite what eslint says
20
- throw R;if("development"===process.env.NODE_ENV){let e=`${R?.status}: api[${l}] ${i.toUpperCase()} ${q}`;R?.ok?console.info(`🟢 ${e}`):console.info(`🔴 ${e}`);}return R},o),{})};
3
+ let o=["get","post","put","patch","delete"];let createApi=(l,a,i)=>{let{headers:s={},request:n={},throwErr:p,timeout:c=1e4,processReq:u,processRes:f,processErr:d}=i||{};return o.reduce((o,i)=>(o[i]=async(o,h)=>{let $,m;let{request:w=n,headers:y=s,timeout:b=c,processReq:g,processRes:E=f,processErr:N=d,throwErr:k=p}=h||{},{params:A,json:C,query:j}=h||{},q=`${a}/${o+"".replace(/^\/*/,"")}`,v={method:i.toUpperCase(),...w,headers:{"content-type":"application/json",...y}};if(u){let e=u(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(g){let e=g(i,q,j,C,A,v);q=e[0],j=e[1],C=e[2],A=e[3],v=e[4];}if(isFullObject(A))for(let e in A)q=q.replace(`{${e}}`,A[e]);let x=Number(b);C&&(v.body=JSON.stringify(C)),x>0&&($=new AbortController,m=setTimeout(()=>$.abort(),x),v.signal=$.signal),j&&(q+=buildUrlQueryString(j));let O=null,R=null,T="";try{O=await fetch(q,v);}catch(e){T=errorToString(e);}if(m&&clearTimeout(m),O)try{R=E?await E(O,h||{}):await O.json();}catch(e){T=errorToString(e);}if(null===R&&(R=N?await N(T,h||{}):{data:null,msg:T,status:100,fail:!0,ok:!1}),k&&R?.fail)throw R;if("development"===process.env.NODE_ENV){let e=`${R?.status}: api[${l}] ${i.toUpperCase()} ${q}`;R?.ok?console.info(`🟢 ${e}`):console.info(`🔴 ${e}`);}return R},o),{})};
21
4
 
22
5
  export { createApi, createApi as default };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@koine/api",
3
3
  "sideEffects": false,
4
4
  "dependencies": {
5
- "@koine/utils": "2.0.0-beta.132"
5
+ "@koine/utils": "2.0.0-beta.134"
6
6
  },
7
7
  "exports": {
8
8
  "./swr/createSwrApi": {
@@ -88,5 +88,5 @@
88
88
  "module": "./index.esm.js",
89
89
  "main": "./index.cjs.js",
90
90
  "types": "./index.esm.d.ts",
91
- "version": "2.0.0-beta.132"
91
+ "version": "2.0.0-beta.134"
92
92
  }
@@ -6,42 +6,7 @@ var e = require('swr');
6
6
  var utils = require('@koine/utils');
7
7
  var createApi = require('../createApi.cjs.js');
8
8
 
9
- /**
10
- * Conditional fetching as option
11
- *
12
- * Moving this to an option allows us to keep the endpoints typed dictionary,
13
- * e.g. we can write:
14
- *
15
- * ```js
16
- * const { data, mutate } = myApi.use("User/{id}",
17
- * { params: { id: aVariableMaybeContainingAnId || "" }, },
18
- * { when: !!aVariableMaybeContainingAnId }
19
- * );
20
- *
21
- * // we still have typed `data`, `mutate`
22
- * ```
23
- * @see https://swr.vercel.app/docs/conditional-fetching
24
- *//**
25
- * @private
26
- */let createUseApi=t=>(i,o,p)=>{// const fetcher = async (_endpoint: TEndpoint) => {
27
- // try {
28
- // const { ok, data } = await api.get(_endpoint, {
29
- // ...(options || {}),
30
- // throwErr: true,
31
- // });
32
- // if (ok) {
33
- // return data;
34
- // }
35
- // throw new Error() as unknown as Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>;
36
- // } catch(e) {
37
- // throw new Error() as unknown as Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>;;
38
- // }
39
- // };
40
- // }
41
- let a=async()=>{let{data:e}=await t.get(i,{...o||{},throwErr:!0});return e};// <Data = any, Error = any>(key: Key, config: SWRConfigurationExtended<Data, Error, Fetcher<Data>> | undefined): SWRResponse<Data, Error>;
42
- return e(p?.when===!1||utils.isFunction(p?.when)&&p?.when()===!1?null:o?[i,o]:[i],a,p)};/**
43
- * It creates an api client extended with auto-generated SWR wrapper hooks
44
- */let createSwrApi=(...e)=>{let r=createApi.createApi(...e);return r.use=createUseApi(r),r};
9
+ let createUseApi=t=>(i,o,p)=>{let a=async()=>{let{data:e}=await t.get(i,{...o||{},throwErr:!0});return e};return e(p?.when===!1||utils.isFunction(p?.when)&&p?.when()===!1?null:o?[i,o]:[i],a,p)};let createSwrApi=(...e)=>{let r=createApi.createApi(...e);return r.use=createUseApi(r),r};
45
10
 
46
11
  exports.createSwrApi = createSwrApi;
47
12
  exports.createUseApi = createUseApi;
@@ -1,9 +1,31 @@
1
1
  import { type BareFetcher, type SWRConfiguration, type SWRResponse } from "swr";
2
2
  import type { Api } from "../types";
3
3
  type SWRConfigurationExtended<Data = any, Error = any, Fn extends BareFetcher<any> = BareFetcher<any>> = SWRConfiguration<Data, Error, Fn> & {
4
+ /**
5
+ * Conditional fetching as option
6
+ *
7
+ * Moving this to an option allows us to keep the endpoints typed dictionary,
8
+ * e.g. we can write:
9
+ *
10
+ * ```js
11
+ * const { data, mutate } = myApi.use("User/{id}",
12
+ * { params: { id: aVariableMaybeContainingAnId || "" }, },
13
+ * { when: !!aVariableMaybeContainingAnId }
14
+ * );
15
+ *
16
+ * // we still have typed `data`, `mutate`
17
+ * ```
18
+ * @see https://swr.vercel.app/docs/conditional-fetching
19
+ */
4
20
  when?: boolean | (() => boolean);
5
21
  };
22
+ /**
23
+ * @private
24
+ */
6
25
  export declare let createUseApi: <TEndpoints extends Api.Endpoints>(api: Api.Client<TEndpoints>) => <TEndpoint extends Api.EndpointUrl<TEndpoints>>(endpoint: TEndpoint, options?: Api.EndpointOptions<TEndpoints, TEndpoint, "get">, config?: SWRConfigurationExtended<Api.EndpointResponseOk<TEndpoints, TEndpoint, "get">, Api.EndpointResponseFail<TEndpoints, TEndpoint, "get">>) => SWRResponse<Api.EndpointResponseOk<TEndpoints, TEndpoint, "get">, Api.EndpointResponseFail<TEndpoints, TEndpoint, "get">>;
26
+ /**
27
+ * It creates an api client extended with auto-generated SWR wrapper hooks
28
+ */
7
29
  export declare let createSwrApi: <TEndpoints extends Api.Endpoints>(apiName: string, baseUrl: string, options?: Api.ClientOptions | undefined) => Api.Client<TEndpoints> & {
8
30
  use: ReturnType<typeof createUseApi<TEndpoints>>;
9
31
  };
@@ -2,41 +2,6 @@ import e from 'swr';
2
2
  import { isFunction } from '@koine/utils';
3
3
  import { createApi } from '../createApi.esm.js';
4
4
 
5
- /**
6
- * Conditional fetching as option
7
- *
8
- * Moving this to an option allows us to keep the endpoints typed dictionary,
9
- * e.g. we can write:
10
- *
11
- * ```js
12
- * const { data, mutate } = myApi.use("User/{id}",
13
- * { params: { id: aVariableMaybeContainingAnId || "" }, },
14
- * { when: !!aVariableMaybeContainingAnId }
15
- * );
16
- *
17
- * // we still have typed `data`, `mutate`
18
- * ```
19
- * @see https://swr.vercel.app/docs/conditional-fetching
20
- *//**
21
- * @private
22
- */let createUseApi=t=>(i,o,p)=>{// const fetcher = async (_endpoint: TEndpoint) => {
23
- // try {
24
- // const { ok, data } = await api.get(_endpoint, {
25
- // ...(options || {}),
26
- // throwErr: true,
27
- // });
28
- // if (ok) {
29
- // return data;
30
- // }
31
- // throw new Error() as unknown as Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>;
32
- // } catch(e) {
33
- // throw new Error() as unknown as Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>;;
34
- // }
35
- // };
36
- // }
37
- let a=async()=>{let{data:e}=await t.get(i,{...o||{},throwErr:!0});return e};// <Data = any, Error = any>(key: Key, config: SWRConfigurationExtended<Data, Error, Fetcher<Data>> | undefined): SWRResponse<Data, Error>;
38
- return e(p?.when===!1||isFunction(p?.when)&&p?.when()===!1?null:o?[i,o]:[i],a,p)};/**
39
- * It creates an api client extended with auto-generated SWR wrapper hooks
40
- */let createSwrApi=(...e)=>{let r=createApi(...e);return r.use=createUseApi(r),r};
5
+ let createUseApi=t=>(i,o,p)=>{let a=async()=>{let{data:e}=await t.get(i,{...o||{},throwErr:!0});return e};return e(p?.when===!1||isFunction(p?.when)&&p?.when()===!1?null:o?[i,o]:[i],a,p)};let createSwrApi=(...e)=>{let r=createApi(...e);return r.use=createUseApi(r),r};
41
6
 
42
7
  export { createSwrApi, createUseApi, createSwrApi as default };
@@ -6,15 +6,7 @@ var r = require('swr/mutation');
6
6
  var createApi = require('../createApi.cjs.js');
7
7
  var createSwrApi = require('../swr/createSwrApi.cjs.js');
8
8
 
9
- let a=(t,e)=>(a,o,i)=>// config.fetcher = sender;
10
- r(// @ts-expect-error FIXME: I can't get it...
11
- o?[a,o]:a,async(// if the first argument is an array the second one are the base options
12
- // defined when calling the usePost/Put/etc. hook, these will be overriden
13
- // by the _options just here below
14
- r,// these are the options arriving when calling `trigger({ json, query, etc... })
15
- a)=>{let o=Array.isArray(r)?r[0]:r,i=Array.isArray(r)?r[1]:{},{ok:p,data:s}=await t[e](o,{...i,...a.arg||{},throwErr:!0});return s},i);/**
16
- * It creates an api client extended with auto-generated SWR wrapper hooks
17
- */let createSwrMutationApi=(...r)=>{let o=createApi.createApi(...r);return o.use=createSwrApi.createUseApi(o),["post","put","patch","delete"].forEach(r=>{o[`use${r.charAt(0).toUpperCase()+r.slice(1)}`]=a(o,r);}),o};
9
+ let a=(t,e)=>(a,o,i)=>r(o?[a,o]:a,async(r,a)=>{let o=Array.isArray(r)?r[0]:r,i=Array.isArray(r)?r[1]:{},{ok:p,data:s}=await t[e](o,{...i,...a.arg||{},throwErr:!0});return s},i);let createSwrMutationApi=(...r)=>{let o=createApi.createApi(...r);return o.use=createSwrApi.createUseApi(o),["post","put","patch","delete"].forEach(r=>{o[`use${r.charAt(0).toUpperCase()+r.slice(1)}`]=a(o,r);}),o};
18
10
 
19
11
  exports.createSwrMutationApi = createSwrMutationApi;
20
12
  exports.default = createSwrMutationApi;
@@ -4,6 +4,9 @@ import type { Api } from "../types";
4
4
  type MutationRequestMethod = Exclude<Api.RequestMethod, "get">;
5
5
  type MutationHookName = Exclude<keyof Api.HooksMapsByName, "use">;
6
6
  type KoineApiMethodHookSWR<THookName extends MutationHookName, TEndpoints extends Api.Endpoints> = <TEndpoint extends Api.EndpointUrl<TEndpoints>, TMethod extends MutationRequestMethod = Api.HooksMapsByName[THookName]>(endpoint: TEndpoint, options?: Api.EndpointOptions<TEndpoints, TEndpoint, TMethod>, config?: SWRMutationConfiguration<Api.EndpointResponseOk<TEndpoints, TEndpoint, TMethod>, Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>, TEndpoint, Api.EndpointOptions<TEndpoints, TEndpoint, TMethod>>) => SWRMutationResponse<Api.EndpointResponseOk<TEndpoints, TEndpoint, TMethod>, Api.EndpointResponseFail<TEndpoints, TEndpoint, TMethod>, TEndpoint, Api.EndpointOptions<TEndpoints, TEndpoint, TMethod>>;
7
+ /**
8
+ * It creates an api client extended with auto-generated SWR wrapper hooks
9
+ */
7
10
  export declare let createSwrMutationApi: <TEndpoints extends Api.Endpoints>(apiName: string, baseUrl: string, options?: Api.ClientOptions | undefined) => Api.Client<TEndpoints> & {
8
11
  usePost: KoineApiMethodHookSWR<"usePost", TEndpoints>;
9
12
  usePut: KoineApiMethodHookSWR<"usePut", TEndpoints>;
@@ -2,14 +2,6 @@ import r from 'swr/mutation';
2
2
  import { createApi } from '../createApi.esm.js';
3
3
  import { createUseApi } from '../swr/createSwrApi.esm.js';
4
4
 
5
- let a=(t,e)=>(a,o,i)=>// config.fetcher = sender;
6
- r(// @ts-expect-error FIXME: I can't get it...
7
- o?[a,o]:a,async(// if the first argument is an array the second one are the base options
8
- // defined when calling the usePost/Put/etc. hook, these will be overriden
9
- // by the _options just here below
10
- r,// these are the options arriving when calling `trigger({ json, query, etc... })
11
- a)=>{let o=Array.isArray(r)?r[0]:r,i=Array.isArray(r)?r[1]:{},{ok:p,data:s}=await t[e](o,{...i,...a.arg||{},throwErr:!0});return s},i);/**
12
- * It creates an api client extended with auto-generated SWR wrapper hooks
13
- */let createSwrMutationApi=(...r)=>{let o=createApi(...r);return o.use=createUseApi(o),["post","put","patch","delete"].forEach(r=>{o[`use${r.charAt(0).toUpperCase()+r.slice(1)}`]=a(o,r);}),o};
5
+ let a=(t,e)=>(a,o,i)=>r(o?[a,o]:a,async(r,a)=>{let o=Array.isArray(r)?r[0]:r,i=Array.isArray(r)?r[1]:{},{ok:p,data:s}=await t[e](o,{...i,...a.arg||{},throwErr:!0});return s},i);let createSwrMutationApi=(...r)=>{let o=createApi(...r);return o.use=createUseApi(o),["post","put","patch","delete"].forEach(r=>{o[`use${r.charAt(0).toUpperCase()+r.slice(1)}`]=a(o,r);}),o};
14
6
 
15
7
  export { createSwrMutationApi, createSwrMutationApi as default };
package/types.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  type _Response = Response;
2
+ /**
3
+ * @borrows [awesome-template-literal-types](https://github.com/ghoullier/awesome-template-literal-types#router-params-parsing)
4
+ */
2
5
  type ExtractEndpointParams<T extends string> = string | number extends T ? Record<string, string> : T extends `${infer _Start}{${infer Param}}${infer Rest}` ? {
3
6
  [k in Param | keyof ExtractEndpointParams<Rest>]: string | number;
4
7
  } : T extends `${infer _Start}{${infer Param}}` ? {
@@ -6,15 +9,60 @@ type ExtractEndpointParams<T extends string> = string | number extends T ? Recor
6
9
  } : {};
7
10
  export declare namespace Api {
8
11
  export type ClientOptions = {
12
+ /**
13
+ * Headers will be merged with
14
+ * ```
15
+ * { "content-type": "application/json" }
16
+ * ```
17
+ *
18
+ * @default {}
19
+ */
9
20
  headers?: RequestInit["headers"];
21
+ /**
22
+ * Basic request options to supply to `fetch`
23
+ *
24
+ * @see RequestInit
25
+ *
26
+ * @default {}
27
+ */
10
28
  request?: Omit<RequestInit, "body" | "headers" | "method">;
29
+ /**
30
+ * Flag to throw error within the catch block, by default we return a
31
+ * normalised error result {@link ResultFail}
32
+ *
33
+ * @default false
34
+ */
11
35
  throwErr?: boolean;
36
+ /**
37
+ * Timeout in `ms`, if `falsy` there is no timeout
38
+ *
39
+ * @default 10000
40
+ */
12
41
  timeout?: number | false | null;
42
+ /**
43
+ * Process request before actual http call
44
+ *
45
+ * @default undefined
46
+ */
13
47
  processReq?: RequestProcessor;
48
+ /**
49
+ * Process ok/failed response just after http response
50
+ *
51
+ * @default undefined
52
+ */
14
53
  processRes?: ResponseProcessorRes;
54
+ /**
55
+ * Process maybe-thrown error originated either from `fetch` function
56
+ * invokation or from its `response.json()` parsing
57
+ *
58
+ * @default undefined
59
+ */
15
60
  processErr?: ResponseProcessorErr;
16
61
  };
17
62
  type ClientMethod<TMethod extends RequestMethod, TEndpoints extends Endpoints> = <TEndpoint extends EndpointUrl<TEndpoints>, TOptions extends EndpointOptions<TEndpoints, TEndpoint, TMethod>, TOk extends ResponseOk = EndpointResponseOk<TEndpoints, TEndpoint, TMethod>, TFail extends ResponseFail = EndpointResponseFail<TEndpoints, TEndpoint, TMethod>>(endpoint: TEndpoint, options?: TOptions) => Promise<EndpointResult<TEndpoints, TEndpoint, TMethod>>;
63
+ /**
64
+ * The `api` interface generated by `createApi`
65
+ */
18
66
  export type Client<TEndpoints extends Endpoints> = {
19
67
  [TMethod in RequestMethod]: ClientMethod<TMethod, TEndpoints>;
20
68
  };
@@ -29,19 +77,51 @@ export declare namespace Api {
29
77
  };
30
78
  export type EndpointUrl<TEndpoints extends Endpoints> = Extract<keyof TEndpoints, string>;
31
79
  type DataTypes<TMethod extends Uppercase<RequestMethod>> = {
80
+ /**
81
+ * The request body of a non-GET request
82
+ */
32
83
  json?: RequestJson;
84
+ /**
85
+ * The parameters to encode in the URL of the request
86
+ */
33
87
  query?: RequestQuery;
88
+ /**
89
+ * The JSON response data returned by the request in case of success
90
+ */
34
91
  ok?: null | unknown;
92
+ /**
93
+ * The shape of the error data returned by the request in case of
94
+ * failure
95
+ */
35
96
  fail?: null | unknown;
36
97
  };
37
98
  export type RequestMethod = "get" | "post" | "put" | "patch" | "delete";
38
99
  type RequestJson = unknown;
39
100
  type RequestQuery = unknown;
40
101
  type RequestParams = unknown;
102
+ /**
103
+ * Request options
104
+ *
105
+ * `ClientOptions` can be overriden here at the single request level.
106
+ */
41
107
  type RequestOptions<TEndpoints extends Endpoints, TEndpoint extends EndpointUrl<TEndpoints>, TMethod extends RequestMethod, TJson extends RequestJson, TQuery extends RequestQuery> = Omit<ClientOptions, "processReq"> & {
42
108
  processReq?: EndpointRequestProcessor<TEndpoints, TEndpoint, TMethod>;
109
+ /**
110
+ * A dictionary to dynamically interpolate endpoint url params, e.g.:
111
+ *
112
+ * ```js
113
+ * myapi.get("user/{id}", { params: { id: "12" }})
114
+ * ```
115
+ * results in a call to the endpoint `"user/12"`
116
+ */
43
117
  params?: ExtractEndpointParams<TEndpoint>;
118
+ /**
119
+ * Query parameters will be serialized into a string and appended to the URL
120
+ */
44
121
  query?: TQuery;
122
+ /**
123
+ * JSON request body
124
+ */
45
125
  json?: TJson;
46
126
  };
47
127
  export type ResponseOk = unknown;
@@ -73,6 +153,10 @@ export declare namespace Api {
73
153
  fail: true;
74
154
  data: TResponseFail;
75
155
  };
156
+ /**
157
+ * The request processor at the client level, this is meant to apply global
158
+ * transformations to all endpoints requests
159
+ */
76
160
  export type RequestProcessor = (method: RequestMethod, url: string, query: any, json: any, params: any, requestInit: RequestInit) => [
77
161
  string,
78
162
  RequestQuery,
@@ -80,6 +164,13 @@ export declare namespace Api {
80
164
  RequestParams,
81
165
  RequestInit
82
166
  ];
167
+ /**
168
+ * The request processor at the request level, this is meant to apply
169
+ * transformations to a single endpoint request. Request processor applied at
170
+ * the whole client level is still applied just before this one, hence one
171
+ * might set some global processing and override it or undo it at the single
172
+ * request level.
173
+ */
83
174
  export type EndpointRequestProcessor<TEndpoints extends Endpoints, TEndpoint extends EndpointUrl<TEndpoints>, TMethod extends RequestMethod> = (method: TMethod, url: string, query: EndpointOptions<TEndpoints, TEndpoint, TMethod>["query"], json: EndpointOptions<TEndpoints, TEndpoint, TMethod>["json"], params: EndpointOptions<TEndpoints, TEndpoint, TMethod>["params"], requestInit: RequestInit) => [
84
175
  string,
85
176
  EndpointOptions<TEndpoints, TEndpoint, TMethod>["query"],
@@ -87,8 +178,23 @@ export declare namespace Api {
87
178
  EndpointOptions<TEndpoints, TEndpoint, TMethod>["params"],
88
179
  RequestInit
89
180
  ];
181
+ /**
182
+ * The ok/fail response processor at the request level, this is meant to apply
183
+ * transformations to a single or all endpoint responses
184
+ */
90
185
  type ResponseProcessorRes = <TResponseOk extends ResponseOk = ResponseOk, TResponseFail extends ResponseFail = ResponseFail>(response: _Response, options: any) => Promise<Result<TResponseOk, TResponseFail>>;
186
+ /**
187
+ * The error response processor at the request level, this is meant to apply
188
+ * transformations to a single or all endpoint responses
189
+ */
91
190
  type ResponseProcessorErr = <TResponseOk extends ResponseOk = ResponseOk, TResponseFail extends ResponseFail = ResponseFail>(msg: string, options: any) => Promise<Result<TResponseOk, TResponseFail>>;
191
+ /**
192
+ * Api hooks map for `react`, each request method has its own `use{Method}`
193
+ * hook.
194
+ *
195
+ * These hooks are implemented with different libraries or, in the future as
196
+ * standalone hooks, see SWR ones to start with.
197
+ */
92
198
  type HooksMaps = {
93
199
  [TMethod in RequestMethod]: `use${TMethod extends "get" ? "" : Capitalize<TMethod>}`;
94
200
  };
@@ -97,7 +203,33 @@ export declare namespace Api {
97
203
  };
98
204
  export {};
99
205
  }
206
+ /**
207
+ * To generate all available helpers use in your `API` types:
208
+ *
209
+ * @example
210
+ * ```ts
211
+ * type Response = Api.Generate.ResponseHelpers<Endpoints>;
212
+ * type Request = Api.Generate.RequestHelpers<Endpoints>;
213
+ * type Get = Api.Generate.GetHelpers<Endpoints>;
214
+ * type Post = Api.Generate.PostHelpers<Endpoints>;
215
+ * ```
216
+ */
100
217
  export declare namespace Api.Generate {
218
+ /**
219
+ * @example
220
+ * ```ts
221
+ * // define the type on your `API` types:
222
+ * type Result = Api.Generate.ResultShortcuts<Endpoints>;
223
+ *
224
+ * // consume the type wherever in your app:
225
+ * type MyResult = API.Result["get"]["my/endpoint"];
226
+ *
227
+ * MyResult["ok"];
228
+ * ^
229
+ * MyResult["fail"];
230
+ * ^
231
+ * ```
232
+ */
101
233
  type ResultShortcuts<TEndpoints extends Endpoints> = {
102
234
  [TMethod in RequestMethod]: {
103
235
  [TEndpoint in Extract<keyof TEndpoints, string>]: {
@@ -106,19 +238,59 @@ export declare namespace Api.Generate {
106
238
  };
107
239
  };
108
240
  };
241
+ /**
242
+ * @example
243
+ * ```ts
244
+ * // define the type on your `API` types:
245
+ * type Response = Api.Generate.ResponseShortcuts<Endpoints>;
246
+ *
247
+ * // consume the type wherever in your app:
248
+ * type MyData = API.Response["get"]["my/endpoint"];
249
+ * ```
250
+ */
109
251
  type ResponseShortcuts<TEndpoints extends Endpoints> = {
110
252
  [TMethod in RequestMethod]: {
111
253
  [TEndpoint in Extract<keyof TEndpoints, string>]: GetDataType<TEndpoints, TEndpoint, TMethod, "ok">;
112
254
  };
113
255
  };
256
+ /**
257
+ * @example
258
+ * ```ts
259
+ * // define the type on your `API` types:
260
+ * type Request = Api.Generate.RequestShortcuts<Endpoints>;
261
+ *
262
+ * // consume the type wherever in your app:
263
+ * type MyData = API.Request["get"]["my/endpoint"];
264
+ * ```
265
+ */
114
266
  type RequestShortcuts<TEndpoints extends Endpoints> = {
115
267
  [TMethod in RequestMethod]: {
116
268
  [TEndpoint in Extract<keyof TEndpoints, string>]: TMethod extends "get" ? GetDataType<TEndpoints, TEndpoint, TMethod, "query"> : GetDataType<TEndpoints, TEndpoint, TMethod, "json">;
117
269
  };
118
270
  };
271
+ /**
272
+ * @example
273
+ * ```ts
274
+ * // define the type on your `API` types:
275
+ * type Get = Api.Generate.ResponseShortcuts<Endpoints>;
276
+ *
277
+ * // consume the type wherever in your app:
278
+ * type MyData = API.Get["my/endpoint"];
279
+ * ```
280
+ */
119
281
  type GetShortcuts<TEndpoints extends Endpoints> = {
120
282
  [TEndpoint in Extract<keyof TEndpoints, string>]: GetDataType<TEndpoints, TEndpoint, "get", "ok">;
121
283
  };
284
+ /**
285
+ * @example
286
+ * ```ts
287
+ * // define the type on your `API` types:
288
+ * type Post = Api.Generate.ResponseShortcuts<Endpoints>;
289
+ *
290
+ * // consume the type wherever in your app:
291
+ * type MyData = API.Post["my/endpoint"];
292
+ * ```
293
+ */
122
294
  type PostShortcuts<TEndpoints extends Endpoints> = {
123
295
  [TEndpoint in Extract<keyof TEndpoints, string>]: GetDataType<TEndpoints, TEndpoint, "post", "ok">;
124
296
  };