@busymango/fetch-driver
Version:
fetch with middlewares for the browser
390 lines (389 loc) • 11 kB
JavaScript
var tt = Object.defineProperty, et = Object.defineProperties;
var rt = Object.getOwnPropertyDescriptors;
var N = Object.getOwnPropertySymbols;
var x = Object.prototype.hasOwnProperty, G = Object.prototype.propertyIsEnumerable;
var O = (t, e, r) => e in t ? tt(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r, R = (t, e) => {
for (var r in e || (e = {}))
x.call(e, r) && O(t, r, e[r]);
if (N)
for (var r of N(e))
G.call(e, r) && O(t, r, e[r]);
return t;
}, U = (t, e) => et(t, rt(e));
var D = (t, e) => {
var r = {};
for (var n in t)
x.call(t, n) && e.indexOf(n) < 0 && (r[n] = t[n]);
if (t != null && N)
for (var n of N(t))
e.indexOf(n) < 0 && G.call(t, n) && (r[n] = t[n]);
return r;
};
var o = (t, e, r) => O(t, typeof e != "symbol" ? e + "" : e, r);
var y = (t, e, r) => new Promise((n, i) => {
var s = (u) => {
try {
h(r.next(u));
} catch (f) {
i(f);
}
}, a = (u) => {
try {
h(r.throw(u));
} catch (f) {
i(f);
}
}, h = (u) => u.done ? n(u.value) : Promise.resolve(u.value).then(s, a);
h((r = r.apply(t, e)).next());
});
import { isString as d, pipe as M, filter as nt, map as it, join as st, isPlainObject as X, mapValues as ot, omitBy as ct, isNullish as j, isNumber as at, isArray as F, hasAtLeast as z, isObjectType as S, isEmpty as ft, isFunction as K } from "remeda";
import ut from "mime";
function ht(t) {
return function(e, r) {
function n(i) {
if (i === t.length)
return Promise.resolve(r == null ? void 0 : r());
const s = t[i];
return Promise.resolve(
s(e, n.bind(null, i + 1))
);
}
return n(0);
};
}
function dt(t) {
return t.filter(Boolean);
}
function lt(t) {
return d(t) && t.trim() !== "";
}
const pt = (t) => at(t) ? Number.isNaN(t) : d(t) ? t.length === 0 : F(t) ? !z(t, 1) : !!(S(t) && ft(t)), yt = (t) => F(t) && z(t, 1);
function mt(t) {
return yt(t) && t.every(d);
}
function v(t) {
return Number.isFinite(t);
}
function $(t, e, r) {
return t in e && r(e[t]);
}
function Q(t) {
return t instanceof FormData;
}
function bt(t) {
return t instanceof ReadableStream;
}
function H(t) {
return t instanceof ArrayBuffer;
}
function wt(t) {
return t instanceof Uint8Array;
}
function W(t) {
return H(t) || wt(t) || S(t) && $("ArrayBuffer", t, H);
}
function At(t) {
return S(t) && $("byteLength", t, v) && $("byteOffset", t, v) && $("buffer", t, W);
}
function St(t) {
return ArrayBuffer.isView(t) || W(t) || At(t) || H(t);
}
function Y(t) {
return t instanceof URLSearchParams;
}
function gt(t) {
return t instanceof Blob;
}
function Et(t) {
return gt(t) || Q(t) || St(t) || bt(t);
}
function Tt(t) {
switch (t) {
case "css":
case "xml":
case "html":
case "plain":
case "richtext":
case "javascript":
return !0;
}
return !1;
}
function $t(t, e) {
const r = document.createElement("a");
document.body.appendChild(r), r.style.display = "none", r.download = e, r.href = t, r.click(), document.body.removeChild(r);
}
function jt(t) {
return t;
}
function Ct(t) {
if (!pt(t)) {
if (d(t) || Y(t))
return new URLSearchParams(t);
if (mt(t))
return new URLSearchParams(
M(
t,
nt((e) => e.includes("=")),
it((e) => e.trim()),
st("&")
)
);
if (X(t))
return new URLSearchParams(
M(
t,
ot((e) => e == null ? void 0 : e.toString()),
ct(j)
)
);
}
}
class Pt {
constructor(e, r, n) {
/** the fetch src */
o(this, "api");
/** the fetch init options */
o(this, "options");
/** the fetch response body (parse val) */
o(this, "body");
/** the fetch request body */
o(this, "data");
/** the fetch response */
o(this, "response");
/** the response type */
o(this, "responseType");
/** the response charset */
o(this, "responseCharset");
/** init request src */
o(this, "initApi", () => {
const { api: e, data: r } = this;
if (Y(r)) {
const n = e.split("?"), [i, ...s] = n, a = s.join("?"), h = `${r.toString()}&${a}`;
this.api = `${i}?${new URLSearchParams(h).toString()}`;
}
});
/** init request body */
o(this, "initBody", () => {
const { body: e, headers: r } = this.options;
if (j(e)) {
const { data: n } = this;
if (Et(n) && (this.options.body = n), F(n) || X(n)) {
const i = "Content-Type", s = "application/json";
this.options.body = JSON.stringify(n), !r.has(i) && r.set(i, s);
}
}
});
/** init method */
o(this, "initMethod", () => {
if (!this.options.method) {
const { body: e } = this.options;
this.options.method = j(e) ? "GET" : "POST";
}
});
/** init context */
o(this, "init", () => {
this.initApi(), this.initBody(), this.initMethod();
});
/** use `AbortController` abort cur fetch when timeout */
o(this, "initAbort", (e) => {
if (K(AbortController) && v(e)) {
const r = new AbortController();
this.options.signal = r.signal, setTimeout(() => r.abort(), e);
}
});
/** get Content-Type & charset by response header before response */
o(this, "decodeHeader", (e) => {
const { headers: r } = e, n = r.get("Content-Type");
if (lt(n)) {
const i = n.split(";");
for (const h of i) {
const { responseType: u } = this, f = ut.getExtension(h);
d(f) && !d(u) && (this.responseType = f);
}
const s = Ct(i), a = s == null ? void 0 : s.get("charset");
d(a) && (this.responseCharset = a);
}
});
const a = n != null ? n : {}, { headers: i } = a, s = D(a, ["headers"]);
this.api = e, this.data = r, this.options = U(R({}, s), {
headers: new Headers(i)
});
}
}
class vt {
}
const Z = [
"GET",
"PUT",
"POST",
"HEAD",
"TRACE",
"PATCH",
"DELETE",
"CONNECT",
"OPTIONS"
];
function _(t, e, r) {
return y(this, null, function* () {
const n = yield t.read();
n.done ? e.close() : (r == null || r(n), e.enqueue(n.value), yield _(t, e, r));
});
}
const Bt = () => (n, i, ...s) => y(void 0, [n, i, ...s], function* (t, e, r = {}) {
const { body: a, ok: h, headers: u } = t, { responseType: f } = e, c = u.get("Content-Disposition"), q = c == null ? void 0 : c.includes("attachment");
if (h) {
const { receiver: g } = r, m = Number(u.get("Content-Length")), w = v(m) && K(g);
if (a && w && m > 0) {
const l = { bytes: 0 }, A = a.getReader(), b = new ReadableStream({
start(E) {
_(A, E, ({ value: p, done: T }) => {
l.bytes += p.length, g({
done: T,
size: m,
value: p,
reader: A,
context: e,
percentage: 100 * l.bytes / m
});
});
}
});
e.response = new Response(b);
return;
}
}
if (q) {
e.body = yield t.blob();
return;
}
if (f === "txt") {
e.body = yield t.text();
return;
}
if (f === "json") {
e.body = yield t.json();
return;
}
if (Tt(f != null ? f : void 0)) {
e.body = yield t.text();
return;
}
});
function J(t, e, r) {
return S(t) ? t : R({ api: t, data: e }, r);
}
class Ft {
constructor(e = {}) {
o(this, "report");
o(this, "middleware");
o(this, "request", (u) => y(this, null, function* () {
var f = u, {
api: e,
use: r,
data: n,
timeout: i,
receiver: s,
parse: a = Bt()
} = f, h = D(f, [
"api",
"use",
"data",
"timeout",
"receiver",
"parse"
]);
const c = new Pt(e, n, h);
return yield ht(
r != null ? r : this.middleware
)(c, () => y(this, null, function* () {
var l, A, b, E, p, T, C, V, P, I, B, k;
(A = (l = this.report) == null ? void 0 : l.beforeInit) == null || A.call(l, c), c.init(), (E = (b = this.report) == null ? void 0 : b.afterInit) == null || E.call(b, c), c.initAbort(i);
const { api: g, options: m } = c;
(T = (p = this.report) == null ? void 0 : p.beforeFetch) == null || T.call(p, c);
const w = yield fetch(g, m);
(V = (C = this.report) == null ? void 0 : C.affterFetch) == null || V.call(C, c), c.response = w, c.decodeHeader(w), (I = (P = this.report) == null ? void 0 : P.beforeParse) == null || I.call(P, c), yield a(w, c, { receiver: s }), (k = (B = this.report) == null ? void 0 : B.afterParse) == null || k.call(B, c);
})), c;
}));
o(this, "drive", (...e) => y(this, null, function* () {
return (yield this.request(J(...e))).body;
}));
var n;
const r = F(e) ? { use: e } : e;
this.report = r.report, this.middleware = (n = r.use) != null ? n : [], Z.forEach((i) => {
const s = i.toLowerCase();
this.drive[s] = (...a) => y(this, null, function* () {
return (yield this.request(U(R({}, J(...a)), { method: i }))).body;
});
});
}
}
class Ot extends Error {
constructor(r, n) {
super(r, {
cause: n == null ? void 0 : n.cause
});
o(this, "code");
o(this, "context");
this.code = n == null ? void 0 : n.code, this.context = n == null ? void 0 : n.context;
}
}
const L = {
/**
* see https://fetch.spec.whatwg.org/#methods
*
* @param {any} RequestInit
*/
method: ({ method: t = "" } = {}) => {
const e = t.toUpperCase();
return Z.includes(e) ? `-X ${e}` : "-X GET";
},
/**
* @param {object={}} options
* @param {object|Headers} options.headers
* @returns {HeaderParams} An Object with the header info
*/
header: ({ headers: t } = {}) => {
if (j(t)) return;
const e = new Headers(t);
e.delete("content-length");
const r = (i, s) => `-H "${i}: ${s.replace(/(\\|")/g, "\\$1")}"`;
return Array.from(e).reduce((i, s) => [...i, r(...s)], []).join(" ");
},
body: ({ body: t } = {}) => {
if (Q(t))
return Array.from(t).map(([i, s]) => `-F "${i}=${s}"`).join(" ");
function e(n) {
if (d(n)) return n.replace(/'/g, "'\\''");
if (S(n)) return e(JSON.stringify(n));
}
const r = e(t != null ? t : void 0);
if (d(r)) return `--data-binary '${r}'`;
},
compress: ({ headers: t } = {}) => {
var e;
return (e = new Headers(t)) != null && e.has("accept-encoding") ? " --compressed" : "";
}
}, Ut = (t, e) => {
const r = d(t) ? t : t.toString();
return dt([
"curl",
`"${r}"`,
L.method(e),
L.header(e),
L.body(e),
L.compress(e)
]).join(" ").trim();
};
export {
Pt as DriveContext,
vt as DriveReport,
Ot as FetchError,
jt as createMiddleware,
Ft as default,
$t as downloader,
Ut as fetch2curl,
Et as isNonRawBodyInit,
Tt as isRawTextBody,
Z as methods
};