@hey-api/client-fetch
Advanced tools
Comparing version 0.7.0 to 0.7.1
@@ -1,5 +0,7 @@ | ||
type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; | ||
type ObjectStyle = 'form' | 'deepObject'; | ||
type QuerySerializer = (query: Record<string, unknown>) => string; | ||
type BodySerializer = (body: any) => any; | ||
interface Auth { | ||
in?: 'header' | 'query'; | ||
name?: string; | ||
scheme?: 'basic' | 'bearer'; | ||
type: 'apiKey' | 'http'; | ||
} | ||
interface SerializerOptions<T> { | ||
@@ -12,2 +14,7 @@ /** | ||
} | ||
type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; | ||
type ObjectStyle = 'form' | 'deepObject'; | ||
type QuerySerializer = (query: Record<string, unknown>) => string; | ||
type BodySerializer = (body: any) => any; | ||
interface QuerySerializerOptions { | ||
@@ -18,2 +25,12 @@ allowReserved?: boolean; | ||
} | ||
declare const formDataBodySerializer: { | ||
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T) => FormData; | ||
}; | ||
declare const jsonBodySerializer: { | ||
bodySerializer: <T>(body: T) => string; | ||
}; | ||
declare const urlSearchParamsBodySerializer: { | ||
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T) => URLSearchParams; | ||
}; | ||
type ErrInterceptor<Err, Res, Req, Options> = (error: Err, response: Res, request: Req, options: Options) => Err | Promise<Err>; | ||
@@ -35,11 +52,2 @@ type ReqInterceptor<Req, Options> = (request: Req, options: Options) => Req | Promise<Req>; | ||
} | ||
declare const formDataBodySerializer: { | ||
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T) => FormData; | ||
}; | ||
declare const jsonBodySerializer: { | ||
bodySerializer: <T>(body: T) => string; | ||
}; | ||
declare const urlSearchParamsBodySerializer: { | ||
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(body: T) => URLSearchParams; | ||
}; | ||
declare const createConfig: (override?: Config) => Config; | ||
@@ -64,3 +72,3 @@ | ||
*/ | ||
bodySerializer?: BodySerializer; | ||
bodySerializer?: BodySerializer | null; | ||
/** | ||
@@ -121,8 +129,2 @@ * Fetch API implementation. You can use this option to provide a custom | ||
} | ||
interface Auth { | ||
in?: 'header' | 'query'; | ||
name?: string; | ||
scheme?: 'basic' | 'bearer'; | ||
type: 'apiKey' | 'http'; | ||
} | ||
type AuthToken = string | undefined; | ||
@@ -129,0 +131,0 @@ interface RequestOptions<ThrowOnError extends boolean = boolean, Url extends string = string> extends Config<ThrowOnError> { |
@@ -1,2 +0,2 @@ | ||
var U=/\{[^{}]+\}/g,S=({allowReserved:t,name:r,value:e})=>{if(e==null)return "";if(typeof e=="object")throw new Error("Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these.");return `${r}=${t?e:encodeURIComponent(e)}`},$=t=>{switch(t){case "label":return ".";case "matrix":return ";";case "simple":return ",";default:return "&"}},k=t=>{switch(t){case "form":return ",";case "pipeDelimited":return "|";case "spaceDelimited":return "%20";default:return ","}},D=t=>{switch(t){case "label":return ".";case "matrix":return ";";case "simple":return ",";default:return "&"}},j=({allowReserved:t,explode:r,name:e,style:s,value:o})=>{if(!r){let n=(t?o:o.map(c=>encodeURIComponent(c))).join(k(s));switch(s){case "label":return `.${n}`;case "matrix":return `;${e}=${n}`;case "simple":return n;default:return `${e}=${n}`}}let a=$(s),i=o.map(n=>s==="label"||s==="simple"?t?n:encodeURIComponent(n):S({allowReserved:t,name:e,value:n})).join(a);return s==="label"||s==="matrix"?a+i:i},A=({allowReserved:t,explode:r,name:e,style:s,value:o})=>{if(o instanceof Date)return `${e}=${o.toISOString()}`;if(s!=="deepObject"&&!r){let n=[];Object.entries(o).forEach(([f,p])=>{n=[...n,f,t?p:encodeURIComponent(p)];});let c=n.join(",");switch(s){case "form":return `${e}=${c}`;case "label":return `.${c}`;case "matrix":return `;${e}=${c}`;default:return c}}let a=D(s),i=Object.entries(o).map(([n,c])=>S({allowReserved:t,name:s==="deepObject"?`${e}[${n}]`:n,value:c})).join(a);return s==="label"||s==="matrix"?a+i:i},_=({path:t,url:r})=>{let e=r,s=r.match(U);if(s)for(let o of s){let a=false,i=o.substring(1,o.length-1),n="simple";i.endsWith("*")&&(a=true,i=i.substring(0,i.length-1)),i.startsWith(".")?(i=i.substring(1),n="label"):i.startsWith(";")&&(i=i.substring(1),n="matrix");let c=t[i];if(c==null)continue;if(Array.isArray(c)){e=e.replace(o,j({explode:a,name:i,style:n,value:c}));continue}if(typeof c=="object"){e=e.replace(o,A({explode:a,name:i,style:n,value:c}));continue}if(n==="matrix"){e=e.replace(o,`;${S({name:i,value:c})}`);continue}let f=encodeURIComponent(n==="label"?`.${c}`:c);e=e.replace(o,f);}return e},C=({allowReserved:t,array:r,object:e}={})=>o=>{let a=[];if(o&&typeof o=="object")for(let i in o){let n=o[i];if(n!=null){if(Array.isArray(n)){a=[...a,j({allowReserved:t,explode:true,name:i,style:"form",value:n,...r})];continue}if(typeof n=="object"){a=[...a,A({allowReserved:t,explode:true,name:i,style:"deepObject",value:n,...e})];continue}a=[...a,S({allowReserved:t,name:i,value:n})];}}return a.join("&")},w=t=>{if(!t)return "stream";let r=t.split(";")[0]?.trim();if(r){if(r.startsWith("application/json")||r.endsWith("+json"))return "json";if(r==="multipart/form-data")return "formData";if(["application/","audio/","image/","video/"].some(e=>r.startsWith(e)))return "blob";if(r.startsWith("text/"))return "text"}},H=async(t,r)=>{let e=typeof r=="function"?await r(t):r;if(e)return t.scheme==="bearer"?`Bearer ${e}`:t.scheme==="basic"?`Basic ${btoa(e)}`:e},P=async({security:t,...r})=>{for(let e of t){let s=await H(e,r.auth);if(!s)continue;let o=e.name??"Authorization";switch(e.in){case "query":r.query||(r.query={}),r.query[o]=s;break;case "header":default:r.headers.set(o,s);break}return}},b=t=>B({baseUrl:t.baseUrl??"",path:t.path,query:t.query,querySerializer:typeof t.querySerializer=="function"?t.querySerializer:C(t.querySerializer),url:t.url}),B=({baseUrl:t,path:r,query:e,querySerializer:s,url:o})=>{let a=o.startsWith("/")?o:`/${o}`,i=t+a;r&&(i=_({path:r,url:i}));let n=e?s(e):"";return n.startsWith("?")&&(n=n.substring(1)),n&&(i+=`?${n}`),i},R=(t,r)=>{let e={...t,...r};return e.baseUrl?.endsWith("/")&&(e.baseUrl=e.baseUrl.substring(0,e.baseUrl.length-1)),e.headers=O(t.headers,r.headers),e},O=(...t)=>{let r=new Headers;for(let e of t){if(!e||typeof e!="object")continue;let s=e instanceof Headers?e.entries():Object.entries(e);for(let[o,a]of s)if(a===null)r.delete(o);else if(Array.isArray(a))for(let i of a)r.append(o,i);else a!==undefined&&r.set(o,typeof a=="object"?JSON.stringify(a):a);}return r},y=class{_fns;constructor(){this._fns=[];}clear(){this._fns=[];}exists(r){return this._fns.indexOf(r)!==-1}eject(r){let e=this._fns.indexOf(r);e!==-1&&(this._fns=[...this._fns.slice(0,e),...this._fns.slice(e+1)]);}use(r){this._fns=[...this._fns,r];}},E=()=>({error:new y,request:new y,response:new y}),x=(t,r,e)=>{typeof e=="string"||e instanceof Blob?t.append(r,e):t.append(r,JSON.stringify(e));},W={bodySerializer:t=>{let r=new FormData;return Object.entries(t).forEach(([e,s])=>{s!=null&&(Array.isArray(s)?s.forEach(o=>x(r,e,o)):x(r,e,s));}),r}},I={bodySerializer:t=>JSON.stringify(t)},z=(t,r,e)=>{typeof e=="string"?t.append(r,e):t.append(r,JSON.stringify(e));},N={bodySerializer:t=>{let r=new URLSearchParams;return Object.entries(t).forEach(([e,s])=>{s!=null&&(Array.isArray(s)?s.forEach(o=>z(r,e,o)):z(r,e,s));}),r}},Q=C({allowReserved:false,array:{explode:true,style:"form"},object:{explode:true,style:"deepObject"}}),V={"Content-Type":"application/json"},q=(t={})=>({...I,baseUrl:"",headers:V,parseAs:"auto",querySerializer:Q,...t});var M=(t={})=>{let r=R(q(),t),e=()=>({...r}),s=i=>(r=R(r,i),e()),o=E(),a=async i=>{let n={...r,...i,fetch:i.fetch??r.fetch??globalThis.fetch,headers:O(r.headers,i.headers)};n.security&&await P({...n,security:n.security}),n.body&&n.bodySerializer&&(n.body=n.bodySerializer(n.body)),n.body||n.headers.delete("Content-Type");let c=b(n),f={redirect:"follow",...n},p=new Request(c,f);for(let u of o.request._fns)p=await u(p,n);let T=n.fetch,l=await T(p);for(let u of o.response._fns)l=await u(l,p,n);let h={request:p,response:l};if(l.ok){if(l.status===204||l.headers.get("Content-Length")==="0")return {data:{},...h};let u=(n.parseAs==="auto"?w(l.headers.get("Content-Type")):n.parseAs)??"json";if(u==="stream")return {data:l.body,...h};let g=await l[u]();return u==="json"&&(n.responseValidator&&await n.responseValidator(g),n.responseTransformer&&(g=await n.responseTransformer(g))),{data:g,...h}}let m=await l.text();try{m=JSON.parse(m);}catch{}let d=m;for(let u of o.error._fns)d=await u(m,l,p,n);if(d=d||{},n.throwOnError)throw d;return {error:d,...h}};return {buildUrl:b,connect:i=>a({...i,method:"CONNECT"}),delete:i=>a({...i,method:"DELETE"}),get:i=>a({...i,method:"GET"}),getConfig:e,head:i=>a({...i,method:"HEAD"}),interceptors:o,options:i=>a({...i,method:"OPTIONS"}),patch:i=>a({...i,method:"PATCH"}),post:i=>a({...i,method:"POST"}),put:i=>a({...i,method:"PUT"}),request:a,setConfig:s,trace:i=>a({...i,method:"TRACE"})}};export{M as createClient,q as createConfig,W as formDataBodySerializer,I as jsonBodySerializer,N as urlSearchParamsBodySerializer};//# sourceMappingURL=index.js.map | ||
var A=async(t,r)=>{let e=typeof r=="function"?await r(t):r;if(e)return t.scheme==="bearer"?`Bearer ${e}`:t.scheme==="basic"?`Basic ${btoa(e)}`:e},j=(t,r,e)=>{typeof e=="string"||e instanceof Blob?t.append(r,e):t.append(r,JSON.stringify(e));},z=(t,r,e)=>{typeof e=="string"?t.append(r,e):t.append(r,JSON.stringify(e));},U={bodySerializer:t=>{let r=new FormData;return Object.entries(t).forEach(([e,i])=>{i!=null&&(Array.isArray(i)?i.forEach(a=>j(r,e,a)):j(r,e,i));}),r}},b={bodySerializer:t=>JSON.stringify(t)},k={bodySerializer:t=>{let r=new URLSearchParams;return Object.entries(t).forEach(([e,i])=>{i!=null&&(Array.isArray(i)?i.forEach(a=>z(r,e,a)):z(r,e,i));}),r}},T=t=>{switch(t){case "label":return ".";case "matrix":return ";";case "simple":return ",";default:return "&"}},_=t=>{switch(t){case "form":return ",";case "pipeDelimited":return "|";case "spaceDelimited":return "%20";default:return ","}},D=t=>{switch(t){case "label":return ".";case "matrix":return ";";case "simple":return ",";default:return "&"}},q=({allowReserved:t,explode:r,name:e,style:i,value:a})=>{if(!r){let s=(t?a:a.map(l=>encodeURIComponent(l))).join(_(i));switch(i){case "label":return `.${s}`;case "matrix":return `;${e}=${s}`;case "simple":return s;default:return `${e}=${s}`}}let o=T(i),n=a.map(s=>i==="label"||i==="simple"?t?s:encodeURIComponent(s):y({allowReserved:t,name:e,value:s})).join(o);return i==="label"||i==="matrix"?o+n:n},y=({allowReserved:t,name:r,value:e})=>{if(e==null)return "";if(typeof e=="object")throw new Error("Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these.");return `${r}=${t?e:encodeURIComponent(e)}`},O=({allowReserved:t,explode:r,name:e,style:i,value:a})=>{if(a instanceof Date)return `${e}=${a.toISOString()}`;if(i!=="deepObject"&&!r){let s=[];Object.entries(a).forEach(([f,u])=>{s=[...s,f,t?u:encodeURIComponent(u)];});let l=s.join(",");switch(i){case "form":return `${e}=${l}`;case "label":return `.${l}`;case "matrix":return `;${e}=${l}`;default:return l}}let o=D(i),n=Object.entries(a).map(([s,l])=>y({allowReserved:t,name:i==="deepObject"?`${e}[${s}]`:s,value:l})).join(o);return i==="label"||i==="matrix"?o+n:n};var H=/\{[^{}]+\}/g,B=({path:t,url:r})=>{let e=r,i=r.match(H);if(i)for(let a of i){let o=false,n=a.substring(1,a.length-1),s="simple";n.endsWith("*")&&(o=true,n=n.substring(0,n.length-1)),n.startsWith(".")?(n=n.substring(1),s="label"):n.startsWith(";")&&(n=n.substring(1),s="matrix");let l=t[n];if(l==null)continue;if(Array.isArray(l)){e=e.replace(a,q({explode:o,name:n,style:s,value:l}));continue}if(typeof l=="object"){e=e.replace(a,O({explode:o,name:n,style:s,value:l}));continue}if(s==="matrix"){e=e.replace(a,`;${y({name:n,value:l})}`);continue}let f=encodeURIComponent(s==="label"?`.${l}`:l);e=e.replace(a,f);}return e},E=({allowReserved:t,array:r,object:e}={})=>a=>{let o=[];if(a&&typeof a=="object")for(let n in a){let s=a[n];if(s!=null){if(Array.isArray(s)){o=[...o,q({allowReserved:t,explode:true,name:n,style:"form",value:s,...r})];continue}if(typeof s=="object"){o=[...o,O({allowReserved:t,explode:true,name:n,style:"deepObject",value:s,...e})];continue}o=[...o,y({allowReserved:t,name:n,value:s})];}}return o.join("&")},P=t=>{if(!t)return "stream";let r=t.split(";")[0]?.trim();if(r){if(r.startsWith("application/json")||r.endsWith("+json"))return "json";if(r==="multipart/form-data")return "formData";if(["application/","audio/","image/","video/"].some(e=>r.startsWith(e)))return "blob";if(r.startsWith("text/"))return "text"}},I=async({security:t,...r})=>{for(let e of t){let i=await A(e,r.auth);if(!i)continue;let a=e.name??"Authorization";switch(e.in){case "query":r.query||(r.query={}),r.query[a]=i;break;case "header":default:r.headers.set(a,i);break}return}},S=t=>W({baseUrl:t.baseUrl??"",path:t.path,query:t.query,querySerializer:typeof t.querySerializer=="function"?t.querySerializer:E(t.querySerializer),url:t.url}),W=({baseUrl:t,path:r,query:e,querySerializer:i,url:a})=>{let o=a.startsWith("/")?a:`/${a}`,n=t+o;r&&(n=B({path:r,url:n}));let s=e?i(e):"";return s.startsWith("?")&&(s=s.substring(1)),s&&(n+=`?${s}`),n},x=(t,r)=>{let e={...t,...r};return e.baseUrl?.endsWith("/")&&(e.baseUrl=e.baseUrl.substring(0,e.baseUrl.length-1)),e.headers=w(t.headers,r.headers),e},w=(...t)=>{let r=new Headers;for(let e of t){if(!e||typeof e!="object")continue;let i=e instanceof Headers?e.entries():Object.entries(e);for(let[a,o]of i)if(o===null)r.delete(a);else if(Array.isArray(o))for(let n of o)r.append(a,n);else o!==undefined&&r.set(a,typeof o=="object"?JSON.stringify(o):o);}return r},h=class{_fns;constructor(){this._fns=[];}clear(){this._fns=[];}exists(r){return this._fns.indexOf(r)!==-1}eject(r){let e=this._fns.indexOf(r);e!==-1&&(this._fns=[...this._fns.slice(0,e),...this._fns.slice(e+1)]);}use(r){this._fns=[...this._fns,r];}},v=()=>({error:new h,request:new h,response:new h}),N=E({allowReserved:false,array:{explode:true,style:"form"},object:{explode:true,style:"deepObject"}}),Q={"Content-Type":"application/json"},C=(t={})=>({...b,baseUrl:"",headers:Q,parseAs:"auto",querySerializer:N,...t});var F=(t={})=>{let r=x(C(),t),e=()=>({...r}),i=n=>(r=x(r,n),e()),a=v(),o=async n=>{let s={...r,...n,fetch:n.fetch??r.fetch??globalThis.fetch,headers:w(r.headers,n.headers)};s.security&&await I({...s,security:s.security}),s.body&&s.bodySerializer&&(s.body=s.bodySerializer(s.body)),s.body||s.headers.delete("Content-Type");let l=S(s),f={redirect:"follow",...s},u=new Request(l,f);for(let p of a.request._fns)u=await p(u,s);let $=s.fetch,c=await $(u);for(let p of a.response._fns)c=await p(c,u,s);let m={request:u,response:c};if(c.ok){if(c.status===204||c.headers.get("Content-Length")==="0")return {data:{},...m};let p=(s.parseAs==="auto"?P(c.headers.get("Content-Type")):s.parseAs)??"json";if(p==="stream")return {data:c.body,...m};let R=await c[p]();return p==="json"&&(s.responseValidator&&await s.responseValidator(R),s.responseTransformer&&(R=await s.responseTransformer(R))),{data:R,...m}}let g=await c.text();try{g=JSON.parse(g);}catch{}let d=g;for(let p of a.error._fns)d=await p(g,c,u,s);if(d=d||{},s.throwOnError)throw d;return {error:d,...m}};return {buildUrl:S,connect:n=>o({...n,method:"CONNECT"}),delete:n=>o({...n,method:"DELETE"}),get:n=>o({...n,method:"GET"}),getConfig:e,head:n=>o({...n,method:"HEAD"}),interceptors:a,options:n=>o({...n,method:"OPTIONS"}),patch:n=>o({...n,method:"PATCH"}),post:n=>o({...n,method:"POST"}),put:n=>o({...n,method:"PUT"}),request:o,setConfig:i,trace:n=>o({...n,method:"TRACE"})}};export{F as createClient,C as createConfig,U as formDataBodySerializer,b as jsonBodySerializer,k as urlSearchParamsBodySerializer};//# sourceMappingURL=index.js.map | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@hey-api/client-fetch", | ||
"version": "0.7.0", | ||
"version": "0.7.1", | ||
"description": "π Fetch API client for `@hey-api/openapi-ts` codegen.", | ||
@@ -56,4 +56,7 @@ "homepage": "https://heyapi.dev/", | ||
], | ||
"devDependencies": { | ||
"@hey-api/client-core": "0.1.2" | ||
}, | ||
"scripts": { | ||
"build": "tsup && pnpm check-exports", | ||
"build": "tsup && rollup -c && pnpm check-exports", | ||
"check-exports": "attw --pack .", | ||
@@ -60,0 +63,0 @@ "dev": "tsup --watch", |
@@ -0,56 +1,6 @@ | ||
import type { Auth } from '@hey-api/client-core'; | ||
import { describe, expect, it, vi } from 'vitest'; | ||
import type { Auth } from '../types'; | ||
import { getAuthToken, getParseAs, setAuthParams } from '../utils'; | ||
import { getParseAs, setAuthParams } from '../utils'; | ||
describe('getAuthToken', () => { | ||
it('returns bearer token', async () => { | ||
const auth = vi.fn().mockReturnValue('foo'); | ||
const token = await getAuthToken( | ||
{ | ||
scheme: 'bearer', | ||
type: 'http', | ||
}, | ||
auth, | ||
); | ||
expect(auth).toHaveBeenCalled(); | ||
expect(token).toBe('Bearer foo'); | ||
}); | ||
it('returns basic token', async () => { | ||
const auth = vi.fn().mockReturnValue('foo:bar'); | ||
const token = await getAuthToken( | ||
{ | ||
scheme: 'basic', | ||
type: 'http', | ||
}, | ||
auth, | ||
); | ||
expect(auth).toHaveBeenCalled(); | ||
expect(token).toBe(`Basic ${btoa('foo:bar')}`); | ||
}); | ||
it('returns raw token', async () => { | ||
const auth = vi.fn().mockReturnValue('foo'); | ||
const token = await getAuthToken( | ||
{ | ||
type: 'http', | ||
}, | ||
auth, | ||
); | ||
expect(auth).toHaveBeenCalled(); | ||
expect(token).toBe('foo'); | ||
}); | ||
it('returns nothing when auth function is undefined', async () => { | ||
const token = await getAuthToken( | ||
{ | ||
type: 'http', | ||
}, | ||
undefined, | ||
); | ||
expect(token).toBeUndefined(); | ||
}); | ||
}); | ||
describe('getParseAs', () => { | ||
@@ -57,0 +7,0 @@ const scenarios: Array<{ |
@@ -170,3 +170,2 @@ import type { Client, Config, RequestOptions } from './types'; | ||
export type { | ||
Auth, | ||
Client, | ||
@@ -179,8 +178,8 @@ Config, | ||
} from './types'; | ||
export { createConfig } from './utils'; | ||
export type { Auth, QuerySerializerOptions } from '@hey-api/client-core'; | ||
export { | ||
createConfig, | ||
formDataBodySerializer, | ||
jsonBodySerializer, | ||
type QuerySerializerOptions, | ||
urlSearchParamsBodySerializer, | ||
} from './utils'; | ||
} from '@hey-api/client-core'; |
import type { | ||
Auth, | ||
BodySerializer, | ||
Middleware, | ||
QuerySerializer, | ||
QuerySerializerOptions, | ||
} from './utils'; | ||
} from '@hey-api/client-core'; | ||
import type { Middleware } from './utils'; | ||
type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>; | ||
@@ -27,3 +29,3 @@ | ||
*/ | ||
bodySerializer?: BodySerializer; | ||
bodySerializer?: BodySerializer | null; | ||
/** | ||
@@ -105,9 +107,2 @@ * Fetch API implementation. You can use this option to provide a custom | ||
export interface Auth { | ||
in?: 'header' | 'query'; | ||
name?: string; | ||
scheme?: 'basic' | 'bearer'; | ||
type: 'apiKey' | 'http'; | ||
} | ||
type AuthToken = string | undefined; | ||
@@ -114,0 +109,0 @@ |
284
src/utils.ts
@@ -1,3 +0,15 @@ | ||
import type { Auth, Client, Config, RequestOptions } from './types'; | ||
import type { | ||
QuerySerializer, | ||
QuerySerializerOptions, | ||
} from '@hey-api/client-core'; | ||
import { | ||
getAuthToken, | ||
jsonBodySerializer, | ||
serializeArrayParam, | ||
serializeObjectParam, | ||
serializePrimitiveParam, | ||
} from '@hey-api/client-core'; | ||
import type { Client, Config, RequestOptions } from './types'; | ||
interface PathSerializer { | ||
@@ -13,185 +25,3 @@ path: Record<string, unknown>; | ||
type ArraySeparatorStyle = ArrayStyle | MatrixStyle; | ||
type ObjectStyle = 'form' | 'deepObject'; | ||
type ObjectSeparatorStyle = ObjectStyle | MatrixStyle; | ||
export type QuerySerializer = (query: Record<string, unknown>) => string; | ||
export type BodySerializer = (body: any) => any; | ||
interface SerializerOptions<T> { | ||
/** | ||
* @default true | ||
*/ | ||
explode: boolean; | ||
style: T; | ||
} | ||
interface SerializeOptions<T> | ||
extends SerializePrimitiveOptions, | ||
SerializerOptions<T> {} | ||
interface SerializePrimitiveOptions { | ||
allowReserved?: boolean; | ||
name: string; | ||
} | ||
interface SerializePrimitiveParam extends SerializePrimitiveOptions { | ||
value: string; | ||
} | ||
export interface QuerySerializerOptions { | ||
allowReserved?: boolean; | ||
array?: SerializerOptions<ArrayStyle>; | ||
object?: SerializerOptions<ObjectStyle>; | ||
} | ||
const serializePrimitiveParam = ({ | ||
allowReserved, | ||
name, | ||
value, | ||
}: SerializePrimitiveParam) => { | ||
if (value === undefined || value === null) { | ||
return ''; | ||
} | ||
if (typeof value === 'object') { | ||
throw new Error( | ||
'Deeply-nested arrays/objects arenβt supported. Provide your own `querySerializer()` to handle these.', | ||
); | ||
} | ||
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`; | ||
}; | ||
const separatorArrayExplode = (style: ArraySeparatorStyle) => { | ||
switch (style) { | ||
case 'label': | ||
return '.'; | ||
case 'matrix': | ||
return ';'; | ||
case 'simple': | ||
return ','; | ||
default: | ||
return '&'; | ||
} | ||
}; | ||
const separatorArrayNoExplode = (style: ArraySeparatorStyle) => { | ||
switch (style) { | ||
case 'form': | ||
return ','; | ||
case 'pipeDelimited': | ||
return '|'; | ||
case 'spaceDelimited': | ||
return '%20'; | ||
default: | ||
return ','; | ||
} | ||
}; | ||
const separatorObjectExplode = (style: ObjectSeparatorStyle) => { | ||
switch (style) { | ||
case 'label': | ||
return '.'; | ||
case 'matrix': | ||
return ';'; | ||
case 'simple': | ||
return ','; | ||
default: | ||
return '&'; | ||
} | ||
}; | ||
const serializeArrayParam = ({ | ||
allowReserved, | ||
explode, | ||
name, | ||
style, | ||
value, | ||
}: SerializeOptions<ArraySeparatorStyle> & { | ||
value: unknown[]; | ||
}) => { | ||
if (!explode) { | ||
const joinedValues = ( | ||
allowReserved ? value : value.map((v) => encodeURIComponent(v as string)) | ||
).join(separatorArrayNoExplode(style)); | ||
switch (style) { | ||
case 'label': | ||
return `.${joinedValues}`; | ||
case 'matrix': | ||
return `;${name}=${joinedValues}`; | ||
case 'simple': | ||
return joinedValues; | ||
default: | ||
return `${name}=${joinedValues}`; | ||
} | ||
} | ||
const separator = separatorArrayExplode(style); | ||
const joinedValues = value | ||
.map((v) => { | ||
if (style === 'label' || style === 'simple') { | ||
return allowReserved ? v : encodeURIComponent(v as string); | ||
} | ||
return serializePrimitiveParam({ | ||
allowReserved, | ||
name, | ||
value: v as string, | ||
}); | ||
}) | ||
.join(separator); | ||
return style === 'label' || style === 'matrix' | ||
? separator + joinedValues | ||
: joinedValues; | ||
}; | ||
const serializeObjectParam = ({ | ||
allowReserved, | ||
explode, | ||
name, | ||
style, | ||
value, | ||
}: SerializeOptions<ObjectSeparatorStyle> & { | ||
value: Record<string, unknown> | Date; | ||
}) => { | ||
if (value instanceof Date) { | ||
return `${name}=${value.toISOString()}`; | ||
} | ||
if (style !== 'deepObject' && !explode) { | ||
let values: string[] = []; | ||
Object.entries(value).forEach(([key, v]) => { | ||
values = [ | ||
...values, | ||
key, | ||
allowReserved ? (v as string) : encodeURIComponent(v as string), | ||
]; | ||
}); | ||
const joinedValues = values.join(','); | ||
switch (style) { | ||
case 'form': | ||
return `${name}=${joinedValues}`; | ||
case 'label': | ||
return `.${joinedValues}`; | ||
case 'matrix': | ||
return `;${name}=${joinedValues}`; | ||
default: | ||
return joinedValues; | ||
} | ||
} | ||
const separator = separatorObjectExplode(style); | ||
const joinedValues = Object.entries(value) | ||
.map(([key, v]) => | ||
serializePrimitiveParam({ | ||
allowReserved, | ||
name: style === 'deepObject' ? `${name}[${key}]` : key, | ||
value: v as string, | ||
}), | ||
) | ||
.join(separator); | ||
return style === 'label' || style === 'matrix' | ||
? separator + joinedValues | ||
: joinedValues; | ||
}; | ||
const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => { | ||
@@ -368,24 +198,2 @@ let url = _url; | ||
export const getAuthToken = async ( | ||
auth: Auth, | ||
callback: RequestOptions['auth'], | ||
): Promise<string | undefined> => { | ||
const token = | ||
typeof callback === 'function' ? await callback(auth) : callback; | ||
if (!token) { | ||
return; | ||
} | ||
if (auth.scheme === 'bearer') { | ||
return `Bearer ${token}`; | ||
} | ||
if (auth.scheme === 'basic') { | ||
return `Basic ${btoa(token)}`; | ||
} | ||
return token; | ||
}; | ||
export const setAuthParams = async ({ | ||
@@ -573,68 +381,2 @@ security, | ||
const serializeFormDataPair = (data: FormData, key: string, value: unknown) => { | ||
if (typeof value === 'string' || value instanceof Blob) { | ||
data.append(key, value); | ||
} else { | ||
data.append(key, JSON.stringify(value)); | ||
} | ||
}; | ||
export const formDataBodySerializer = { | ||
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>( | ||
body: T, | ||
) => { | ||
const data = new FormData(); | ||
Object.entries(body).forEach(([key, value]) => { | ||
if (value === undefined || value === null) { | ||
return; | ||
} | ||
if (Array.isArray(value)) { | ||
value.forEach((v) => serializeFormDataPair(data, key, v)); | ||
} else { | ||
serializeFormDataPair(data, key, value); | ||
} | ||
}); | ||
return data; | ||
}, | ||
}; | ||
export const jsonBodySerializer = { | ||
bodySerializer: <T>(body: T) => JSON.stringify(body), | ||
}; | ||
const serializeUrlSearchParamsPair = ( | ||
data: URLSearchParams, | ||
key: string, | ||
value: unknown, | ||
) => { | ||
if (typeof value === 'string') { | ||
data.append(key, value); | ||
} else { | ||
data.append(key, JSON.stringify(value)); | ||
} | ||
}; | ||
export const urlSearchParamsBodySerializer = { | ||
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>( | ||
body: T, | ||
) => { | ||
const data = new URLSearchParams(); | ||
Object.entries(body).forEach(([key, value]) => { | ||
if (value === undefined || value === null) { | ||
return; | ||
} | ||
if (Array.isArray(value)) { | ||
value.forEach((v) => serializeUrlSearchParamsPair(data, key, v)); | ||
} else { | ||
serializeUrlSearchParamsPair(data, key, value); | ||
} | ||
}); | ||
return data; | ||
}, | ||
}; | ||
const defaultQuerySerializer = createQuerySerializer({ | ||
@@ -641,0 +383,0 @@ allowReserved: false, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
133050
1
1208