Skip to content

Instantly share code, notes, and snippets.

@guest271314
Created April 21, 2024 18:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guest271314/72a0ad0220f8b93f10d816bc084f7881 to your computer and use it in GitHub Desktop.
Save guest271314/72a0ad0220f8b93f10d816bc084f7881 to your computer and use it in GitHub Desktop.
L-Blondy up-fetch bundled with bun buil
// response-error.ts
class ResponseError extends Error {
name;
response;
options;
data;
constructor(res, data, options) {
super(`Request failed with status ${res.status}`);
this.data = data;
this.name = "ResponseError";
this.response = res;
this.options = options;
}
}
var isResponseError = (error) => error instanceof ResponseError;
// default-options.ts
var defaultOptions = {
parseResponse: (res) => res.clone().json().catch(() => res.text()).then((data) => data || null),
parseResponseError: async (res, options) => new ResponseError(res, await defaultOptions.parseResponse(res, {}), options),
serializeParams: (params) => new URLSearchParams(JSON.parse(JSON.stringify(params))).toString(),
serializeBody: (val) => JSON.stringify(val)
};
// utils.ts
var mergeHeaders = (...headerInits) => {
let res = {};
headerInits.forEach((init) => {
new Headers(init).forEach((value, key) => {
if (value === "null" || value === "undefined") {
delete res[key];
} else {
res[key] = value;
}
});
});
return res;
};
var buildParams = (upParams, input, fetcherParams) => isRequest(input) ? {} : strip({
...strip(upParams, [
...new URL(input, "http://a").searchParams.keys()
]),
...fetcherParams
});
var strip = (obj, keys = []) => {
let copy = { ...obj };
for (let key in copy) {
if (keys.includes(key) || copy[key] === undefined)
delete copy[key];
}
return copy;
};
var isJsonifiableObjectOrArray = (body) => {
if (!body || typeof body !== "object")
return false;
return body?.constructor?.name === "Object" || Array.isArray(body) || typeof body?.toJSON === "function";
};
var withPrefix = (prefix, str) => !str ? "" : str.startsWith(prefix) ? str : `${prefix}${str}`;
var isRequest = (input) => {
return !!input.url;
};
var emptyOptions = {};
// build-options.ts
var eventListeners = [
"onSuccess",
"onBeforeFetch",
"onParsingError",
"onResponseError",
"onRequestError"
];
var buildOptions = (input, upOpts = emptyOptions, fetcherOpts = emptyOptions) => ({
...{},
...defaultOptions,
...strip(upOpts, eventListeners),
...strip(fetcherOpts, eventListeners),
headers: mergeHeaders(isJsonifiableObjectOrArray(fetcherOpts.body) ? { "content-type": "application/json" } : {}, upOpts.headers, fetcherOpts.headers),
params: buildParams(upOpts.params, input, fetcherOpts.params),
rawBody: fetcherOpts.body,
get body() {
return isJsonifiableObjectOrArray(this.rawBody) ? this.serializeBody(this.rawBody) : this.rawBody;
},
get input() {
if (isRequest(input))
return input;
if (input instanceof URL)
return input.toString();
let base = this.baseUrl ? new URL(this.baseUrl) : undefined;
let path = [base?.pathname, input.toString()].map((str) => str?.startsWith("/") ? str.slice(1) : str).filter(Boolean).join("/");
let url = new URL(path, base?.origin);
let serializedParams = this.serializeParams(this.params);
return `${url.href}${withPrefix(url.search ? "&" : "?", serializedParams)}`;
}
});
// up.ts
function up(fetchFn, getUpOptions = () => emptyOptions) {
return (input, upfetchOptions = emptyOptions) => {
let upOptions = getUpOptions();
let upfetchOpts = typeof upfetchOptions === "function" ? upfetchOptions(upOptions) : upfetchOptions;
let options = buildOptions(input, upOptions, upfetchOpts);
upfetchOpts.onBeforeFetch?.(options);
upOptions.onBeforeFetch?.(options);
return fetchFn(options.input, options).catch((error) => {
upfetchOpts.onRequestError?.(error, options);
upOptions.onRequestError?.(error, options);
throw error;
}).then(async (res) => {
if (res.ok) {
let data;
try {
data = await options.parseResponse(res, options);
} catch (error) {
upfetchOpts.onParsingError?.(error, options);
upOptions.onParsingError?.(error, options);
throw error;
}
upfetchOpts.onSuccess?.(data, options);
upOptions.onSuccess?.(data, options);
return data;
} else {
let respError;
try {
respError = await options.parseResponseError(res, options);
} catch (error) {
upfetchOpts.onParsingError?.(error, options);
upOptions.onParsingError?.(error, options);
throw error;
}
upfetchOpts.onResponseError?.(respError, options);
upOptions.onResponseError?.(respError, options);
throw respError;
}
});
};
}
// parsers/zod.ts
function withZod(schema) {
return async (response, options) => schema.parse(await defaultOptions.parseResponse(response, options));
}
// ../node_modules/valibot/dist/index.js
var getGlobalConfig = function(config) {
return {
lang: config?.lang ?? store?.lang,
message: config?.message,
abortEarly: config?.abortEarly ?? store?.abortEarly,
abortPipeEarly: config?.abortPipeEarly ?? store?.abortPipeEarly,
skipPipe: config?.skipPipe ?? store?.skipPipe
};
};
var parse = function(schema, input, config) {
const result = schema._parse(input, getGlobalConfig(config));
if (result.issues) {
throw new ValiError(result.issues);
}
return result.output;
};
var ValiError = class extends Error {
issues;
constructor(issues) {
super(issues[0].message);
this.name = "ValiError";
this.issues = issues;
}
};
var BrandSymbol = Symbol("brand");
var store;
// parsers/valibot.ts
function withValibot(schema) {
return async (response, options) => parse(schema, await defaultOptions.parseResponse(response, options));
}
export {
withZod,
withValibot,
up,
isResponseError,
defaultOptions,
ResponseError
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment