UNPKG

@scalar/api-client

Version:

the open source API testing client

141 lines (139 loc) 5.54 kB
import { isDefined as N } from "@scalar/helpers/array/is-defined"; import { httpStatusCodes as Y } from "@scalar/helpers/http/http-status-codes"; import { mergeUrls as G } from "@scalar/helpers/url/merge-urls"; import { shouldUseProxy as H, redirectToProxy as J } from "@scalar/oas-utils/helpers"; import { isElectron as U } from "../electron.js"; import { ERRORS as b, normalizeError as w } from "../errors.js"; import { normalizeHeaders as Z } from "../normalize-headers.js"; import { createFetchBody as $ } from "./create-fetch-body.js"; import { createFetchHeaders as M } from "./create-fetch-headers.js"; import { createFetchQueryParams as ee } from "./create-fetch-query-params.js"; import { decodeBuffer as te } from "./decode-buffer.js"; import { setRequestCookies as oe, getCookieHeader as re } from "./set-request-cookies.js"; import { replaceTemplateVariables as d } from "../string-template.js"; import { buildRequestSecurity as se } from "./build-request-security.js"; const Ce = ({ environment: P, example: s, globalCookies: q, proxyUrl: h, request: a, securitySchemes: v, selectedSecuritySchemeUids: D = [], server: R, status: u, pluginManager: l }) => { try { const o = P ?? {}, k = new AbortController(), C = s.parameters.path.reduce((t, e) => { if (e.enabled) { const i = d(e.value, o); t[e.key] = encodeURIComponent(i); } return t; }, {}), _ = d(R?.url ?? "", o), f = d(d(a.path, o), C); let r = _ || f; if (!r) throw b.URL_EMPTY; Object.entries(R?.variables ?? {}).forEach(([t, e]) => { r = d(r, { [t]: C[t] || e.default }); }); const L = ee(s, o, a), B = M(s, o), { body: F } = $(a.method, s, o), { cookieParams: z } = oe({ example: s, env: o, globalCookies: q, serverUrl: r, proxyUrl: h }), O = D.flat().map((t) => v[t]).filter(N), p = se(O, o), n = { ...Object.entries(p.headers).reduce( (t, [e, i]) => (t[e.toLowerCase()] = i, t), {} ), ...B }, A = [...z, ...p.cookies], I = new URLSearchParams([...L, ...p.urlParams]); U() && n["user-agent"] && (n["X-Scalar-User-Agent"] = n["user-agent"]), r = G(r, f, I); const y = d(re(A, n.Cookie), o); y && (U() || H(h, 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"] = y) : (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 = y)); const W = J(h, r), S = new Request(W, { method: a.method.toUpperCase(), body: F ?? null, headers: n }); return [ null, { request: S, sendRequest: async () => { if (u?.emit("start"), l) try { await l.executeHook("onBeforeRequest", { request: S }); } catch (e) { const i = new Error(b.ON_BEFORE_REQUEST_FAILED, { cause: e }); return u?.emit("abort"), [w(i), null]; } const t = Date.now(); try { const e = await fetch(S, { signal: k.signal }), i = e.headers.get("content-type")?.startsWith("text/event-stream"); u?.emit("stop"); const x = Date.now() - t, Q = e.clone(), g = Z(e.headers, H(h, r)), V = e.headers.get("content-type") ?? "text/plain;charset=UTF-8", T = await Q.arrayBuffer(), X = te(T, V), c = e.clone(), j = c.statusText || Y[c.status]?.name || "", K = [204, 205, 304].includes(c.status), m = new Response(K ? null : c.body, { status: c.status, statusText: j, headers: c.headers }); l && await l.executeHook("onResponseReceived", { response: m, operation: a }); const E = "getSetCookie" in m.headers && typeof m.headers.getSetCookie == "function" ? m.headers.getSetCookie() : []; return i && e.body ? [ null, { timestamp: Date.now(), request: s, response: { ...m, headers: g, cookieHeaderKeys: E, reader: e.body?.getReader(), duration: x, method: a.method, path: f } } ] : [ null, { timestamp: Date.now(), request: s, response: { ...e, headers: g, cookieHeaderKeys: E, data: X, size: T.byteLength, duration: Date.now() - t, method: a.method, status: e.status, path: f } } ]; } catch (e) { return u?.emit("abort"), [w(e, b.REQUEST_FAILED), null]; } }, controller: k } ]; } catch (o) { return console.error(o), u?.emit("abort"), [w(o), null]; } }; export { Ce as createRequestOperation };