@zimic/fetch 0.1.3 → 0.2.0-canary.1

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
@@ -147,7 +147,7 @@ interface FetchRequest<Schema extends HttpSchema, Method extends HttpSchemaMetho
147
147
  method: Method;
148
148
  }
149
149
  declare namespace FetchRequest {
150
- /** A loosely typed version of {@link FetchRequest `FetchRequest`}. */
150
+ /** A loosely typed version of a {@link FetchRequest `FetchRequest`}. */
151
151
  interface Loose extends Request {
152
152
  /** The path of the request, excluding the base URL. */
153
153
  path: string;
@@ -157,6 +157,21 @@ declare namespace FetchRequest {
157
157
  clone: () => Loose;
158
158
  }
159
159
  }
160
+ /**
161
+ * A plain object representation of a {@link FetchRequest `FetchRequest`}, compatible with JSON.
162
+ *
163
+ * If the body is included in the object, it is represented as a string or null if empty.
164
+ */
165
+ type FetchRequestObject = Pick<FetchRequest.Loose, 'url' | 'path' | 'method' | 'cache' | 'destination' | 'credentials' | 'integrity' | 'keepalive' | 'mode' | 'redirect' | 'referrer' | 'referrerPolicy'> & {
166
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) */
167
+ headers: HttpHeadersSchema;
168
+ /**
169
+ * The body of the response, represented as a string or null if empty.
170
+ *
171
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body)
172
+ */
173
+ body?: string | null;
174
+ };
160
175
  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
176
  /** The request that originated the response. */
162
177
  request: FetchRequest<Schema, Method, Path>;
@@ -221,7 +236,7 @@ interface FetchResponsePerStatusCode<Schema extends HttpSchema, Method extends H
221
236
  */
222
237
  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;
223
238
  declare namespace FetchResponse {
224
- /** A loosely typed version of {@link FetchResponse}. */
239
+ /** A loosely typed version of a {@link FetchResponse}. */
225
240
  interface Loose extends Response {
226
241
  /** The request that originated the response. */
227
242
  request: FetchRequest.Loose;
@@ -236,6 +251,21 @@ declare namespace FetchResponse {
236
251
  clone: () => Loose;
237
252
  }
238
253
  }
254
+ /**
255
+ * A plain object representation of a {@link FetchResponse `FetchResponse`}, compatible with JSON.
256
+ *
257
+ * If the body is included in the object, it is represented as a string or null if empty.
258
+ */
259
+ type FetchResponseObject = Pick<FetchResponse.Loose, 'url' | 'type' | 'status' | 'statusText' | 'ok' | 'redirected'> & {
260
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) */
261
+ headers: HttpHeadersSchema;
262
+ /**
263
+ * The body of the response, represented as a string or null if empty.
264
+ *
265
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body)
266
+ */
267
+ body?: string | null;
268
+ };
239
269
  /**
240
270
  * A constructor for {@link FetchRequest} instances, typed with an HTTP schema and compatible with the
241
271
  * {@link https://developer.mozilla.org/docs/Web/API/Request Request class constructor}.
@@ -269,6 +299,26 @@ declare namespace FetchResponse {
269
299
  */
270
300
  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>>;
271
301
 
302
+ /**
303
+ * Options for converting a {@link FetchResponseError `FetchResponseError`} into a plain object.
304
+ *
305
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}
306
+ */
307
+ interface FetchResponseErrorObjectOptions {
308
+ includeBody?: boolean;
309
+ }
310
+ /**
311
+ * A plain object representation of a {@link FetchResponseError `FetchResponseError`}, compatible with JSON. It is useful
312
+ * for serialization, debugging, and logging purposes.
313
+ *
314
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}
315
+ */
316
+ interface FetchResponseErrorObject {
317
+ name: string;
318
+ message: string;
319
+ request: FetchRequestObject;
320
+ response: FetchResponseObject;
321
+ }
272
322
  /**
273
323
  * An error representing a response with a failure status code (4XX or 5XX).
274
324
  *
@@ -306,6 +356,10 @@ type FetchRequestConstructor<Schema extends HttpSchema> = new <Method extends Ht
306
356
  * console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>
307
357
  * console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>
308
358
  * console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>
359
+ *
360
+ * const plainError = response.error.toObject();
361
+ * console.log(JSON.stringify(plainError));
362
+ * // {"name":"FetchResponseError","message":"...","request":{...},"response":{...}}
309
363
  * }
310
364
  *
311
365
  * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}
@@ -314,7 +368,41 @@ declare class FetchResponseError<Schema extends HttpSchema, Method extends HttpS
314
368
  request: FetchRequest<Schema, Method, Path>;
315
369
  response: FetchResponse<Schema, Method, Path, true, 'manual'>;
316
370
  constructor(request: FetchRequest<Schema, Method, Path>, response: FetchResponse<Schema, Method, Path, true, 'manual'>);
317
- get cause(): FetchResponse<Schema, Method, Path, true, "manual">;
371
+ /**
372
+ * Converts this error into a plain object. This method is useful for serialization, debugging, and logging purposes.
373
+ *
374
+ * @example
375
+ * const fetch = createFetch<Schema>({
376
+ * baseURL: 'http://localhost:3000',
377
+ * });
378
+ *
379
+ * const response = await fetch(`/users/${userId}`, {
380
+ * method: 'GET',
381
+ * });
382
+ *
383
+ * if (!response.ok) {
384
+ * const plainError = response.error.toObject();
385
+ * console.log(JSON.stringify(plainError));
386
+ * // {"name":"FetchResponseError","message":"...","request":{...},"response":{...}}
387
+ * }
388
+ *
389
+ * @param options.includeBody Whether to include the body of the request and response in the output. Defaults to
390
+ * `false`.
391
+ * @returns A plain object representing this error. If `options.includeBody` is `true`, the body of the request and
392
+ * response will be included and the return of this method will be a `Promise`. Otherwise, the return will be the
393
+ * plain object itself without the body.
394
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}
395
+ */
396
+ toObject(options: {
397
+ includeBody: true;
398
+ }): Promise<FetchResponseErrorObject>;
399
+ toObject(options?: {
400
+ includeBody?: false;
401
+ }): FetchResponseErrorObject;
402
+ toObject(options?: FetchResponseErrorObjectOptions): Promise<FetchResponseErrorObject> | FetchResponseErrorObject;
403
+ private convertRequestToObject;
404
+ private convertResponseToObject;
405
+ private convertHeadersToObject;
318
406
  }
319
407
  type AnyFetchRequestError = FetchResponseError<any, any, any>;
320
408
 
@@ -940,4 +1028,4 @@ type InferFetchSchema<FetchInstance> = FetchInstance extends Fetch<infer Schema>
940
1028
  */
941
1029
  declare function createFetch<Schema extends HttpSchema>(options: FetchOptions<Schema>): Fetch<Schema>;
942
1030
 
943
- export { type Fetch, type FetchDefaults, type FetchInput, type FetchOptions, FetchRequest, type FetchRequestConstructor, FetchRequestInit, FetchResponse, FetchResponseError, type InferFetchSchema, type JSONStringified, createFetch };
1031
+ export { type Fetch, type FetchDefaults, type FetchInput, type FetchOptions, FetchRequest, type FetchRequestConstructor, FetchRequestInit, type FetchRequestObject, FetchResponse, FetchResponseError, type FetchResponseErrorObject, type FetchResponseErrorObjectOptions, type FetchResponseObject, type InferFetchSchema, type JSONStringified, createFetch };
package/dist/index.js CHANGED
@@ -4,8 +4,6 @@ var http = require('@zimic/http');
4
4
 
5
5
  var __defProp = Object.defineProperty;
