@zayne-labs/callapi
Version:
A lightweight wrapper over fetch with quality of life improvements like built-in request cancellation, retries, interceptors and more
230 lines (224 loc) • 7.65 kB
JavaScript
import { t as extraOptionDefaults } from "./defaults-B-dOt2Dd.js";
//#region src/utils/guards.ts
const isArray = (value) => Array.isArray(value);
const isBoolean = (value) => typeof value === "boolean";
const isBlob = (value) => value instanceof Blob;
const isObject = (value) => {
return typeof value === "object" && value !== null;
};
const hasObjectPrototype = (value) => {
return Object.prototype.toString.call(value) === "[object Object]";
};
/**
* @description Copied from TanStack Query's isPlainObject
* @see https://github.com/TanStack/query/blob/main/packages/query-core/src/utils.ts#L321
*/
const isPlainObject = (value) => {
if (!hasObjectPrototype(value)) return false;
const constructor = value?.constructor;
if (constructor === void 0) return true;
const prototype = constructor.prototype;
if (!hasObjectPrototype(prototype)) return false;
if (!Object.hasOwn(prototype, "isPrototypeOf")) return false;
if (Object.getPrototypeOf(value) !== Object.prototype) return false;
return true;
};
const isValidJsonString = (value) => {
if (!isString(value)) return false;
try {
JSON.parse(value);
return true;
} catch {
return false;
}
};
const isSerializableObject = (value) => {
return isPlainObject(value) || isArray(value) || typeof value?.toJSON === "function";
};
const isFunction = (value) => typeof value === "function";
const isQueryString = (value) => isString(value) && value.includes("=");
const isString = (value) => typeof value === "string";
const isPromise = (value) => value instanceof Promise;
const isReadableStream = (value) => {
return value instanceof ReadableStream;
};
//#endregion
//#region src/utils/external/body.ts
const toStringOrStringify = (value) => {
return isString(value) ? value : JSON.stringify(value);
};
const toQueryString = (data) => {
const queryString = new URLSearchParams();
for (const [key, value] of Object.entries(data)) {
if (value == null) continue;
if (isArray(value)) {
for (const innerValue of value) queryString.append(key, toStringOrStringify(innerValue));
continue;
}
queryString.set(key, toStringOrStringify(value));
}
return queryString.toString();
};
const toBlobOrString = (value) => {
return isBlob(value) ? value : String(value);
};
/**
* @description Converts a plain object to FormData.
*
* Handles various data types:
* - **Primitives** (string, number, boolean): Converted to strings
* - **Blobs/Files**: Added directly to FormData
* - **Arrays**: Each item is appended (allows multiple values for same key)
* - **Objects**: JSON stringified before adding to FormData
*
* @example
* ```ts
* // Basic usage
* const formData = toFormData({
* name: "John",
* age: 30,
* active: true
* });
*
* // With arrays
* const formData = toFormData({
* tags: ["javascript", "typescript"],
* name: "John"
* });
*
* // With files
* const formData = toFormData({
* avatar: fileBlob,
* name: "John"
* });
*
* // With nested objects (one level only)
* const formData = toFormData({
* user: { name: "John", age: 30 },
* settings: { theme: "dark" }
* });
*/
const toFormData = (data) => {
const formData = new FormData();
for (const [key, value] of Object.entries(data)) {
if (isArray(value)) {
for (const innerValue of value) formData.append(key, toBlobOrString(innerValue));
continue;
}
if (isObject(value) && !isBlob(value)) {
formData.set(key, JSON.stringify(value));
continue;
}
formData.set(key, toBlobOrString(value));
}
return formData;
};
//#endregion
//#region src/utils/external/error.ts
const httpErrorSymbol = Symbol("HTTPError");
var HTTPError = class HTTPError extends Error {
errorData;
httpErrorSymbol = httpErrorSymbol;
name = "HTTPError";
response;
constructor(errorDetails, errorOptions) {
const { defaultHTTPErrorMessage, errorData, response } = errorDetails;
const selectedDefaultErrorMessage = (isString(defaultHTTPErrorMessage) ? defaultHTTPErrorMessage : defaultHTTPErrorMessage?.({
errorData,
response
})) ?? (response.statusText || extraOptionDefaults.defaultHTTPErrorMessage);
const message = errorData?.message ?? selectedDefaultErrorMessage;
super(message, errorOptions);
this.errorData = errorData;
this.response = response;
}
/**
* @description Checks if the given error is an instance of HTTPError
* @param error - The error to check
* @returns true if the error is an instance of HTTPError, false otherwise
*/
static isError(error) {
if (!isObject(error)) return false;
if (error instanceof HTTPError) return true;
const actualError = error;
return actualError.httpErrorSymbol === httpErrorSymbol && actualError.name === "HTTPError";
}
};
const prettifyPath = (path) => {
if (!path || path.length === 0) return "";
return ` → at ${path.map((segment) => isObject(segment) ? segment.key : segment).join(".")}`;
};
const prettifyValidationIssues = (issues) => {
return issues.map((issue) => `✖ ${issue.message}${prettifyPath(issue.path)}`).join(" | ");
};
const validationErrorSymbol = Symbol("ValidationErrorSymbol");
var ValidationError = class ValidationError extends Error {
errorData;
issueCause;
name = "ValidationError";
response;
validationErrorSymbol = validationErrorSymbol;
constructor(details, errorOptions) {
const { issueCause, issues, response } = details;
const prettyMessage = prettifyValidationIssues(issues);
const message = `(${issueCause.toUpperCase()}) - ${prettyMessage}`;
super(message, errorOptions);
this.errorData = issues;
this.response = response;
this.issueCause = issueCause;
}
/**
* @description Checks if the given error is an instance of ValidationError
* @param error - The error to check
* @returns true if the error is an instance of ValidationError, false otherwise
*/
static isError(error) {
if (!isObject(error)) return false;
if (error instanceof ValidationError) return true;
const actualError = error;
return actualError.validationErrorSymbol === validationErrorSymbol && actualError.name === "ValidationError";
}
};
//#endregion
//#region src/utils/external/define.ts
const defineSchema = (routes, config) => {
return {
config: defineSchemaConfig(config),
routes: defineSchemaRoutes(routes)
};
};
const defineSchemaRoutes = (routes) => {
return routes;
};
const defineMainSchema = (mainSchema) => {
return mainSchema;
};
const defineSchemaConfig = (config) => {
return config;
};
const definePlugin = (plugin) => {
return plugin;
};
const defineBaseConfig = (baseConfig) => {
return baseConfig;
};
//#endregion
//#region src/utils/external/guards.ts
const isHTTPError = (error) => {
return isObject(error) && error.name === "HTTPError";
};
const isHTTPErrorInstance = (error) => {
return HTTPError.isError(error);
};
const isValidationError = (error) => {
return isObject(error) && error.name === "ValidationError";
};
const isValidationErrorInstance = (error) => {
return ValidationError.isError(error);
};
const isJavascriptError = (error) => {
return isObject(error) && !isHTTPError(error) && !isValidationError(error);
};
//#endregion
export { isReadableStream as C, isValidJsonString as E, isQueryString as S, isString as T, isBoolean as _, isValidationErrorInstance as a, isPlainObject as b, definePlugin as c, defineSchemaRoutes as d, HTTPError as f, isArray as g, toQueryString as h, isValidationError as i, defineSchema as l, toFormData as m, isHTTPErrorInstance as n, defineBaseConfig as o, ValidationError as p, isJavascriptError as r, defineMainSchema as s, isHTTPError as t, defineSchemaConfig as u, isFunction as v, isSerializableObject as w, isPromise as x, isObject as y };
//# sourceMappingURL=external-DXaCWLPN.js.map