1000fetches 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +94 -68
- package/dist/client-C7dvgNnD.js +2 -0
- package/dist/client-C7dvgNnD.js.map +1 -0
- package/dist/client-DOv6m2TJ.mjs +2 -0
- package/dist/client-DOv6m2TJ.mjs.map +1 -0
- package/dist/client.d.ts +22 -0
- package/dist/core.d.ts +57 -0
- package/dist/errors.d.ts +76 -0
- package/dist/http.cjs +2 -0
- package/dist/http.cjs.map +1 -0
- package/dist/http.d.ts +9 -0
- package/dist/http.mjs +2 -0
- package/dist/http.mjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +15 -347
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/schema.d.ts +35 -0
- package/dist/types.d.ts +145 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/path.d.ts +73 -0
- package/dist/utils/streaming.d.ts +9 -0
- package/docs/API.md +754 -0
- package/docs/BEST_PRACTICES.md +606 -0
- package/docs/MIGRATION.md +719 -0
- package/package.json +40 -53
- package/dist/index.cjs.js +0 -2
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.es.js +0 -793
- package/dist/index.es.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-DOv6m2TJ.mjs","names":[],"sources":["../src/errors.ts","../src/utils/path.ts","../src/utils/streaming.ts","../src/core.ts","../src/schema.ts","../src/client.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec'\n\ninterface HttpClientError {\n name: string\n message: string\n cause?: Error\n stack?: string\n}\n\nfunction formatErrorData(data: unknown): string {\n if (data === null || data === undefined || data === '') {\n return 'No response data'\n }\n\n let dataString: string\n\n try {\n dataString = typeof data === 'string' ? data : JSON.stringify(data)\n } catch {\n dataString = String(data)\n }\n\n return dataString.length > 500\n ? dataString.substring(0, 500) + '...'\n : dataString\n}\n\nexport class HttpError<TErrorData = unknown>\n extends Error\n implements HttpClientError\n{\n public readonly name = 'HttpError'\n public readonly status: number\n public readonly statusText: string\n public readonly data: TErrorData\n public readonly response: Response\n public readonly url: string\n public readonly method: string\n public override readonly cause?: Error\n\n constructor(\n message: string,\n status: number,\n statusText: string,\n data: TErrorData,\n response: Response,\n url: string,\n method: string,\n cause?: Error\n ) {\n const statusCategory =\n status >= 500\n ? 'Server Error'\n : status >= 400\n ? 'Client Error'\n : status >= 300\n ? 'Redirect'\n : 'Success'\n\n const enhancedMessage = `HTTP ${statusCategory} (${status}): ${message}\nRequest: ${method} ${url}\nData: ${formatErrorData(data)}`\n\n super(enhancedMessage, { cause })\n this.status = status\n this.statusText = statusText\n this.data = data\n this.response = response\n this.url = url\n this.method = method\n this.cause = cause\n }\n}\n\nexport class NetworkError extends Error implements HttpClientError {\n public readonly name = 'NetworkError'\n public override readonly cause?: Error\n\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n this.cause = cause\n }\n}\n\nexport class SchemaValidationError extends Error implements HttpClientError {\n public readonly name = 'SchemaValidationError'\n public readonly schema: unknown\n public readonly data: unknown\n public readonly issues?: ReadonlyArray<StandardSchemaV1.Issue>\n public override readonly cause?: Error\n\n constructor(\n message: string,\n schema: unknown,\n data: unknown,\n cause?: Error,\n issues?: ReadonlyArray<StandardSchemaV1.Issue>\n ) {\n super(message, { cause })\n this.schema = schema\n this.data = data\n this.issues = issues\n this.cause = cause\n }\n}\n\nexport class TimeoutError extends Error implements HttpClientError {\n public readonly name = 'TimeoutError'\n public override readonly cause?: Error\n\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n this.cause = cause\n }\n}\n\nexport class PathParameterError extends Error implements HttpClientError {\n public readonly name = 'PathParameterError'\n public readonly url: string\n public readonly requiredParams: string[]\n public readonly providedParams: string[]\n public override readonly cause?: Error\n\n constructor(\n message: string,\n url: string,\n requiredParams: string[],\n providedParams: string[],\n cause?: Error\n ) {\n const enhancedMessage = `${message}\nURL Template: ${url}\nExpected: [${requiredParams.map(p => `\"${p}\"`).join(', ')}], Actual: [${providedParams.map(p => `\"${p}\"`).join(', ')}]`\n\n super(enhancedMessage, { cause })\n this.url = url\n this.requiredParams = requiredParams\n this.providedParams = providedParams\n this.cause = cause\n }\n}\n\nexport class MiddlewareError extends Error implements HttpClientError {\n public readonly name = 'MiddlewareError'\n public readonly type: 'request' | 'response'\n public readonly url?: string\n public readonly method?: string\n public override readonly cause?: Error\n\n constructor(\n message: string,\n type: 'request' | 'response',\n url?: string,\n method?: string,\n cause?: Error\n ) {\n const requestInfo = url ? `Request: ${method || 'UNKNOWN'} ${url}` : ''\n const enhancedMessage = requestInfo ? `${message}\\n${requestInfo}` : message\n\n super(enhancedMessage, { cause })\n this.type = type\n this.url = url\n this.method = method\n this.cause = cause\n }\n}\n\nexport class SerializationError extends Error implements HttpClientError {\n public readonly name = 'SerializationError'\n public override readonly cause?: Error\n\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n this.cause = cause\n }\n}\n\nexport class InvalidSchemaError extends Error implements HttpClientError {\n public readonly name = 'InvalidSchemaError'\n public readonly schema: unknown\n public override readonly cause?: Error\n\n constructor(message: string, schema: unknown, cause?: Error) {\n super(message, { cause })\n this.schema = schema\n this.cause = cause\n }\n}\n\nexport class AsyncSchemaValidationError\n extends Error\n implements HttpClientError\n{\n public readonly name = 'AsyncSchemaValidationError'\n public readonly schema: unknown\n public override readonly cause?: Error\n\n constructor(message: string, schema: unknown, cause?: Error) {\n super(message, { cause })\n this.schema = schema\n this.cause = cause\n }\n}\n\nexport class InvalidBaseUrlError extends Error implements HttpClientError {\n public readonly name = 'InvalidBaseUrlError'\n public readonly baseUrl: string\n public override readonly cause?: Error\n\n constructor(message: string, baseUrl: string, cause?: Error) {\n const enhancedMessage = `${message}\nBase URL: ${baseUrl}`\n\n super(enhancedMessage, { cause })\n this.baseUrl = baseUrl\n this.cause = cause\n }\n}\n","import { PathParameterError } from '../errors'\n\n/**\n * Strips protocol from URL (e.g., https://, http://)\n */\ntype StripProtocol<T extends string> = T extends `${string}://${infer After}`\n ? After\n : T\n\n/**\n * Strips host and optional port from URL, keeping only the path\n * Handles cases like \"localhost:3000/users\" -> \"/users\"\n */\ntype StripHost<T extends string> = T extends `${infer _Host}/${infer Path}`\n ? `/${Path}`\n : T\n\n/**\n * Strips query string from path (e.g., \"/users?x=1\" -> \"/users\")\n * Only strips ? that comes after the path, not ? that's part of path parameters\n */\ntype StripQuery<T extends string> = T extends `${infer Path}?${infer Query}`\n ? Query extends\n | `${string}=${string}`\n | `${string}&${string}`\n | `${string}=${string}&${string}`\n ? Path // Contains query parameters (has = or &)\n : Query extends `/${string}`\n ? T // It's another path segment, not a query\n : Query extends ``\n ? T // It's an optional param marker (?)\n : Path // Plain query params like ?param\n : T\n\n/**\n * Normalizes URL to path only, stripping protocol, host, port, and query\n */\ntype NormalizePath<T extends string> = StripQuery<StripHost<StripProtocol<T>>>\n\n/**\n * Removes optional suffix from param name (e.g., \":id?\" -> \"id\", \":id\" -> \"id\")\n */\ntype CleanParamName<S extends string> = S extends `:${infer Name}?`\n ? Name\n : S extends `:${infer Name}`\n ? Name\n : S\n\n/**\n * Extracts required path parameters from a route\n */\ntype ExtractRequiredRouteParams<T extends string> =\n NormalizePath<T> extends `${infer _Before}:${infer AfterColon}`\n ? AfterColon extends `${infer Param}/${infer Rest}`\n ? Param extends `${string}?`\n ? ExtractRequiredRouteParams<`/${Rest}`>\n : CleanParamName<`:${Param}`> | ExtractRequiredRouteParams<`/${Rest}`>\n : AfterColon extends `${string}?`\n ? never\n : CleanParamName<`:${AfterColon}`>\n : never\n\n/**\n * Extracts optional path parameters from a route\n */\ntype ExtractOptionalRouteParams<T extends string> =\n NormalizePath<T> extends `${infer _Before}:${infer AfterColon}`\n ? AfterColon extends `${infer Param}/${infer Rest}`\n ?\n | (Param extends `${string}?` ? CleanParamName<`:${Param}`> : never)\n | ExtractOptionalRouteParams<`/${Rest}`>\n : AfterColon extends `${string}?`\n ? CleanParamName<`:${AfterColon}`>\n : never\n : never\n\ntype ExtractRouteParams<T extends string> =\n | ExtractRequiredRouteParams<T>\n | ExtractOptionalRouteParams<T>\n\ntype HasNonTrailingOptionalRouteParams<T extends string> = string extends T\n ? false\n : NormalizePath<T> extends `${infer _Before}:${infer AfterColon}`\n ? AfterColon extends `${infer Param}/${infer Rest}`\n ? Param extends `${string}?`\n ? true\n : HasNonTrailingOptionalRouteParams<`/${Rest}`>\n : false\n : false\n\nexport type AssertSupportedPath<Path extends string> = string extends Path\n ? Path\n : HasNonTrailingOptionalRouteParams<Path> extends true\n ? never\n : Path\n\nexport type HasRequiredParams<T extends string> = [\n ExtractRequiredRouteParams<T>,\n] extends [never]\n ? false\n : true\n\ntype HasPathParams<T extends string> = [ExtractRouteParams<T>] extends [never]\n ? false\n : true\n\ntype Simplify<T> = { [K in keyof T]: T[K] }\n\n/**\n * PathParams type - extracts parameter names and their types\n */\nexport type PathParams<Path extends string> = [\n AssertSupportedPath<Path>,\n] extends [never]\n ? never\n : Simplify<\n {\n [K in ExtractRequiredRouteParams<Path>]: string | number\n } & {\n [K in ExtractOptionalRouteParams<Path>]?: string | number\n }\n >\n\n/**\n * RequirePathParams enforces pathParams when needed\n */\nexport type RequirePathParams<Path extends string, T> = [\n AssertSupportedPath<Path>,\n] extends [never]\n ? never\n : HasRequiredParams<Path> extends true\n ? T & { pathParams: PathParams<Path> }\n : HasPathParams<Path> extends true\n ? T & { pathParams?: PathParams<Path> }\n : T\n\n/**\n * Interpolates parameters into a URL template\n * Similar to React Router's generatePath function\n *\n * @example\n * ```ts\n * const path = generatePath('/users/:id/posts/:postId', { id: '123', postId: '456' });\n * // => '/users/123/posts/456'\n * ```\n */\nexport function generatePath<Path extends string>(\n path: AssertSupportedPath<Path>\n): string\nexport function generatePath<Path extends string>(\n path: AssertSupportedPath<Path>,\n params: PathParams<Path>\n): string\nexport function generatePath(\n path: string,\n params: Record<string, string | number | undefined> = {}\n): string {\n validateSupportedOptionalPath(path, Object.keys(params))\n\n return path.replace(\n /(^|\\/):([^/\\s?#]+?)(\\?)?(?=\\/|$|[?#])/g,\n (_match, prefix: string, paramName: string, optionalMarker?: string) => {\n const isOptional = optionalMarker === '?'\n\n // Validate parameter name\n if (!/^[a-zA-Z0-9_]+$/.test(paramName)) {\n throw new PathParameterError(\n `Invalid path parameter name: \"${paramName}\"`,\n path,\n [paramName],\n Object.keys(params)\n )\n }\n\n // Get and validate parameter value\n const paramValue = params[paramName]\n\n if (paramValue === undefined) {\n if (isOptional) {\n return ''\n }\n\n throw new PathParameterError(\n `Missing required path parameter: \"${paramName}\"`,\n path,\n [paramName],\n Object.keys(params)\n )\n }\n\n return `${prefix}${encodeURIComponent(String(paramValue))}`\n }\n )\n}\n\nfunction validateSupportedOptionalPath(\n path: string,\n providedParams: string[]\n): void {\n const invalidOptionalMatch = path.match(/(^|\\/):([^/\\s?#]+)\\?(?=\\/)/)\n\n if (!invalidOptionalMatch) {\n return\n }\n\n const [, , paramName] = invalidOptionalMatch\n\n throw new PathParameterError(\n `Optional path parameter \"${paramName}\" is not supported here. Optional path parameters are only supported at the end of the path.`,\n path,\n [paramName],\n providedParams\n )\n}\n","import type { DownloadStreamingEvent, UploadStreamingEvent } from '../types'\n\nfunction createStreamingStream(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n onChunk: (\n chunk: Uint8Array,\n totalBytes: number | undefined,\n transferredBytes: number\n ) => void,\n totalBytes: number | undefined,\n signal?: AbortSignal\n): ReadableStream<Uint8Array> {\n let transferredBytes = 0\n let readerReleased = false\n let isAborted = false\n\n const releaseReader = () => {\n if (!readerReleased) {\n readerReleased = true\n try {\n reader.releaseLock()\n } catch {\n // Reader might already be released, ignore\n }\n }\n }\n\n // Handle abort signal\n const abortHandler = () => {\n isAborted = true\n releaseReader()\n }\n\n signal?.addEventListener('abort', abortHandler)\n\n return new ReadableStream({\n async start(controller) {\n try {\n while (!isAborted) {\n const { done, value } = await reader.read()\n if (done) break\n\n transferredBytes += value.length\n onChunk(value, totalBytes, transferredBytes)\n controller.enqueue(value)\n }\n\n if (!isAborted) {\n controller.close()\n }\n } catch (error) {\n if (!isAborted) {\n controller.error(error)\n }\n throw error\n } finally {\n signal?.removeEventListener('abort', abortHandler)\n releaseReader()\n }\n },\n cancel() {\n isAborted = true\n signal?.removeEventListener('abort', abortHandler)\n releaseReader()\n },\n })\n}\n\n/**\n * Creates a request with upload streaming tracking\n */\nexport async function toStreamableRequest(\n request: Request,\n onUploadStreaming?: (event: UploadStreamingEvent) => void\n): Promise<Request> {\n if (!onUploadStreaming || !request.body) {\n return request\n }\n\n if (!request.body.getReader) {\n return request\n }\n\n const reader = request.body.getReader()\n const totalBytes = request.headers.get('content-length')\n ? parseInt(request.headers.get('content-length') || '0', 10)\n : undefined\n\n const stream = createStreamingStream(\n reader,\n (chunk, totalBytes, transferredBytes) => {\n onUploadStreaming({\n chunk,\n totalBytes,\n transferredBytes,\n })\n },\n totalBytes,\n request.signal\n )\n\n return new Request(request.url, {\n method: request.method,\n headers: request.headers,\n body: stream,\n signal: request.signal,\n credentials: request.credentials,\n cache: request.cache,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n integrity: request.integrity,\n keepalive: request.keepalive,\n duplex: 'half',\n } as RequestInit)\n}\n\n/**\n * Creates a response with download streaming tracking\n */\nexport async function toStreamableResponse(\n response: Response,\n onDownloadStreaming?: (event: DownloadStreamingEvent) => void\n): Promise<Response> {\n if (!onDownloadStreaming || !response.body) {\n return response\n }\n\n if (!response.body.getReader) {\n return response\n }\n\n const reader = response.body.getReader()\n const totalBytes = response.headers.get('content-length')\n ? parseInt(response.headers.get('content-length') || '0', 10)\n : undefined\n\n const stream = createStreamingStream(\n reader,\n (chunk, totalBytes, transferredBytes) => {\n onDownloadStreaming({\n chunk,\n totalBytes,\n transferredBytes,\n })\n },\n totalBytes\n )\n\n return new Response(stream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n}\n","import {\n HttpError,\n InvalidBaseUrlError,\n MiddlewareError,\n NetworkError,\n SerializationError,\n TimeoutError,\n} from './errors'\nimport type { SchemaValidator } from './schema'\nimport type {\n CustomFetch,\n DownloadStreamingEvent,\n ExtendedRequestInit,\n FetchOptions,\n HttpHeaders,\n HttpMethod,\n RequestContext,\n RequestParamsType,\n ResponseType,\n RetryContext,\n RetryEvent,\n RetryOptions,\n SerializeBody,\n SerializeParams,\n UploadStreamingEvent,\n} from './types'\nimport {\n type AssertSupportedPath,\n generatePath,\n toStreamableRequest,\n toStreamableResponse,\n type PathParams,\n} from './utils'\n\ntype ResolvedRetryOptions = {\n maxRetries: number\n retryDelay: number\n backoffFactor: number\n retryStatusCodes: number[]\n retryNetworkErrors: boolean\n maxRetryDelay: number\n retryMethods: readonly HttpMethod[]\n retryUnsafeMethods: boolean\n jitter: NonNullable<RetryOptions['jitter']>\n respectRetryAfter: boolean\n shouldRetry?: RetryOptions['shouldRetry']\n onRetry?: RetryOptions['onRetry']\n}\n\ntype ParsedResponse<T> = ResponseType<T> & {\n parseError?: SerializationError\n}\n\nconst DEFAULT_RETRY_OPTIONS: Omit<\n ResolvedRetryOptions,\n 'shouldRetry' | 'onRetry'\n> = {\n maxRetries: 3,\n retryDelay: 300,\n backoffFactor: 2,\n retryStatusCodes: [408, 429, 500, 502, 503, 504],\n retryNetworkErrors: true,\n maxRetryDelay: 30_000,\n retryMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE'],\n retryUnsafeMethods: false,\n jitter: 'none',\n respectRetryAfter: true,\n}\n\nexport interface HttpRequestOptions<\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n> {\n method?: HttpMethod\n headers?: HttpHeaders\n /** Query parameters */\n params?: TParams\n /** Path parameters for URL template */\n pathParams?: Record<string, string | number | undefined>\n /** Request body */\n body?: TBody\n timeout?: number\n signal?: AbortSignal\n /** Fetch options */\n credentials?: RequestCredentials\n cache?: RequestCache\n mode?: RequestMode\n redirect?: RequestRedirect\n /** Additional Fetch/Node options passed through to the underlying fetch call */\n fetchOptions?: FetchOptions\n /** Upload streaming tracking for this specific request */\n onUploadStreaming?: (event: UploadStreamingEvent) => void\n /** Download streaming tracking for this specific request */\n onDownloadStreaming?: (event: DownloadStreamingEvent) => void\n /** Response type override */\n responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData'\n /** Per-request retry configuration */\n retry?: RetryOptions | boolean\n}\n\nexport interface HttpClientConfig {\n /** Base URL for all requests */\n baseUrl?: string\n /** Default headers */\n headers?: HttpHeaders\n /** Default timeout */\n timeout?: number\n /** Schema validator */\n schemaValidator?: SchemaValidator\n /** Default retry configuration */\n retry?: RetryOptions | boolean\n /** Custom fetch implementation */\n fetch?: CustomFetch\n /** Custom body serializer */\n serializeBody?: SerializeBody\n /** Custom params serializer */\n serializeParams?: SerializeParams\n /** Request middleware - can modify request before sending */\n onRequestMiddleware?: <TBody = unknown>(\n context: RequestContext<TBody>\n ) => RequestContext<TBody> | Promise<RequestContext<TBody>>\n /** Response middleware - can modify response after receiving */\n onResponseMiddleware?: (\n response: ResponseType<unknown>\n ) => ResponseType<unknown> | Promise<ResponseType<unknown>>\n}\n\n/**\n * Creates an HTTP request handler with the given configuration.\n * This is the core function that handles all HTTP requests with retry logic,\n * interceptors, and streaming.\n */\nexport function createHttpRequest(config: HttpClientConfig = {}) {\n const {\n baseUrl = '',\n headers: defaultHeaders = {},\n timeout: defaultTimeout = 30_000,\n fetch: customFetch,\n serializeBody: customSerializeBody,\n serializeParams: customSerializeParams,\n onRequestMiddleware,\n onResponseMiddleware,\n } = config\n const usesNativeFetch = customFetch === undefined\n\n return async function fetcher<\n Path extends string = string,\n TResponse = unknown,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n options: HttpRequestOptions<TBody, TParams> = {}\n ): Promise<ResponseType<TResponse>> {\n const {\n method = 'GET',\n headers = {},\n params,\n pathParams,\n body,\n timeout = defaultTimeout,\n signal,\n credentials,\n cache,\n mode,\n redirect,\n fetchOptions,\n onUploadStreaming,\n onDownloadStreaming,\n responseType,\n retry: requestRetry,\n } = options\n\n let resolvedUrl =\n pathParams === undefined\n ? generatePath(url as AssertSupportedPath<Path>)\n : generatePath(\n url as AssertSupportedPath<Path>,\n pathParams as PathParams<Path>\n )\n\n if (baseUrl) {\n resolvedUrl = constructUrl(baseUrl, resolvedUrl)\n }\n\n const requestFetchOptions = mergeFetchOptions(fetchOptions, {\n cache,\n credentials,\n mode,\n redirect,\n })\n\n const baseRequestContext: RequestContext<TBody> = {\n url: resolvedUrl,\n method,\n params,\n headers: new Headers({ ...defaultHeaders, ...headers }),\n body,\n signal,\n fetchOptions: requestFetchOptions,\n }\n\n let requestContext: RequestContext<TBody> = baseRequestContext\n\n if (onRequestMiddleware) {\n try {\n // prevent middleware from mutating the original context\n const contextCopy: RequestContext<TBody> = {\n ...baseRequestContext,\n headers: new Headers(baseRequestContext.headers),\n fetchOptions: { ...baseRequestContext.fetchOptions },\n }\n\n requestContext = await onRequestMiddleware(contextCopy)\n } catch (error) {\n throw new MiddlewareError(\n createErrorMessage('Request middleware failed', error),\n 'request',\n requestContext.url,\n requestContext.method,\n createStandardizedError(error, 'Request middleware')\n )\n }\n }\n\n if (requestContext.params) {\n const serializedParams = customSerializeParams\n ? customSerializeParams(requestContext.params)\n : serializeQueryParams(requestContext.params)\n\n if (serializedParams) {\n requestContext.url = appendQueryString(\n requestContext.url,\n serializedParams\n )\n }\n }\n\n assertRequestUrlSupported(requestContext.url, usesNativeFetch)\n\n const baseRequestInit: ExtendedRequestInit = {\n method: requestContext.method,\n headers: requestContext.headers,\n ...requestContext.fetchOptions,\n }\n\n if (\n requestContext.body !== undefined &&\n requestContext.method !== 'GET' &&\n requestContext.method !== 'HEAD'\n ) {\n let body: BodyInit\n let contentType: string | undefined\n\n if (customSerializeBody) {\n const serializedBody = customSerializeBody(requestContext.body)\n if (serializedBody == null) {\n body = ''\n } else {\n body = serializedBody\n }\n } else {\n const serialized = serializeRequestBody(requestContext.body)\n body = serialized.body\n contentType = serialized.contentType\n }\n\n baseRequestInit.body = body\n\n if (contentType) {\n requestContext.headers.set('content-type', contentType)\n }\n\n baseRequestInit.duplex = 'half'\n }\n\n const mergedRetryOptions = resolveRetryOptions(config.retry, requestRetry)\n const maxRetries = mergedRetryOptions?.maxRetries ?? 0\n const bodyReplayable = isReplayableBody(baseRequestInit.body)\n let lastError: Error | undefined\n\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n const controller = new AbortController()\n let didTimeout = false\n const timeoutId = setTimeout(() => {\n didTimeout = true\n controller.abort()\n }, timeout)\n\n const { signal: finalSignal, cleanup: cleanupSignal } =\n createCombinedSignal(requestContext.signal, controller.signal)\n let attemptCleanedUp = false\n const cleanupAttempt = () => {\n if (attemptCleanedUp) {\n return\n }\n\n attemptCleanedUp = true\n clearTimeout(timeoutId)\n cleanupSignal()\n }\n\n try {\n const requestInit: ExtendedRequestInit = {\n ...baseRequestInit,\n headers: requestContext.headers,\n signal: finalSignal,\n ...requestContext.fetchOptions,\n }\n\n if (onUploadStreaming && requestInit.body !== undefined) {\n const streamableRequest = await toStreamableRequest(\n createInternalRequest(requestContext.url, requestInit),\n onUploadStreaming\n )\n\n requestInit.body = streamableRequest.body ?? undefined\n requestInit.headers = streamableRequest.headers\n }\n\n const response = await fetchWithNetworkError(\n customFetch ?? globalThis.fetch,\n requestContext.url,\n requestInit\n )\n\n const trackedResponse = onDownloadStreaming\n ? await toStreamableResponse(response, onDownloadStreaming)\n : response\n\n const responseData = await processResponse<TResponse>(trackedResponse, {\n responseType,\n method: requestContext.method,\n url: requestContext.url,\n tolerateParseError: !isSuccessfulStatus(trackedResponse.status),\n })\n\n let finalResponse = responseData\n\n if (onResponseMiddleware) {\n try {\n const middlewareResult = await onResponseMiddleware(responseData)\n if (!isResponseTypeLike(middlewareResult)) {\n throw new MiddlewareError(\n 'Response middleware must return a valid ResponseType object',\n 'response',\n requestContext.url,\n requestContext.method\n )\n }\n finalResponse = middlewareResult as ResponseType<TResponse>\n } catch (error) {\n throw new MiddlewareError(\n createErrorMessage('Response middleware failed', error),\n 'response',\n requestContext.url,\n requestContext.method,\n createStandardizedError(error, 'Response middleware')\n )\n }\n }\n\n if (!isSuccessfulStatus(finalResponse.status)) {\n throw createHttpError(finalResponse, responseData.parseError)\n }\n\n return finalResponse\n } catch (error) {\n lastError = createStandardizedError(error, 'Request execution')\n\n if (isAbortError(lastError) && didTimeout) {\n lastError = new TimeoutError(\n `Request timeout after ${timeout}ms`,\n lastError\n )\n }\n\n if (\n attempt >= maxRetries ||\n !(await shouldRetry(lastError, attempt, mergedRetryOptions, {\n bodyReplayable,\n method: requestContext.method,\n url: requestContext.url,\n }))\n ) {\n throw lastError\n }\n\n const delay = calculateRetryDelay(\n attempt,\n mergedRetryOptions,\n lastError\n )\n await notifyRetry(mergedRetryOptions, {\n bodyReplayable,\n delay,\n error: lastError,\n method: requestContext.method,\n nextAttempt: attempt + 1,\n retryCount: attempt,\n url: requestContext.url,\n })\n cleanupAttempt()\n await sleep(delay, requestContext.signal)\n } finally {\n cleanupAttempt()\n }\n }\n\n throw new Error('Retry loop terminated unexpectedly')\n }\n}\n\nasync function processResponse<T = unknown>(\n response: Response,\n options: {\n responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData'\n method: HttpMethod\n url: string\n tolerateParseError?: boolean\n }\n): Promise<ParsedResponse<T>> {\n const headers = Object.fromEntries(response.headers.entries())\n\n let data: unknown\n let parseError: SerializationError | undefined\n const responseClone = response.clone()\n\n try {\n const requestedType = options.responseType\n const contentType = response.headers.get('content-type') ?? ''\n\n const detectedType:\n | 'json'\n | 'text'\n | 'arrayBuffer'\n | 'formData'\n | undefined = contentType.includes('application/json')\n ? 'json'\n : contentType.includes('text/')\n ? 'text'\n : contentType.includes('application/octet-stream') ||\n contentType.includes('application/pdf') ||\n contentType.includes('image/') ||\n contentType.includes('video/') ||\n contentType.includes('audio/')\n ? 'arrayBuffer'\n : contentType.includes('multipart/form-data') ||\n contentType.includes('application/x-www-form-urlencoded')\n ? 'formData'\n : undefined\n\n const finalType:\n | 'json'\n | 'text'\n | 'arrayBuffer'\n | 'blob'\n | 'formData'\n | undefined = requestedType ?? detectedType\n\n if (finalType === 'json') {\n data = await response.json()\n } else if (finalType === 'text') {\n data = await response.text()\n } else if (finalType === 'blob') {\n data = await response.blob()\n } else if (finalType === 'arrayBuffer') {\n data = await response.arrayBuffer()\n } else if (finalType === 'formData') {\n data = await response.formData()\n } else {\n try {\n data = await response.json()\n } catch {\n data = await responseClone.text()\n }\n }\n } catch (error) {\n parseError = new SerializationError(\n createErrorMessage('Failed to parse response body', error),\n error instanceof Error ? error : undefined\n )\n\n if (!options.tolerateParseError) {\n throw parseError\n }\n\n try {\n data = await responseClone.text()\n } catch {\n data = ''\n }\n }\n\n return {\n data: data as T,\n status: response.status,\n statusText: response.statusText,\n headers,\n method: options.method,\n url: options.url,\n raw: response,\n parseError,\n }\n}\n\nasync function shouldRetry(\n error: Error,\n retryCount: number,\n retryConfig: ResolvedRetryOptions | undefined,\n context: Pick<RetryContext, 'bodyReplayable' | 'method' | 'url'>\n): Promise<boolean> {\n if (!retryConfig) return false\n\n const retryContext: RetryContext = {\n ...context,\n error,\n retryCount,\n }\n\n if (retryConfig.shouldRetry) {\n return await retryConfig.shouldRetry(error, retryCount, retryContext)\n }\n\n if (\n !context.bodyReplayable ||\n !isRetryMethodAllowed(context.method, retryConfig)\n ) {\n return false\n }\n\n if (error instanceof HttpError) {\n return retryConfig.retryStatusCodes.includes(error.status)\n }\n\n if (\n error instanceof NetworkError ||\n (error.name === 'TypeError' && !isInvalidUrlError(error))\n ) {\n return retryConfig.retryNetworkErrors\n }\n\n return false\n}\n\nfunction calculateRetryDelay(\n attempt: number,\n retryConfig: ResolvedRetryOptions | undefined,\n error: Error\n): number {\n if (!retryConfig) return 0\n\n const retryAfterDelay = retryConfig.respectRetryAfter\n ? getRetryAfterDelay(error)\n : undefined\n\n if (retryAfterDelay !== undefined) {\n return Math.min(retryAfterDelay, retryConfig.maxRetryDelay)\n }\n\n const delay =\n retryConfig.retryDelay * Math.pow(retryConfig.backoffFactor, attempt)\n\n return applyJitter(\n Math.min(delay, retryConfig.maxRetryDelay),\n retryConfig.jitter,\n attempt\n )\n}\n\nasync function notifyRetry(\n retryConfig: ResolvedRetryOptions | undefined,\n event: RetryEvent\n): Promise<void> {\n await retryConfig?.onRetry?.(event)\n}\n\nfunction resolveRetryOptions(\n clientRetry?: RetryOptions | boolean,\n requestRetry?: RetryOptions | boolean\n): ResolvedRetryOptions | undefined {\n const clientRetryOptions =\n typeof clientRetry === 'object' ? clientRetry : undefined\n const shouldEnableRetries =\n clientRetry === true ||\n clientRetryOptions !== undefined ||\n requestRetry === true ||\n typeof requestRetry === 'object'\n\n if (requestRetry === false) {\n return undefined\n }\n\n if (!shouldEnableRetries) {\n return undefined\n }\n\n const baseRetryOptions = {\n ...DEFAULT_RETRY_OPTIONS,\n ...clientRetryOptions,\n }\n\n if (requestRetry === true) {\n return baseRetryOptions\n }\n\n if (typeof requestRetry === 'object') {\n return {\n ...baseRetryOptions,\n ...requestRetry,\n }\n }\n\n return baseRetryOptions\n}\n\nfunction mergeFetchOptions(\n fetchOptions: FetchOptions | undefined,\n aliases: Pick<RequestInit, 'cache' | 'credentials' | 'mode' | 'redirect'>\n): FetchOptions {\n const merged: FetchOptions = { ...(fetchOptions ?? {}) }\n\n if (aliases.cache !== undefined) {\n merged.cache = aliases.cache\n }\n\n if (aliases.credentials !== undefined) {\n merged.credentials = aliases.credentials\n }\n\n if (aliases.mode !== undefined) {\n merged.mode = aliases.mode\n }\n\n if (aliases.redirect !== undefined) {\n merged.redirect = aliases.redirect\n }\n\n return merged\n}\n\nfunction isRetryMethodAllowed(\n method: HttpMethod,\n retryConfig: ResolvedRetryOptions\n): boolean {\n if (retryConfig.retryUnsafeMethods) {\n return true\n }\n\n const normalizedMethod = method.toUpperCase()\n return retryConfig.retryMethods.some(\n retryMethod => retryMethod.toUpperCase() === normalizedMethod\n )\n}\n\nfunction getRetryAfterDelay(error: Error): number | undefined {\n if (!(error instanceof HttpError)) {\n return undefined\n }\n\n const retryAfter = error.response.headers.get('retry-after')\n if (!retryAfter) {\n return undefined\n }\n\n const retryAfterSeconds = Number(retryAfter)\n if (Number.isFinite(retryAfterSeconds)) {\n return Math.max(0, retryAfterSeconds * 1000)\n }\n\n const retryAfterDate = Date.parse(retryAfter)\n if (Number.isNaN(retryAfterDate)) {\n return undefined\n }\n\n return Math.max(0, retryAfterDate - Date.now())\n}\n\nfunction applyJitter(\n delay: number,\n jitter: ResolvedRetryOptions['jitter'],\n attempt: number\n): number {\n if (typeof jitter === 'function') {\n return Math.max(0, jitter(delay, attempt))\n }\n\n if (jitter === 'full') {\n return Math.floor(Math.random() * delay)\n }\n\n if (jitter === 'equal') {\n return Math.floor(delay / 2 + Math.random() * (delay / 2))\n }\n\n return delay\n}\n\nfunction isObjectLike(\n value: unknown\n): value is Record<string, unknown> | unknown[] | { toJSON(): unknown } {\n return (\n value !== null &&\n typeof value === 'object' &&\n (Array.isArray(value) ||\n ('toJSON' in value && typeof value.toJSON === 'function') ||\n Object.prototype.toString.call(value) === '[object Object]')\n )\n}\n\nfunction serializeQueryParams(params: RequestParamsType): string {\n const searchParams = new URLSearchParams()\n\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item !== undefined && item !== null) {\n searchParams.append(key, String(item))\n }\n }\n } else if (value !== undefined && value !== null) {\n searchParams.append(key, String(value))\n }\n }\n\n return searchParams.toString()\n}\n\nfunction serializeRequestBody(body: unknown): {\n body: BodyInit\n contentType?: string\n} {\n if (ArrayBuffer.isView(body)) {\n const bytes = new Uint8Array(body.buffer, body.byteOffset, body.byteLength)\n return { body: new Uint8Array(bytes).buffer }\n }\n\n if (\n typeof body === 'string' ||\n body instanceof FormData ||\n body instanceof URLSearchParams ||\n body instanceof ArrayBuffer ||\n body instanceof Blob ||\n body instanceof ReadableStream\n ) {\n return { body: body }\n }\n\n if (isObjectLike(body)) {\n return {\n body: JSON.stringify(body),\n contentType: 'application/json',\n }\n }\n\n if (body === null || body === undefined) {\n return { body: '' }\n }\n\n return { body: String(body) }\n}\n\nfunction createErrorMessage(context: string, error: unknown): string {\n return `${context}: ${error instanceof Error ? error.message : String(error)}`\n}\n\nfunction isReplayableBody(body: BodyInit | null | undefined): boolean {\n return !(body instanceof ReadableStream)\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) {\n return Promise.resolve()\n }\n\n if (signal?.aborted) {\n return Promise.reject(createAbortError(signal.reason))\n }\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n signal?.removeEventListener('abort', handleAbort)\n resolve()\n }, ms)\n\n const handleAbort = () => {\n clearTimeout(timeoutId)\n signal?.removeEventListener('abort', handleAbort)\n reject(createAbortError(signal?.reason))\n }\n\n signal?.addEventListener('abort', handleAbort, { once: true })\n })\n}\n\nfunction createAbortError(reason: unknown): Error {\n if (reason instanceof Error) {\n return reason\n }\n\n const error = new Error('The operation was aborted')\n error.name = 'AbortError'\n return error\n}\n\nfunction createCombinedSignal(\n requestSignal?: AbortSignal,\n timeoutSignal?: AbortSignal\n): { signal?: AbortSignal; cleanup: () => void } {\n if (!requestSignal && !timeoutSignal) {\n return {\n signal: undefined,\n cleanup: () => undefined,\n }\n }\n\n if (!requestSignal) {\n return {\n signal: timeoutSignal,\n cleanup: () => undefined,\n }\n }\n\n if (!timeoutSignal) {\n return {\n signal: requestSignal,\n cleanup: () => undefined,\n }\n }\n\n if (requestSignal?.aborted) {\n return {\n signal: requestSignal,\n cleanup: () => undefined,\n }\n }\n\n if (timeoutSignal.aborted) {\n return {\n signal: timeoutSignal,\n cleanup: () => undefined,\n }\n }\n\n const combinedController = new AbortController()\n\n const handleAbort = (event: Event) => {\n const sourceSignal = event.target\n\n if (sourceSignal instanceof AbortSignal) {\n combinedController.abort(sourceSignal.reason)\n return\n }\n\n combinedController.abort()\n }\n\n requestSignal.addEventListener('abort', handleAbort, { once: true })\n timeoutSignal.addEventListener('abort', handleAbort, { once: true })\n\n return {\n signal: combinedController.signal,\n cleanup: () => {\n requestSignal.removeEventListener('abort', handleAbort)\n timeoutSignal.removeEventListener('abort', handleAbort)\n },\n }\n}\n\nfunction createStandardizedError(error: unknown, context: string): Error {\n if (error instanceof Error) {\n return error\n }\n\n return new Error(`${context}: ${String(error)}`)\n}\n\nasync function fetchWithNetworkError(\n fetchImplementation: CustomFetch,\n url: string,\n requestInit: RequestInit\n): Promise<Response> {\n try {\n return await fetchImplementation(url, requestInit)\n } catch (error) {\n const standardizedError = createStandardizedError(\n error,\n 'Network request failed'\n )\n\n if (\n isAbortError(standardizedError) ||\n standardizedError instanceof NetworkError\n ) {\n throw standardizedError\n }\n\n throw new NetworkError(standardizedError.message, standardizedError)\n }\n}\n\nfunction createHttpError(\n response: ResponseType<unknown>,\n cause?: Error\n): HttpError {\n return new HttpError(\n `HTTP ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n response.data,\n response.raw,\n response.url,\n response.method,\n cause\n )\n}\n\nfunction constructUrl(baseUrl: string, requestUrl: string): string {\n if (isAbsoluteUrl(requestUrl)) {\n return requestUrl\n }\n\n return isAbsoluteUrl(baseUrl)\n ? constructAbsoluteUrl(baseUrl, requestUrl)\n : constructRelativeUrl(baseUrl, requestUrl)\n}\n\nfunction constructAbsoluteUrl(baseUrl: string, requestUrl: string): string {\n const baseUrlObj = new URL(baseUrl)\n const basePath = baseUrlObj.pathname.replace(/\\/$/, '')\n const { path, search, hash } = splitUrl(requestUrl)\n\n if (path.startsWith('/')) {\n baseUrlObj.pathname = basePath + path\n } else if (path) {\n baseUrlObj.pathname = basePath + '/' + path\n }\n\n if (search) {\n baseUrlObj.search = mergeSearch(baseUrlObj.search, search)\n }\n\n if (hash) {\n baseUrlObj.hash = hash\n }\n\n return baseUrlObj.toString()\n}\n\nfunction constructRelativeUrl(baseUrl: string, requestUrl: string): string {\n const {\n path: basePath,\n search: baseSearch,\n hash: baseHash,\n } = splitUrl(baseUrl)\n const {\n path: requestPath,\n search: requestSearch,\n hash: requestHash,\n } = splitUrl(requestUrl)\n\n const pathname = requestPath\n ? joinPathSegments(basePath, requestPath)\n : basePath || requestPath\n\n return `${pathname}${mergeSearch(baseSearch, requestSearch)}${\n requestHash || baseHash\n }`\n}\n\nfunction appendQueryString(url: string, queryString: string): string {\n const normalizedQuery = queryString.startsWith('?')\n ? queryString.slice(1)\n : queryString\n\n if (!normalizedQuery) {\n return url\n }\n\n const { path, search, hash } = splitUrl(url)\n const nextSearch = search\n ? `${search}&${normalizedQuery}`\n : `?${normalizedQuery}`\n\n return `${path}${nextSearch}${hash}`\n}\n\nfunction splitUrl(url: string): {\n path: string\n search: string\n hash: string\n} {\n const hashIndex = url.indexOf('#')\n const hash = hashIndex === -1 ? '' : url.slice(hashIndex)\n const withoutHash = hashIndex === -1 ? url : url.slice(0, hashIndex)\n const searchIndex = withoutHash.indexOf('?')\n\n return {\n path: searchIndex === -1 ? withoutHash : withoutHash.slice(0, searchIndex),\n search: searchIndex === -1 ? '' : withoutHash.slice(searchIndex),\n hash,\n }\n}\n\nfunction mergeSearch(baseSearch: string, requestSearch: string): string {\n if (!baseSearch) {\n return requestSearch\n }\n\n if (!requestSearch) {\n return baseSearch\n }\n\n return `${baseSearch}&${requestSearch.slice(1)}`\n}\n\nfunction joinPathSegments(basePath: string, requestPath: string): string {\n if (!basePath) {\n return requestPath.startsWith('/') ? requestPath : `/${requestPath}`\n }\n\n if (!requestPath) {\n return basePath\n }\n\n return requestPath.startsWith('/')\n ? `${basePath}${requestPath}`\n : `${basePath}/${requestPath}`\n}\n\nfunction createInternalRequest(\n url: string,\n requestInit: ExtendedRequestInit\n): Request {\n return new Request(toInternalRequestUrl(url), requestInit)\n}\n\nfunction isSuccessfulStatus(status: number): boolean {\n return status >= 200 && status < 300\n}\n\nfunction isResponseTypeLike(value: unknown): value is ResponseType<unknown> {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'data' in value &&\n 'status' in value &&\n typeof value.status === 'number' &&\n 'statusText' in value &&\n typeof value.statusText === 'string' &&\n 'headers' in value &&\n typeof value.headers === 'object' &&\n value.headers !== null &&\n 'method' in value &&\n typeof value.method === 'string' &&\n 'url' in value &&\n typeof value.url === 'string' &&\n 'raw' in value &&\n value.raw instanceof Response\n )\n}\n\nfunction assertRequestUrlSupported(\n url: string,\n usesNativeFetch: boolean\n): void {\n if (!usesNativeFetch || isAbsoluteUrl(url) || supportsRelativeRequestUrls()) {\n return\n }\n\n throw new InvalidBaseUrlError(\n `Relative request URL \"${url}\" requires an absolute baseUrl in non-browser environments. Pass an absolute baseUrl or use a custom fetch implementation.`,\n url\n )\n}\n\nfunction isAbsoluteUrl(url: string): boolean {\n return /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//.test(url)\n}\n\nfunction supportsRelativeRequestUrls(): boolean {\n return (\n typeof window !== 'undefined' &&\n typeof window.location !== 'undefined' &&\n window.location.origin !== 'null'\n )\n}\n\nfunction toInternalRequestUrl(url: string): string {\n if (isAbsoluteUrl(url)) {\n return url\n }\n\n if (!url) {\n return 'https://1000fetches.local/'\n }\n\n return `https://1000fetches.local${url.startsWith('/') ? url : `/${url}`}`\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError'\n}\n\nfunction isInvalidUrlError(error: Error): boolean {\n return (\n error.message.includes('Invalid URL') ||\n error.message.includes('Failed to parse URL')\n )\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport { InvalidSchemaError, SchemaValidationError } from './errors'\nimport { Schema } from './types'\n\n/**\n * Type guard to check if an object conforms to the Standard Schema V1 specification\n */\nfunction isStandardSchema(obj: unknown): obj is StandardSchemaV1 {\n return (\n obj !== null &&\n (typeof obj === 'object' || typeof obj === 'function') &&\n '~standard' in obj &&\n typeof obj['~standard'] === 'object' &&\n obj['~standard'] !== null &&\n 'validate' in obj['~standard'] &&\n typeof obj['~standard'].validate === 'function' &&\n 'version' in obj['~standard'] &&\n obj['~standard'].version === 1 &&\n 'vendor' in obj['~standard'] &&\n typeof obj['~standard'].vendor === 'string'\n )\n}\n\n/**\n * Interface for schema validators that can validate data against schemas.\n *\n * This interface allows you to create custom schema validators that work\n * with different validation libraries (Zod, Valibot, Arktype, etc.).\n */\nexport interface SchemaValidator {\n /**\n * Validate data against a schema.\n *\n * @template T - The expected type after validation\n * @param schema - The schema to validate against\n * @param data - The data to validate\n * @returns The validated data with the correct type, synchronously or asynchronously\n * @throws {SchemaValidationError} If the data doesn't match the schema\n */\n validate<T>(schema: Schema<T>, data: unknown): T | Promise<T>\n}\n\nfunction isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n 'then' in value &&\n typeof value.then === 'function'\n )\n}\n\nfunction readValidationResult<T>(\n schema: Schema<T>,\n data: unknown,\n result: StandardSchemaV1.Result<T>\n): T {\n if (result.issues) {\n throw new SchemaValidationError(\n JSON.stringify(result.issues),\n schema,\n data,\n undefined,\n result.issues\n )\n }\n\n return result.value\n}\n\n/**\n * Create a default schema validator that supports Standard Schema.\n *\n * This validator works with schemas that implement the Standard Schema\n * interface, including both synchronous and asynchronous validators.\n *\n * @returns A schema validator instance\n *\n * @example\n * ```ts\n * const validator = createSchemaValidator()\n *\n * const parsed = validator.validate(schema, data)\n * ```\n */\nexport function createSchemaValidator(): SchemaValidator {\n return {\n validate<T>(schema: Schema<T>, data: unknown): T | Promise<T> {\n if (!isStandardSchema(schema)) {\n throw new InvalidSchemaError(\n 'Schema must implement the Standard Schema interface',\n schema\n )\n }\n\n const result = schema['~standard'].validate(data) as\n | StandardSchemaV1.Result<T>\n | PromiseLike<StandardSchemaV1.Result<T>>\n\n if (isPromiseLike<StandardSchemaV1.Result<T>>(result)) {\n return Promise.resolve(result).then(asyncResult =>\n readValidationResult(schema, data, asyncResult)\n )\n }\n\n return readValidationResult(schema, data, result)\n },\n }\n}\n","import type { HttpClientConfig, HttpRequestOptions } from './core'\nimport { createHttpRequest } from './core'\nimport {\n InvalidBaseUrlError,\n InvalidSchemaError,\n SchemaValidationError,\n} from './errors'\nimport { createSchemaValidator } from './schema'\nimport type { SchemaValidator } from './schema'\nimport type {\n EnforcedPathParamsOptions,\n ExtractableResponse,\n InferSchemaOutput,\n RequestParamsType,\n ResponseType,\n Schema,\n SchemaableResponse,\n} from './types'\nimport type {\n AssertSupportedPath,\n HasRequiredParams,\n RequirePathParams,\n} from './utils'\n\ntype PathOptionsArgs<Path extends string, TOptions> = [\n AssertSupportedPath<Path>,\n] extends [never]\n ? [options: never]\n : HasRequiredParams<AssertSupportedPath<Path>> extends true\n ? [options: TOptions]\n : [options?: TOptions]\n\ntype EnforcedHttpRequestOptions<\n TBody,\n TParams extends RequestParamsType,\n Path extends string,\n> = RequirePathParams<\n AssertSupportedPath<Path>,\n string extends Path\n ? HttpRequestOptions<TBody, TParams>\n : Omit<HttpRequestOptions<TBody, TParams>, 'pathParams'>\n>\n\nfunction validateAndNormalizeBaseUrl(baseUrl?: string): string {\n if (!baseUrl) {\n return ''\n }\n\n if (baseUrl.startsWith('/')) {\n return baseUrl.replace(/\\/$/, '')\n }\n\n try {\n new URL(baseUrl)\n } catch {\n throw new InvalidBaseUrlError(\n `Invalid baseUrl: \"${baseUrl}\". Must be a valid absolute URL or relative path starting with \"/\".`,\n baseUrl\n )\n }\n\n return baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n}\n\nfunction createExtractableResponse<T>(\n promise: Promise<ResponseType<T>>\n): ExtractableResponse<T> {\n const extractable = promise as ExtractableResponse<T>\n extractable.data = async () => (await promise).data\n extractable.void = async () => {\n await promise\n }\n return extractable\n}\n\n/**\n * Creates a chainable response that allows adding schema validation and extracting data\n */\nfunction createSchemaableResponse<\n Path extends string,\n TResponse,\n TBody,\n TParams extends RequestParamsType,\n>(\n url: Path,\n options: HttpRequestOptions<TBody, TParams>,\n requestHandler: ReturnType<typeof createHttpRequest>,\n schemaValidator: SchemaValidator\n): SchemaableResponse<TResponse> {\n const basePromise = requestHandler<Path, TResponse, TBody, TParams>(\n url,\n options\n )\n\n return Object.assign(basePromise, {\n schema<S extends Schema>(\n schema: S\n ): ExtractableResponse<InferSchemaOutput<S>> {\n const validatedPromise = basePromise.then(async response => {\n try {\n const validatedData = (await schemaValidator.validate(\n schema,\n response.data\n )) as InferSchemaOutput<S>\n return {\n ...response,\n data: validatedData,\n }\n } catch (error) {\n if (\n error instanceof InvalidSchemaError ||\n error instanceof SchemaValidationError\n ) {\n throw error\n }\n\n throw new SchemaValidationError(\n error instanceof Error ? error.message : 'Schema validation failed',\n schema,\n response.data,\n error instanceof Error ? error : undefined\n )\n }\n })\n\n return createExtractableResponse(validatedPromise)\n },\n async data() {\n return (await basePromise).data\n },\n async void() {\n await basePromise\n },\n })\n}\n\n/**\n * Creates a complete HTTP client with method builders\n */\nexport function createHttpClient(config: HttpClientConfig = {}) {\n const validatedConfig = {\n ...config,\n baseUrl: validateAndNormalizeBaseUrl(config.baseUrl),\n }\n\n const requestHandler = createHttpRequest(validatedConfig)\n const schemaValidator = config.schemaValidator ?? createSchemaValidator()\n\n function get<\n Path extends string = string,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<never, TParams, Path>\n >\n ) {\n return createSchemaableResponse<Path, unknown, never, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'GET',\n },\n requestHandler,\n schemaValidator\n )\n }\n\n return {\n get,\n\n post: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n body?: TBody,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'POST',\n body,\n },\n requestHandler,\n schemaValidator\n ),\n\n put: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n body?: TBody,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'PUT',\n body,\n },\n requestHandler,\n schemaValidator\n ),\n\n patch: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n body?: TBody,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'PATCH',\n body,\n },\n requestHandler,\n schemaValidator\n ),\n\n delete: <\n Path extends string = string,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<never, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, never, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'DELETE',\n },\n requestHandler,\n schemaValidator\n ),\n\n /**\n * Generic request method for custom HTTP methods and full control\n */\n request: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n ...args: PathOptionsArgs<\n Path,\n EnforcedHttpRequestOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n args[0] ?? {},\n requestHandler,\n schemaValidator\n ),\n }\n}\n"],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { HttpClientConfig, HttpRequestOptions } from './core';
|
|
2
|
+
import { EnforcedPathParamsOptions, RequestParamsType, SchemaableResponse } from './types';
|
|
3
|
+
import { AssertSupportedPath, HasRequiredParams, RequirePathParams } from './utils';
|
|
4
|
+
type PathOptionsArgs<Path extends string, TOptions> = [
|
|
5
|
+
AssertSupportedPath<Path>
|
|
6
|
+
] extends [never] ? [options: never] : HasRequiredParams<AssertSupportedPath<Path>> extends true ? [options: TOptions] : [options?: TOptions];
|
|
7
|
+
type EnforcedHttpRequestOptions<TBody, TParams extends RequestParamsType, Path extends string> = RequirePathParams<AssertSupportedPath<Path>, string extends Path ? HttpRequestOptions<TBody, TParams> : Omit<HttpRequestOptions<TBody, TParams>, 'pathParams'>>;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a complete HTTP client with method builders
|
|
10
|
+
*/
|
|
11
|
+
export declare function createHttpClient(config?: HttpClientConfig): {
|
|
12
|
+
get: <Path extends string = string, TParams extends RequestParamsType = RequestParamsType>(url: Path, ...args: PathOptionsArgs<Path, EnforcedPathParamsOptions<never, TParams, Path>>) => SchemaableResponse<unknown>;
|
|
13
|
+
post: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: PathOptionsArgs<Path, EnforcedPathParamsOptions<TBody, TParams, Path>>) => SchemaableResponse<unknown>;
|
|
14
|
+
put: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: PathOptionsArgs<Path, EnforcedPathParamsOptions<TBody, TParams, Path>>) => SchemaableResponse<unknown>;
|
|
15
|
+
patch: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: PathOptionsArgs<Path, EnforcedPathParamsOptions<TBody, TParams, Path>>) => SchemaableResponse<unknown>;
|
|
16
|
+
delete: <Path extends string = string, TParams extends RequestParamsType = RequestParamsType>(url: Path, ...args: PathOptionsArgs<Path, EnforcedPathParamsOptions<never, TParams, Path>>) => SchemaableResponse<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Generic request method for custom HTTP methods and full control
|
|
19
|
+
*/
|
|
20
|
+
request: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, ...args: PathOptionsArgs<Path, EnforcedHttpRequestOptions<TBody, TParams, Path>>) => SchemaableResponse<unknown>;
|
|
21
|
+
};
|
|
22
|
+
export {};
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SchemaValidator } from './schema';
|
|
2
|
+
import { CustomFetch, DownloadStreamingEvent, FetchOptions, HttpHeaders, HttpMethod, RequestContext, RequestParamsType, ResponseType, RetryOptions, SerializeBody, SerializeParams, UploadStreamingEvent } from './types';
|
|
3
|
+
export interface HttpRequestOptions<TBody = unknown, TParams extends RequestParamsType = RequestParamsType> {
|
|
4
|
+
method?: HttpMethod;
|
|
5
|
+
headers?: HttpHeaders;
|
|
6
|
+
/** Query parameters */
|
|
7
|
+
params?: TParams;
|
|
8
|
+
/** Path parameters for URL template */
|
|
9
|
+
pathParams?: Record<string, string | number | undefined>;
|
|
10
|
+
/** Request body */
|
|
11
|
+
body?: TBody;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
/** Fetch options */
|
|
15
|
+
credentials?: RequestCredentials;
|
|
16
|
+
cache?: RequestCache;
|
|
17
|
+
mode?: RequestMode;
|
|
18
|
+
redirect?: RequestRedirect;
|
|
19
|
+
/** Additional Fetch/Node options passed through to the underlying fetch call */
|
|
20
|
+
fetchOptions?: FetchOptions;
|
|
21
|
+
/** Upload streaming tracking for this specific request */
|
|
22
|
+
onUploadStreaming?: (event: UploadStreamingEvent) => void;
|
|
23
|
+
/** Download streaming tracking for this specific request */
|
|
24
|
+
onDownloadStreaming?: (event: DownloadStreamingEvent) => void;
|
|
25
|
+
/** Response type override */
|
|
26
|
+
responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData';
|
|
27
|
+
/** Per-request retry configuration */
|
|
28
|
+
retry?: RetryOptions | boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface HttpClientConfig {
|
|
31
|
+
/** Base URL for all requests */
|
|
32
|
+
baseUrl?: string;
|
|
33
|
+
/** Default headers */
|
|
34
|
+
headers?: HttpHeaders;
|
|
35
|
+
/** Default timeout */
|
|
36
|
+
timeout?: number;
|
|
37
|
+
/** Schema validator */
|
|
38
|
+
schemaValidator?: SchemaValidator;
|
|
39
|
+
/** Default retry configuration */
|
|
40
|
+
retry?: RetryOptions | boolean;
|
|
41
|
+
/** Custom fetch implementation */
|
|
42
|
+
fetch?: CustomFetch;
|
|
43
|
+
/** Custom body serializer */
|
|
44
|
+
serializeBody?: SerializeBody;
|
|
45
|
+
/** Custom params serializer */
|
|
46
|
+
serializeParams?: SerializeParams;
|
|
47
|
+
/** Request middleware - can modify request before sending */
|
|
48
|
+
onRequestMiddleware?: <TBody = unknown>(context: RequestContext<TBody>) => RequestContext<TBody> | Promise<RequestContext<TBody>>;
|
|
49
|
+
/** Response middleware - can modify response after receiving */
|
|
50
|
+
onResponseMiddleware?: (response: ResponseType<unknown>) => ResponseType<unknown> | Promise<ResponseType<unknown>>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Creates an HTTP request handler with the given configuration.
|
|
54
|
+
* This is the core function that handles all HTTP requests with retry logic,
|
|
55
|
+
* interceptors, and streaming.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createHttpRequest(config?: HttpClientConfig): <Path extends string = string, TResponse = unknown, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, options?: HttpRequestOptions<TBody, TParams>) => Promise<ResponseType<TResponse>>;
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
interface HttpClientError {
|
|
3
|
+
name: string;
|
|
4
|
+
message: string;
|
|
5
|
+
cause?: Error;
|
|
6
|
+
stack?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class HttpError<TErrorData = unknown> extends Error implements HttpClientError {
|
|
9
|
+
readonly name = "HttpError";
|
|
10
|
+
readonly status: number;
|
|
11
|
+
readonly statusText: string;
|
|
12
|
+
readonly data: TErrorData;
|
|
13
|
+
readonly response: Response;
|
|
14
|
+
readonly url: string;
|
|
15
|
+
readonly method: string;
|
|
16
|
+
readonly cause?: Error;
|
|
17
|
+
constructor(message: string, status: number, statusText: string, data: TErrorData, response: Response, url: string, method: string, cause?: Error);
|
|
18
|
+
}
|
|
19
|
+
export declare class NetworkError extends Error implements HttpClientError {
|
|
20
|
+
readonly name = "NetworkError";
|
|
21
|
+
readonly cause?: Error;
|
|
22
|
+
constructor(message: string, cause?: Error);
|
|
23
|
+
}
|
|
24
|
+
export declare class SchemaValidationError extends Error implements HttpClientError {
|
|
25
|
+
readonly name = "SchemaValidationError";
|
|
26
|
+
readonly schema: unknown;
|
|
27
|
+
readonly data: unknown;
|
|
28
|
+
readonly issues?: ReadonlyArray<StandardSchemaV1.Issue>;
|
|
29
|
+
readonly cause?: Error;
|
|
30
|
+
constructor(message: string, schema: unknown, data: unknown, cause?: Error, issues?: ReadonlyArray<StandardSchemaV1.Issue>);
|
|
31
|
+
}
|
|
32
|
+
export declare class TimeoutError extends Error implements HttpClientError {
|
|
33
|
+
readonly name = "TimeoutError";
|
|
34
|
+
readonly cause?: Error;
|
|
35
|
+
constructor(message: string, cause?: Error);
|
|
36
|
+
}
|
|
37
|
+
export declare class PathParameterError extends Error implements HttpClientError {
|
|
38
|
+
readonly name = "PathParameterError";
|
|
39
|
+
readonly url: string;
|
|
40
|
+
readonly requiredParams: string[];
|
|
41
|
+
readonly providedParams: string[];
|
|
42
|
+
readonly cause?: Error;
|
|
43
|
+
constructor(message: string, url: string, requiredParams: string[], providedParams: string[], cause?: Error);
|
|
44
|
+
}
|
|
45
|
+
export declare class MiddlewareError extends Error implements HttpClientError {
|
|
46
|
+
readonly name = "MiddlewareError";
|
|
47
|
+
readonly type: 'request' | 'response';
|
|
48
|
+
readonly url?: string;
|
|
49
|
+
readonly method?: string;
|
|
50
|
+
readonly cause?: Error;
|
|
51
|
+
constructor(message: string, type: 'request' | 'response', url?: string, method?: string, cause?: Error);
|
|
52
|
+
}
|
|
53
|
+
export declare class SerializationError extends Error implements HttpClientError {
|
|
54
|
+
readonly name = "SerializationError";
|
|
55
|
+
readonly cause?: Error;
|
|
56
|
+
constructor(message: string, cause?: Error);
|
|
57
|
+
}
|
|
58
|
+
export declare class InvalidSchemaError extends Error implements HttpClientError {
|
|
59
|
+
readonly name = "InvalidSchemaError";
|
|
60
|
+
readonly schema: unknown;
|
|
61
|
+
readonly cause?: Error;
|
|
62
|
+
constructor(message: string, schema: unknown, cause?: Error);
|
|
63
|
+
}
|
|
64
|
+
export declare class AsyncSchemaValidationError extends Error implements HttpClientError {
|
|
65
|
+
readonly name = "AsyncSchemaValidationError";
|
|
66
|
+
readonly schema: unknown;
|
|
67
|
+
readonly cause?: Error;
|
|
68
|
+
constructor(message: string, schema: unknown, cause?: Error);
|
|
69
|
+
}
|
|
70
|
+
export declare class InvalidBaseUrlError extends Error implements HttpClientError {
|
|
71
|
+
readonly name = "InvalidBaseUrlError";
|
|
72
|
+
readonly baseUrl: string;
|
|
73
|
+
readonly cause?: Error;
|
|
74
|
+
constructor(message: string, baseUrl: string, cause?: Error);
|
|
75
|
+
}
|
|
76
|
+
export {};
|
package/dist/http.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.cjs","names":[],"sources":["../src/http.ts"],"sourcesContent":["import { createHttpClient } from './client'\n\nconst http = /* @__PURE__ */ createHttpClient()\n\nexport default http\n"],"mappings":"+FAEA,IAAM,kCAAuB"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare const http: {
|
|
2
|
+
get: <Path extends string = string, TParams extends import('./types').RequestParamsType = import('./types').RequestParamsType>(url: Path, ...args: [import('./utils').AssertSupportedPath<Path>] extends [never] ? [options: never] : import('./utils').HasRequiredParams<import('./utils').AssertSupportedPath<Path>> extends true ? [options: import('./types').EnforcedPathParamsOptions<never, TParams, Path>] : [options?: import('./types').EnforcedPathParamsOptions<never, TParams, Path> | undefined]) => import('./types').SchemaableResponse<unknown>;
|
|
3
|
+
post: <Path extends string = string, TBody = unknown, TParams extends import('./types').RequestParamsType = import('./types').RequestParamsType>(url: Path, body?: TBody, ...args: [import('./utils').AssertSupportedPath<Path>] extends [never] ? [options: never] : import('./utils').HasRequiredParams<import('./utils').AssertSupportedPath<Path>> extends true ? [options: import('./types').EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: import('./types').EnforcedPathParamsOptions<TBody, TParams, Path> | undefined]) => import('./types').SchemaableResponse<unknown>;
|
|
4
|
+
put: <Path extends string = string, TBody = unknown, TParams extends import('./types').RequestParamsType = import('./types').RequestParamsType>(url: Path, body?: TBody, ...args: [import('./utils').AssertSupportedPath<Path>] extends [never] ? [options: never] : import('./utils').HasRequiredParams<import('./utils').AssertSupportedPath<Path>> extends true ? [options: import('./types').EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: import('./types').EnforcedPathParamsOptions<TBody, TParams, Path> | undefined]) => import('./types').SchemaableResponse<unknown>;
|
|
5
|
+
patch: <Path extends string = string, TBody = unknown, TParams extends import('./types').RequestParamsType = import('./types').RequestParamsType>(url: Path, body?: TBody, ...args: [import('./utils').AssertSupportedPath<Path>] extends [never] ? [options: never] : import('./utils').HasRequiredParams<import('./utils').AssertSupportedPath<Path>> extends true ? [options: import('./types').EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: import('./types').EnforcedPathParamsOptions<TBody, TParams, Path> | undefined]) => import('./types').SchemaableResponse<unknown>;
|
|
6
|
+
delete: <Path extends string = string, TParams extends import('./types').RequestParamsType = import('./types').RequestParamsType>(url: Path, ...args: [import('./utils').AssertSupportedPath<Path>] extends [never] ? [options: never] : import('./utils').HasRequiredParams<import('./utils').AssertSupportedPath<Path>> extends true ? [options: import('./types').EnforcedPathParamsOptions<never, TParams, Path>] : [options?: import('./types').EnforcedPathParamsOptions<never, TParams, Path> | undefined]) => import('./types').SchemaableResponse<unknown>;
|
|
7
|
+
request: <Path extends string = string, TBody = unknown, TParams extends import('./types').RequestParamsType = import('./types').RequestParamsType>(url: Path, ...args: [import('./utils').AssertSupportedPath<Path>] extends [never] ? [options: never] : import('./utils').HasRequiredParams<import('./utils').AssertSupportedPath<Path>> extends true ? [options: import('./utils').RequirePathParams<import('./utils').AssertSupportedPath<Path>, string extends Path ? import('./core').HttpRequestOptions<TBody, TParams> : Omit<import('./core').HttpRequestOptions<TBody, TParams>, "pathParams">>] : [options?: import('./utils').RequirePathParams<import('./utils').AssertSupportedPath<Path>, string extends Path ? import('./core').HttpRequestOptions<TBody, TParams> : Omit<import('./core').HttpRequestOptions<TBody, TParams>, "pathParams">> | undefined]) => import('./types').SchemaableResponse<unknown>;
|
|
8
|
+
};
|
|
9
|
+
export default http;
|
package/dist/http.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.mjs","names":[],"sources":["../src/http.ts"],"sourcesContent":["import { createHttpClient } from './client'\n\nconst http = /* @__PURE__ */ createHttpClient()\n\nexport default http\n"],"mappings":"qCAEA,IAAM,iBAAuB"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const r=require("./client-C7dvgNnD.js");var e=r.createHttpClient();exports.AsyncSchemaValidationError=r.AsyncSchemaValidationError,exports.HttpError=r.HttpError,exports.InvalidBaseUrlError=r.InvalidBaseUrlError,exports.InvalidSchemaError=r.InvalidSchemaError,exports.MiddlewareError=r.MiddlewareError,exports.NetworkError=r.NetworkError,exports.PathParameterError=r.PathParameterError,exports.SchemaValidationError=r.SchemaValidationError,exports.SerializationError=r.SerializationError,exports.TimeoutError=r.TimeoutError,exports.createHttpClient=r.createHttpClient,exports.createSchemaValidator=r.createSchemaValidator,exports.default=e,exports.http=e;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { createHttpClient } from './client'\n\nexport { createHttpClient } from './client'\nexport { createSchemaValidator } from './schema'\n\nexport const http = /* @__PURE__ */ createHttpClient()\nexport default http\n\nexport {\n AsyncSchemaValidationError,\n HttpError,\n InvalidBaseUrlError,\n InvalidSchemaError,\n MiddlewareError,\n NetworkError,\n PathParameterError,\n SchemaValidationError,\n SerializationError,\n TimeoutError,\n} from './errors'\n\nexport type {\n CustomFetch,\n DownloadStreamingEvent,\n EnforcedPathParamsOptions,\n ExtractableResponse,\n FetchOptions,\n HttpHeaders,\n HttpMethod,\n InferSchemaOutput,\n RequestContext,\n RequestOptions,\n RequestParamsType,\n ResponseType,\n RetryContext,\n RetryEvent,\n RetryJitter,\n RetryOptions,\n Schema,\n SchemaableResponse,\n SerializeBody,\n SerializeParams,\n UploadStreamingEvent,\n} from './types'\n\nexport type { HttpClientConfig, HttpRequestOptions } from './core'\nexport type { SchemaValidator } from './schema'\n"],"mappings":"uIAKA,IAAa,EAAuB,EAAA"}
|