@zimic/fetch 0.1.0-canary.2 → 0.1.0-canary.21

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,12 +1,13 @@
1
- import { HttpSchema, HttpSchemaPath, HttpSchemaMethod, HttpMethod, HttpSearchParams, HttpMethodSchema, HttpRequest, HttpRequestHeadersSchema, AllowAnyStringInPathParams, LiteralHttpSchemaPathFromNonLiteral, HttpRequestSchema, HttpStatusCode, HttpResponse, HttpResponseBodySchema, HttpResponseHeadersSchema, HttpHeaders, JSONValue, HttpResponseSchemaStatusCode } from '@zimic/http';
2
-
3
- type Default<Type, IfEmpty = never> = [undefined | void] extends [Type] ? IfEmpty : Exclude<Type, undefined | void>;
4
- type DefaultNoExclude<Type, IfEmpty = never> = [undefined | void] extends Type ? IfEmpty : Type;
5
- type IfNever<Type, Yes, No = Type> = [Type] extends [never] ? Yes : No;
6
- type PossiblePromise<Type> = Type | PromiseLike<Type>;
7
- type ReplaceBy<Type, Source, Target> = Type extends Source ? Target : Type;
1
+ import { HttpSchema, HttpSchemaMethod, HttpSchemaPath, HttpRequestSchema, HttpHeaders, HttpSearchParams, JSONValue, HttpMethod, HttpHeadersSchema, HttpSearchParamsSchema, HttpMethodSchema, HttpStatusCode, HttpResponseSchemaStatusCode, HttpResponse, HttpResponseBodySchema, HttpResponseHeadersSchema, HttpRequest, HttpRequestHeadersSchema, AllowAnyStringInPathParams, LiteralHttpSchemaPathFromNonLiteral } from '@zimic/http';
8
2
 
9
3
  declare const value: unique symbol;
4
+ /**
5
+ * Represents a value stringified by `JSON.stringify`, maintaining a reference to the original type.
6
+ *
7
+ * This type is used to validate that the expected stringified body is passed to `fetch`.
8
+ *
9
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#using-a-json-body}
10
+ */
10
11
  type JSONStringified<Value> = string & {
11
12
  [value]: Value;
12
13
  };
@@ -16,101 +17,927 @@ declare global {
16
17
  }
17
18
  }
18
19
 
20
+ type Default<Type, IfEmpty = never> = [undefined | void] extends [Type] ? IfEmpty : Exclude<Type, undefined | void>;
21
+ type DefaultNoExclude<Type, IfEmpty = never> = [undefined | void] extends Type ? IfEmpty : Type;
22
+ type IfNever<Type, Yes, No = Type> = [Type] extends [never] ? Yes : No;
23
+ type PossiblePromise<Type> = Type | PromiseLike<Type>;
24
+ type ReplaceBy<Type, Source, Target> = Type extends Source ? Target : Type;
25
+ type RequiredByKey<Type, Key extends keyof Type> = Omit<Type, Key> & Required<Pick<Type, Key>>;
26
+
27
+ type FetchRequestInitHeaders<RequestSchema extends HttpRequestSchema> = RequestSchema['headers'] | HttpHeaders<Default<RequestSchema['headers']>>;
19
28
  type FetchRequestInitWithHeaders<RequestSchema extends HttpRequestSchema> = [RequestSchema['headers']] extends [never] ? {
20
29
  headers?: undefined;
21
30
  } : undefined extends RequestSchema['headers'] ? {
22
- headers?: RequestSchema['headers'] | HttpHeaders<Default<RequestSchema['headers']>>;
31
+ headers?: FetchRequestInitHeaders<RequestSchema>;
23
32
  } : {
24
- headers: RequestSchema['headers'] | HttpHeaders<Default<RequestSchema['headers']>>;
33
+ headers: FetchRequestInitHeaders<RequestSchema>;
25
34
  };
35
+ type FetchRequestInitSearchParams<RequestSchema extends HttpRequestSchema> = RequestSchema['searchParams'] | HttpSearchParams<Default<RequestSchema['searchParams']>>;
26
36
  type FetchRequestInitWithSearchParams<RequestSchema extends HttpRequestSchema> = [
27
37
  RequestSchema['searchParams']
28
38
  ] extends [never] ? {
29
39
  searchParams?: undefined;
30
40
  } : undefined extends RequestSchema['searchParams'] ? {
31
- searchParams?: RequestSchema['searchParams'] | HttpSearchParams<Default<RequestSchema['searchParams']>>;
41
+ searchParams?: FetchRequestInitSearchParams<RequestSchema>;
32
42
  } : {
33
- searchParams: RequestSchema['searchParams'] | HttpSearchParams<Default<RequestSchema['searchParams']>>;
43
+ searchParams: FetchRequestInitSearchParams<RequestSchema>;
34
44
  };
35
45
  type FetchRequestInitWithBody<RequestSchema extends HttpRequestSchema> = [RequestSchema['body']] extends [never] ? {
36
46
  body?: null;
37
- } : undefined extends RequestSchema['body'] ? {
47
+ } : RequestSchema['body'] extends string ? undefined extends RequestSchema['body'] ? {
38
48
  body?: ReplaceBy<RequestSchema['body'], undefined, null>;
39
- } : RequestSchema['body'] extends string ? {
49
+ } : {
40
50
  body: RequestSchema['body'];
41
- } : RequestSchema['body'] extends JSONValue ? {
51
+ } : RequestSchema['body'] extends JSONValue ? undefined extends RequestSchema['body'] ? {
52
+ body?: JSONStringified<ReplaceBy<RequestSchema['body'], undefined, null>>;
53
+ } : {
42
54
  body: JSONStringified<RequestSchema['body']>;
55
+ } : undefined extends RequestSchema['body'] ? {
56
+ body?: ReplaceBy<RequestSchema['body'], undefined, null>;
43
57
  } : {
44
58
  body: RequestSchema['body'];
45
59
  };