6
6
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
-
8
- // src/client/errors/FetchResponseError.ts
9
7
  var FetchResponseError = class extends Error {
10
8
  constructor(request, response) {
11
9
  super(`${request.method} ${request.url} failed with status ${response.status}: ${response.statusText}`);
@@ -16,8 +14,66 @@ var FetchResponseError = class extends Error {
16
14
  static {
17
15
  __name(this, "FetchResponseError");
18
16
  }
19
- get cause() {
20
- return this.response;
17
+ toObject(options = {}) {
18
+ const { includeBody = false } = options;
19
+ const partialObject = {
20
+ name: this.name,
21
+ message: this.message
22
+ };
23
+ if (!includeBody) {
24
+ const request = this.convertRequestToObject({ includeBody: false });
25
+ const response = this.convertResponseToObject({ includeBody: false });
26
+ return { ...partialObject, request, response };
27
+ }
28
+ return Promise.all([
29
+ this.convertRequestToObject({ includeBody: true }),
30
+ this.convertResponseToObject({ includeBody: true })
31
+ ]).then(([request, response]) => ({ ...partialObject, request, response }));
32
+ }
33
+ convertRequestToObject(options) {
34
+ const partialObject = {
35
+ url: this.request.url,
36
+ path: this.request.path,
37
+ method: this.request.method,
38
+ headers: this.convertHeadersToObject(this.request.headers),
39
+ cache: this.request.cache,
40
+ destination: this.request.destination,
41
+ credentials: this.request.credentials,
42
+ integrity: this.request.integrity,
43
+ keepalive: this.request.keepalive,
44
+ mode: this.request.mode,
45
+ redirect: this.request.redirect,
46
+ referrer: this.request.referrer,
47
+ referrerPolicy: this.request.referrerPolicy
48
+ };
49
+ if (!options.includeBody) {
50
+ return partialObject;
51
+ }
52
+ return this.request.text().then((bodyAsText) => ({
53
+ ...partialObject,
54
+ body: bodyAsText.length > 0 ? bodyAsText : null
55
+ }));
56
+ }
57
+ convertResponseToObject(options) {
58
+ const partialObject = {
59
+ url: this.response.url,
60
+ type: this.response.type,
61
+ status: this.response.status,
62
+ statusText: this.response.statusText,
63
+ ok: this.response.ok,
64
+ headers: this.convertHeadersToObject(this.response.headers),
65
+ redirected: this.response.redirected
66
+ };
67
+ if (!options.includeBody) {
68
+ return partialObject;
69
+ }
70
+ return this.response.text().then((bodyAsText) => ({
71
+ ...partialObject,
72
+ body: bodyAsText.length > 0 ? bodyAsText : null
73
+ }));
74
+ }
75
+ convertHeadersToObject(headers) {
76
+ return http.HttpHeaders.prototype.toObject.call(headers);
21
77
  }
22
78
  };
23
79
  var FetchResponseError_default = FetchResponseError;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/errors/FetchResponseError.ts","../../zimic-utils/dist/chunk-PAWJFY3S.mjs","../../zimic-utils/src/url/createRegExpFromURL.ts","../../zimic-utils/src/url/excludeURLParams.ts","../../zimic-utils/src/url/joinURL.ts","../src/client/FetchClient.ts","../src/client/factory.ts"],"names":["__defProp","__name","Request","HttpHeaders","HttpSearchParams"],"mappings":"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","file":"index.js","sourcesContent":["import { HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';\n\nimport { FetchRequest, FetchResponse } from '../types/requests';\n\n/**\n * An error representing a response with a failure status code (4XX or 5XX).\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users/:userId': {\n * GET: {\n * response: {\n * 200: { body: User };\n * 404: { body: { message: string } };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * const response = await fetch(`/users/${userId}`, {\n * method: 'GET',\n * });\n *\n * if (!response.ok) {\n * console.log(response.status); // 404\n *\n * console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>\n * console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>\n * console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>\n * }\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}\n */\nclass FetchResponseError<\n Schema extends HttpSchema,\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n> extends Error {\n constructor(\n public request: FetchRequest<Schema, Method, Path>,\n public response: FetchResponse<Schema, Method, Path, true, 'manual'>,\n ) {\n super(`${request.method} ${request.url} failed with status ${response.status}: ${response.statusText}`);\n this.name = 'FetchResponseError';\n }\n\n get cause() {\n return this.response;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyFetchRequestError = FetchResponseError<any, any, any>;\n\nexport default FetchResponseError;\n","var __defProp = Object.defineProperty;\nvar __name = (target, value) => __defProp(target, \"name\", { value, configurable: true });\n\nexport { __name };\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map","export const URL_PATH_PARAM_REGEX = /\\/:([^/]+)/g;\n\nfunction createRegExpFromURL(url: string) {\n URL_PATH_PARAM_REGEX.lastIndex = 0;\n\n const urlWithReplacedPathParams = encodeURI(url)\n .replace(/([.()*?+$\\\\])/g, '\\\\$1')\n .replace(URL_PATH_PARAM_REGEX, '/(?<$1>[^/]+)')\n .replace(/^(\\/)|(\\/)$/g, '');\n\n return new RegExp(`^(?:/)?${urlWithReplacedPathParams}(?:/)?$`);\n}\n\nexport default createRegExpFromURL;\n","function excludeURLParams(url: URL) {\n url.hash = '';\n url.search = '';\n url.username = '';\n url.password = '';\n return url;\n}\n\nexport default excludeURLParams;\n","function joinURL(...parts: (URL | string)[]) {\n return parts\n .map((part, index) => {\n const isFirstPart = index === 0;\n const isLastPart = index === parts.length - 1;\n\n let partAsString = part.toString();\n\n if (!isFirstPart) {\n partAsString = partAsString.replace(/^\\//, '');\n }\n if (!isLastPart) {\n partAsString = partAsString.replace(/\\/$/, '');\n }\n\n return partAsString;\n })\n .filter((part) => part.length > 0)\n .join('/');\n}\n\nexport default joinURL;\n","import {\n HttpSchemaPath,\n HttpSchemaMethod,\n HttpSearchParams,\n LiteralHttpSchemaPathFromNonLiteral,\n HttpSchema,\n HttpHeaders,\n} from '@zimic/http';\nimport createRegexFromURL from '@zimic/utils/url/createRegExpFromURL';\nimport excludeURLParams from '@zimic/utils/url/excludeURLParams';\nimport joinURL from '@zimic/utils/url/joinURL';\n\nimport FetchResponseError from './errors/FetchResponseError';\nimport {\n FetchInput,\n FetchOptions,\n Fetch,\n FetchClient as PublicFetchClient,\n FetchDefaults,\n FetchFunction,\n} from './types/public';\nimport { FetchRequestConstructor, FetchRequestInit, FetchRequest, FetchResponse } from './types/requests';\n\nclass FetchClient<Schema extends HttpSchema>\n implements Omit<PublicFetchClient<Schema>, 'defaults' | 'loose' | 'Request'>\n{\n fetch: Fetch<Schema>;\n\n constructor({ onRequest, onResponse, ...defaults }: FetchOptions<Schema>) {\n this.fetch = this.createFetchFunction();\n\n this.fetch.defaults = {\n ...defaults,\n headers: defaults.headers ?? {},\n searchParams: defaults.searchParams ?? {},\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.fetch.loose = this.fetch as Fetch<any> as FetchFunction.Loose;\n\n this.fetch.Request = this.createRequestClass(this.fetch.defaults);\n this.fetch.onRequest = onRequest;\n this.fetch.onResponse = onResponse;\n }\n\n private createFetchFunction() {\n const fetch = async <\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) => {\n const request = await this.createFetchRequest<Method, Path>(input, init);\n const requestClone = request.clone();\n\n const rawResponse = await globalThis.fetch(\n // Optimize type checking by narrowing the type of request\n requestClone as Request,\n );\n const response = await this.createFetchResponse<\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >(request, rawResponse);\n\n return response;\n };\n\n Object.setPrototypeOf(fetch, this);\n\n return fetch as Fetch<Schema>;\n }\n\n private async createFetchRequest<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n let request = input instanceof Request ? input : new this.fetch.Request(input, init);\n\n if (this.fetch.onRequest) {\n const requestAfterInterceptor = await this.fetch.onRequest(\n // Optimize type checking by narrowing the type of request\n request as FetchRequest.Loose,\n );\n\n if (requestAfterInterceptor !== request) {\n const isFetchRequest = requestAfterInterceptor instanceof this.fetch.Request;\n\n request = isFetchRequest\n ? (requestAfterInterceptor as Request as typeof request)\n : new this.fetch.Request(requestAfterInterceptor as FetchInput<Schema, Method, Path>, init);\n }\n }\n\n return request;\n }\n\n private async createFetchResponse<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, rawResponse: Response) {\n let response = this.defineFetchResponseProperties<Method, Path>(fetchRequest, rawResponse);\n\n if (this.fetch.onResponse) {\n const responseAfterInterceptor = await this.fetch.onResponse(\n // Optimize type checking by narrowing the type of response\n response as FetchResponse.Loose,\n );\n\n const isFetchResponse =\n responseAfterInterceptor instanceof Response &&\n 'request' in responseAfterInterceptor &&\n responseAfterInterceptor.request instanceof this.fetch.Request;\n\n response = isFetchResponse\n ? (responseAfterInterceptor as typeof response)\n : this.defineFetchResponseProperties<Method, Path>(fetchRequest, responseAfterInterceptor);\n }\n\n return response;\n }\n\n private defineFetchResponseProperties<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, response: Response) {\n const fetchResponse = response as FetchResponse<Schema, Method, Path>;\n\n Object.defineProperty(fetchResponse, 'request', {\n value: fetchRequest satisfies FetchResponse.Loose['request'],\n writable: false,\n enumerable: true,\n configurable: false,\n });\n\n let responseError: FetchResponse.Loose['error'] | undefined;\n\n Object.defineProperty(fetchResponse, 'error', {\n get() {\n if (responseError === undefined) {\n responseError = fetchResponse.ok\n ? null\n : new FetchResponseError(\n fetchRequest,\n fetchResponse as FetchResponse<Schema, Method, Path, true, 'manual'>,\n );\n }\n return responseError;\n },\n enumerable: true,\n configurable: false,\n });\n\n return fetchResponse;\n }\n\n private createRequestClass(defaults: FetchDefaults) {\n class Request<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n > extends globalThis.Request {\n path: LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n\n constructor(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n const initWithDefaults = { ...defaults, ...init };\n\n const headersFromDefaults = new HttpHeaders(defaults.headers);\n const headersFromInit = new HttpHeaders((init satisfies RequestInit as RequestInit).headers);\n\n let url: URL;\n const baseURL = new URL(initWithDefaults.baseURL);\n\n if (input instanceof globalThis.Request) {\n // Optimize type checking by narrowing the type of input\n const request = input as globalThis.Request;\n const headersFromRequest = new HttpHeaders(input.headers);\n\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromRequest.toObject(),\n ...headersFromInit.toObject(),\n };\n\n super(request, initWithDefaults);\n\n url = new URL(input.url);\n } else {\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromInit.toObject(),\n };\n\n url = input instanceof URL ? new URL(input) : new URL(joinURL(baseURL, input));\n\n const searchParamsFromDefaults = new HttpSearchParams(defaults.searchParams);\n const searchParamsFromInit = new HttpSearchParams(initWithDefaults.searchParams);\n\n initWithDefaults.searchParams = {\n ...searchParamsFromDefaults.toObject(),\n ...searchParamsFromInit.toObject(),\n };\n\n url.search = new HttpSearchParams(initWithDefaults.searchParams).toString();\n\n super(url, initWithDefaults);\n }\n\n const baseURLWithoutTrailingSlash = baseURL.toString().replace(/\\/$/, '');\n\n this.path = excludeURLParams(url)\n .toString()\n .replace(baseURLWithoutTrailingSlash, '') as LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n }\n\n clone(): Request<Method, Path> {\n const rawClone = super.clone();\n\n return new Request<Method, Path>(\n rawClone as unknown as FetchInput<Schema, Method, Path>,\n rawClone as unknown as FetchRequestInit<\n Schema,\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >,\n );\n }\n }\n\n return Request as FetchRequestConstructor<Schema>;\n }\n\n isRequest<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n request: unknown,\n method: Method,\n path: Path,\n ): request is FetchRequest<Schema, Method, Path> {\n return (\n request instanceof Request &&\n request.method === method &&\n 'path' in request &&\n typeof request.path === 'string' &&\n createRegexFromURL(path).test(request.path)\n );\n }\n\n isResponse<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n response: unknown,\n method: Method,\n path: Path,\n ): response is FetchResponse<Schema, Method, Path> {\n return (\n response instanceof Response &&\n 'request' in response &&\n this.isRequest(response.request, method, path) &&\n 'error' in response &&\n (response.error === null || response.error instanceof FetchResponseError)\n );\n }\n\n isResponseError<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n error: unknown,\n method: Method,\n path: Path,\n ): error is FetchResponseError<Schema, Method, Path> {\n return (\n error instanceof FetchResponseError &&\n this.isRequest(error.request, method, path) &&\n this.isResponse(error.response, method, path)\n );\n }\n}\n\nexport default FetchClient;\n","import { HttpSchema } from '@zimic/http';\n\nimport FetchClient from './FetchClient';\nimport { FetchOptions, Fetch } from './types/public';\n\n/**\n * Creates a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance} typed with an HTTP\n * schema, closely compatible with the {@link https://developer.mozilla.org/docs/Web/API/Fetch_API native Fetch API}. All\n * requests and responses are typed by default with the schema, including methods, paths, status codes, parameters, and\n * bodies.\n *\n * Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance.\n * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch.defaults Default options} are also applied to the\n * requests, if provided.\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users': {\n * POST: {\n * request: {\n * headers: { 'content-type': 'application/json' };\n * body: { username: string };\n * };\n * response: {\n * 201: { body: User };\n * };\n * };\n *\n * GET: {\n * request: {\n * searchParams: {\n * query?: string;\n * page?: number;\n * limit?: number;\n * };\n * };\n * response: {\n * 200: { body: User[] };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#createfetch `createFetch(options)` API reference}\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}\n */\nfunction createFetch<Schema extends HttpSchema>(options: FetchOptions<Schema>): Fetch<Schema> {\n const { fetch } = new FetchClient<Schema>(options);\n return fetch;\n}\n\nexport default createFetch;\n"]}
1
+ {"version":3,"sources":["../src/client/errors/FetchResponseError.ts","../../zimic-utils/dist/chunk-PAWJFY3S.mjs","../../zimic-utils/src/url/createRegExpFromURL.ts","../../zimic-utils/src/url/excludeURLParams.ts","../../zimic-utils/src/url/joinURL.ts","../src/client/FetchClient.ts","../src/client/factory.ts"],"names":["HttpHeaders","__defProp","__name","Request","HttpSearchParams"],"mappings":"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","file":"index.js","sourcesContent":["import { HttpHeaders, HttpHeadersSchema, HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';\n\nimport { FetchRequest, FetchRequestObject, FetchResponse, FetchResponseObject } from '../types/requests';\n\n/**\n * Options for converting a {@link FetchResponseError `FetchResponseError`} into a plain object.\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}\n */\nexport interface FetchResponseErrorObjectOptions {\n includeBody?: boolean;\n}\n\n/**\n * A plain object representation of a {@link FetchResponseError `FetchResponseError`}, compatible with JSON. It is useful\n * for serialization, debugging, and logging purposes.\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}\n */\nexport interface FetchResponseErrorObject {\n name: string;\n message: string;\n request: FetchRequestObject;\n response: FetchResponseObject;\n}\n\n/**\n * An error representing a response with a failure status code (4XX or 5XX).\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users/:userId': {\n * GET: {\n * response: {\n * 200: { body: User };\n * 404: { body: { message: string } };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * const response = await fetch(`/users/${userId}`, {\n * method: 'GET',\n * });\n *\n * if (!response.ok) {\n * console.log(response.status); // 404\n *\n * console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>\n * console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>\n * console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>\n *\n * const plainError = response.error.toObject();\n * console.log(JSON.stringify(plainError));\n * // {\"name\":\"FetchResponseError\",\"message\":\"...\",\"request\":{...},\"response\":{...}}\n * }\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}\n */\nclass FetchResponseError<\n Schema extends HttpSchema,\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n> extends Error {\n constructor(\n public request: FetchRequest<Schema, Method, Path>,\n public response: FetchResponse<Schema, Method, Path, true, 'manual'>,\n ) {\n super(`${request.method} ${request.url} failed with status ${response.status}: ${response.statusText}`);\n this.name = 'FetchResponseError';\n }\n\n /**\n * Converts this error into a plain object. This method is useful for serialization, debugging, and logging purposes.\n *\n * @example\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * const response = await fetch(`/users/${userId}`, {\n * method: 'GET',\n * });\n *\n * if (!response.ok) {\n * const plainError = response.error.toObject();\n * console.log(JSON.stringify(plainError));\n * // {\"name\":\"FetchResponseError\",\"message\":\"...\",\"request\":{...},\"response\":{...}}\n * }\n *\n * @param options.includeBody Whether to include the body of the request and response in the output. Defaults to\n * `false`.\n * @returns A plain object representing this error. If `options.includeBody` is `true`, the body of the request and\n * response will be included and the return of this method will be a `Promise`. Otherwise, the return will be the\n * plain object itself without the body.\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}\n */\n toObject(options: { includeBody: true }): Promise<FetchResponseErrorObject>;\n toObject(options?: { includeBody?: false }): FetchResponseErrorObject;\n toObject(options?: FetchResponseErrorObjectOptions): Promise<FetchResponseErrorObject> | FetchResponseErrorObject;\n toObject(\n options: FetchResponseErrorObjectOptions = {},\n ): Promise<FetchResponseErrorObject> | FetchResponseErrorObject {\n const { includeBody = false } = options;\n\n const partialObject = {\n name: this.name,\n message: this.message,\n } satisfies Partial<FetchResponseErrorObject>;\n\n if (!includeBody) {\n const request = this.convertRequestToObject({ includeBody: false });\n const response = this.convertResponseToObject({ includeBody: false });\n return { ...partialObject, request, response };\n }\n\n return Promise.all([\n this.convertRequestToObject({ includeBody: true }),\n this.convertResponseToObject({ includeBody: true }),\n ]).then(([request, response]) => ({ ...partialObject, request, response }));\n }\n\n private convertRequestToObject(options: { includeBody: true }): Promise<FetchRequestObject>;\n private convertRequestToObject(options: { includeBody: false }): FetchRequestObject;\n private convertRequestToObject(options: { includeBody: boolean }): Promise<FetchRequestObject> | FetchRequestObject {\n const partialObject = {\n url: this.request.url,\n path: this.request.path,\n method: this.request.method,\n headers: this.convertHeadersToObject(this.request.headers),\n cache: this.request.cache,\n destination: this.request.destination,\n credentials: this.request.credentials,\n integrity: this.request.integrity,\n keepalive: this.request.keepalive,\n mode: this.request.mode,\n redirect: this.request.redirect,\n referrer: this.request.referrer,\n referrerPolicy: this.request.referrerPolicy,\n } satisfies Partial<FetchRequestObject>;\n\n if (!options.includeBody) {\n return partialObject;\n }\n\n return this.request.text().then((bodyAsText: string) => ({\n ...partialObject,\n body: bodyAsText.length > 0 ? bodyAsText : null,\n }));\n }\n\n private convertResponseToObject(options: { includeBody: true }): Promise<FetchResponseObject>;\n private convertResponseToObject(options: { includeBody: false }): FetchResponseObject;\n private convertResponseToObject(options: {\n includeBody: boolean;\n }): Promise<FetchResponseObject> | FetchResponseObject {\n const partialObject = {\n url: this.response.url,\n type: this.response.type,\n status: this.response.status,\n statusText: this.response.statusText,\n ok: this.response.ok,\n headers: this.convertHeadersToObject(this.response.headers),\n redirected: this.response.redirected,\n } satisfies Partial<FetchResponseObject>;\n\n if (!options.includeBody) {\n return partialObject;\n }\n\n return this.response.text().then((bodyAsText: string) => ({\n ...partialObject,\n body: bodyAsText.length > 0 ? bodyAsText : null,\n }));\n }\n\n private convertHeadersToObject(headers: Headers) {\n return HttpHeaders.prototype.toObject.call(headers) as HttpHeadersSchema;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyFetchRequestError = FetchResponseError<any, any, any>;\n\nexport default FetchResponseError;\n","var __defProp = Object.defineProperty;\nvar __name = (target, value) => __defProp(target, \"name\", { value, configurable: true });\n\nexport { __name };\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map","export const URL_PATH_PARAM_REGEX = /\\/:([^/]+)/g;\n\nfunction createRegExpFromURL(url: string) {\n URL_PATH_PARAM_REGEX.lastIndex = 0;\n\n const urlWithReplacedPathParams = encodeURI(url)\n .replace(/([.()*?+$\\\\])/g, '\\\\$1')\n .replace(URL_PATH_PARAM_REGEX, '/(?<$1>[^/]+)')\n .replace(/^(\\/)|(\\/)$/g, '');\n\n return new RegExp(`^(?:/)?${urlWithReplacedPathParams}(?:/)?$`);\n}\n\nexport default createRegExpFromURL;\n","function excludeURLParams(url: URL) {\n url.hash = '';\n url.search = '';\n url.username = '';\n url.password = '';\n return url;\n}\n\nexport default excludeURLParams;\n","function joinURL(...parts: (URL | string)[]) {\n return parts\n .map((part, index) => {\n const isFirstPart = index === 0;\n const isLastPart = index === parts.length - 1;\n\n let partAsString = part.toString();\n\n if (!isFirstPart) {\n partAsString = partAsString.replace(/^\\//, '');\n }\n if (!isLastPart) {\n partAsString = partAsString.replace(/\\/$/, '');\n }\n\n return partAsString;\n })\n .filter((part) => part.length > 0)\n .join('/');\n}\n\nexport default joinURL;\n","import {\n HttpSchemaPath,\n HttpSchemaMethod,\n HttpSearchParams,\n LiteralHttpSchemaPathFromNonLiteral,\n HttpSchema,\n HttpHeaders,\n} from '@zimic/http';\nimport createRegexFromURL from '@zimic/utils/url/createRegExpFromURL';\nimport excludeURLParams from '@zimic/utils/url/excludeURLParams';\nimport joinURL from '@zimic/utils/url/joinURL';\n\nimport FetchResponseError from './errors/FetchResponseError';\nimport {\n FetchInput,\n FetchOptions,\n Fetch,\n FetchClient as PublicFetchClient,\n FetchDefaults,\n FetchFunction,\n} from './types/public';\nimport { FetchRequestConstructor, FetchRequestInit, FetchRequest, FetchResponse } from './types/requests';\n\nclass FetchClient<Schema extends HttpSchema>\n implements Omit<PublicFetchClient<Schema>, 'defaults' | 'loose' | 'Request'>\n{\n fetch: Fetch<Schema>;\n\n constructor({ onRequest, onResponse, ...defaults }: FetchOptions<Schema>) {\n this.fetch = this.createFetchFunction();\n\n this.fetch.defaults = {\n ...defaults,\n headers: defaults.headers ?? {},\n searchParams: defaults.searchParams ?? {},\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.fetch.loose = this.fetch as Fetch<any> as FetchFunction.Loose;\n\n this.fetch.Request = this.createRequestClass(this.fetch.defaults);\n this.fetch.onRequest = onRequest;\n this.fetch.onResponse = onResponse;\n }\n\n private createFetchFunction() {\n const fetch = async <\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) => {\n const request = await this.createFetchRequest<Method, Path>(input, init);\n const requestClone = request.clone();\n\n const rawResponse = await globalThis.fetch(\n // Optimize type checking by narrowing the type of request\n requestClone as Request,\n );\n const response = await this.createFetchResponse<\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >(request, rawResponse);\n\n return response;\n };\n\n Object.setPrototypeOf(fetch, this);\n\n return fetch as Fetch<Schema>;\n }\n\n private async createFetchRequest<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n let request = input instanceof Request ? input : new this.fetch.Request(input, init);\n\n if (this.fetch.onRequest) {\n const requestAfterInterceptor = await this.fetch.onRequest(\n // Optimize type checking by narrowing the type of request\n request as FetchRequest.Loose,\n );\n\n if (requestAfterInterceptor !== request) {\n const isFetchRequest = requestAfterInterceptor instanceof this.fetch.Request;\n\n request = isFetchRequest\n ? (requestAfterInterceptor as Request as typeof request)\n : new this.fetch.Request(requestAfterInterceptor as FetchInput<Schema, Method, Path>, init);\n }\n }\n\n return request;\n }\n\n private async createFetchResponse<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, rawResponse: Response) {\n let response = this.defineFetchResponseProperties<Method, Path>(fetchRequest, rawResponse);\n\n if (this.fetch.onResponse) {\n const responseAfterInterceptor = await this.fetch.onResponse(\n // Optimize type checking by narrowing the type of response\n response as FetchResponse.Loose,\n );\n\n const isFetchResponse =\n responseAfterInterceptor instanceof Response &&\n 'request' in responseAfterInterceptor &&\n responseAfterInterceptor.request instanceof this.fetch.Request;\n\n response = isFetchResponse\n ? (responseAfterInterceptor as typeof response)\n : this.defineFetchResponseProperties<Method, Path>(fetchRequest, responseAfterInterceptor);\n }\n\n return response;\n }\n\n private defineFetchResponseProperties<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, response: Response) {\n const fetchResponse = response as FetchResponse<Schema, Method, Path>;\n\n Object.defineProperty(fetchResponse, 'request', {\n value: fetchRequest satisfies FetchResponse.Loose['request'],\n writable: false,\n enumerable: true,\n configurable: false,\n });\n\n let responseError: FetchResponse.Loose['error'] | undefined;\n\n Object.defineProperty(fetchResponse, 'error', {\n get() {\n if (responseError === undefined) {\n responseError = fetchResponse.ok\n ? null\n : new FetchResponseError(\n fetchRequest,\n fetchResponse as FetchResponse<Schema, Method, Path, true, 'manual'>,\n );\n }\n return responseError;\n },\n enumerable: true,\n configurable: false,\n });\n\n return fetchResponse;\n }\n\n private createRequestClass(defaults: FetchDefaults) {\n class Request<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n > extends globalThis.Request {\n path: LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n\n constructor(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n const initWithDefaults = { ...defaults, ...init };\n\n const headersFromDefaults = new HttpHeaders(defaults.headers);\n const headersFromInit = new HttpHeaders((init satisfies RequestInit as RequestInit).headers);\n\n let url: URL;\n const baseURL = new URL(initWithDefaults.baseURL);\n\n if (input instanceof globalThis.Request) {\n // Optimize type checking by narrowing the type of input\n const request = input as globalThis.Request;\n const headersFromRequest = new HttpHeaders(input.headers);\n\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromRequest.toObject(),\n ...headersFromInit.toObject(),\n };\n\n super(request, initWithDefaults);\n\n url = new URL(input.url);\n } else {\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromInit.toObject(),\n };\n\n url = input instanceof URL ? new URL(input) : new URL(joinURL(baseURL, input));\n\n const searchParamsFromDefaults = new HttpSearchParams(defaults.searchParams);\n const searchParamsFromInit = new HttpSearchParams(initWithDefaults.searchParams);\n\n initWithDefaults.searchParams = {\n ...searchParamsFromDefaults.toObject(),\n ...searchParamsFromInit.toObject(),\n };\n\n url.search = new HttpSearchParams(initWithDefaults.searchParams).toString();\n\n super(url, initWithDefaults);\n }\n\n const baseURLWithoutTrailingSlash = baseURL.toString().replace(/\\/$/, '');\n\n this.path = excludeURLParams(url)\n .toString()\n .replace(baseURLWithoutTrailingSlash, '') as LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n }\n\n clone(): Request<Method, Path> {\n const rawClone = super.clone();\n\n return new Request<Method, Path>(\n rawClone as unknown as FetchInput<Schema, Method, Path>,\n rawClone as unknown as FetchRequestInit<\n Schema,\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >,\n );\n }\n }\n\n return Request as FetchRequestConstructor<Schema>;\n }\n\n isRequest<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n request: unknown,\n method: Method,\n path: Path,\n ): request is FetchRequest<Schema, Method, Path> {\n return (\n request instanceof Request &&\n request.method === method &&\n 'path' in request &&\n typeof request.path === 'string' &&\n createRegexFromURL(path).test(request.path)\n );\n }\n\n isResponse<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n response: unknown,\n method: Method,\n path: Path,\n ): response is FetchResponse<Schema, Method, Path> {\n return (\n response instanceof Response &&\n 'request' in response &&\n this.isRequest(response.request, method, path) &&\n 'error' in response &&\n (response.error === null || response.error instanceof FetchResponseError)\n );\n }\n\n isResponseError<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n error: unknown,\n method: Method,\n path: Path,\n ): error is FetchResponseError<Schema, Method, Path> {\n return (\n error instanceof FetchResponseError &&\n this.isRequest(error.request, method, path) &&\n this.isResponse(error.response, method, path)\n );\n }\n}\n\nexport default FetchClient;\n","import { HttpSchema } from '@zimic/http';\n\nimport FetchClient from './FetchClient';\nimport { FetchOptions, Fetch } from './types/public';\n\n/**\n * Creates a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance} typed with an HTTP\n * schema, closely compatible with the {@link https://developer.mozilla.org/docs/Web/API/Fetch_API native Fetch API}. All\n * requests and responses are typed by default with the schema, including methods, paths, status codes, parameters, and\n * bodies.\n *\n * Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance.\n * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch.defaults Default options} are also applied to the\n * requests, if provided.\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users': {\n * POST: {\n * request: {\n * headers: { 'content-type': 'application/json' };\n * body: { username: string };\n * };\n * response: {\n * 201: { body: User };\n * };\n * };\n *\n * GET: {\n * request: {\n * searchParams: {\n * query?: string;\n * page?: number;\n * limit?: number;\n * };\n * };\n * response: {\n * 200: { body: User[] };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#createfetch `createFetch(options)` API reference}\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}\n */\nfunction createFetch<Schema extends HttpSchema>(options: FetchOptions<Schema>): Fetch<Schema> {\n const { fetch } = new FetchClient<Schema>(options);\n return fetch;\n}\n\nexport default createFetch;\n"]}
package/dist/index.mjs CHANGED
@@ -2,8 +2,6 @@ import { HttpHeaders, HttpSearchParams } from '@zimic/http';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
4
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
-
6
- // src/client/errors/FetchResponseError.ts
7
5
  var FetchResponseError = class extends Error {
8
6
  constructor(request, response) {
9
7
  super(`${request.method} ${request.url} failed with status ${response.status}: ${response.statusText}`);
@@ -14,8 +12,66 @@ var FetchResponseError = class extends Error {
14
12
  static {
15
13
  __name(this, "FetchResponseError");
16
14
  }
17
- get cause() {
18
- return this.response;
15
+ toObject(options = {}) {
16
+ const { includeBody = false } = options;
17
+ const partialObject = {
18
+ name: this.name,
19
+ message: this.message
20
+ };
21
+ if (!includeBody) {
22
+ const request = this.convertRequestToObject({ includeBody: false });
23
+ const response = this.convertResponseToObject({ includeBody: false });
24
+ return { ...partialObject, request, response };
25
+ }
26
+ return Promise.all([
27
+ this.convertRequestToObject({ includeBody: true }),
28
+ this.convertResponseToObject({ includeBody: true })
29
+ ]).then(([request, response]) => ({ ...partialObject, request, response }));
30
+ }
31
+ convertRequestToObject(options) {
32
+ const partialObject = {
33
+ url: this.request.url,
34
+ path: this.request.path,
35
+ method: this.request.method,
36
+ headers: this.convertHeadersToObject(this.request.headers),
37
+ cache: this.request.cache,
38
+ destination: this.request.destination,
39
+ credentials: this.request.credentials,
40
+ integrity: this.request.integrity,
41
+ keepalive: this.request.keepalive,
42
+ mode: this.request.mode,
43
+ redirect: this.request.redirect,
44
+ referrer: this.request.referrer,
45
+ referrerPolicy: this.request.referrerPolicy
46
+ };
47
+ if (!options.includeBody) {
48
+ return partialObject;
49
+ }
50
+ return this.request.text().then((bodyAsText) => ({
51
+ ...partialObject,
52
+ body: bodyAsText.length > 0 ? bodyAsText : null
53
+ }));
54
+ }
55
+ convertResponseToObject(options) {
56
+ const partialObject = {
57
+ url: this.response.url,
58
+ type: this.response.type,
59
+ status: this.response.status,
60
+ statusText: this.response.statusText,
61
+ ok: this.response.ok,
62
+ headers: this.convertHeadersToObject(this.response.headers),
63
+ redirected: this.response.redirected
64
+ };
65
+ if (!options.includeBody) {
66
+ return partialObject;
67
+ }
68
+ return this.response.text().then((bodyAsText) => ({
69
+ ...partialObject,
70
+ body: bodyAsText.length > 0 ? bodyAsText : null
71
+ }));
72
+ }
73
+ convertHeadersToObject(headers) {
74
+ return HttpHeaders.prototype.toObject.call(headers);
19
75
  }
20
76
  };
21
77
  var FetchResponseError_default = FetchResponseError;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/errors/FetchResponseError.ts","../../zimic-utils/dist/chunk-PAWJFY3S.mjs","../../zimic-utils/src/url/createRegExpFromURL.ts","../../zimic-utils/src/url/excludeURLParams.ts","../../zimic-utils/src/url/joinURL.ts","../src/client/FetchClient.ts","../src/client/factory.ts"],"names":["__defProp","__name","Request"],"mappings":"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","file":"index.mjs","sourcesContent":["import { HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';\n\nimport { FetchRequest, FetchResponse } from '../types/requests';\n\n/**\n * An error representing a response with a failure status code (4XX or 5XX).\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users/:userId': {\n * GET: {\n * response: {\n * 200: { body: User };\n * 404: { body: { message: string } };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * const response = await fetch(`/users/${userId}`, {\n * method: 'GET',\n * });\n *\n * if (!response.ok) {\n * console.log(response.status); // 404\n *\n * console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>\n * console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>\n * console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>\n * }\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}\n */\nclass FetchResponseError<\n Schema extends HttpSchema,\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n> extends Error {\n constructor(\n public request: FetchRequest<Schema, Method, Path>,\n public response: FetchResponse<Schema, Method, Path, true, 'manual'>,\n ) {\n super(`${request.method} ${request.url} failed with status ${response.status}: ${response.statusText}`);\n this.name = 'FetchResponseError';\n }\n\n get cause() {\n return this.response;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyFetchRequestError = FetchResponseError<any, any, any>;\n\nexport default FetchResponseError;\n","var __defProp = Object.defineProperty;\nvar __name = (target, value) => __defProp(target, \"name\", { value, configurable: true });\n\nexport { __name };\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map","export const URL_PATH_PARAM_REGEX = /\\/:([^/]+)/g;\n\nfunction createRegExpFromURL(url: string) {\n URL_PATH_PARAM_REGEX.lastIndex = 0;\n\n const urlWithReplacedPathParams = encodeURI(url)\n .replace(/([.()*?+$\\\\])/g, '\\\\$1')\n .replace(URL_PATH_PARAM_REGEX, '/(?<$1>[^/]+)')\n .replace(/^(\\/)|(\\/)$/g, '');\n\n return new RegExp(`^(?:/)?${urlWithReplacedPathParams}(?:/)?$`);\n}\n\nexport default createRegExpFromURL;\n","function excludeURLParams(url: URL) {\n url.hash = '';\n url.search = '';\n url.username = '';\n url.password = '';\n return url;\n}\n\nexport default excludeURLParams;\n","function joinURL(...parts: (URL | string)[]) {\n return parts\n .map((part, index) => {\n const isFirstPart = index === 0;\n const isLastPart = index === parts.length - 1;\n\n let partAsString = part.toString();\n\n if (!isFirstPart) {\n partAsString = partAsString.replace(/^\\//, '');\n }\n if (!isLastPart) {\n partAsString = partAsString.replace(/\\/$/, '');\n }\n\n return partAsString;\n })\n .filter((part) => part.length > 0)\n .join('/');\n}\n\nexport default joinURL;\n","import {\n HttpSchemaPath,\n HttpSchemaMethod,\n HttpSearchParams,\n LiteralHttpSchemaPathFromNonLiteral,\n HttpSchema,\n HttpHeaders,\n} from '@zimic/http';\nimport createRegexFromURL from '@zimic/utils/url/createRegExpFromURL';\nimport excludeURLParams from '@zimic/utils/url/excludeURLParams';\nimport joinURL from '@zimic/utils/url/joinURL';\n\nimport FetchResponseError from './errors/FetchResponseError';\nimport {\n FetchInput,\n FetchOptions,\n Fetch,\n FetchClient as PublicFetchClient,\n FetchDefaults,\n FetchFunction,\n} from './types/public';\nimport { FetchRequestConstructor, FetchRequestInit, FetchRequest, FetchResponse } from './types/requests';\n\nclass FetchClient<Schema extends HttpSchema>\n implements Omit<PublicFetchClient<Schema>, 'defaults' | 'loose' | 'Request'>\n{\n fetch: Fetch<Schema>;\n\n constructor({ onRequest, onResponse, ...defaults }: FetchOptions<Schema>) {\n this.fetch = this.createFetchFunction();\n\n this.fetch.defaults = {\n ...defaults,\n headers: defaults.headers ?? {},\n searchParams: defaults.searchParams ?? {},\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.fetch.loose = this.fetch as Fetch<any> as FetchFunction.Loose;\n\n this.fetch.Request = this.createRequestClass(this.fetch.defaults);\n this.fetch.onRequest = onRequest;\n this.fetch.onResponse = onResponse;\n }\n\n private createFetchFunction() {\n const fetch = async <\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) => {\n const request = await this.createFetchRequest<Method, Path>(input, init);\n const requestClone = request.clone();\n\n const rawResponse = await globalThis.fetch(\n // Optimize type checking by narrowing the type of request\n requestClone as Request,\n );\n const response = await this.createFetchResponse<\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >(request, rawResponse);\n\n return response;\n };\n\n Object.setPrototypeOf(fetch, this);\n\n return fetch as Fetch<Schema>;\n }\n\n private async createFetchRequest<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n let request = input instanceof Request ? input : new this.fetch.Request(input, init);\n\n if (this.fetch.onRequest) {\n const requestAfterInterceptor = await this.fetch.onRequest(\n // Optimize type checking by narrowing the type of request\n request as FetchRequest.Loose,\n );\n\n if (requestAfterInterceptor !== request) {\n const isFetchRequest = requestAfterInterceptor instanceof this.fetch.Request;\n\n request = isFetchRequest\n ? (requestAfterInterceptor as Request as typeof request)\n : new this.fetch.Request(requestAfterInterceptor as FetchInput<Schema, Method, Path>, init);\n }\n }\n\n return request;\n }\n\n private async createFetchResponse<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, rawResponse: Response) {\n let response = this.defineFetchResponseProperties<Method, Path>(fetchRequest, rawResponse);\n\n if (this.fetch.onResponse) {\n const responseAfterInterceptor = await this.fetch.onResponse(\n // Optimize type checking by narrowing the type of response\n response as FetchResponse.Loose,\n );\n\n const isFetchResponse =\n responseAfterInterceptor instanceof Response &&\n 'request' in responseAfterInterceptor &&\n responseAfterInterceptor.request instanceof this.fetch.Request;\n\n response = isFetchResponse\n ? (responseAfterInterceptor as typeof response)\n : this.defineFetchResponseProperties<Method, Path>(fetchRequest, responseAfterInterceptor);\n }\n\n return response;\n }\n\n private defineFetchResponseProperties<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, response: Response) {\n const fetchResponse = response as FetchResponse<Schema, Method, Path>;\n\n Object.defineProperty(fetchResponse, 'request', {\n value: fetchRequest satisfies FetchResponse.Loose['request'],\n writable: false,\n enumerable: true,\n configurable: false,\n });\n\n let responseError: FetchResponse.Loose['error'] | undefined;\n\n Object.defineProperty(fetchResponse, 'error', {\n get() {\n if (responseError === undefined) {\n responseError = fetchResponse.ok\n ? null\n : new FetchResponseError(\n fetchRequest,\n fetchResponse as FetchResponse<Schema, Method, Path, true, 'manual'>,\n );\n }\n return responseError;\n },\n enumerable: true,\n configurable: false,\n });\n\n return fetchResponse;\n }\n\n private createRequestClass(defaults: FetchDefaults) {\n class Request<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n > extends globalThis.Request {\n path: LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n\n constructor(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n const initWithDefaults = { ...defaults, ...init };\n\n const headersFromDefaults = new HttpHeaders(defaults.headers);\n const headersFromInit = new HttpHeaders((init satisfies RequestInit as RequestInit).headers);\n\n let url: URL;\n const baseURL = new URL(initWithDefaults.baseURL);\n\n if (input instanceof globalThis.Request) {\n // Optimize type checking by narrowing the type of input\n const request = input as globalThis.Request;\n const headersFromRequest = new HttpHeaders(input.headers);\n\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromRequest.toObject(),\n ...headersFromInit.toObject(),\n };\n\n super(request, initWithDefaults);\n\n url = new URL(input.url);\n } else {\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromInit.toObject(),\n };\n\n url = input instanceof URL ? new URL(input) : new URL(joinURL(baseURL, input));\n\n const searchParamsFromDefaults = new HttpSearchParams(defaults.searchParams);\n const searchParamsFromInit = new HttpSearchParams(initWithDefaults.searchParams);\n\n initWithDefaults.searchParams = {\n ...searchParamsFromDefaults.toObject(),\n ...searchParamsFromInit.toObject(),\n };\n\n url.search = new HttpSearchParams(initWithDefaults.searchParams).toString();\n\n super(url, initWithDefaults);\n }\n\n const baseURLWithoutTrailingSlash = baseURL.toString().replace(/\\/$/, '');\n\n this.path = excludeURLParams(url)\n .toString()\n .replace(baseURLWithoutTrailingSlash, '') as LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n }\n\n clone(): Request<Method, Path> {\n const rawClone = super.clone();\n\n return new Request<Method, Path>(\n rawClone as unknown as FetchInput<Schema, Method, Path>,\n rawClone as unknown as FetchRequestInit<\n Schema,\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >,\n );\n }\n }\n\n return Request as FetchRequestConstructor<Schema>;\n }\n\n isRequest<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n request: unknown,\n method: Method,\n path: Path,\n ): request is FetchRequest<Schema, Method, Path> {\n return (\n request instanceof Request &&\n request.method === method &&\n 'path' in request &&\n typeof request.path === 'string' &&\n createRegexFromURL(path).test(request.path)\n );\n }\n\n isResponse<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n response: unknown,\n method: Method,\n path: Path,\n ): response is FetchResponse<Schema, Method, Path> {\n return (\n response instanceof Response &&\n 'request' in response &&\n this.isRequest(response.request, method, path) &&\n 'error' in response &&\n (response.error === null || response.error instanceof FetchResponseError)\n );\n }\n\n isResponseError<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n error: unknown,\n method: Method,\n path: Path,\n ): error is FetchResponseError<Schema, Method, Path> {\n return (\n error instanceof FetchResponseError &&\n this.isRequest(error.request, method, path) &&\n this.isResponse(error.response, method, path)\n );\n }\n}\n\nexport default FetchClient;\n","import { HttpSchema } from '@zimic/http';\n\nimport FetchClient from './FetchClient';\nimport { FetchOptions, Fetch } from './types/public';\n\n/**\n * Creates a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance} typed with an HTTP\n * schema, closely compatible with the {@link https://developer.mozilla.org/docs/Web/API/Fetch_API native Fetch API}. All\n * requests and responses are typed by default with the schema, including methods, paths, status codes, parameters, and\n * bodies.\n *\n * Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance.\n * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch.defaults Default options} are also applied to the\n * requests, if provided.\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users': {\n * POST: {\n * request: {\n * headers: { 'content-type': 'application/json' };\n * body: { username: string };\n * };\n * response: {\n * 201: { body: User };\n * };\n * };\n *\n * GET: {\n * request: {\n * searchParams: {\n * query?: string;\n * page?: number;\n * limit?: number;\n * };\n * };\n * response: {\n * 200: { body: User[] };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#createfetch `createFetch(options)` API reference}\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}\n */\nfunction createFetch<Schema extends HttpSchema>(options: FetchOptions<Schema>): Fetch<Schema> {\n const { fetch } = new FetchClient<Schema>(options);\n return fetch;\n}\n\nexport default createFetch;\n"]}
1
+ {"version":3,"sources":["../src/client/errors/FetchResponseError.ts","../../zimic-utils/dist/chunk-PAWJFY3S.mjs","../../zimic-utils/src/url/createRegExpFromURL.ts","../../zimic-utils/src/url/excludeURLParams.ts","../../zimic-utils/src/url/joinURL.ts","../src/client/FetchClient.ts","../src/client/factory.ts"],"names":["__defProp","__name","Request","HttpHeaders"],"mappings":"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","file":"index.mjs","sourcesContent":["import { HttpHeaders, HttpHeadersSchema, HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';\n\nimport { FetchRequest, FetchRequestObject, FetchResponse, FetchResponseObject } from '../types/requests';\n\n/**\n * Options for converting a {@link FetchResponseError `FetchResponseError`} into a plain object.\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}\n */\nexport interface FetchResponseErrorObjectOptions {\n includeBody?: boolean;\n}\n\n/**\n * A plain object representation of a {@link FetchResponseError `FetchResponseError`}, compatible with JSON. It is useful\n * for serialization, debugging, and logging purposes.\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}\n */\nexport interface FetchResponseErrorObject {\n name: string;\n message: string;\n request: FetchRequestObject;\n response: FetchResponseObject;\n}\n\n/**\n * An error representing a response with a failure status code (4XX or 5XX).\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users/:userId': {\n * GET: {\n * response: {\n * 200: { body: User };\n * 404: { body: { message: string } };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * const response = await fetch(`/users/${userId}`, {\n * method: 'GET',\n * });\n *\n * if (!response.ok) {\n * console.log(response.status); // 404\n *\n * console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>\n * console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>\n * console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>\n *\n * const plainError = response.error.toObject();\n * console.log(JSON.stringify(plainError));\n * // {\"name\":\"FetchResponseError\",\"message\":\"...\",\"request\":{...},\"response\":{...}}\n * }\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}\n */\nclass FetchResponseError<\n Schema extends HttpSchema,\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n> extends Error {\n constructor(\n public request: FetchRequest<Schema, Method, Path>,\n public response: FetchResponse<Schema, Method, Path, true, 'manual'>,\n ) {\n super(`${request.method} ${request.url} failed with status ${response.status}: ${response.statusText}`);\n this.name = 'FetchResponseError';\n }\n\n /**\n * Converts this error into a plain object. This method is useful for serialization, debugging, and logging purposes.\n *\n * @example\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * const response = await fetch(`/users/${userId}`, {\n * method: 'GET',\n * });\n *\n * if (!response.ok) {\n * const plainError = response.error.toObject();\n * console.log(JSON.stringify(plainError));\n * // {\"name\":\"FetchResponseError\",\"message\":\"...\",\"request\":{...},\"response\":{...}}\n * }\n *\n * @param options.includeBody Whether to include the body of the request and response in the output. Defaults to\n * `false`.\n * @returns A plain object representing this error. If `options.includeBody` is `true`, the body of the request and\n * response will be included and the return of this method will be a `Promise`. Otherwise, the return will be the\n * plain object itself without the body.\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}\n */\n toObject(options: { includeBody: true }): Promise<FetchResponseErrorObject>;\n toObject(options?: { includeBody?: false }): FetchResponseErrorObject;\n toObject(options?: FetchResponseErrorObjectOptions): Promise<FetchResponseErrorObject> | FetchResponseErrorObject;\n toObject(\n options: FetchResponseErrorObjectOptions = {},\n ): Promise<FetchResponseErrorObject> | FetchResponseErrorObject {\n const { includeBody = false } = options;\n\n const partialObject = {\n name: this.name,\n message: this.message,\n } satisfies Partial<FetchResponseErrorObject>;\n\n if (!includeBody) {\n const request = this.convertRequestToObject({ includeBody: false });\n const response = this.convertResponseToObject({ includeBody: false });\n return { ...partialObject, request, response };\n }\n\n return Promise.all([\n this.convertRequestToObject({ includeBody: true }),\n this.convertResponseToObject({ includeBody: true }),\n ]).then(([request, response]) => ({ ...partialObject, request, response }));\n }\n\n private convertRequestToObject(options: { includeBody: true }): Promise<FetchRequestObject>;\n private convertRequestToObject(options: { includeBody: false }): FetchRequestObject;\n private convertRequestToObject(options: { includeBody: boolean }): Promise<FetchRequestObject> | FetchRequestObject {\n const partialObject = {\n url: this.request.url,\n path: this.request.path,\n method: this.request.method,\n headers: this.convertHeadersToObject(this.request.headers),\n cache: this.request.cache,\n destination: this.request.destination,\n credentials: this.request.credentials,\n integrity: this.request.integrity,\n keepalive: this.request.keepalive,\n mode: this.request.mode,\n redirect: this.request.redirect,\n referrer: this.request.referrer,\n referrerPolicy: this.request.referrerPolicy,\n } satisfies Partial<FetchRequestObject>;\n\n if (!options.includeBody) {\n return partialObject;\n }\n\n return this.request.text().then((bodyAsText: string) => ({\n ...partialObject,\n body: bodyAsText.length > 0 ? bodyAsText : null,\n }));\n }\n\n private convertResponseToObject(options: { includeBody: true }): Promise<FetchResponseObject>;\n private convertResponseToObject(options: { includeBody: false }): FetchResponseObject;\n private convertResponseToObject(options: {\n includeBody: boolean;\n }): Promise<FetchResponseObject> | FetchResponseObject {\n const partialObject = {\n url: this.response.url,\n type: this.response.type,\n status: this.response.status,\n statusText: this.response.statusText,\n ok: this.response.ok,\n headers: this.convertHeadersToObject(this.response.headers),\n redirected: this.response.redirected,\n } satisfies Partial<FetchResponseObject>;\n\n if (!options.includeBody) {\n return partialObject;\n }\n\n return this.response.text().then((bodyAsText: string) => ({\n ...partialObject,\n body: bodyAsText.length > 0 ? bodyAsText : null,\n }));\n }\n\n private convertHeadersToObject(headers: Headers) {\n return HttpHeaders.prototype.toObject.call(headers) as HttpHeadersSchema;\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyFetchRequestError = FetchResponseError<any, any, any>;\n\nexport default FetchResponseError;\n","var __defProp = Object.defineProperty;\nvar __name = (target, value) => __defProp(target, \"name\", { value, configurable: true });\n\nexport { __name };\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map\n//# sourceMappingURL=chunk-PAWJFY3S.mjs.map","export const URL_PATH_PARAM_REGEX = /\\/:([^/]+)/g;\n\nfunction createRegExpFromURL(url: string) {\n URL_PATH_PARAM_REGEX.lastIndex = 0;\n\n const urlWithReplacedPathParams = encodeURI(url)\n .replace(/([.()*?+$\\\\])/g, '\\\\$1')\n .replace(URL_PATH_PARAM_REGEX, '/(?<$1>[^/]+)')\n .replace(/^(\\/)|(\\/)$/g, '');\n\n return new RegExp(`^(?:/)?${urlWithReplacedPathParams}(?:/)?$`);\n}\n\nexport default createRegExpFromURL;\n","function excludeURLParams(url: URL) {\n url.hash = '';\n url.search = '';\n url.username = '';\n url.password = '';\n return url;\n}\n\nexport default excludeURLParams;\n","function joinURL(...parts: (URL | string)[]) {\n return parts\n .map((part, index) => {\n const isFirstPart = index === 0;\n const isLastPart = index === parts.length - 1;\n\n let partAsString = part.toString();\n\n if (!isFirstPart) {\n partAsString = partAsString.replace(/^\\//, '');\n }\n if (!isLastPart) {\n partAsString = partAsString.replace(/\\/$/, '');\n }\n\n return partAsString;\n })\n .filter((part) => part.length > 0)\n .join('/');\n}\n\nexport default joinURL;\n","import {\n HttpSchemaPath,\n HttpSchemaMethod,\n HttpSearchParams,\n LiteralHttpSchemaPathFromNonLiteral,\n HttpSchema,\n HttpHeaders,\n} from '@zimic/http';\nimport createRegexFromURL from '@zimic/utils/url/createRegExpFromURL';\nimport excludeURLParams from '@zimic/utils/url/excludeURLParams';\nimport joinURL from '@zimic/utils/url/joinURL';\n\nimport FetchResponseError from './errors/FetchResponseError';\nimport {\n FetchInput,\n FetchOptions,\n Fetch,\n FetchClient as PublicFetchClient,\n FetchDefaults,\n FetchFunction,\n} from './types/public';\nimport { FetchRequestConstructor, FetchRequestInit, FetchRequest, FetchResponse } from './types/requests';\n\nclass FetchClient<Schema extends HttpSchema>\n implements Omit<PublicFetchClient<Schema>, 'defaults' | 'loose' | 'Request'>\n{\n fetch: Fetch<Schema>;\n\n constructor({ onRequest, onResponse, ...defaults }: FetchOptions<Schema>) {\n this.fetch = this.createFetchFunction();\n\n this.fetch.defaults = {\n ...defaults,\n headers: defaults.headers ?? {},\n searchParams: defaults.searchParams ?? {},\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n this.fetch.loose = this.fetch as Fetch<any> as FetchFunction.Loose;\n\n this.fetch.Request = this.createRequestClass(this.fetch.defaults);\n this.fetch.onRequest = onRequest;\n this.fetch.onResponse = onResponse;\n }\n\n private createFetchFunction() {\n const fetch = async <\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) => {\n const request = await this.createFetchRequest<Method, Path>(input, init);\n const requestClone = request.clone();\n\n const rawResponse = await globalThis.fetch(\n // Optimize type checking by narrowing the type of request\n requestClone as Request,\n );\n const response = await this.createFetchResponse<\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >(request, rawResponse);\n\n return response;\n };\n\n Object.setPrototypeOf(fetch, this);\n\n return fetch as Fetch<Schema>;\n }\n\n private async createFetchRequest<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n >(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n let request = input instanceof Request ? input : new this.fetch.Request(input, init);\n\n if (this.fetch.onRequest) {\n const requestAfterInterceptor = await this.fetch.onRequest(\n // Optimize type checking by narrowing the type of request\n request as FetchRequest.Loose,\n );\n\n if (requestAfterInterceptor !== request) {\n const isFetchRequest = requestAfterInterceptor instanceof this.fetch.Request;\n\n request = isFetchRequest\n ? (requestAfterInterceptor as Request as typeof request)\n : new this.fetch.Request(requestAfterInterceptor as FetchInput<Schema, Method, Path>, init);\n }\n }\n\n return request;\n }\n\n private async createFetchResponse<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, rawResponse: Response) {\n let response = this.defineFetchResponseProperties<Method, Path>(fetchRequest, rawResponse);\n\n if (this.fetch.onResponse) {\n const responseAfterInterceptor = await this.fetch.onResponse(\n // Optimize type checking by narrowing the type of response\n response as FetchResponse.Loose,\n );\n\n const isFetchResponse =\n responseAfterInterceptor instanceof Response &&\n 'request' in responseAfterInterceptor &&\n responseAfterInterceptor.request instanceof this.fetch.Request;\n\n response = isFetchResponse\n ? (responseAfterInterceptor as typeof response)\n : this.defineFetchResponseProperties<Method, Path>(fetchRequest, responseAfterInterceptor);\n }\n\n return response;\n }\n\n private defineFetchResponseProperties<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.Literal<Schema, Method>,\n >(fetchRequest: FetchRequest<Schema, Method, Path>, response: Response) {\n const fetchResponse = response as FetchResponse<Schema, Method, Path>;\n\n Object.defineProperty(fetchResponse, 'request', {\n value: fetchRequest satisfies FetchResponse.Loose['request'],\n writable: false,\n enumerable: true,\n configurable: false,\n });\n\n let responseError: FetchResponse.Loose['error'] | undefined;\n\n Object.defineProperty(fetchResponse, 'error', {\n get() {\n if (responseError === undefined) {\n responseError = fetchResponse.ok\n ? null\n : new FetchResponseError(\n fetchRequest,\n fetchResponse as FetchResponse<Schema, Method, Path, true, 'manual'>,\n );\n }\n return responseError;\n },\n enumerable: true,\n configurable: false,\n });\n\n return fetchResponse;\n }\n\n private createRequestClass(defaults: FetchDefaults) {\n class Request<\n Method extends HttpSchemaMethod<Schema>,\n Path extends HttpSchemaPath.NonLiteral<Schema, Method>,\n > extends globalThis.Request {\n path: LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n\n constructor(\n input: FetchInput<Schema, Method, Path>,\n init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,\n ) {\n const initWithDefaults = { ...defaults, ...init };\n\n const headersFromDefaults = new HttpHeaders(defaults.headers);\n const headersFromInit = new HttpHeaders((init satisfies RequestInit as RequestInit).headers);\n\n let url: URL;\n const baseURL = new URL(initWithDefaults.baseURL);\n\n if (input instanceof globalThis.Request) {\n // Optimize type checking by narrowing the type of input\n const request = input as globalThis.Request;\n const headersFromRequest = new HttpHeaders(input.headers);\n\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromRequest.toObject(),\n ...headersFromInit.toObject(),\n };\n\n super(request, initWithDefaults);\n\n url = new URL(input.url);\n } else {\n initWithDefaults.headers = {\n ...headersFromDefaults.toObject(),\n ...headersFromInit.toObject(),\n };\n\n url = input instanceof URL ? new URL(input) : new URL(joinURL(baseURL, input));\n\n const searchParamsFromDefaults = new HttpSearchParams(defaults.searchParams);\n const searchParamsFromInit = new HttpSearchParams(initWithDefaults.searchParams);\n\n initWithDefaults.searchParams = {\n ...searchParamsFromDefaults.toObject(),\n ...searchParamsFromInit.toObject(),\n };\n\n url.search = new HttpSearchParams(initWithDefaults.searchParams).toString();\n\n super(url, initWithDefaults);\n }\n\n const baseURLWithoutTrailingSlash = baseURL.toString().replace(/\\/$/, '');\n\n this.path = excludeURLParams(url)\n .toString()\n .replace(baseURLWithoutTrailingSlash, '') as LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>;\n }\n\n clone(): Request<Method, Path> {\n const rawClone = super.clone();\n\n return new Request<Method, Path>(\n rawClone as unknown as FetchInput<Schema, Method, Path>,\n rawClone as unknown as FetchRequestInit<\n Schema,\n Method,\n LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>\n >,\n );\n }\n }\n\n return Request as FetchRequestConstructor<Schema>;\n }\n\n isRequest<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n request: unknown,\n method: Method,\n path: Path,\n ): request is FetchRequest<Schema, Method, Path> {\n return (\n request instanceof Request &&\n request.method === method &&\n 'path' in request &&\n typeof request.path === 'string' &&\n createRegexFromURL(path).test(request.path)\n );\n }\n\n isResponse<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n response: unknown,\n method: Method,\n path: Path,\n ): response is FetchResponse<Schema, Method, Path> {\n return (\n response instanceof Response &&\n 'request' in response &&\n this.isRequest(response.request, method, path) &&\n 'error' in response &&\n (response.error === null || response.error instanceof FetchResponseError)\n );\n }\n\n isResponseError<Path extends HttpSchemaPath.Literal<Schema, Method>, Method extends HttpSchemaMethod<Schema>>(\n error: unknown,\n method: Method,\n path: Path,\n ): error is FetchResponseError<Schema, Method, Path> {\n return (\n error instanceof FetchResponseError &&\n this.isRequest(error.request, method, path) &&\n this.isResponse(error.response, method, path)\n );\n }\n}\n\nexport default FetchClient;\n","import { HttpSchema } from '@zimic/http';\n\nimport FetchClient from './FetchClient';\nimport { FetchOptions, Fetch } from './types/public';\n\n/**\n * Creates a {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch fetch instance} typed with an HTTP\n * schema, closely compatible with the {@link https://developer.mozilla.org/docs/Web/API/Fetch_API native Fetch API}. All\n * requests and responses are typed by default with the schema, including methods, paths, status codes, parameters, and\n * bodies.\n *\n * Requests sent by the fetch instance have their URL automatically prefixed with the base URL of the instance.\n * {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch.defaults Default options} are also applied to the\n * requests, if provided.\n *\n * @example\n * import { type HttpSchema } from '@zimic/http';\n * import { createFetch } from '@zimic/fetch';\n *\n * interface User {\n * id: string;\n * username: string;\n * }\n *\n * type Schema = HttpSchema<{\n * '/users': {\n * POST: {\n * request: {\n * headers: { 'content-type': 'application/json' };\n * body: { username: string };\n * };\n * response: {\n * 201: { body: User };\n * };\n * };\n *\n * GET: {\n * request: {\n * searchParams: {\n * query?: string;\n * page?: number;\n * limit?: number;\n * };\n * };\n * response: {\n * 200: { body: User[] };\n * };\n * };\n * };\n * }>;\n *\n * const fetch = createFetch<Schema>({\n * baseURL: 'http://localhost:3000',\n * });\n *\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#createfetch `createFetch(options)` API reference}\n * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetch `fetch` API reference}\n */\nfunction createFetch<Schema extends HttpSchema>(options: FetchOptions<Schema>): Fetch<Schema> {\n const { fetch } = new FetchClient<Schema>(options);\n return fetch;\n}\n\nexport default createFetch;\n"]}
package/package.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "api",
14
14
  "static"
15
15
  ],
16
- "version": "0.1.3",
16
+ "version": "0.2.0-canary.1",
17
17
  "repository": {
18
18
  "type": "git",
19
19
  "url": "https://github.com/zimicjs/zimic.git",
@@ -56,20 +56,20 @@
56
56
  "./package.json": "./package.json"
57
57
  },
58
58
  "devDependencies": {
59
- "@types/node": "^22.13.10",
59
+ "@types/node": "^22.13.11",
60
60
  "@vitest/browser": "^3.0.9",
61
61
  "@vitest/coverage-istanbul": "^3.0.9",
62
62
  "dotenv-cli": "^8.0.0",
63
- "eslint": "^9.22.0",
63
+ "eslint": "^9.23.0",
64
64
  "playwright": "^1.51.1",
65
65
  "tsup": "^8.4.0",
66
66
  "typescript": "^5.8.2",
67
67
  "vitest": "^3.0.9",
68
- "@zimic/interceptor": "0.16.0",
69
68
  "@zimic/eslint-config-node": "0.0.0",
69
+ "@zimic/interceptor": "0.16.0",
70
70
  "@zimic/tsconfig": "0.0.0",
71
- "@zimic/lint-staged-config": "0.0.0",
72
- "@zimic/utils": "0.0.0"
71
+ "@zimic/utils": "0.0.0",
72
+ "@zimic/lint-staged-config": "0.0.0"
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@zimic/http": "^0.2.0 || ^0.2.0-canary.0",
@@ -1,6 +1,28 @@
1
- import { HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';
1
+ import { HttpHeaders, HttpHeadersSchema, HttpSchema, HttpSchemaMethod, HttpSchemaPath } from '@zimic/http';
2
2
 
3
- import { FetchRequest, FetchResponse } from '../types/requests';
3
+ import { FetchRequest, FetchRequestObject, FetchResponse, FetchResponseObject } from '../types/requests';
4
+
5
+ /**
6
+ * Options for converting a {@link FetchResponseError `FetchResponseError`} into a plain object.
7
+ *
8
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}
9
+ */
10
+ export interface FetchResponseErrorObjectOptions {
11
+ includeBody?: boolean;
12
+ }
13
+
14
+ /**
15
+ * A plain object representation of a {@link FetchResponseError `FetchResponseError`}, compatible with JSON. It is useful
16
+ * for serialization, debugging, and logging purposes.
17
+ *
18
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}
19
+ */
20
+ export interface FetchResponseErrorObject {
21
+ name: string;
22
+ message: string;
23
+ request: FetchRequestObject;
24
+ response: FetchResponseObject;
25
+ }
4
26
 
5
27
  /**
6
28
  * An error representing a response with a failure status code (4XX or 5XX).
@@ -39,6 +61,10 @@ import { FetchRequest, FetchResponse } from '../types/requests';
39
61
  * console.log(response.error); // FetchResponseError<Schema, 'GET', '/users'>
40
62
  * console.log(response.error.request); // FetchRequest<Schema, 'GET', '/users'>
41
63
  * console.log(response.error.response); // FetchResponse<Schema, 'GET', '/users'>
64
+ *
65
+ * const plainError = response.error.toObject();
66
+ * console.log(JSON.stringify(plainError));
67
+ * // {"name":"FetchResponseError","message":"...","request":{...},"response":{...}}
42
68
  * }
43
69
  *
44
70
  * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerror `FetchResponseError` API reference}
@@ -56,8 +82,112 @@ class FetchResponseError<
56
82
  this.name = 'FetchResponseError';
57
83
  }
58
84
 
59
- get cause() {
60
- return this.response;
85
+ /**
86
+ * Converts this error into a plain object. This method is useful for serialization, debugging, and logging purposes.
87
+ *
88
+ * @example
89
+ * const fetch = createFetch<Schema>({
90
+ * baseURL: 'http://localhost:3000',
91
+ * });
92
+ *
93
+ * const response = await fetch(`/users/${userId}`, {
94
+ * method: 'GET',
95
+ * });
96
+ *
97
+ * if (!response.ok) {
98
+ * const plainError = response.error.toObject();
99
+ * console.log(JSON.stringify(plainError));
100
+ * // {"name":"FetchResponseError","message":"...","request":{...},"response":{...}}
101
+ * }
102
+ *
103
+ * @param options.includeBody Whether to include the body of the request and response in the output. Defaults to
104
+ * `false`.
105
+ * @returns A plain object representing this error. If `options.includeBody` is `true`, the body of the request and
106
+ * response will be included and the return of this method will be a `Promise`. Otherwise, the return will be the
107
+ * plain object itself without the body.
108
+ * @see {@link https://github.com/zimicjs/zimic/wiki/api‐zimic‐fetch#fetchresponseerrortoobject `FetchResponseError#toObject` API reference}
109
+ */
110
+ toObject(options: { includeBody: true }): Promise<FetchResponseErrorObject>;
111
+ toObject(options?: { includeBody?: false }): FetchResponseErrorObject;
112
+ toObject(options?: FetchResponseErrorObjectOptions): Promise<FetchResponseErrorObject> | FetchResponseErrorObject;
113
+ toObject(
114
+ options: FetchResponseErrorObjectOptions = {},
115
+ ): Promise<FetchResponseErrorObject> | FetchResponseErrorObject {
116
+ const { includeBody = false } = options;
117
+
118
+ const partialObject = {
119
+ name: this.name,
120
+ message: this.message,
121
+ } satisfies Partial<FetchResponseErrorObject>;
122
+
123
+ if (!includeBody) {
124
+ const request = this.convertRequestToObject({ includeBody: false });
125
+ const response = this.convertResponseToObject({ includeBody: false });
126
+ return { ...partialObject, request, response };
127
+ }
128
+
129
+ return Promise.all([
130
+ this.convertRequestToObject({ includeBody: true }),
131
+ this.convertResponseToObject({ includeBody: true }),
132
+ ]).then(([request, response]) => ({ ...partialObject, request, response }));
133
+ }
134
+
135
+ private convertRequestToObject(options: { includeBody: true }): Promise<FetchRequestObject>;
136
+ private convertRequestToObject(options: { includeBody: false }): FetchRequestObject;
137
+ private convertRequestToObject(options: { includeBody: boolean }): Promise<FetchRequestObject> | FetchRequestObject {
138
+ const partialObject = {
139
+ url: this.request.url,
140
+ path: this.request.path,
141
+ method: this.request.method,
142
+ headers: this.convertHeadersToObject(this.request.headers),
143
+ cache: this.request.cache,
144
+ destination: this.request.destination,
145
+ credentials: this.request.credentials,
146
+ integrity: this.request.integrity,
147
+ keepalive: this.request.keepalive,
148
+ mode: this.request.mode,
149
+ redirect: this.request.redirect,
150
+ referrer: this.request.referrer,
151
+ referrerPolicy: this.request.referrerPolicy,
152
+ } satisfies Partial<FetchRequestObject>;
153
+
154
+ if (!options.includeBody) {
155
+ return partialObject;
156
+ }
157
+
158
+ return this.request.text().then((bodyAsText: string) => ({
159
+ ...partialObject,
160
+ body: bodyAsText.length > 0 ? bodyAsText : null,
161
+ }));
162
+ }
163
+
164
+ private convertResponseToObject(options: { includeBody: true }): Promise<FetchResponseObject>;
165
+ private convertResponseToObject(options: { includeBody: false }): FetchResponseObject;
166
+ private convertResponseToObject(options: {
167
+ includeBody: boolean;
168
+ }): Promise<FetchResponseObject> | FetchResponseObject {
169
+ const partialObject = {
170
+ url: this.response.url,
171
+ type: this.response.type,
172
+ status: this.response.status,
173
+ statusText: this.response.statusText,
174
+ ok: this.response.ok,
175
+ headers: this.convertHeadersToObject(this.response.headers),
176
+ redirected: this.response.redirected,
177
+ } satisfies Partial<FetchResponseObject>;
178
+
179
+ if (!options.includeBody) {
180
+ return partialObject;
181
+ }
182
+
183
+ return this.response.text().then((bodyAsText: string) => ({
184
+ ...partialObject,
185
+ body: bodyAsText.length > 0 ? bodyAsText : null,
186
+ }));
187
+ }
188
+
189
+ private convertHeadersToObject(headers: Headers) {
190
+ return HttpHeaders.prototype.toObject.call(headers) as HttpHeadersSchema;
61
191
  }
62
192
  }
63
193
 
@@ -199,7 +199,7 @@ export interface FetchRequest<
199
199
  }
200
200
 
201
201
  export namespace FetchRequest {
202
- /** A loosely typed version of {@link FetchRequest `FetchRequest`}. */
202
+ /** A loosely typed version of a {@link FetchRequest `FetchRequest`}. */
203
203
  export interface Loose extends Request {
204
204
  /** The path of the request, excluding the base URL. */
205
205
  path: string;
@@ -210,6 +210,36 @@ export namespace FetchRequest {
210
210
  }
211
211
  }
212
212
 
213
+ /**
214
+ * A plain object representation of a {@link FetchRequest `FetchRequest`}, compatible with JSON.
215
+ *
216
+ * If the body is included in the object, it is represented as a string or null if empty.
217
+ */
218
+ export type FetchRequestObject = Pick<
219
+ FetchRequest.Loose,
220
+ | 'url'
221
+ | 'path'
222
+ | 'method'
223
+ | 'cache'
224
+ | 'destination'
225
+ | 'credentials'
226
+ | 'integrity'
227
+ | 'keepalive'
228
+ | 'mode'
229
+ | 'redirect'
230
+ | 'referrer'
231
+ | 'referrerPolicy'
232
+ > & {
233
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) */
234
+ headers: HttpHeadersSchema;
235
+ /**
236
+ * The body of the response, represented as a string or null if empty.
237
+ *
238
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body)
239
+ */
240
+ body?: string | null;
241
+ };
242
+
213
243
  export interface FetchResponsePerStatusCode<
214
244
  Schema extends HttpSchema,
215
245
  Method extends HttpSchemaMethod<Schema>,
@@ -299,7 +329,7 @@ export type FetchResponse<
299
329
  > = StatusCode extends StatusCode ? FetchResponsePerStatusCode<Schema, Method, Path, StatusCode> : never;
300
330
 
301
331
  export namespace FetchResponse {
302
- /** A loosely typed version of {@link FetchResponse}. */
332
+ /** A loosely typed version of a {@link FetchResponse}. */
303
333
  export interface Loose extends Response {
304
334
  /** The request that originated the response. */
305
335
  request: FetchRequest.Loose;
@@ -317,6 +347,25 @@ export namespace FetchResponse {
317
347
  }
318
348
  }
319
349
 
350
+ /**
351
+ * A plain object representation of a {@link FetchResponse `FetchResponse`}, compatible with JSON.
352
+ *
353
+ * If the body is included in the object, it is represented as a string or null if empty.
354
+ */
355
+ export type FetchResponseObject = Pick<
356
+ FetchResponse.Loose,
357
+ 'url' | 'type' | 'status' | 'statusText' | 'ok' | 'redirected'
358
+ > & {
359
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/headers) */
360
+ headers: HttpHeadersSchema;
361
+ /**
362
+ * The body of the response, represented as a string or null if empty.
363
+ *
364
+ * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/body)
365
+ */
366
+ body?: string | null;
367
+ };
368
+
320
369
  /**
321
370
  * A constructor for {@link FetchRequest} instances, typed with an HTTP schema and compatible with the
322
371
  * {@link https://developer.mozilla.org/docs/Web/API/Request Request class constructor}.
package/src/index.ts CHANGED
@@ -2,8 +2,16 @@ export type { JSONStringified } from './client/types/json';
2
2
 
3
3
  export type { Fetch, InferFetchSchema, FetchOptions, FetchDefaults, FetchInput } from './client/types/public';
4
4
 
5
- export type { FetchRequest, FetchRequestInit, FetchResponse, FetchRequestConstructor } from './client/types/requests';
5
+ export type {
6
+ FetchRequestConstructor,
7
+ FetchRequest,
8
+ FetchRequestObject,
9
+ FetchRequestInit,
10
+ FetchResponse,
11
+ FetchResponseObject,
12
+ } from './client/types/requests';
6
13
 
7
14
  export { default as FetchResponseError } from './client/errors/FetchResponseError';
15
+ export type { FetchResponseErrorObject, FetchResponseErrorObjectOptions } from './client/errors/FetchResponseError';
8
16
 
9
17
  export { default as createFetch } from './client/factory';