@scalar/api-client
Version:
the open source API testing client
135 lines (133 loc) • 5.45 kB
JavaScript
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 P } from "../electron.js";
import { ERRORS as w, normalizeError as b } 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 c } from "../string-template.js";
import { buildRequestSecurity as se } from "./build-request-security.js";
const Ce = ({
environment: U,
example: s,
globalCookies: q,
proxyUrl: h,
request: a,
securitySchemes: v,
selectedSecuritySchemeUids: D = [],
server: k,
status: d,
pluginManager: l
}) => {
try {
const o = U ?? {}, R = new AbortController(), C = s.parameters.path.reduce((t, e) => (e.enabled && (t[e.key] = c(e.value, o)), t), {}), _ = c(k?.url ?? "", o), f = c(c(a.path, o), C);
let r = _ || f;
if (!r)
throw w.URL_EMPTY;
Object.entries(k?.variables ?? {}).forEach(([t, e]) => {
r = c(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, m]) => (t[e.toLowerCase()] = m, t),
{}
), ...B }, A = [...z, ...p.cookies], W = new URLSearchParams([...L, ...p.urlParams]);
P() && n["user-agent"] && (n["X-Scalar-User-Agent"] = n["user-agent"]), r = G(r, f, W);
const y = c(re(A, n.Cookie), o);
y && (P() || 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 x = J(h, r), S = new Request(x, {
method: a.method.toUpperCase(),
body: F ?? null,
headers: n
});
return [
null,
{
request: S,
sendRequest: async () => {
if (d?.emit("start"), l)
try {
await l.executeHook("onBeforeRequest", { request: S });
} catch (e) {
const m = new Error(w.ON_BEFORE_REQUEST_FAILED, { cause: e });
return d?.emit("abort"), [b(m), null];
}
const t = Date.now();
try {
const e = await fetch(S, {
signal: R.signal
}), m = e.headers.get("content-type")?.startsWith("text/event-stream");
d?.emit("stop");
const I = Date.now() - t, Q = e.clone(), g = Z(e.headers, H(h, r)), X = e.headers.get("content-type") ?? "text/plain;charset=UTF-8", T = await Q.arrayBuffer(), j = te(T, X), i = e.clone(), V = i.statusText || Y[i.status]?.name || "", K = [204, 205, 304].includes(i.status), u = new Response(K ? null : i.body, {
status: i.status,
statusText: V,
headers: i.headers
});
l && await l.executeHook("onResponseReceived", { response: u, operation: a });
const E = "getSetCookie" in u.headers && typeof u.headers.getSetCookie == "function" ? u.headers.getSetCookie() : [];
return m && e.body ? [
null,
{
timestamp: Date.now(),
request: s,
response: {
...u,
headers: g,
cookieHeaderKeys: E,
reader: e.body?.getReader(),
duration: I,
method: a.method,
path: f
}
}
] : [
null,
{
timestamp: Date.now(),
request: s,
response: {
...e,
headers: g,
cookieHeaderKeys: E,
data: j,
size: T.byteLength,
duration: Date.now() - t,
method: a.method,
status: e.status,
path: f
}
}
];
} catch (e) {
return d?.emit("abort"), [b(e, w.REQUEST_FAILED), null];
}
},
controller: R
}
];
} catch (o) {
return console.error(o), d?.emit("abort"), [b(o), null];
}
};
export {
Ce as createRequestOperation
};