46
60
  type FetchRequestInitPerPath<RequestSchema extends HttpRequestSchema> = FetchRequestInitWithHeaders<RequestSchema> & FetchRequestInitWithSearchParams<RequestSchema> & FetchRequestInitWithBody<RequestSchema>;
47
- type FetchRequestInit<Schema extends HttpSchema, Path extends HttpSchemaPath<Schema, Method>, Method extends HttpSchemaMethod<Schema>> = RequestInit & {
48
- baseURL?: string;
61
+ /**
62
+ * The options to create a {@link FetchRequest} instance, compatible with
63
+ * {@link https://developer.mozilla.org/docs/Web/API/RequestInit `RequestInit`}.
64
+ *
65
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}
66
+ * @see {@link https://developer.mozilla.org/docs/Web/API/RequestInit `RequestInit`}
67
+ */
68
+ type FetchRequestInit<Schema extends HttpSchema, Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath<Schema, Method>, Redirect extends RequestRedirect = 'follow'> = Omit<RequestInit, 'method' | 'headers' | 'body'> & {
69
+ /** The HTTP method of the request. */
49
70
  method: Method;
71
+ /** The base URL to prefix the path of the request. */
72
+ baseURL?: string;
73
+ redirect?: Redirect;
50
74
  } & (Path extends Path ? FetchRequestInitPerPath<Default<Default<Schema[Path][Method]>['request']>> : never);
51
75
  declare namespace FetchRequestInit {
52
- interface Defaults extends RequestInit {
76
+ /** The default options for each request sent by a fetch instance. */
77
+ interface Defaults extends Omit<RequestInit, 'headers'> {
53
78
  baseURL: string;
79
+ /** The HTTP method of the request. */
54
80
  method?: HttpMethod;
55
- searchParams?: HttpSearchParams;
81
+ /** The headers of the request. */
82
+ headers?: HttpHeadersSchema;
83
+ /** The search parameters of the request. */
84
+ searchParams?: HttpSearchParamsSchema;
56
85
  }
86
+ /** A loosely typed version of {@link FetchRequestInit `FetchRequestInit`}. */
87
+ type Loose = Partial<Defaults>;
57
88
  }
58
89
  type AllFetchResponseStatusCode<MethodSchema extends HttpMethodSchema> = HttpResponseSchemaStatusCode<Default<MethodSchema['response']>>;
59
- type FetchResponseStatusCode<MethodSchema extends HttpMethodSchema, ErrorOnly extends boolean> = ErrorOnly extends true ? AllFetchResponseStatusCode<MethodSchema> & (HttpStatusCode.ClientError | HttpStatusCode.ServerError) : AllFetchResponseStatusCode<MethodSchema>;
90
+ type FilterFetchResponseStatusCodeByError<StatusCode extends HttpStatusCode, ErrorOnly extends boolean> = ErrorOnly extends true ? Extract<StatusCode, HttpStatusCode.ClientError | HttpStatusCode.ServerError> : StatusCode;
91
+ type FilterFetchResponseStatusCodeByRedirect<StatusCode extends HttpStatusCode, Redirect extends RequestRedirect> = Redirect extends 'error' ? FilterFetchResponseStatusCodeByRedirect<StatusCode, 'follow'> : Redirect extends 'follow' ? Exclude<StatusCode, Exclude<HttpStatusCode.Redirection, 304>> : StatusCode;
92
+ type FetchResponseStatusCode<MethodSchema extends HttpMethodSchema, ErrorOnly extends boolean, Redirect extends RequestRedirect> = FilterFetchResponseStatusCodeByRedirect<FilterFetchResponseStatusCodeByError<AllFetchResponseStatusCode<MethodSchema>, ErrorOnly>, Redirect>;
60
93
  type HttpRequestBodySchema<MethodSchema extends HttpMethodSchema> = ReplaceBy<ReplaceBy<IfNever<DefaultNoExclude<Default<MethodSchema['request']>['body']>, null>, undefined, null>, ArrayBuffer, Blob>;
61
- interface FetchRequest<Path extends string = string, Method extends HttpMethod = HttpMethod, MethodSchema extends HttpMethodSchema = HttpMethodSchema> extends HttpRequest<HttpRequestBodySchema<MethodSchema>, HttpRequestHeadersSchema<MethodSchema>> {
94
+ /**
95
+ * A request instance typed with an HTTP schema, closely compatible with the
96
+ * {@link https://developer.mozilla.org/docs/Web/API/Request native Request class}.
97
+ *
98
+ * On top of the properties available in native {@link https://developer.mozilla.org/docs/Web/API/Request `Request`}
99
+ * instances, fetch requests have their URL automatically prefixed with the base URL of their fetch instance. Default
100
+ * options are also applied, if present in the fetch instance.
101
+ *
102
+ * The path of the request is extracted from the URL, excluding the base URL, and is available in the `path` property.
103
+ *
104
+ * @example
105
+ * import { type HttpSchema } from '@zimic/http';
106
+ * import { createFetch } from '@zimic/fetch';
107
+ *
108
+ * interface User {
109
+ * id: string;
110
+ * username: string;
111
+ * }
112
+ *
113
+ * type Schema = HttpSchema<{
114
+ * '/users': {
115
+ * POST: {
116
+ * request: {
117
+ * headers: { 'content-type': 'application/json' };
118
+ * body: { username: string };
119
+ * };
120
+ * response: {
121
+ * 201: { body: User };
122
+ * };
123
+ * };
124
+ * };
125
+ * }>;
126
+ *
127
+ * const fetch = createFetch<Schema>({
128
+ * baseURL: 'http://localhost:3000',
129
+ * });
130
+ *
131
+ * const request = new fetch.Request('/users', {
132
+ * method: 'POST',
133
+ * headers: { 'content-type': 'application/json' },
134
+ * body: JSON.stringify({ username: 'me' }),
135
+ * });
136
+ *
137
+ * console.log(request); // FetchRequest<Schema, 'POST', '/users'>
138
+ * console.log(request.path); // '/users'
139
+ *
140
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchrequest `FetchRequest` API reference}
141
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Request}
142
+ */
143
+ interface FetchRequest<Schema extends HttpSchema, Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.Literal<Schema, Method>> extends HttpRequest<HttpRequestBodySchema<Default<Schema[Path][Method]>>, HttpRequestHeadersSchema<Default<Schema[Path][Method]>>> {
144
+ /** The path of the request, excluding the base URL. */
62
145
  path: AllowAnyStringInPathParams<Path>;
146
+ /** The HTTP method of the request. */
63
147
  method: Method;
64
148
  }
65
149
  declare namespace FetchRequest {
150
+ /** A loosely typed version of {@link FetchRequest `FetchRequest`}. */
66
151
  interface Loose extends Request {
152
+ /** The path of the request, excluding the base URL. */
67
153
  path: string;
154
+ /** The HTTP method of the request. */
68
155
  method: HttpMethod;
156
+ /** Clones the request instance, returning a new instance with the same properties. */
69
157
  clone: () => Loose;
70
158
  }
71
159
  }
72
- interface FetchResponsePerStatusCode<Path extends string = string, Method extends HttpMethod = HttpMethod, MethodSchema extends HttpMethodSchema = HttpMethodSchema, StatusCode extends HttpStatusCode = HttpStatusCode> extends HttpResponse<HttpResponseBodySchema<MethodSchema, StatusCode>, StatusCode, HttpResponseHeadersSchema<MethodSchema, StatusCode>> {
73
- request: FetchRequest<Path, Method, MethodSchema>;
74
- error: StatusCode extends HttpStatusCode.ClientError | HttpStatusCode.ServerError ? FetchResponseError<Path, Method, MethodSchema> : null;
160
+ interface FetchResponsePerStatusCode<Schema extends HttpSchema, Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.Literal<Schema, Method>, StatusCode extends HttpStatusCode = HttpStatusCode> extends HttpResponse<HttpResponseBodySchema<Default<Schema[Path][Method]>, StatusCode>, StatusCode, HttpResponseHeadersSchema<Default<Schema[Path][Method]>, StatusCode>> {
161
+ /** The request that originated the response. */
162
+ request: FetchRequest<Schema, Method, Path>;
163
+ /**
164
+ * An error representing a response with a failure status code (4XX or 5XX). It can be thrown to handle the error
165
+ * upper in the call stack.
166
+ *
167
+ * If the response has a success status code (1XX, 2XX or 3XX), this property will be null.
168
+ */
169
+ error: StatusCode extends HttpStatusCode.ClientError | HttpStatusCode.ServerError ? FetchResponseError<Schema, Method, Path> : null;
75
170
  }
76
- type FetchResponse<Path extends string = string, Method extends HttpMethod = HttpMethod, MethodSchema extends HttpMethodSchema = HttpMethodSchema, ErrorOnly extends boolean = false, StatusCode extends FetchResponseStatusCode<MethodSchema, ErrorOnly> = FetchResponseStatusCode<MethodSchema, ErrorOnly>> = StatusCode extends StatusCode ? FetchResponsePerStatusCode<Path, Method, MethodSchema, StatusCode> : never;
171
+ /**
172
+ * A response instance typed with an HTTP schema, closely compatible with the
173
+ * {@link https://developer.mozilla.org/docs/Web/API/Response native Response class}.
174
+ *
175
+ * On top of the properties available in native Response instances, fetch responses have a reference to the request that
176
+ * originated them, available in the `request` property.
177
+ *
178
+ * If the response has a failure status code (4XX or 5XX), an error is available in the `error` property.
179
+ *
180
+ * @example
181
+ * import { type HttpSchema } from '@zimic/http';
182
+ * import { createFetch } from '@zimic/fetch';
183
+ *
184
+ * interface User {
185
+ * id: string;
186
+ * username: string;
187
+ * }
188
+ *
189
+ * type Schema = HttpSchema<{
190
+ * '/users/:userId': {
191
+ * GET: {
192
+ * response: {
193
+ * 200: { body: User };
194
+ * 404: { body: { message: string } };
195
+ * };
196
+ * };
197
+ * };
198
+ * }>;
199
+ *
200
+ * const fetch = createFetch<Schema>({
201
+ * baseURL: 'http://localhost:3000',
202
+ * });
203
+ *
204
+ * const response = await fetch(`/users/${userId}`, {
205
+ * method: 'GET',
206
+ * });
207
+ *
208
+ * console.log(response); // FetchResponse<Schema, 'GET', '/users'>
209
+ *
210
+ * if (response.status === 404) {
211
+ * const errorBody = await response.json(); // { message: string }
212
+ * console.error(errorBody.message);
213
+ * return null;
214
+ * } else {
215
+ * const user = await response.json(); // User
216
+ * return user;
217
+ * }
218
+ *
219
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponse `FetchResponse` API reference}
220
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Response}
221
+ */
222
+ type FetchResponse<Schema extends HttpSchema, Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.Literal<Schema, Method>, ErrorOnly extends boolean = false, Redirect extends RequestRedirect = 'follow', StatusCode extends FetchResponseStatusCode<Default<Schema[Path][Method]>, ErrorOnly, Redirect> = FetchResponseStatusCode<Default<Schema[Path][Method]>, ErrorOnly, Redirect>> = StatusCode extends StatusCode ? FetchResponsePerStatusCode<Schema, Method, Path, StatusCode> : never;
77
223
  declare namespace FetchResponse {
224
+ /** A loosely typed version of {@link FetchResponse}. */
78
225
  interface Loose extends Response {
226
+ /** The request that originated the response. */
79
227
  request: FetchRequest.Loose;
228
+ /**
229
+ * An error representing a response with a failure status code (4XX or 5XX). It can be thrown to handle the error
230
+ * upper in the call stack.
231
+ *
232
+ * If the response has a success status code (1XX, 2XX or 3XX), this property will be null.
233
+ */
80
234
  error: AnyFetchRequestError | null;
235
+ /** Clones the request instance, returning a new instance with the same properties. */
81
236
  clone: () => Loose;
82
237
  }
83
238
  }
84
- type FetchRequestConstructor<Schema extends HttpSchema> = new <Path extends HttpSchemaPath.NonLiteral<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(input: FetchInput<Schema, Path, Method>, init: FetchRequestInit<Schema, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method>) => FetchRequest<LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method, Default<Schema[LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>][Method]>>;
239
+ /**
240
+ * A constructor for {@link FetchRequest} instances, typed with an HTTP schema and compatible with the
241
+ * {@link https://developer.mozilla.org/docs/Web/API/Request Request class constructor}.
242
+ *
243
+ * @example
244
+ * import { type HttpSchema } from '@zimic/http';
245
+ * import { createFetch } from '@zimic/fetch';
246
+ *
247
+ * type Schema = HttpSchema<{
248
+ * // ...
249
+ * }>;
250
+ *
251
+ * const fetch = createFetch<Schema>({
252
+ * baseURL: 'http://localhost:3000',
253
+ * });
254
+ *
255
+ * const request = new fetch.Request('POST', '/users', {
256
+ * body: JSON.stringify({ username: 'me' }),
257
+ * });
258
+ * console.log(request); // FetchRequest<Schema, 'POST', '/users'>
259
+ *
260
+ * @param input The resource to fetch, either a path, a URL, or a {@link FetchRequest request}. If a path is provided, it
261
+ * is automatically prefixed with the base URL of the fetch instance when the request is sent. If a URL or a request
262
+ * is provided, it is used as is.
263
+ * @param init The request options. If a path or a URL is provided as the first argument, this argument is required and
264
+ * should contain at least the method of the request. If the first argument is a {@link FetchRequest request}, this
265
+ * argument is optional.
266
+ * @returns A promise that resolves to the response to the request.
267
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponse `FetchResponse` API reference}
268
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Request}
269
+ */
270
+ type FetchRequestConstructor<Schema extends HttpSchema> = new <Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.NonLiteral<Schema, Method>>(input: FetchInput<Schema, Method, Path>, init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>) => FetchRequest<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>;
85
271
 
86
- declare class FetchResponseError<Path extends string = string, Method extends HttpMethod = HttpMethod, MethodSchema extends HttpMethodSchema = HttpMethodSchema> extends Error {
87
- request: FetchRequest<Path, Method, MethodSchema>;
88
- response: FetchResponse<Path, Method, MethodSchema, true>;
89
- constructor(request: FetchRequest<Path, Method, MethodSchema>, response: FetchResponse<Path, Method, MethodSchema, true>);
90
- get cause(): FetchResponse<Path, Method, MethodSchema, true>;
272
+ /**
273
+ * An error representing a response with a failure status code (4XX or 5XX).
274
+ *
275
+ * @example
276
+ * import { type HttpSchema } from '@zimic/http';
277
+ * import { createFetch } from '@zimic/fetch';
278
+ *
279
+ * interface User {
280
+ * id: string;
281
+ * username: string;
282
+ * }
283
+ *
284
+ * type Schema = HttpSchema<{
285
+ * '/users/:userId': {
286
+ * GET: {
287
+ * response: {
288
+ * 200: { body: User };
289
+ * 404: { body: { message: string } };
290
+ * };
291
+ * };
292
+ * };
293
+ * }>;
294
+ *
295
+ * const fetch = createFetch<Schema>({
296
+ * baseURL: 'http://localhost:3000',
297
+ * });
298
+ *
299
+ * const response = await fetch(`/users/${userId}`, {
300
+ * method: 'GET',
301
+ * });
302
+ *
303
+ * if (!response.ok) {
304
+ * console.log(response.status); // 404
305
+ *
306
+ * console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>
307
+ * console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>
308
+ * console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>
309
+ * }
310
+ *
311
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}
312
+ */
313
+ declare class FetchResponseError<Schema extends HttpSchema, Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.Literal<Schema, Method>> extends Error {
314
+ request: FetchRequest<Schema, Method, Path>;
315
+ response: FetchResponse<Schema, Method, Path, true, 'manual'>;
316
+ constructor(request: FetchRequest<Schema, Method, Path>, response: FetchResponse<Schema, Method, Path, true, 'manual'>);
317
+ get cause(): FetchResponse<Schema, Method, Path, true, "manual">;
91
318
  }
92
319
  type AnyFetchRequestError = FetchResponseError<any, any, any>;
93
320
 
94
- type FetchInput<Schema extends HttpSchema, Path extends HttpSchemaPath.NonLiteral<Schema, Method>, Method extends HttpSchemaMethod<Schema>> = Path | URL | FetchRequest<LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method, Default<Schema[LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>][Method]>>;
321
+ /**
322
+ * The input to fetch a resource, either a path, a URL, or a {@link FetchRequest request}.
323
+ *
324
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}
325
+ */
326
+ type FetchInput<Schema extends HttpSchema, Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.NonLiteral<Schema, Method>> = Path | URL | FetchRequest<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>;
95
327
  interface FetchFunction<Schema extends HttpSchema> {
96
- <Path extends HttpSchemaPath.NonLiteral<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(input: Path | URL, init: FetchRequestInit<Schema, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method>): Promise<FetchResponse<LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method, Default<Schema[LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>][Method]>>>;
97
- <Path extends HttpSchemaPath.NonLiteral<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(input: FetchRequest<LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method, Default<Schema[LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>][Method]>>, init?: FetchRequestInit<Schema, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method>): Promise<FetchResponse<LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method, Default<Schema[LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>][Method]>>>;
328
+ <Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.NonLiteral<Schema, Method>, Redirect extends RequestRedirect = 'follow'>(input: Path | URL, init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Redirect>): Promise<FetchResponse<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, false, Redirect>>;
329
+ <Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.NonLiteral<Schema, Method>, Redirect extends RequestRedirect = 'follow'>(input: FetchRequest<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>, init?: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Redirect>): Promise<FetchResponse<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, false, Redirect>>;
330
+ }
331
+ declare namespace FetchFunction {
332
+ type Loose = (input: string | URL | FetchRequest.Loose, init?: FetchRequestInit.Loose) => Promise<FetchResponse.Loose>;
98
333
  }
334
+ /**
335
+ * The options to create a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance}.
336
+ *
337
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#createfetch `createFetch(options)` API reference}
338
+ */
99
339
  interface FetchOptions<Schema extends HttpSchema> extends Omit<FetchRequestInit.Defaults, 'method'> {
100
- onRequest?: (request: FetchRequest.Loose, fetch: Fetch<Schema>) => PossiblePromise<Request>;
101
- onResponse?: (response: FetchResponse.Loose, fetch: Fetch<Schema>) => PossiblePromise<Response>;
340
+ /**
341
+ * A listener function that is called for each request. It can modify the requests before they are sent.
342
+ *
343
+ * @example
344
+ * import { createFetch } from '@zimic/fetch';
345
+ * import { type HttpSchema } from '@zimic/http';
346
+ *
347
+ * interface User {
348
+ * id: string;
349
+ * username: string;
350
+ * }
351
+ *
352
+ * type Schema = HttpSchema<{
353
+ * '/users': {
354
+ * GET: {
355
+ * request: {
356
+ * searchParams: { page?: number; limit?: number };
357
+ * };
358
+ * response: {
359
+ * 200: { body: User[] };
360
+ * };
361
+ * };
362
+ * };
363
+ * }>;
364
+ *
365
+ * const fetch = createFetch<Schema>({
366
+ * baseURL: 'http://localhost:80',
367
+ *
368
+ * onRequest(request) {
369
+ * if (this.isRequest(request, 'GET', '/users')) {
370
+ * const url = new URL(request.url);
371
+ * url.searchParams.append('limit', '10');
372
+ *
373
+ * const updatedRequest = new Request(url, request);
374
+ * return updatedRequest;
375
+ * }
376
+ *
377
+ * return request;
378
+ * },
379
+ * });
380
+ *
381
+ * @param request The original request.
382
+ * @returns The request to be sent. It can be the original request or a modified version of it.
383
+ * @this {Fetch<Schema>} The fetch instance that is sending the request.
384
+ */
385
+ onRequest?: (this: Fetch<Schema>, request: FetchRequest.Loose) => PossiblePromise<Request>;
386
+ /**
387
+ * A listener function that is called after each response is received. It can modify the responses before they are
388
+ * returned to the fetch caller.
389
+ *
390
+ * @example
391
+ * import { type HttpSchema } from '@zimic/http';
392
+ * import { createFetch } from '@zimic/fetch';
393
+ *
394
+ * interface User {
395
+ * id: string;
396
+ * username: string;
397
+ * }
398
+ *
399
+ * type Schema = HttpSchema<{
400
+ * '/users': {
401
+ * GET: {
402
+ * response: {
403
+ * 200: {
404
+ * headers: { 'content-encoding'?: string };
405
+ * body: User[];
406
+ * };
407
+ * };
408
+ * };
409
+ * };
410
+ * }>;
411
+ *
412
+ * const fetch = createFetch<Schema>({
413
+ * baseURL: 'http://localhost:80',
414
+ *
415
+ * onResponse(response) {
416
+ * if (this.isResponse(response, 'GET', '/users')) {
417
+ * console.log(response.headers.get('content-encoding'));
418
+ * }
419
+ * return response;
420
+ * },
421
+ * });
422
+ *
423
+ * @param response The original response.
424
+ * @returns The response to be returned.
425
+ * @this {Fetch<Schema>} The fetch instance that received the response.
426
+ */
427
+ onResponse?: (this: Fetch<Schema>, response: FetchResponse.Loose) => PossiblePromise<Response>;
102
428
  }
103
- interface FetchClient<Schema extends HttpSchema> {
104
- defaults: FetchRequestInit.Defaults;
429
+ /**
430
+ * The default options for each request sent by the fetch instance.
431
+ *
432
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchdefaults `fetch.defaults` API reference}
433
+ */
434
+ type FetchDefaults = RequiredByKey<FetchRequestInit.Defaults, 'headers' | 'searchParams'>;
435
+ interface FetchClient<Schema extends HttpSchema> extends Pick<FetchOptions<Schema>, 'onRequest' | 'onResponse'> {
436
+ /**
437
+ * The default options for each request sent by the fetch instance. The available options are the same as the
438
+ * {@link https://developer.mozilla.org/docs/Web/API/RequestInit `RequestInit`} options, plus `baseURL`.
439
+ *
440
+ * @example
441
+ * import { type HttpSchema } from '@zimic/http';
442
+ * import { createFetch } from '@zimic/fetch';
443
+ *
444
+ * interface Post {
445
+ * id: string;
446
+ * title: string;
447
+ * }
448
+ *
449
+ * type Schema = HttpSchema<{
450
+ * '/posts': {
451
+ * POST: {
452
+ * request: {
453
+ * headers: { 'content-type': 'application/json' };
454
+ * body: { title: string };
455
+ * };
456
+ * response: {
457
+ * 201: { body: Post };
458
+ * };
459
+ * };
460
+ * };
461
+ * }>;
462
+ *
463
+ * const fetch = createFetch<Schema>({
464
+ * baseURL: 'http://localhost:3000',
465
+ * headers: { 'accept-language': 'en' },
466
+ * });
467
+ *
468
+ * // Set the authorization header for all requests
469
+ * const { accessToken } = await authenticate();
470
+ *
471
+ * fetch.defaults.headers.authorization = `Bearer ${accessToken}`;
472
+ * console.log(fetch.defaults.headers);
473
+ *
474
+ * const response = await fetch('/posts', {
475
+ * method: 'POST',
476
+ * headers: { 'content-type': 'application/json' },
477
+ * body: JSON.stringify({ title: 'My post' }),
478
+ * });
479
+ *
480
+ * const post = await response.json(); // Post
481
+ */
482
+ defaults: FetchDefaults;
483
+ /**
484
+ * A loosely-typed version of {@link Fetch `fetch`}. This can be useful to make requests with fewer type constraints,
485
+ * such as in {@link onRequest `onRequest`} and {@link onResponse `onResponse`} listeners.
486
+ *
487
+ * @example
488
+ * import { type HttpSchema } from '@zimic/http';
489
+ * import { createFetch } from '@zimic/fetch';
490
+ *
491
+ * interface User {
492
+ * id: string;
493
+ * username: string;
494
+ * }
495
+ *
496
+ * type Schema = HttpSchema<{
497
+ * '/auth/login': {
498
+ * POST: {
499
+ * request: {
500
+ * headers: { 'content-type': 'application/json' };
501
+ * body: { username: string; password: string };
502
+ * };
503
+ * response: {
504
+ * 201: { body: { accessToken: string } };
505
+ * };
506
+ * };
507
+ * };
508
+ *
509
+ * '/auth/refresh': {
510
+ * POST: {
511
+ * response: {
512
+ * 201: { body: { accessToken: string } };
513
+ * };
514
+ * };
515
+ * };
516
+ *
517
+ * '/users': {
518
+ * GET: {
519
+ * request: {
520
+ * headers: { authorization: string };
521
+ * };
522
+ * response: {
523
+ * 200: { body: User[] };
524
+ * 401: { body: { message: string } };
525
+ * 403: { body: { message: string } };
526
+ * };
527
+ * };
528
+ * };
529
+ * }>;
530
+ *
531
+ * const fetch = createFetch<Schema>({
532
+ * baseURL,
533
+ *
534
+ * async onResponse(response) {
535
+ * if (response.status === 401) {
536
+ * const body = await response.clone().json();
537
+ *
538
+ * if (body.message === 'Access token expired') {
539
+ * // Refresh the access token
540
+ * const refreshResponse = await this('/auth/refresh', { method: 'POST' });
541
+ * const { accessToken } = await refreshResponse.json();
542
+ *
543
+ * // Clone the original request and update its headers
544
+ * const updatedRequest = response.request.clone();
545
+ * updatedRequest.headers.set('authorization', `Bearer ${accessToken}`);
546
+ *
547
+ * // Retry the original request with the updated headers
548
+ * return this.loose(updatedRequest);
549
+ * }
550
+ * }
551
+ *
552
+ * return response;
553
+ * },
554
+ * });
555
+ *
556
+ * // Authenticate to your service before requests
557
+ * const loginRequest = await fetch('/auth/login', {
558
+ * method: 'POST',
559
+ * headers: { 'content-type': 'application/json' },
560
+ * body: JSON.stringify({ username: 'me', password: 'password' }),
561
+ * });
562
+ * const { accessToken } = await loginRequest.json();
563
+ *
564
+ * // Set the authorization header for all requests
565
+ * fetch.defaults.headers.authorization = `Bearer ${accessToken}`;
566
+ *
567
+ * const request = await fetch('/users', {
568
+ * method: 'GET',
569
+ * searchParams: { query: 'u' },
570
+ * });
571
+ *
572
+ * const users = await request.json(); // User[]
573
+ *
574
+ * @param input The resource to fetch, either a path, a URL, or a {@link FetchRequest request}. If a path is provided,
575
+ * it is automatically prefixed with the base URL of the fetch instance when the request is sent. If a URL or a
576
+ * request is provided, it is used as is.
577
+ * @param init The request options. If a path or a URL is provided as the first argument, this argument is required
578
+ * and should contain at least the method of the request. If the first argument is a {@link FetchRequest request},
579
+ * this argument is optional.
580
+ * @returns A promise that resolves to the response to the request.
581
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchloose `fetch.loose` API reference}
582
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Fetch_API}
583
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Request}
584
+ * @see {@link https://developer.mozilla.org/docs/Web/API/RequestInit}
585
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Response}
586
+ */
587
+ loose: FetchFunction.Loose;
588
+ /**
589
+ * A constructor for creating
590
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchrequest-1 `FetchRequest`}, closely compatible with
591
+ * the native {@link https://developer.mozilla.org/docs/Web/API/Request Request} constructor.
592
+ *
593
+ * @example
594
+ * import { type HttpSchema } from '@zimic/http';
595
+ * import { createFetch } from '@zimic/fetch';
596
+ *
597
+ * interface User {
598
+ * id: string;
599
+ * username: string;
600
+ * }
601
+ *
602
+ * type Schema = HttpSchema<{
603
+ * '/users': {
604
+ * POST: {
605
+ * request: {
606
+ * headers: { 'content-type': 'application/json' };
607
+ * body: { username: string };
608
+ * };
609
+ * response: {
610
+ * 201: { body: User };
611
+ * };
612
+ * };
613
+ * };
614
+ * }>;
615
+ *
616
+ * const fetch = createFetch<Schema>({
617
+ * baseURL: 'http://localhost:3000',
618
+ * });
619
+ *
620
+ * const request = new fetch.Request('/users', {
621
+ * method: 'POST',
622
+ * headers: { 'content-type': 'application/json' },
623
+ * body: JSON.stringify({ username: 'me' }),
624
+ * });
625
+ *
626
+ * console.log(request); // FetchRequest<Schema, 'POST', '/users'>
627
+ * console.log(request.path); // '/users'
628
+ *
629
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchrequest-1 `FetchRequest`}
630
+ */
105
631
  Request: FetchRequestConstructor<Schema>;
106
- onRequest?: FetchOptions<Schema>['onRequest'];
107
- onResponse?: FetchOptions<Schema>['onResponse'];
108
- isRequest: <Path extends HttpSchemaPath<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(request: unknown, path: Path, method: Method) => request is FetchRequest<Path, Method, Default<Schema[Path][Method]>>;
109
- isResponse: <Path extends HttpSchemaPath<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(response: unknown, path: Path, method: Method) => response is FetchResponse<Path, Method, Default<Schema[Path][Method]>>;
110
- isResponseError: <Path extends HttpSchemaPath<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(error: unknown, path: Path, method: Method) => error is FetchResponseError<Path, Method, Default<Schema[Path][Method]>>;
632
+ /**
633
+ * A type guard that checks if a request is a {@link FetchRequest}, was created by the fetch instance, and has a
634
+ * specific method and path. This is useful to narrow down the type of a request before using it.
635
+ *
636
+ * @example
637
+ * import { type HttpSchema } from '@zimic/http';
638
+ * import { createFetch } from '@zimic/fetch';
639
+ *
640
+ * interface User {
641
+ * id: string;
642
+ * username: string;
643
+ * }
644
+ *
645
+ * type Schema = HttpSchema<{
646
+ * '/users': {
647
+ * POST: {
648
+ * request: {
649
+ * headers: { 'content-type': 'application/json' };
650
+ * body: { username: string };
651
+ * };
652
+ * response: {
653
+ * 201: { body: User };
654
+ * };
655
+ * };
656
+ * };
657
+ * }>;
658
+ *
659
+ * const fetch = createFetch<Schema>({
660
+ * baseURL: 'http://localhost:3000',
661
+ * });
662
+ *
663
+ * const request = new fetch.Request('/users', {
664
+ * method: 'POST',
665
+ * headers: { 'content-type': 'application/json' },
666
+ * body: JSON.stringify({ username: 'me' }),
667
+ * });
668
+ *
669
+ * if (fetch.isRequest(request, 'POST', '/users')) {
670
+ * // request is a FetchRequest<Schema, 'POST', '/users'>
671
+ *
672
+ * const contentType = request.headers.get('content-type'); // 'application/json'
673
+ * const body = await request.json(); // { username: string }
674
+ * }
675
+ *
676
+ * @param request The request to check.
677
+ * @param method The method to check.
678
+ * @param path The path to check.
679
+ * @returns `true` if the request was created by the fetch instance and has the specified method and path; `false`
680
+ * otherwise.
681
+ */
682
+ isRequest: <Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.Literal<Schema, Method>>(request: unknown, method: Method, path: Path) => request is FetchRequest<Schema, Method, Path>;
683
+ /**
684
+ * A type guard that checks if a response is a {@link FetchResponse}, was received by the fetch instance, and has a
685
+ * specific method and path. This is useful to narrow down the type of a response before using it.
686
+ *
687
+ * @example
688
+ * import { type HttpSchema } from '@zimic/http';
689
+ * import { createFetch } from '@zimic/fetch';
690
+ *
691
+ * interface User {
692
+ * id: string;
693
+ * username: string;
694
+ * }
695
+ *
696
+ * type Schema = HttpSchema<{
697
+ * '/users': {
698
+ * GET: {
699
+ * request: {
700
+ * searchParams: { query?: string };
701
+ * };
702
+ * response: {
703
+ * 200: { body: User[] };
704
+ * };
705
+ * };
706
+ * };
707
+ * }>;
708
+ *
709
+ * const fetch = createFetch<Schema>({
710
+ * baseURL: 'http://localhost:3000',
711
+ * });
712
+ *
713
+ * const response = await fetch('/users', {
714
+ * method: 'GET',
715
+ * searchParams: { query: 'u' },
716
+ * });
717
+ *
718
+ * if (fetch.isResponse(response, 'GET', '/users')) {
719
+ * // response is a FetchResponse<Schema, 'GET', '/users'>
720
+ *
721
+ * const users = await response.json(); // User[]
722
+ * }
723
+ *
724
+ * @param response The response to check.
725
+ * @param method The method to check.
726
+ * @param path The path to check.
727
+ * @returns `true` if the response was received by the fetch instance and has the specified method and path; `false`
728
+ * otherwise.
729
+ */
730
+ isResponse: <Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.Literal<Schema, Method>>(response: unknown, method: Method, path: Path) => response is FetchResponse<Schema, Method, Path>;
731
+ /**
732
+ * A type guard that checks if an error is a {@link FetchResponseError} related to a {@link FetchResponse response}
733
+ * received by the fetch instance with a specific method and path. This is useful to narrow down the type of an error
734
+ * before handling it.
735
+ *
736
+ * @example
737
+ * import { type HttpSchema } from '@zimic/http';
738
+ * import { createFetch } from '@zimic/fetch';
739
+ *
740
+ * interface User {
741
+ * id: string;
742
+ * username: string;
743
+ * }
744
+ *
745
+ * type Schema = HttpSchema<{
746
+ * '/users': {
747
+ * GET: {
748
+ * request: {
749
+ * searchParams: { query?: string };
750
+ * };
751
+ * response: {
752
+ * 200: { body: User[] };
753
+ * 400: { body: { message: string } };
754
+ * 500: { body: { message: string } };
755
+ * };
756
+ * };
757
+ * };
758
+ * }>;
759
+ *
760
+ * const fetch = createFetch<Schema>({
761
+ * baseURL: 'http://localhost:3000',
762
+ * });
763
+ *
764
+ * try {
765
+ * const response = await fetch('/users', {
766
+ * method: 'GET',
767
+ * searchParams: { query: 'u' },
768
+ * });
769
+ *
770
+ * if (!response.ok) {
771
+ * throw response.error; // FetchResponseError<Schema, 'GET', '/users'>
772
+ * }
773
+ * } catch (error) {
774
+ * if (fetch.isResponseError(error, 'GET', '/users')) {
775
+ * // error is a FetchResponseError<Schema, 'GET', '/users'>
776
+ *
777
+ * const status = error.response.status; // 400 | 500
778
+ * const { message } = await error.response.json(); // { message: string }
779
+ *
780
+ * console.error('Could not fetch users:', { status, message });
781
+ * }
782
+ * }
783
+ *
784
+ * @param error The error to check.
785
+ * @param method The method to check.
786
+ * @param path The path to check.
787
+ * @returns `true` if the error is a response error received by the fetch instance and has the specified method and
788
+ * path; `false` otherwise.
789
+ */
790
+ isResponseError: <Method extends HttpSchemaMethod<Schema>, Path extends HttpSchemaPath.Literal<Schema, Method>>(error: unknown, method: Method, path: Path) => error is FetchResponseError<Schema, Method, Path>;
111
791
  }
792
+ /**
793
+ * A fetch instance typed with an HTTP schema, closely compatible with the
794
+ * {@link https://developer.mozilla.org/docs/Web/API/Fetch_API native Fetch API}. All requests and responses are typed by
795
+ * default with the schema, including methods, paths, status codes, parameters, and bodies.
796
+ *
797
+ * Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance. Default
798
+ * options are also applied to the requests, if present in the instance.
799
+ *
800
+ * @example
801
+ * import { type HttpSchema } from '@zimic/http';
802
+ * import { createFetch } from '@zimic/fetch';
803
+ *
804
+ * interface User {
805
+ * id: string;
806
+ * username: string;
807
+ * }
808
+ *
809
+ * type Schema = HttpSchema<{
810
+ * '/users': {
811
+ * GET: {
812
+ * request: {
813
+ * searchParams: { query?: string };
814
+ * };
815
+ * response: {
816
+ * 200: { body: User[] };
817
+ * 404: { body: { message: string } };
818
+ * 500: { body: { message: string } };
819
+ * };
820
+ * };
821
+ * };
822
+ * }>;
823
+ *
824
+ * const fetch = createFetch<Schema>({
825
+ * baseURL: 'http://localhost:3000',
826
+ * headers: { 'accept-language': 'en' },
827
+ * });
828
+ *
829
+ * const response = await fetch('/users', {
830
+ * method: 'GET',
831
+ * searchParams: { query: 'u' },
832
+ * });
833
+ *
834
+ * if (response.status === 404) {
835
+ * return null; // User not found
836
+ * }
837
+ *
838
+ * if (!response.ok) {
839
+ * throw response.error;
840
+ * }
841
+ *
842
+ * const users = await response.json();
843
+ * return users; // User[]
844
+ *
845
+ * @param input The resource to fetch, either a path, a URL, or a {@link FetchRequest request}. If a path is provided, it
846
+ * is automatically prefixed with the base URL of the fetch instance when the request is sent. If a URL or a request
847
+ * is provided, it is used as is.
848
+ * @param init The request options. If a path or a URL is provided as the first argument, this argument is required and
849
+ * should contain at least the method of the request. If the first argument is a {@link FetchRequest request}, this
850
+ * argument is optional.
851
+ * @returns A promise that resolves to the response to the request.
852
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}
853
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Fetch_API}
854
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Request}
855
+ * @see {@link https://developer.mozilla.org/docs/Web/API/RequestInit}
856
+ * @see {@link https://developer.mozilla.org/docs/Web/API/Response}
857
+ */
112
858
  type Fetch<Schema extends HttpSchema> = FetchFunction<Schema> & FetchClient<Schema>;
859
+ /**
860
+ * Infers the schema of a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance}.
861
+ *
862
+ * @example
863
+ * import { type HttpSchema } from '@zimic/http';
864
+ * import { createFetch, InferFetchSchema } from '@zimic/fetch';
865
+ *
866
+ * const fetch = createFetch<{
867
+ * '/users': {
868
+ * GET: {
869
+ * response: { 200: { body: User[] } };
870
+ * };
871
+ * };
872
+ * }>({
873
+ * baseURL: 'http://localhost:3000',
874
+ * });
875
+ *
876
+ * type Schema = InferFetchSchema<typeof fetch>;
877
+ * // {
878
+ * // '/users': {
879
+ * // GET: {
880
+ * // response: { 200: { body: User[] } };
881
+ * // };
882
+ * // };
883
+ *
884
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}
885
+ */
886
+ type InferFetchSchema<FetchInstance> = FetchInstance extends Fetch<infer Schema> ? Schema : never;
113
887
 
114
- declare function createFetch<Schema extends HttpSchema>(options: FetchOptions<HttpSchema<Schema>>): Fetch<HttpSchema<Schema>>;
888
+ /**
889
+ * Creates a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance} typed with an HTTP
890
+ * schema, closely compatible with the {@link https://developer.mozilla.org/docs/Web/API/Fetch_API native Fetch API}. All
891
+ * requests and responses are typed by default with the schema, including methods, paths, status codes, parameters, and
892
+ * bodies.
893
+ *
894
+ * Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance.
895
+ * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch.defaults Default options} are also applied to the
896
+ * requests, if provided.
897
+ *
898
+ * @example
899
+ * import { type HttpSchema } from '@zimic/http';
900
+ * import { createFetch } from '@zimic/fetch';
901
+ *
902
+ * interface User {
903
+ * id: string;
904
+ * username: string;
905
+ * }
906
+ *
907
+ * type Schema = HttpSchema<{
908
+ * '/users': {
909
+ * POST: {
910
+ * request: {
911
+ * headers: { 'content-type': 'application/json' };
912
+ * body: { username: string };
913
+ * };
914
+ * response: {
915
+ * 201: { body: User };
916
+ * };
917
+ * };
918
+ *
919
+ * GET: {
920
+ * request: {
921
+ * searchParams: {
922
+ * query?: string;
923
+ * page?: number;
924
+ * limit?: number;
925
+ * };
926
+ * };
927
+ * response: {
928
+ * 200: { body: User[] };
929
+ * };
930
+ * };
931
+ * };
932
+ * }>;
933
+ *
934
+ * const fetch = createFetch<Schema>({
935
+ * baseURL: 'http://localhost:3000',
936
+ * });
937
+ *
938
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#createfetch `createFetch(options)` API reference}
939
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}
940
+ */
941
+ declare function createFetch<Schema extends HttpSchema>(options: FetchOptions<Schema>): Fetch<Schema>;
115
942
 
116
- export { type Fetch, type FetchClient, type FetchOptions as FetchClientOptions, type FetchFunction, type FetchInput, FetchRequest, type FetchRequestConstructor, FetchRequestInit, FetchResponse, FetchResponseError, createFetch };
943
+ export { type Fetch, type FetchDefaults, type FetchInput, type FetchOptions, FetchRequest, type FetchRequestConstructor, FetchRequestInit, FetchResponse, FetchResponseError, type InferFetchSchema, type JSONStringified, createFetch };