@hey-api/client-fetch
Advanced tools
Comparing version 0.5.2 to 0.5.3
@@ -47,3 +47,14 @@ type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; | ||
/** | ||
* Access token or a function returning access token. The resolved token | ||
* will be added to request headers where it's required. | ||
*/ | ||
accessToken?: (() => Promise<string | undefined>) | string | undefined; | ||
/** | ||
* API key or a function returning API key. The resolved key will be added | ||
* to the request payload as required. | ||
*/ | ||
apiKey?: (() => Promise<string | undefined>) | string | undefined; | ||
/** | ||
* Base URL for all requests made by this client. | ||
* | ||
* @default '' | ||
@@ -60,2 +71,3 @@ */ | ||
* fetch instance. | ||
* | ||
* @default globalThis.fetch | ||
@@ -82,2 +94,3 @@ */ | ||
* Select `stream` if you don't want to parse response data at all. | ||
* | ||
* @default 'auto' | ||
@@ -102,2 +115,3 @@ */ | ||
* Throw an error instead of returning it in the response? | ||
* | ||
* @default false | ||
@@ -122,2 +136,6 @@ */ | ||
query?: Record<string, unknown>; | ||
/** | ||
* Security mechanism(s) to use for the request. | ||
*/ | ||
security?: ReadonlyArray<Security>; | ||
url: Url; | ||
@@ -139,2 +157,7 @@ } | ||
}>; | ||
interface Security { | ||
fn: 'accessToken' | 'apiKey'; | ||
in: 'header' | 'query'; | ||
name: string; | ||
} | ||
type MethodFn = <Data = unknown, TError = unknown, ThrowOnError extends boolean = false>(options: Omit<RequestOptions<ThrowOnError>, 'method'>) => RequestResult<Data, TError, ThrowOnError>; | ||
@@ -141,0 +164,0 @@ type RequestFn = <Data = unknown, TError = unknown, ThrowOnError extends boolean = false>(options: Omit<RequestOptions<ThrowOnError>, 'method'> & Pick<Required<RequestOptions<ThrowOnError>>, 'method'>) => RequestResult<Data, TError, ThrowOnError>; |
@@ -1,5 +0,5 @@ | ||
var U=/\{[^{}]+\}/g,S=({allowReserved:n,name:t,value:r})=>{if(r==null)return "";if(typeof r=="object")throw new Error("Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these.");return `${t}=${n?r:encodeURIComponent(r)}`},$=n=>{switch(n){case"label":return ".";case"matrix":return ";";case"simple":return ",";default:return "&"}},D=n=>{switch(n){case"form":return ",";case"pipeDelimited":return "|";case"spaceDelimited":return "%20";default:return ","}},_=n=>{switch(n){case"label":return ".";case"matrix":return ";";case"simple":return ",";default:return "&"}},C=({allowReserved:n,explode:t,name:r,style:o,value:a})=>{if(!t){let e=(n?a:a.map(s=>encodeURIComponent(s))).join(D(o));switch(o){case"label":return `.${e}`;case"matrix":return `;${r}=${e}`;case"simple":return e;default:return `${r}=${e}`}}let c=$(o),i=a.map(e=>o==="label"||o==="simple"?n?e:encodeURIComponent(e):S({allowReserved:n,name:r,value:e})).join(c);return o==="label"||o==="matrix"?c+i:i},A=({allowReserved:n,explode:t,name:r,style:o,value:a})=>{if(a instanceof Date)return `${r}=${a.toISOString()}`;if(o!=="deepObject"&&!t){let e=[];Object.entries(a).forEach(([u,g])=>{e=[...e,u,n?g:encodeURIComponent(g)];});let s=e.join(",");switch(o){case"form":return `${r}=${s}`;case"label":return `.${s}`;case"matrix":return `;${r}=${s}`;default:return s}}let c=_(o),i=Object.entries(a).map(([e,s])=>S({allowReserved:n,name:o==="deepObject"?`${r}[${e}]`:e,value:s})).join(c);return o==="label"||o==="matrix"?c+i:i},k=({path:n,url:t})=>{let r=t,o=t.match(U);if(o)for(let a of o){let c=!1,i=a.substring(1,a.length-1),e="simple";i.endsWith("*")&&(c=!0,i=i.substring(0,i.length-1)),i.startsWith(".")?(i=i.substring(1),e="label"):i.startsWith(";")&&(i=i.substring(1),e="matrix");let s=n[i];if(s==null)continue;if(Array.isArray(s)){r=r.replace(a,C({explode:c,name:i,style:e,value:s}));continue}if(typeof s=="object"){r=r.replace(a,A({explode:c,name:i,style:e,value:s}));continue}if(e==="matrix"){r=r.replace(a,`;${S({name:i,value:s})}`);continue}let u=encodeURIComponent(e==="label"?`.${s}`:s);r=r.replace(a,u);}return r},R=({allowReserved:n,array:t,object:r}={})=>a=>{let c=[];if(a&&typeof a=="object")for(let i in a){let e=a[i];if(e!=null){if(Array.isArray(e)){c=[...c,C({allowReserved:n,explode:!0,name:i,style:"form",value:e,...t})];continue}if(typeof e=="object"){c=[...c,A({allowReserved:n,explode:!0,name:i,style:"deepObject",value:e,...r})];continue}c=[...c,S({allowReserved:n,name:i,value:e})];}}return c.join("&")},w=n=>{if(!n)return;let t=n.split(";")[0].trim();if(t.startsWith("application/json")||t.endsWith("+json"))return "json";if(t==="multipart/form-data")return "formData";if(["application/","audio/","image/","video/"].some(r=>t.startsWith(r)))return "blob";if(t.startsWith("text/"))return "text"},P=({baseUrl:n,path:t,query:r,querySerializer:o,url:a})=>{let c=a.startsWith("/")?a:`/${a}`,i=n+c;t&&(i=k({path:t,url:i}));let e=r?o(r):"";return e.startsWith("?")&&(e=e.substring(1)),e&&(i+=`?${e}`),i},O=(n,t)=>{let r={...n,...t};return r.baseUrl?.endsWith("/")&&(r.baseUrl=r.baseUrl.substring(0,r.baseUrl.length-1)),r.headers=x(n.headers,t.headers),r},x=(...n)=>{let t=new Headers;for(let r of n){if(!r||typeof r!="object")continue;let o=r instanceof Headers?r.entries():Object.entries(r);for(let[a,c]of o)if(c===null)t.delete(a);else if(Array.isArray(c))for(let i of c)t.append(a,i);else c!==void 0&&t.set(a,typeof c=="object"?JSON.stringify(c):c);}return t},y=class{_fns;constructor(){this._fns=[];}clear(){this._fns=[];}exists(t){return this._fns.indexOf(t)!==-1}eject(t){let r=this._fns.indexOf(t);r!==-1&&(this._fns=[...this._fns.slice(0,r),...this._fns.slice(r+1)]);}use(t){this._fns=[...this._fns,t];}},E=()=>({error:new y,request:new y,response:new y}),j=(n,t,r)=>{typeof r=="string"||r instanceof Blob?n.append(t,r):n.append(t,JSON.stringify(r));},H={bodySerializer:n=>{let t=new FormData;return Object.entries(n).forEach(([r,o])=>{o!=null&&(Array.isArray(o)?o.forEach(a=>j(t,r,a)):j(t,r,o));}),t}},I={bodySerializer:n=>JSON.stringify(n)},q=(n,t,r)=>{typeof r=="string"?n.append(t,r):n.append(t,JSON.stringify(r));},W={bodySerializer:n=>{let t=new URLSearchParams;return Object.entries(n).forEach(([r,o])=>{o!=null&&(Array.isArray(o)?o.forEach(a=>q(t,r,a)):q(t,r,o));}),t}},N=R({allowReserved:!1,array:{explode:!0,style:"form"},object:{explode:!0,style:"deepObject"}}),B={"Content-Type":"application/json"},z=(n={})=>({...I,baseUrl:"",headers:B,parseAs:"auto",querySerializer:N,...n});var L=(n={})=>{let t=O(z(),n),r=()=>({...t}),o=e=>(t=O(t,e),r()),a=e=>P({baseUrl:e.baseUrl??"",path:e.path,query:e.query,querySerializer:typeof e.querySerializer=="function"?e.querySerializer:R(e.querySerializer),url:e.url}),c=E(),i=async e=>{let s={...t,...e,fetch:e.fetch??t.fetch??globalThis.fetch,headers:x(t.headers,e.headers)};s.body&&s.bodySerializer&&(s.body=s.bodySerializer(s.body)),s.body||s.headers.delete("Content-Type");let u=a(s),g={redirect:"follow",...s},f=new Request(u,g);for(let p of c.request._fns)f=await p(f,s);let T=s.fetch,l=await T(f);for(let p of c.response._fns)l=await p(l,f,s);let m={request:f,response:l};if(l.ok){if(l.status===204||l.headers.get("Content-Length")==="0")return {data:{},...m};if(s.parseAs==="stream")return {data:l.body,...m};let p=(s.parseAs==="auto"?w(l.headers.get("Content-Type")):s.parseAs)??"json",b=await l[p]();return p==="json"&&s.responseTransformer&&(b=await s.responseTransformer(b)),{data:b,...m}}let h=await l.text();try{h=JSON.parse(h);}catch{}let d=h;for(let p of c.error._fns)d=await p(h,l,f,s);if(d=d||{},s.throwOnError)throw d;return {error:d,...m}};return {buildUrl:a,connect:e=>i({...e,method:"CONNECT"}),delete:e=>i({...e,method:"DELETE"}),get:e=>i({...e,method:"GET"}),getConfig:r,head:e=>i({...e,method:"HEAD"}),interceptors:c,options:e=>i({...e,method:"OPTIONS"}),patch:e=>i({...e,method:"PATCH"}),post:e=>i({...e,method:"POST"}),put:e=>i({...e,method:"PUT"}),request:i,setConfig:o,trace:e=>i({...e,method:"TRACE"})}}; | ||
var I=/\{[^{}]+\}/g,h=({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)}`},k=t=>{switch(t){case"label":return ".";case"matrix":return ";";case"simple":return ",";default:return "&"}},U=t=>{switch(t){case"form":return ",";case"pipeDelimited":return "|";case"spaceDelimited":return "%20";default:return ","}},$=t=>{switch(t){case"label":return ".";case"matrix":return ";";case"simple":return ",";default:return "&"}},z=({allowReserved:t,explode:r,name:e,style:s,value:a})=>{if(!r){let n=(t?a:a.map(c=>encodeURIComponent(c))).join(U(s));switch(s){case"label":return `.${n}`;case"matrix":return `;${e}=${n}`;case"simple":return n;default:return `${e}=${n}`}}let o=k(s),i=a.map(n=>s==="label"||s==="simple"?t?n:encodeURIComponent(n):h({allowReserved:t,name:e,value:n})).join(o);return s==="label"||s==="matrix"?o+i:i},C=({allowReserved:t,explode:r,name:e,style:s,value:a})=>{if(a instanceof Date)return `${e}=${a.toISOString()}`;if(s!=="deepObject"&&!r){let n=[];Object.entries(a).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 o=$(s),i=Object.entries(a).map(([n,c])=>h({allowReserved:t,name:s==="deepObject"?`${e}[${n}]`:n,value:c})).join(o);return s==="label"||s==="matrix"?o+i:i},D=({path:t,url:r})=>{let e=r,s=r.match(I);if(s)for(let a of s){let o=!1,i=a.substring(1,a.length-1),n="simple";i.endsWith("*")&&(o=!0,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(a,z({explode:o,name:i,style:n,value:c}));continue}if(typeof c=="object"){e=e.replace(a,C({explode:o,name:i,style:n,value:c}));continue}if(n==="matrix"){e=e.replace(a,`;${h({name:i,value:c})}`);continue}let f=encodeURIComponent(n==="label"?`.${c}`:c);e=e.replace(a,f);}return e},A=({allowReserved:t,array:r,object:e}={})=>a=>{let o=[];if(a&&typeof a=="object")for(let i in a){let n=a[i];if(n!=null){if(Array.isArray(n)){o=[...o,z({allowReserved:t,explode:!0,name:i,style:"form",value:n,...r})];continue}if(typeof n=="object"){o=[...o,C({allowReserved:t,explode:!0,name:i,style:"deepObject",value:n,...e})];continue}o=[...o,h({allowReserved:t,name:i,value:n})];}}return o.join("&")},w=t=>{if(!t)return;let r=t.split(";")[0].trim();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"},_=async(t,r)=>{if(t.fn==="accessToken"){let e=typeof r.accessToken=="function"?await r.accessToken():r.accessToken;return e?`Bearer ${e}`:void 0}if(t.fn==="apiKey")return typeof r.apiKey=="function"?await r.apiKey():r.apiKey},P=async({security:t,...r})=>{for(let e of t){let s=await _(e,r);if(s){e.in==="header"?r.headers.set(e.name,s):e.in==="query"&&(r.query||(r.query={}),r.query[e.name]=s);return}}},b=t=>H({baseUrl:t.baseUrl??"",path:t.path,query:t.query,querySerializer:typeof t.querySerializer=="function"?t.querySerializer:A(t.querySerializer),url:t.url}),H=({baseUrl:t,path:r,query:e,querySerializer:s,url:a})=>{let o=a.startsWith("/")?a:`/${a}`,i=t+o;r&&(i=D({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[a,o]of s)if(o===null)r.delete(a);else if(Array.isArray(o))for(let i of o)r.append(a,i);else o!==void 0&&r.set(a,typeof o=="object"?JSON.stringify(o):o);}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];}},T=()=>({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(a=>x(r,e,a)):x(r,e,s));}),r}},E={bodySerializer:t=>JSON.stringify(t)},j=(t,r,e)=>{typeof e=="string"?t.append(r,e):t.append(r,JSON.stringify(e));},B={bodySerializer:t=>{let r=new URLSearchParams;return Object.entries(t).forEach(([e,s])=>{s!=null&&(Array.isArray(s)?s.forEach(a=>j(r,e,a)):j(r,e,s));}),r}},N=A({allowReserved:!1,array:{explode:!0,style:"form"},object:{explode:!0,style:"deepObject"}}),Q={"Content-Type":"application/json"},q=(t={})=>({...E,baseUrl:"",headers:Q,parseAs:"auto",querySerializer:N,...t});var L=(t={})=>{let r=R(q(),t),e=()=>({...r}),s=i=>(r=R(r,i),e()),a=T(),o=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 a.request._fns)p=await u(p,n);let l=await n.fetch(p);for(let u of a.response._fns)l=await u(l,p,n);let m={request:p,response:l};if(l.ok){if(l.status===204||l.headers.get("Content-Length")==="0")return {data:{},...m};if(n.parseAs==="stream")return {data:l.body,...m};let u=(n.parseAs==="auto"?w(l.headers.get("Content-Type")):n.parseAs)??"json",S=await l[u]();return u==="json"&&n.responseTransformer&&(S=await n.responseTransformer(S)),{data:S,...m}}let g=await l.text();try{g=JSON.parse(g);}catch{}let d=g;for(let u of a.error._fns)d=await u(g,l,p,n);if(d=d||{},n.throwOnError)throw d;return {error:d,...m}};return {buildUrl:b,connect:i=>o({...i,method:"CONNECT"}),delete:i=>o({...i,method:"DELETE"}),get:i=>o({...i,method:"GET"}),getConfig:e,head:i=>o({...i,method:"HEAD"}),interceptors:a,options:i=>o({...i,method:"OPTIONS"}),patch:i=>o({...i,method:"PATCH"}),post:i=>o({...i,method:"POST"}),put:i=>o({...i,method:"PUT"}),request:o,setConfig:s,trace:i=>o({...i,method:"TRACE"})}}; | ||
export { L as createClient, z as createConfig, H as formDataBodySerializer, I as jsonBodySerializer, W as urlSearchParamsBodySerializer }; | ||
export { L as createClient, q as createConfig, W as formDataBodySerializer, E as jsonBodySerializer, B as urlSearchParamsBodySerializer }; | ||
//# sourceMappingURL=index.js.map | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@hey-api/client-fetch", | ||
"version": "0.5.2", | ||
"version": "0.5.3", | ||
"description": "π Fetch API client for `@hey-api/openapi-ts` codegen.", | ||
@@ -5,0 +5,0 @@ "homepage": "https://heyapi.dev/", |
import type { Client, Config, RequestOptions } from './types'; | ||
import { | ||
buildUrl, | ||
createConfig, | ||
createInterceptors, | ||
createQuerySerializer, | ||
getParseAs, | ||
getUrl, | ||
mergeConfigs, | ||
mergeHeaders, | ||
setAuthParams, | ||
} from './utils'; | ||
@@ -27,16 +27,2 @@ | ||
const buildUrl: Client['buildUrl'] = (options) => { | ||
const url = getUrl({ | ||
baseUrl: options.baseUrl ?? '', | ||
path: options.path, | ||
query: options.query, | ||
querySerializer: | ||
typeof options.querySerializer === 'function' | ||
? options.querySerializer | ||
: createQuerySerializer(options.querySerializer), | ||
url: options.url, | ||
}); | ||
return url; | ||
}; | ||
const interceptors = createInterceptors< | ||
@@ -57,2 +43,10 @@ Request, | ||
}; | ||
if (opts.security) { | ||
await setAuthParams({ | ||
...opts, | ||
security: opts.security, | ||
}); | ||
} | ||
if (opts.body && opts.bodySerializer) { | ||
@@ -79,4 +73,3 @@ opts.body = opts.bodySerializer(opts.body); | ||
const _fetch = opts.fetch!; | ||
let response = await _fetch(request); | ||
let response = await opts.fetch(request); | ||
@@ -83,0 +76,0 @@ for (const fn of interceptors.response._fns) { |
@@ -13,3 +13,14 @@ import type { | ||
/** | ||
* Access token or a function returning access token. The resolved token | ||
* will be added to request headers where it's required. | ||
*/ | ||
accessToken?: (() => Promise<string | undefined>) | string | undefined; | ||
/** | ||
* API key or a function returning API key. The resolved key will be added | ||
* to the request payload as required. | ||
*/ | ||
apiKey?: (() => Promise<string | undefined>) | string | undefined; | ||
/** | ||
* Base URL for all requests made by this client. | ||
* | ||
* @default '' | ||
@@ -26,2 +37,3 @@ */ | ||
* fetch instance. | ||
* | ||
* @default globalThis.fetch | ||
@@ -68,2 +80,3 @@ */ | ||
* Select `stream` if you don't want to parse response data at all. | ||
* | ||
* @default 'auto' | ||
@@ -88,2 +101,3 @@ */ | ||
* Throw an error instead of returning it in the response? | ||
* | ||
* @default false | ||
@@ -117,2 +131,6 @@ */ | ||
query?: Record<string, unknown>; | ||
/** | ||
* Security mechanism(s) to use for the request. | ||
*/ | ||
security?: ReadonlyArray<Security>; | ||
url: Url; | ||
@@ -141,2 +159,8 @@ } | ||
export interface Security { | ||
fn: 'accessToken' | 'apiKey'; | ||
in: 'header' | 'query'; | ||
name: string; | ||
} | ||
type MethodFn = < | ||
@@ -143,0 +167,0 @@ Data = unknown, |
@@ -1,2 +0,2 @@ | ||
import type { Config } from './types'; | ||
import type { Client, Config, RequestOptions, Security } from './types'; | ||
@@ -361,2 +361,63 @@ interface PathSerializer { | ||
export const getAuthToken = async ( | ||
security: Security, | ||
options: Pick<RequestOptions, 'accessToken' | 'apiKey'>, | ||
): Promise<string | undefined> => { | ||
if (security.fn === 'accessToken') { | ||
const token = | ||
typeof options.accessToken === 'function' | ||
? await options.accessToken() | ||
: options.accessToken; | ||
return token ? `Bearer ${token}` : undefined; | ||
} | ||
if (security.fn === 'apiKey') { | ||
return typeof options.apiKey === 'function' | ||
? await options.apiKey() | ||
: options.apiKey; | ||
} | ||
}; | ||
export const setAuthParams = async ({ | ||
security, | ||
...options | ||
}: Pick<Required<RequestOptions>, 'security'> & | ||
Pick<RequestOptions, 'accessToken' | 'apiKey' | 'query'> & { | ||
headers: Headers; | ||
}) => { | ||
for (const scheme of security) { | ||
const token = await getAuthToken(scheme, options); | ||
if (!token) { | ||
continue; | ||
} | ||
if (scheme.in === 'header') { | ||
options.headers.set(scheme.name, token); | ||
} else if (scheme.in === 'query') { | ||
if (!options.query) { | ||
options.query = {}; | ||
} | ||
options.query[scheme.name] = token; | ||
} | ||
return; | ||
} | ||
}; | ||
export const buildUrl: Client['buildUrl'] = (options) => { | ||
const url = getUrl({ | ||
baseUrl: options.baseUrl ?? '', | ||
path: options.path, | ||
query: options.query, | ||
querySerializer: | ||
typeof options.querySerializer === 'function' | ||
? options.querySerializer | ||
: createQuerySerializer(options.querySerializer), | ||
url: options.url, | ||
}); | ||
return url; | ||
}; | ||
export const getUrl = ({ | ||
@@ -401,3 +462,3 @@ baseUrl, | ||
...headers: Array<Required<Config>['headers'] | undefined> | ||
) => { | ||
): Headers => { | ||
const mergedHeaders = new Headers(); | ||
@@ -404,0 +465,0 @@ for (const header of headers) { |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
136144
14
1472