UNPKG

@scalar/api-client

Version:

the open source API testing client

126 lines (124 loc) 5.08 kB
import { ERRORS as T, normalizeError as H } from "../errors.js"; import { normalizeHeaders as Y } from "../normalize-headers.js"; import { createFetchBody as G } from "./create-fetch-body.js"; import { createFetchHeaders as J } from "./create-fetch-headers.js"; import { createFetchQueryParams as N } from "./create-fetch-query-params.js"; import { decodeBuffer as Z } from "./decode-buffer.js"; import { setRequestCookies as $, getCookieHeader as M } from "./set-request-cookies.js"; import { replaceTemplateVariables as c } from "../string-template.js"; import { isElectron as P } from "../electron.js"; import { isDefined as ee, mergeUrls as te, shouldUseProxy as U, redirectToProxy as oe, httpStatusCodes as re } from "@scalar/oas-utils/helpers"; import { buildRequestSecurity as se } from "./build-request-security.js"; const be = ({ environment: q, example: s, globalCookies: v, proxyUrl: u, request: a, securitySchemes: D, selectedSecuritySchemeUids: E = [], server: k, status: m, pluginManager: h }) => { try { const o = q ?? {}, b = new AbortController(), w = s.parameters.path.reduce((t, e) => (e.enabled && (t[e.key] = c(e.value, o)), t), {}), L = c(k?.url ?? "", o), l = c(c(a.path, o), w); let r = L || l; if (!r) throw T.URL_EMPTY; Object.entries(k?.variables ?? {}).forEach(([t, e]) => { r = c(r, { [t]: w[t] || e.default }); }); const z = N(s, o, a), B = J(s, o), { body: F } = G(a.method, s, o), { cookieParams: _ } = $({ example: s, env: o, globalCookies: v, serverUrl: r, proxyUrl: u }), O = E.flat().map((t) => D[t]).filter(ee), f = se(O, o), n = { ...Object.entries(f.headers).reduce( (t, [e, S]) => (t[e.toLowerCase()] = S, t), {} ), ...B }, W = [..._, ...f.cookies], x = new URLSearchParams([...z, ...f.urlParams]); P() && n["user-agent"] && (n["X-Scalar-User-Agent"] = n["user-agent"]), r = te(r, l, x); const p = c(M(W, n.Cookie), o); p && (P() || U(u, r) ? (console.warn( "We're using a `X-Scalar-Cookie` custom header to the request. The proxy will forward this as a `Cookie` header. We do this to avoid the browser omitting the `Cookie` header for cross-origin requests for security reasons." ), n["X-Scalar-Cookie"] = p) : (console.warn( `We're trying to add a Cookie header, but browsers often omit them for cross-origin requests for various security reasons. If it's not working, that's probably why. Here are the requirements for it to work: - The browser URL must be on the same domain as the server URL. - The connection must be made over HTTPS. ` ), n.Cookie = p)); const A = oe(u, r), y = new Request(A, { method: a.method.toUpperCase(), body: F ?? null, headers: n }); return [ null, { request: y, sendRequest: async () => { m?.emit("start"), h && h.executeHook("onBeforeRequest", { request: y }); const t = Date.now(); try { const e = await fetch(y, { signal: b.signal }), S = e.headers.get("content-type")?.startsWith("text/event-stream"); m?.emit("stop"); const X = Date.now() - t, j = e.clone(), R = Y(e.headers, U(u, r)), I = e.headers.get("content-type") ?? "text/plain;charset=UTF-8", C = await j.arrayBuffer(), Q = Z(C, I), i = e.clone(), V = i.statusText || re[i.status]?.name || "", K = [204, 205, 304].includes(i.status), d = new Response(K ? null : i.body, { status: i.status, statusText: V, headers: i.headers }); h && h.executeHook("onResponseReceived", { response: d, operation: a }); const g = "getSetCookie" in d.headers && typeof d.headers.getSetCookie == "function" ? d.headers.getSetCookie() : []; return S && e.body ? [ null, { timestamp: Date.now(), request: s, response: { ...d, headers: R, cookieHeaderKeys: g, reader: e.body?.getReader(), duration: X, method: a.method, path: l } } ] : [ null, { timestamp: Date.now(), request: s, response: { ...e, headers: R, cookieHeaderKeys: g, data: Q, size: C.byteLength, duration: Date.now() - t, method: a.method, status: e.status, path: l } } ]; } catch (e) { return m?.emit("abort"), [H(e, T.REQUEST_FAILED), null]; } }, controller: b } ]; } catch (o) { return console.error(o), m?.emit("abort"), [H(o), null]; } }; export { be as createRequestOperation };