1000fetches 0.2.0 → 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/dist/index.d.ts CHANGED
@@ -1,346 +1,15 @@
1
- import { StandardSchemaV1 } from '@standard-schema/spec';
2
-
3
- export declare class AsyncSchemaValidationError extends Error implements HttpClientError {
4
- readonly name = "AsyncSchemaValidationError";
5
- readonly schema: unknown;
6
- readonly cause?: Error;
7
- constructor(message: string, schema: unknown, cause?: Error);
8
- }
9
-
10
- /**
11
- * Removes optional suffix from param name (e.g., ":id?" -> "id", ":id" -> "id")
12
- */
13
- declare type CleanParamName<S extends string> = S extends `:${infer Name}?` ? Name : S extends `:${infer Name}` ? Name : S;
14
-
15
- /**
16
- * Creates a complete HTTP client with method builders
17
- */
18
- export declare function createHttpClient(config?: HttpClientConfig): {
19
- get: <Path extends string = string, TParams extends RequestParamsType = RequestParamsType>(url: Path, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<never, TParams, Path>] : [options?: EnforcedPathParamsOptions<never, TParams, Path>]) => SchemaableResponse<unknown>;
20
- post: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: EnforcedPathParamsOptions<TBody, TParams, Path>]) => SchemaableResponse<unknown>;
21
- put: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: EnforcedPathParamsOptions<TBody, TParams, Path>]) => SchemaableResponse<unknown>;
22
- patch: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: EnforcedPathParamsOptions<TBody, TParams, Path>]) => SchemaableResponse<unknown>;
23
- delete: <Path extends string = string, TParams extends RequestParamsType = RequestParamsType>(url: Path, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<never, TParams, Path>] : [options?: EnforcedPathParamsOptions<never, TParams, Path>]) => SchemaableResponse<unknown>;
24
- /**
25
- * Generic request method for custom HTTP methods and full control
26
- */
27
- request: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, options?: HttpRequestOptions<TBody, TParams>) => SchemaableResponse<unknown>;
28
- };
29
-
30
- declare type CustomFetch = typeof fetch;
31
-
32
- declare interface DownloadStreamingEvent {
33
- /** Current data chunk being downloaded */
34
- chunk: Uint8Array;
35
- /** Total bytes to download (from Content-Length header, undefined if unknown) */
36
- totalBytes: number | undefined;
37
- /** Bytes already transferred */
38
- transferredBytes: number;
39
- }
40
-
41
- declare type EnforcedPathParamsOptions<TBody = unknown, TParams extends RequestParamsType = RequestParamsType, Path extends string = string> = RequirePathParams<Path, Omit<RequestOptions<TBody>, 'params'> & {
42
- params?: TParams;
43
- }>;
44
-
45
- declare type ExtractableResponse<T> = Promise<ResponseType_2<T>> & {
46
- data(): Promise<T>;
47
- };
48
-
49
- /**
50
- * Extracts all path parameters from a route
51
- */
52
- declare type ExtractRouteParams<T extends string> = NormalizePath<T> extends `${infer _Before}:${infer AfterColon}` ? AfterColon extends `${infer Param}/${infer Rest}` ? CleanParamName<`:${Param}`> | ExtractRouteParams<`/${Rest}`> : CleanParamName<`:${AfterColon}`> : never;
53
-
54
- declare type HasRequiredParams<T extends string> = [
55
- ExtractRouteParams<T>
56
- ] extends [never] ? false : true;
57
-
58
- declare const http: {
59
- get: <Path extends string = string, TParams extends RequestParamsType = RequestParamsType>(url: Path, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<never, TParams, Path>] : [options?: EnforcedPathParamsOptions<never, TParams, Path>]) => SchemaableResponse<unknown>;
60
- post: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: EnforcedPathParamsOptions<TBody, TParams, Path>]) => SchemaableResponse<unknown>;
61
- put: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: EnforcedPathParamsOptions<TBody, TParams, Path>]) => SchemaableResponse<unknown>;
62
- patch: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, body?: TBody, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<TBody, TParams, Path>] : [options?: EnforcedPathParamsOptions<TBody, TParams, Path>]) => SchemaableResponse<unknown>;
63
- delete: <Path extends string = string, TParams extends RequestParamsType = RequestParamsType>(url: Path, ...args: HasRequiredParams<Path> extends true ? [options: EnforcedPathParamsOptions<never, TParams, Path>] : [options?: EnforcedPathParamsOptions<never, TParams, Path>]) => SchemaableResponse<unknown>;
64
- /**
65
- * Generic request method for custom HTTP methods and full control
66
- */
67
- request: <Path extends string = string, TBody = unknown, TParams extends RequestParamsType = RequestParamsType>(url: Path, options?: HttpRequestOptions<TBody, TParams>) => SchemaableResponse<unknown>;
68
- };
69
- export default http;
70
- export { http }
71
-
72
- export declare interface HttpClientConfig {
73
- /** Base URL for all requests */
74
- baseUrl?: string;
75
- /** Default headers */
76
- headers?: HttpHeaders;
77
- /** Default timeout */
78
- timeout?: number;
79
- /** Schema validator */
80
- schemaValidator?: SchemaValidator;
81
- /** Default retry options */
82
- retryOptions?: RetryOptions;
83
- /** Custom fetch implementation */
84
- fetch?: CustomFetch;
85
- /** Custom body serializer */
86
- serializeBody?: SerializeBody;
87
- /** Custom params serializer */
88
- serializeParams?: SerializeParams;
89
- /** Request middleware - can modify request before sending */
90
- onRequestMiddleware?: <TBody = unknown>(context: RequestContext<TBody>) => RequestContext<TBody> | Promise<RequestContext<TBody>>;
91
- /** Response middleware - can modify response after receiving */
92
- onResponseMiddleware?: (response: ResponseType_2<unknown>) => ResponseType_2<unknown> | Promise<ResponseType_2<unknown>>;
93
- }
94
-
95
- declare interface HttpClientError {
96
- name: string;
97
- message: string;
98
- cause?: Error;
99
- stack?: string;
100
- }
101
-
102
- export declare class HttpError<TErrorData = unknown> extends Error implements HttpClientError {
103
- readonly name = "HttpError";
104
- readonly status: number;
105
- readonly statusText: string;
106
- readonly data: TErrorData;
107
- readonly response: Response;
108
- readonly url: string;
109
- readonly method: string;
110
- readonly cause?: Error;
111
- constructor(message: string, status: number, statusText: string, data: TErrorData, response: Response, url: string, method: string, cause?: Error);
112
- }
113
-
114
- export declare type HttpHeaders = Record<string, string>;
115
-
116
- export declare type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
117
-
118
- export declare interface HttpRequestOptions<TBody = unknown, TParams extends RequestParamsType = RequestParamsType> {
119
- method?: HttpMethod;
120
- headers?: HttpHeaders;
121
- /** Query parameters */
122
- params?: TParams;
123
- /** Path parameters for URL template */
124
- pathParams?: Record<string, string | number>;
125
- /** Request body */
126
- body?: TBody;
127
- timeout?: number;
128
- signal?: AbortSignal;
129
- /** Fetch options */
130
- credentials?: RequestCredentials;
131
- cache?: RequestCache;
132
- mode?: RequestMode;
133
- redirect?: RequestRedirect;
134
- /** Upload streaming tracking for this specific request */
135
- onUploadStreaming?: (event: UploadStreamingEvent) => void;
136
- /** Download streaming tracking for this specific request */
137
- onDownloadStreaming?: (event: DownloadStreamingEvent) => void;
138
- /** Response type override */
139
- responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData';
140
- retryOptions?: RetryOptions;
141
- }
142
-
143
- declare type InferSchemaOutput<ResponseSchema> = IsZodSchema<ResponseSchema> extends true ? ResponseSchema extends {
144
- parse: infer ParseFn;
145
- } ? ParseFn extends (...args: any[]) => infer R ? R : unknown : unknown : ResponseSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<ResponseSchema> : unknown;
146
-
147
- declare type IsZodSchema<S> = S extends {
148
- _def: any;
149
- } ? true : false;
150
-
151
- export declare class MiddlewareError extends Error implements HttpClientError {
152
- readonly name = "MiddlewareError";
153
- readonly type: 'request' | 'response';
154
- readonly url?: string;
155
- readonly method?: string;
156
- readonly cause?: Error;
157
- constructor(message: string, type: 'request' | 'response', url?: string, method?: string, cause?: Error);
158
- }
159
-
160
- export declare class NetworkError extends Error implements HttpClientError {
161
- readonly name = "NetworkError";
162
- readonly cause?: Error;
163
- constructor(message: string, cause?: Error);
164
- }
165
-
166
- /**
167
- * Normalizes URL to path only, stripping protocol, host, port, and query
168
- */
169
- declare type NormalizePath<T extends string> = StripQuery<StripHost<StripProtocol<T>>>;
170
-
171
- export declare class PathParameterError extends Error implements HttpClientError {
172
- readonly name = "PathParameterError";
173
- readonly url: string;
174
- readonly requiredParams: string[];
175
- readonly providedParams: string[];
176
- readonly cause?: Error;
177
- constructor(message: string, url: string, requiredParams: string[], providedParams: string[], cause?: Error);
178
- }
179
-
180
- /**
181
- * PathParams type - extracts parameter names and their types
182
- */
183
- declare type PathParams<Path extends string> = {
184
- [K in ExtractRouteParams<Path>]: string | number;
185
- };
186
-
187
- /**
188
- * Request context that can be modified by onRequest hook
189
- */
190
- declare interface RequestContext<TBody = unknown> {
191
- /** The URL to send the request to */
192
- url: string;
193
- /** The HTTP method (GET, POST, etc.) */
194
- method: HttpMethod;
195
- /** Query parameters to append to the URL */
196
- params?: RequestParamsType;
197
- /** Headers to send with the request */
198
- headers: Headers;
199
- /** Request body */
200
- body?: TBody;
201
- /** AbortSignal for request cancellation */
202
- signal?: AbortSignal;
203
- /** Fetch options */
204
- fetchOptions: Omit<RequestInit, 'body' | 'headers' | 'signal' | 'method'>;
205
- }
206
-
207
- export declare interface RequestOptions<TBody = unknown> {
208
- headers?: HttpHeaders;
209
- params?: RequestParamsType;
210
- body?: TBody;
211
- timeout?: number;
212
- signal?: AbortSignal;
213
- responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData';
214
- cache?: RequestCache;
215
- credentials?: RequestCredentials;
216
- mode?: RequestMode;
217
- redirect?: RequestRedirect;
218
- retry?: RetryOptions | boolean;
219
- onUploadStreaming?: (event: UploadStreamingEvent) => void;
220
- onDownloadStreaming?: (event: DownloadStreamingEvent) => void;
221
- }
222
-
223
- declare type RequestParamsType = Record<string, string | number | boolean | (string | number | boolean | undefined | null)[] | undefined | null>;
224
-
225
- /**
226
- * RequirePathParams enforces pathParams when needed
227
- */
228
- declare type RequirePathParams<Path extends string, T> = HasRequiredParams<Path> extends true ? T & {
229
- pathParams: PathParams<Path>;
230
- } : T;
231
-
232
- declare interface ResponseType_2<T = unknown> {
233
- data: T;
234
- status: number;
235
- statusText: string;
236
- headers: HttpHeaders;
237
- method: HttpMethod;
238
- url: string;
239
- raw: Response;
240
- }
241
- export { ResponseType_2 as ResponseType }
242
-
243
- export declare interface RetryOptions {
244
- /** Maximum number of retry attempts (default: 3) */
245
- maxRetries?: number;
246
- /** Base delay between retries in milliseconds (default: 300) */
247
- retryDelay?: number;
248
- /** Exponential backoff factor (default: 2) */
249
- backoffFactor?: number;
250
- /** Status codes that should trigger a retry (default: [408, 429, 500, 502, 503, 504]) */
251
- retryStatusCodes?: number[];
252
- /** Whether to retry on network errors (default: true) */
253
- retryNetworkErrors?: boolean;
254
- /** Maximum retry delay in milliseconds (default: 30_000) */
255
- maxRetryDelay?: number;
256
- /** Custom function to determine if a request should be retried */
257
- shouldRetry?: (error: Error, retryCount: number) => boolean | Promise<boolean>;
258
- }
259
-
260
- export declare type Schema<T = unknown> = StandardSchemaV1<unknown, T> | (StandardSchemaV1<unknown, T> & {
261
- _output: T;
262
- }) | (StandardSchemaV1<unknown, T> & {
263
- _output?: T;
264
- });
265
-
266
- declare type SchemaableResponse<T> = ExtractableResponse<T> & {
267
- schema<S extends Schema>(schema: S): ExtractableResponse<InferSchemaOutput<S>>;
268
- };
269
-
270
- export declare class SchemaValidationError extends Error implements HttpClientError {
271
- readonly name = "SchemaValidationError";
272
- readonly schema: unknown;
273
- readonly data: unknown;
274
- readonly cause?: Error;
275
- constructor(message: string, schema: unknown, data: unknown, cause?: Error);
276
- }
277
-
278
- /**
279
- * Interface for schema validators that can validate data against schemas.
280
- *
281
- * This interface allows you to create custom schema validators that work
282
- * with different validation libraries (Zod, Valibot, Arktype, etc.).
283
- */
284
- declare interface SchemaValidator {
285
- /**
286
- * Validate data against a schema.
287
- *
288
- * @template T - The expected type after validation
289
- * @param schema - The schema to validate against
290
- * @param data - The data to validate
291
- * @returns The validated data with the correct type
292
- * @throws {SchemaValidationError} If the data doesn't match the schema
293
- */
294
- validate<T>(schema: Schema<T>, data: unknown): T;
295
- /**
296
- * Check if an object is a valid schema.
297
- *
298
- * @param obj - The object to check
299
- * @returns True if the object is a valid schema, false otherwise
300
- */
301
- isSchema(obj: unknown): boolean;
302
- }
303
-
304
- export declare class SerializationError extends Error implements HttpClientError {
305
- readonly name = "SerializationError";
306
- readonly cause?: Error;
307
- constructor(message: string, cause?: Error);
308
- }
309
-
310
- declare type SerializeBody<TBody = unknown> = (body: TBody) => BodyInit | null | undefined;
311
-
312
- declare type SerializeParams = (params: RequestParamsType) => string;
313
-
314
- /**
315
- * Strips host and optional port from URL, keeping only the path
316
- * Handles cases like "localhost:3000/users" -> "/users"
317
- */
318
- declare type StripHost<T extends string> = T extends `${infer _Host}/${infer Path}` ? `/${Path}` : T;
319
-
320
- /**
321
- * Strips protocol from URL (e.g., https://, http://)
322
- */
323
- declare type StripProtocol<T extends string> = T extends `${string}://${infer After}` ? After : T;
324
-
325
- /**
326
- * Strips query string from path (e.g., "/users?x=1" -> "/users")
327
- * Only strips ? that comes after the path, not ? that's part of path parameters
328
- */
329
- declare type StripQuery<T extends string> = T extends `${infer Path}?${infer Query}` ? Query extends `${string}=${string}` | `${string}&${string}` | `${string}=${string}&${string}` ? Path : Query extends `/${string}` ? T : Query extends `` ? T : Path : T;
330
-
331
- export declare class TimeoutError extends Error implements HttpClientError {
332
- readonly name = "TimeoutError";
333
- readonly cause?: Error;
334
- constructor(message: string, cause?: Error);
335
- }
336
-
337
- declare interface UploadStreamingEvent {
338
- /** Current data chunk being uploaded */
339
- chunk: Uint8Array;
340
- /** Total bytes to upload (from Content-Length header or body size) */
341
- totalBytes: number | undefined;
342
- /** Bytes already transferred */
343
- transferredBytes: number;
344
- }
345
-
346
- export { }
1
+ export { createHttpClient } from './client';
2
+ export { createSchemaValidator } from './schema';
3
+ export declare const http: {
4
+ 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>;
5
+ 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>;
6
+ 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>;
7
+ 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>;
8
+ 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>;
9
+ 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>;
10
+ };
11
+ export default http;
12
+ export { AsyncSchemaValidationError, HttpError, InvalidBaseUrlError, InvalidSchemaError, MiddlewareError, NetworkError, PathParameterError, SchemaValidationError, SerializationError, TimeoutError, } from './errors';
13
+ export type { CustomFetch, DownloadStreamingEvent, EnforcedPathParamsOptions, ExtractableResponse, FetchOptions, HttpHeaders, HttpMethod, InferSchemaOutput, RequestContext, RequestOptions, RequestParamsType, ResponseType, RetryContext, RetryEvent, RetryJitter, RetryOptions, Schema, SchemaableResponse, SerializeBody, SerializeParams, UploadStreamingEvent, } from './types';
14
+ export type { HttpClientConfig, HttpRequestOptions } from './core';
15
+ export type { SchemaValidator } from './schema';
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import{a,c as s,d as r,f as t,i as o,l as e,n as f,o as i,r as l,s as m,t as c,u as d}from"./client-DOv6m2TJ.mjs";var n=/* @__PURE__ */c();export{l as AsyncSchemaValidationError,o as HttpError,a as InvalidBaseUrlError,i as InvalidSchemaError,m as MiddlewareError,s as NetworkError,e as PathParameterError,d as SchemaValidationError,r as SerializationError,t as TimeoutError,c as createHttpClient,f as createSchemaValidator,n as default,n as http};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","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":"kHAKA,IAAa,iBAAuB"}
@@ -0,0 +1,35 @@
1
+ import { Schema } from './types';
2
+ /**
3
+ * Interface for schema validators that can validate data against schemas.
4
+ *
5
+ * This interface allows you to create custom schema validators that work
6
+ * with different validation libraries (Zod, Valibot, Arktype, etc.).
7
+ */
8
+ export interface SchemaValidator {
9
+ /**
10
+ * Validate data against a schema.
11
+ *
12
+ * @template T - The expected type after validation
13
+ * @param schema - The schema to validate against
14
+ * @param data - The data to validate
15
+ * @returns The validated data with the correct type, synchronously or asynchronously
16
+ * @throws {SchemaValidationError} If the data doesn't match the schema
17
+ */
18
+ validate<T>(schema: Schema<T>, data: unknown): T | Promise<T>;
19
+ }
20
+ /**
21
+ * Create a default schema validator that supports Standard Schema.
22
+ *
23
+ * This validator works with schemas that implement the Standard Schema
24
+ * interface, including both synchronous and asynchronous validators.
25
+ *
26
+ * @returns A schema validator instance
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * const validator = createSchemaValidator()
31
+ *
32
+ * const parsed = validator.validate(schema, data)
33
+ * ```
34
+ */
35
+ export declare function createSchemaValidator(): SchemaValidator;
@@ -0,0 +1,145 @@
1
+ import { StandardSchemaV1 } from '@standard-schema/spec';
2
+ import { AssertSupportedPath, RequirePathParams } from './utils';
3
+ export type RetryJitter = 'none' | 'full' | 'equal' | ((delay: number, retryCount: number) => number);
4
+ export interface RetryContext {
5
+ /** The error that may trigger a retry */
6
+ error: Error;
7
+ /** Zero-based retry count for the failed attempt */
8
+ retryCount: number;
9
+ /** HTTP method used for the request */
10
+ method: HttpMethod;
11
+ /** Final request URL after base URL, path params, middleware, and query params */
12
+ url: string;
13
+ /** Whether the serialized request body can be sent again safely */
14
+ bodyReplayable: boolean;
15
+ }
16
+ export interface RetryEvent extends RetryContext {
17
+ /** One-based attempt number that will run after the delay */
18
+ nextAttempt: number;
19
+ /** Delay before the next attempt in milliseconds */
20
+ delay: number;
21
+ }
22
+ export interface RetryOptions {
23
+ /** Maximum number of retry attempts when retries are enabled (default: 3) */
24
+ maxRetries?: number;
25
+ /** Base delay between retries in milliseconds when retries are enabled (default: 300) */
26
+ retryDelay?: number;
27
+ /** Exponential backoff factor (default: 2) */
28
+ backoffFactor?: number;
29
+ /** Status codes that should trigger a retry when retries are enabled (default: [408, 429, 500, 502, 503, 504]) */
30
+ retryStatusCodes?: number[];
31
+ /** Whether to retry on network errors when retries are enabled (default: true) */
32
+ retryNetworkErrors?: boolean;
33
+ /** Maximum retry delay in milliseconds when retries are enabled (default: 30_000) */
34
+ maxRetryDelay?: number;
35
+ /** Methods eligible for built-in retries when retries are enabled (default: idempotent methods) */
36
+ retryMethods?: readonly HttpMethod[];
37
+ /** Allows the built-in retry policy to retry methods outside retryMethods (default: false) */
38
+ retryUnsafeMethods?: boolean;
39
+ /** Applies jitter to calculated exponential backoff delays (default: 'none') */
40
+ jitter?: RetryJitter;
41
+ /** Whether to honor Retry-After response headers on HTTP errors (default: true) */
42
+ respectRetryAfter?: boolean;
43
+ /** Called before waiting for the next retry attempt */
44
+ onRetry?: (event: RetryEvent) => void | Promise<void>;
45
+ /** Custom function to determine if a request should be retried */
46
+ shouldRetry?: (error: Error, retryCount: number, context: RetryContext) => boolean | Promise<boolean>;
47
+ }
48
+ export type FetchOptions = Omit<RequestInit, 'body' | 'headers' | 'signal' | 'method'> & {
49
+ /** Node/undici and future Fetch extensions can be passed through here */
50
+ [option: string]: unknown;
51
+ };
52
+ export type EnforcedPathParamsOptions<TBody = unknown, TParams extends RequestParamsType = RequestParamsType, Path extends string = string> = RequirePathParams<AssertSupportedPath<Path>, string extends Path ? Omit<RequestOptions<TBody>, 'params'> & {
53
+ params?: TParams;
54
+ } : Omit<RequestOptions<TBody>, 'params' | 'pathParams'> & {
55
+ params?: TParams;
56
+ }>;
57
+ export interface RequestOptions<TBody = unknown> {
58
+ headers?: HttpHeaders;
59
+ params?: RequestParamsType;
60
+ pathParams?: Record<string, string | number | undefined>;
61
+ body?: TBody;
62
+ timeout?: number;
63
+ signal?: AbortSignal;
64
+ responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData';
65
+ cache?: RequestCache;
66
+ credentials?: RequestCredentials;
67
+ mode?: RequestMode;
68
+ redirect?: RequestRedirect;
69
+ fetchOptions?: FetchOptions;
70
+ retry?: RetryOptions | boolean;
71
+ onUploadStreaming?: (event: UploadStreamingEvent) => void;
72
+ onDownloadStreaming?: (event: DownloadStreamingEvent) => void;
73
+ }
74
+ export interface ResponseType<T = unknown> {
75
+ data: T;
76
+ status: number;
77
+ statusText: string;
78
+ headers: HttpHeaders;
79
+ method: HttpMethod;
80
+ url: string;
81
+ raw: Response;
82
+ }
83
+ export type ExtractableResponse<T> = Promise<ResponseType<T>> & {
84
+ data(): Promise<T>;
85
+ void(): Promise<void>;
86
+ };
87
+ export type SchemaableResponse<T> = ExtractableResponse<T> & {
88
+ schema<S extends Schema>(schema: S): ExtractableResponse<InferSchemaOutput<S>>;
89
+ };
90
+ /**
91
+ * Request context that can be modified by onRequest hook
92
+ */
93
+ export interface RequestContext<TBody = unknown> {
94
+ /** The URL to send the request to */
95
+ url: string;
96
+ /** The HTTP method (GET, POST, etc.) */
97
+ method: HttpMethod;
98
+ /** Query parameters to append to the URL */
99
+ params?: RequestParamsType;
100
+ /** Headers to send with the request */
101
+ headers: Headers;
102
+ /** Request body */
103
+ body?: TBody;
104
+ /** AbortSignal for request cancellation */
105
+ signal?: AbortSignal;
106
+ /** Fetch options */
107
+ fetchOptions: FetchOptions;
108
+ }
109
+ export interface ExtendedRequestInit extends RequestInit {
110
+ duplex?: 'half';
111
+ }
112
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | (string & {});
113
+ export type HttpHeaders = Record<string, string>;
114
+ export type RequestParamsType = Record<string, string | number | boolean | (string | number | boolean | undefined | null)[] | undefined | null>;
115
+ export type Schema<T = unknown> = StandardSchemaV1<unknown, T> | (StandardSchemaV1<unknown, T> & {
116
+ _output: T;
117
+ }) | (StandardSchemaV1<unknown, T> & {
118
+ _output?: T;
119
+ });
120
+ export type InferSchemaOutput<ResponseSchema> = ResponseSchema extends unknown ? ResponseSchema extends {
121
+ parse: infer ParseFn;
122
+ } ? ParseFn extends (...args: infer _Args) => infer Output ? Awaited<Output> : unknown : ResponseSchema extends {
123
+ _output: infer Output;
124
+ } ? Output : ResponseSchema extends {
125
+ _output?: infer Output;
126
+ } ? Output : ResponseSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<ResponseSchema> : unknown : never;
127
+ export interface UploadStreamingEvent {
128
+ /** Current data chunk being uploaded */
129
+ chunk: Uint8Array;
130
+ /** Total bytes to upload (from Content-Length header or body size) */
131
+ totalBytes: number | undefined;
132
+ /** Bytes already transferred */
133
+ transferredBytes: number;
134
+ }
135
+ export interface DownloadStreamingEvent {
136
+ /** Current data chunk being downloaded */
137
+ chunk: Uint8Array;
138
+ /** Total bytes to download (from Content-Length header, undefined if unknown) */
139
+ totalBytes: number | undefined;
140
+ /** Bytes already transferred */
141
+ transferredBytes: number;
142
+ }
143
+ export type SerializeBody<TBody = unknown> = (body: TBody) => BodyInit | null | undefined;
144
+ export type SerializeParams = (params: RequestParamsType) => string;
145
+ export type CustomFetch = typeof fetch;
@@ -0,0 +1,2 @@
1
+ export { type AssertSupportedPath, generatePath, type HasRequiredParams, type PathParams, type RequirePathParams, } from './path';
2
+ export { toStreamableRequest, toStreamableResponse } from './streaming';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Strips protocol from URL (e.g., https://, http://)
3
+ */
4
+ type StripProtocol<T extends string> = T extends `${string}://${infer After}` ? After : T;
5
+ /**
6
+ * Strips host and optional port from URL, keeping only the path
7
+ * Handles cases like "localhost:3000/users" -> "/users"
8
+ */
9
+ type StripHost<T extends string> = T extends `${infer _Host}/${infer Path}` ? `/${Path}` : T;
10
+ /**
11
+ * Strips query string from path (e.g., "/users?x=1" -> "/users")
12
+ * Only strips ? that comes after the path, not ? that's part of path parameters
13
+ */
14
+ type StripQuery<T extends string> = T extends `${infer Path}?${infer Query}` ? Query extends `${string}=${string}` | `${string}&${string}` | `${string}=${string}&${string}` ? Path : Query extends `/${string}` ? T : Query extends `` ? T : Path : T;
15
+ /**
16
+ * Normalizes URL to path only, stripping protocol, host, port, and query
17
+ */
18
+ type NormalizePath<T extends string> = StripQuery<StripHost<StripProtocol<T>>>;
19
+ /**
20
+ * Removes optional suffix from param name (e.g., ":id?" -> "id", ":id" -> "id")
21
+ */
22
+ type CleanParamName<S extends string> = S extends `:${infer Name}?` ? Name : S extends `:${infer Name}` ? Name : S;
23
+ /**
24
+ * Extracts required path parameters from a route
25
+ */
26
+ type ExtractRequiredRouteParams<T extends string> = NormalizePath<T> extends `${infer _Before}:${infer AfterColon}` ? AfterColon extends `${infer Param}/${infer Rest}` ? Param extends `${string}?` ? ExtractRequiredRouteParams<`/${Rest}`> : CleanParamName<`:${Param}`> | ExtractRequiredRouteParams<`/${Rest}`> : AfterColon extends `${string}?` ? never : CleanParamName<`:${AfterColon}`> : never;
27
+ /**
28
+ * Extracts optional path parameters from a route
29
+ */
30
+ type ExtractOptionalRouteParams<T extends string> = NormalizePath<T> extends `${infer _Before}:${infer AfterColon}` ? AfterColon extends `${infer Param}/${infer Rest}` ? (Param extends `${string}?` ? CleanParamName<`:${Param}`> : never) | ExtractOptionalRouteParams<`/${Rest}`> : AfterColon extends `${string}?` ? CleanParamName<`:${AfterColon}`> : never : never;
31
+ type ExtractRouteParams<T extends string> = ExtractRequiredRouteParams<T> | ExtractOptionalRouteParams<T>;
32
+ type HasNonTrailingOptionalRouteParams<T extends string> = string extends T ? false : NormalizePath<T> extends `${infer _Before}:${infer AfterColon}` ? AfterColon extends `${infer Param}/${infer Rest}` ? Param extends `${string}?` ? true : HasNonTrailingOptionalRouteParams<`/${Rest}`> : false : false;
33
+ export type AssertSupportedPath<Path extends string> = string extends Path ? Path : HasNonTrailingOptionalRouteParams<Path> extends true ? never : Path;
34
+ export type HasRequiredParams<T extends string> = [
35
+ ExtractRequiredRouteParams<T>
36
+ ] extends [never] ? false : true;
37
+ type HasPathParams<T extends string> = [ExtractRouteParams<T>] extends [never] ? false : true;
38
+ type Simplify<T> = {
39
+ [K in keyof T]: T[K];
40
+ };
41
+ /**
42
+ * PathParams type - extracts parameter names and their types
43
+ */
44
+ export type PathParams<Path extends string> = [
45
+ AssertSupportedPath<Path>
46
+ ] extends [never] ? never : Simplify<{
47
+ [K in ExtractRequiredRouteParams<Path>]: string | number;
48
+ } & {
49
+ [K in ExtractOptionalRouteParams<Path>]?: string | number;
50
+ }>;
51
+ /**
52
+ * RequirePathParams enforces pathParams when needed
53
+ */
54
+ export type RequirePathParams<Path extends string, T> = [
55
+ AssertSupportedPath<Path>
56
+ ] extends [never] ? never : HasRequiredParams<Path> extends true ? T & {
57
+ pathParams: PathParams<Path>;
58
+ } : HasPathParams<Path> extends true ? T & {
59
+ pathParams?: PathParams<Path>;
60
+ } : T;
61
+ /**
62
+ * Interpolates parameters into a URL template
63
+ * Similar to React Router's generatePath function
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const path = generatePath('/users/:id/posts/:postId', { id: '123', postId: '456' });
68
+ * // => '/users/123/posts/456'
69
+ * ```
70
+ */
71
+ export declare function generatePath<Path extends string>(path: AssertSupportedPath<Path>): string;
72
+ export declare function generatePath<Path extends string>(path: AssertSupportedPath<Path>, params: PathParams<Path>): string;
73
+ export {};
@@ -0,0 +1,9 @@
1
+ import { DownloadStreamingEvent, UploadStreamingEvent } from '../types';
2
+ /**
3
+ * Creates a request with upload streaming tracking
4
+ */
5
+ export declare function toStreamableRequest(request: Request, onUploadStreaming?: (event: UploadStreamingEvent) => void): Promise<Request>;
6
+ /**
7
+ * Creates a response with download streaming tracking
8
+ */
9
+ export declare function toStreamableResponse(response: Response, onDownloadStreaming?: (event: DownloadStreamingEvent) => void): Promise<Response>;