UNPKG

@microsoft/teams.common

Version:

<p> <a href="https://www.npmjs.com/package/@microsoft/teams.common" target="_blank"> <img src="https://img.shields.io/npm/v/@microsoft/teams.common/latest" /> </a> <a href="https://www.npmjs.com/package/@microsoft/teams.common?activeTa

294 lines (292 loc) • 8.52 kB
import axios, { AxiosHeaders } from 'axios'; import { ConsoleLogger } from '../logging/index.mjs'; class Client { token; name; options; log; http; seq = 0; _interceptors; _middlewares; constructor(options = {}) { this.options = options; this.name = options.name || "http"; this.token = options.token; this.log = options.logger || new ConsoleLogger(this.name); this._interceptors = /* @__PURE__ */ new Map(); this._middlewares = /* @__PURE__ */ new Map(); this.http = axios.create({ baseURL: options.baseUrl, timeout: options.timeout, headers: options.headers }); for (const interceptor of options.interceptors || []) { this.use(interceptor); } for (const middleware of options.middlewares || []) { this.use(middleware); } } get interceptors() { return Array.from(this._interceptors.values()).map((i) => i.interceptor); } /** * Registered HTTP middleware in execution order. */ get middlewares() { return Array.from(this._middlewares.values()); } async get(url, config) { return this.invokeMiddleware({ config: { ...config, method: "get", url }, log: this.log }, 0, "method"); } async post(url, data, config) { return this.invokeMiddleware({ config: { ...config, method: "post", url, data }, log: this.log }, 0, "method"); } async put(url, data, config) { return this.invokeMiddleware({ config: { ...config, method: "put", url, data }, log: this.log }, 0, "method"); } async patch(url, data, config) { return this.invokeMiddleware({ config: { ...config, method: "patch", url, data }, log: this.log }, 0, "method"); } async delete(url, config) { return this.invokeMiddleware({ config: { ...config, method: "delete", url }, log: this.log }, 0, "method"); } async request(config) { return this.invokeMiddleware({ config, log: this.log }, 0, "request"); } use(handler) { if (isMiddleware(handler)) { return this.useMiddleware(handler); } return this.useInterceptor(handler); } /** * Eject an interceptor */ eject(id) { const registry = this._interceptors.get(id); if (!registry) { this._middlewares.delete(id); return; } if (registry.requestId !== void 0) { this.http.interceptors.request.eject(registry.requestId); } if (registry.responseId !== void 0) { this.http.interceptors.response.eject(registry.responseId); } this._interceptors.delete(id); } /** * Clear (Eject) all interceptors */ clear() { for (const id of this._interceptors.keys()) { this.eject(id); } this._middlewares.clear(); } /** * Create a copy of the client */ clone(options) { const findUA = (h) => { if (!h) return void 0; const key = Object.keys(h).find((k) => k.toLowerCase() === "user-agent"); return key ? String(h[key]) : void 0; }; const parentUA = findUA(this.options.headers); const childUA = findUA(options?.headers); const mergedUA = parentUA && childUA ? `${childUA} ${parentUA}` : childUA || parentUA; const headers = { ...this.options.headers, ...options?.headers }; if (mergedUA) { for (const key of Object.keys(headers)) { if (key.toLowerCase() === "user-agent") { delete headers[key]; } } headers["User-Agent"] = mergedUA; } return new Client({ ...this.options, ...options, headers, interceptors: [ ...Array.from(this._interceptors.values()).map((i) => i.interceptor) ], middlewares: [ ...this.middlewares ] }); } async withConfig(config = {}) { let token = config.token || this.token; const requestHasAuthorization = hasAuthorizationHeader(config.headers); if (config.token) { delete config.token; } if (this.options.headers) { config.headers = { ...this.options.headers, ...headersToObject(config.headers) }; } if (token && !requestHasAuthorization && !hasAuthorizationHeader(config.headers)) { if (!config.headers) { config.headers = {}; } if (typeof token === "function") { token = await token(config); } if (token && typeof token === "object") { token = token.toString(); } if (!token?.toString().trim()) { return config; } config.headers["Authorization"] = `Bearer ${token}`; } return config; } useMiddleware(middleware) { const id = ++this.seq; this._middlewares.set(id, middleware); return id; } /** * axios >= 1.19 types its verb methods as `AxiosResponseResult<T, R, D, P>`, a conditional keyed on an unexported marker symbol. * For any concrete `R` that conditional collapses to `R`, but TypeScript cannot prove that for an unconstrained generic, so each dispatch is asserted back to `Promise<R>`. */ async send(config, dispatch) { const resolvedConfig = await this.withConfig(config); if (dispatch === "request") { return this.http.request(resolvedConfig); } const method = resolvedConfig.method?.toLowerCase(); const url = resolvedConfig.url; if (url === void 0) { return this.http.request(resolvedConfig); } const transportConfig = { ...resolvedConfig }; delete transportConfig.method; delete transportConfig.url; switch (method) { // get/delete carry any request body on `config.data`, so the resolved // config is forwarded as-is. (Stripping `data` here previously dropped // GET/DELETE request bodies that callers passed through `config`.) case "get": return this.http.get(url, transportConfig); case "delete": return this.http.delete(url, transportConfig); // post/put/patch take the body as a positional argument, so remove it // from the forwarded config to avoid sending it in two places. case "post": { const { data, ...rest } = transportConfig; return this.http.post(url, data, rest); } case "put": { const { data, ...rest } = transportConfig; return this.http.put(url, data, rest); } case "patch": { const { data, ...rest } = transportConfig; return this.http.patch(url, data, rest); } default: return this.http.request(resolvedConfig); } } useInterceptor(interceptor) { const id = ++this.seq; let requestId = void 0; let responseId = void 0; if (interceptor.request) { requestId = this.http.interceptors.request.use( /* istanbul ignore next */ (config) => { return interceptor.request({ config, log: this.log }); }, /* istanbul ignore next */ (error) => { if (!interceptor.error) return error; return interceptor.error({ error, log: this.log }); } ); } if (interceptor.response) { responseId = this.http.interceptors.response.use( /* istanbul ignore next */ (res) => { return interceptor.response({ res, log: this.log }); }, /* istanbul ignore next */ (error) => { if (!interceptor.error) return error; return interceptor.error({ error, log: this.log }); } ); } this._interceptors.set(id, { requestId, responseId, interceptor }); return id; } async invokeMiddleware(context, index, dispatch) { const middleware = this.middlewares.at(index); if (!middleware) { return this.send(context.config, dispatch); } return middleware.invoke( context, () => this.invokeMiddleware(context, index + 1, dispatch) ); } } function isMiddleware(handler) { return typeof handler.invoke === "function"; } function hasAuthorizationHeader(headers) { if (!headers) { return false; } if (headers instanceof AxiosHeaders) { return !!headers.get("Authorization") || !!headers.get("authorization"); } return Object.keys(headers).some((key) => key.toLowerCase() === "authorization"); } function headersToObject(headers) { if (!headers) { return void 0; } if (headers instanceof AxiosHeaders) { return headers.toJSON(); } return headers; } export { Client }; //# sourceMappingURL=client.mjs.map //# sourceMappingURL=client.mjs.map