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

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.
@@ -17,36 +17,49 @@ import {
17
17
  HttpResponseBodySchema,
18
18
  HttpResponseHeadersSchema,
19
19
  HttpRequestHeadersSchema,
20
+ HttpHeadersSchema,
21
+ HttpSearchParamsSchema,
20
22
  } from '@zimic/http';
21
-
22
- import { Default, DefaultNoExclude, IfNever, ReplaceBy } from '@/types/utils';
23
+ import { Default, DefaultNoExclude, IfNever, ReplaceBy } from '@zimic/utils/types';
23
24
 
24
25
  import FetchResponseError, { AnyFetchRequestError } from '../errors/FetchResponseError';
25
26
  import { JSONStringified } from './json';
26
27
  import { FetchInput } from './public';
27
28
 
29
+ type FetchRequestInitHeaders<RequestSchema extends HttpRequestSchema> =
30
+ | RequestSchema['headers']
31
+ | HttpHeaders<Default<RequestSchema['headers']>>;
32
+
28
33
  type FetchRequestInitWithHeaders<RequestSchema extends HttpRequestSchema> = [RequestSchema['headers']] extends [never]
29
34
  ? { headers?: undefined }
30
35
  : undefined extends RequestSchema['headers']
31
- ? { headers?: RequestSchema['headers'] | HttpHeaders<Default<RequestSchema['headers']>> }
32
- : { headers: RequestSchema['headers'] | HttpHeaders<Default<RequestSchema['headers']>> };
36
+ ? { headers?: FetchRequestInitHeaders<RequestSchema> }
37
+ : { headers: FetchRequestInitHeaders<RequestSchema> };
38
+
39
+ type FetchRequestInitSearchParams<RequestSchema extends HttpRequestSchema> =
40
+ | RequestSchema['searchParams']
41
+ | HttpSearchParams<Default<RequestSchema['searchParams']>>;
33
42
 
34
43
  type FetchRequestInitWithSearchParams<RequestSchema extends HttpRequestSchema> = [
35
44
  RequestSchema['searchParams'],
36
45
  ] extends [never]
37
46
  ? { searchParams?: undefined }
38
47
  : undefined extends RequestSchema['searchParams']
39
- ? { searchParams?: RequestSchema['searchParams'] | HttpSearchParams<Default<RequestSchema['searchParams']>> }
40
- : { searchParams: RequestSchema['searchParams'] | HttpSearchParams<Default<RequestSchema['searchParams']>> };
48
+ ? { searchParams?: FetchRequestInitSearchParams<RequestSchema> }
49
+ : { searchParams: FetchRequestInitSearchParams<RequestSchema> };
41
50
 
42
51
  type FetchRequestInitWithBody<RequestSchema extends HttpRequestSchema> = [RequestSchema['body']] extends [never]
43
52
  ? { body?: null }
44
- : undefined extends RequestSchema['body']
45
- ? { body?: ReplaceBy<RequestSchema['body'], undefined, null> }
46
- : RequestSchema['body'] extends string
47
- ? { body: RequestSchema['body'] }
48
- : RequestSchema['body'] extends JSONValue
49
- ? { body: JSONStringified<RequestSchema['body']> }
53
+ : RequestSchema['body'] extends string
54
+ ? undefined extends RequestSchema['body']
55
+ ? { body?: ReplaceBy<RequestSchema['body'], undefined, null> }
56
+ : { body: RequestSchema['body'] }
57
+ : RequestSchema['body'] extends JSONValue
58
+ ? undefined extends RequestSchema['body']
59
+ ? { body?: JSONStringified<ReplaceBy<RequestSchema['body'], undefined, null>> }
60
+ : { body: JSONStringified<RequestSchema['body']> }
61
+ : undefined extends RequestSchema['body']
62
+ ? { body?: ReplaceBy<RequestSchema['body'], undefined, null> }
50
63
  : { body: RequestSchema['body'] };
51
64
 
52
65
  type FetchRequestInitPerPath<RequestSchema extends HttpRequestSchema> = FetchRequestInitWithHeaders<RequestSchema> &
@@ -55,39 +68,68 @@ type FetchRequestInitPerPath<RequestSchema extends HttpRequestSchema> = FetchReq
55
68
 
56
69
  export type FetchRequestInit<
57
70
  Schema extends HttpSchema,
58
- Path extends HttpSchemaPath<Schema, Method>,
59
71
  Method extends HttpSchemaMethod<Schema>,
60
- > = RequestInit & { baseURL?: string; method: Method } & (Path extends Path
61
- ? FetchRequestInitPerPath<Default<Default<Schema[Path][Method]>['request']>>
62
- : never);
72
+ Path extends HttpSchemaPath<Schema, Method>,
73
+ Redirect extends RequestRedirect = 'follow',
74
+ > = Omit<RequestInit, 'method' | 'headers' | 'body'> & {
75
+ method: Method;
76
+ baseURL?: string;
77
+ redirect?: Redirect;
78
+ } & (Path extends Path ? FetchRequestInitPerPath<Default<Default<Schema[Path][Method]>['request']>> : never);
63
79
 
64
80
  export namespace FetchRequestInit {
65
- export interface Defaults extends RequestInit {
81
+ /** The default options for each request sent by a fetch instance. */
82
+ export interface Defaults extends Omit<RequestInit, 'headers'> {
66
83
  baseURL: string;
67
84
  method?: HttpMethod;
68
- searchParams?: HttpSearchParams;
85
+ headers?: HttpHeadersSchema;
86
+ searchParams?: HttpSearchParamsSchema;
69
87
  }
88
+
89
+ export type Loose = Partial<Defaults>;
70
90
  }
71
91
 
72
92
  type AllFetchResponseStatusCode<MethodSchema extends HttpMethodSchema> = HttpResponseSchemaStatusCode<
73
93
  Default<MethodSchema['response']>
74
94
  >;
75
95
 
76
- type FetchResponseStatusCode<MethodSchema extends HttpMethodSchema, ErrorOnly extends boolean> = ErrorOnly extends true
77
- ? AllFetchResponseStatusCode<MethodSchema> & (HttpStatusCode.ClientError | HttpStatusCode.ServerError)
78
- : AllFetchResponseStatusCode<MethodSchema>;
96
+ type FilterFetchResponseStatusCodeByError<
97
+ StatusCode extends HttpStatusCode,
98
+ ErrorOnly extends boolean,
99
+ > = ErrorOnly extends true ? Extract<StatusCode, HttpStatusCode.ClientError | HttpStatusCode.ServerError> : StatusCode;
100
+
101
+ type FilterFetchResponseStatusCodeByRedirect<
102
+ StatusCode extends HttpStatusCode,
103
+ Redirect extends RequestRedirect,
104
+ > = Redirect extends 'error'
105
+ ? FilterFetchResponseStatusCodeByRedirect<StatusCode, 'follow'>
106
+ : Redirect extends 'follow'
107
+ ? Exclude<StatusCode, Exclude<HttpStatusCode.Redirection, 304>>
108
+ : StatusCode;
109
+
110
+ type FetchResponseStatusCode<
111
+ MethodSchema extends HttpMethodSchema,
112
+ ErrorOnly extends boolean,
113
+ Redirect extends RequestRedirect,
114
+ > = FilterFetchResponseStatusCodeByRedirect<
115
+ FilterFetchResponseStatusCodeByError<AllFetchResponseStatusCode<MethodSchema>, ErrorOnly>,
116
+ Redirect
117
+ >;
79
118
 
80
- export type HttpRequestBodySchema<MethodSchema extends HttpMethodSchema> = ReplaceBy<
119
+ type HttpRequestBodySchema<MethodSchema extends HttpMethodSchema> = ReplaceBy<
81
120
  ReplaceBy<IfNever<DefaultNoExclude<Default<MethodSchema['request']>['body']>, null>, undefined, null>,
82
121
  ArrayBuffer,
83
122
  Blob
84
123
  >;
85
124
 
86
125
  export interface FetchRequest<
87
- Path extends string = string,
88
- Method extends HttpMethod = HttpMethod,
89
- MethodSchema extends HttpMethodSchema = HttpMethodSchema,
90
- > extends HttpRequest<HttpRequestBodySchema<MethodSchema>, HttpRequestHeadersSchema<MethodSchema>> {
126
+ Schema extends HttpSchema,
127
+ Method extends HttpSchemaMethod<Schema>,
128
+ Path extends HttpSchemaPath.Literal<Schema, Method>,
129
+ > extends HttpRequest<
130
+ HttpRequestBodySchema<Default<Schema[Path][Method]>>,
131
+ HttpRequestHeadersSchema<Default<Schema[Path][Method]>>
132
+ > {
91
133
  path: AllowAnyStringInPathParams<Path>;
92
134
  method: Method;
93
135
  }
@@ -101,32 +143,34 @@ export namespace FetchRequest {
101
143
  }
102
144
 
103
145
  export interface FetchResponsePerStatusCode<
104
- Path extends string = string,
105
- Method extends HttpMethod = HttpMethod,
106
- MethodSchema extends HttpMethodSchema = HttpMethodSchema,
146
+ Schema extends HttpSchema,
147
+ Method extends HttpSchemaMethod<Schema>,
148
+ Path extends HttpSchemaPath.Literal<Schema, Method>,
107
149
  StatusCode extends HttpStatusCode = HttpStatusCode,
108
150
  > extends HttpResponse<
109
- HttpResponseBodySchema<MethodSchema, StatusCode>,
151
+ HttpResponseBodySchema<Default<Schema[Path][Method]>, StatusCode>,
110
152
  StatusCode,
111
- HttpResponseHeadersSchema<MethodSchema, StatusCode>
153
+ HttpResponseHeadersSchema<Default<Schema[Path][Method]>, StatusCode>
112
154
  > {
113
- request: FetchRequest<Path, Method, MethodSchema>;
155
+ request: FetchRequest<Schema, Method, Path>;
114
156
 
115
157
  error: StatusCode extends HttpStatusCode.ClientError | HttpStatusCode.ServerError
116
- ? FetchResponseError<Path, Method, MethodSchema>
158
+ ? FetchResponseError<Schema, Method, Path>
117
159
  : null;
118
160
  }
119
161
 
120
162
  export type FetchResponse<
121
- Path extends string = string,
122
- Method extends HttpMethod = HttpMethod,
123
- MethodSchema extends HttpMethodSchema = HttpMethodSchema,
163
+ Schema extends HttpSchema,
164
+ Method extends HttpSchemaMethod<Schema>,
165
+ Path extends HttpSchemaPath.Literal<Schema, Method>,
124
166
  ErrorOnly extends boolean = false,
125
- StatusCode extends FetchResponseStatusCode<MethodSchema, ErrorOnly> = FetchResponseStatusCode<
126
- MethodSchema,
127
- ErrorOnly
128
- >,
129
- > = StatusCode extends StatusCode ? FetchResponsePerStatusCode<Path, Method, MethodSchema, StatusCode> : never;
167
+ Redirect extends RequestRedirect = 'follow',
168
+ StatusCode extends FetchResponseStatusCode<
169
+ Default<Schema[Path][Method]>,
170
+ ErrorOnly,
171
+ Redirect
172
+ > = FetchResponseStatusCode<Default<Schema[Path][Method]>, ErrorOnly, Redirect>,
173
+ > = StatusCode extends StatusCode ? FetchResponsePerStatusCode<Schema, Method, Path, StatusCode> : never;
130
174
 
131
175
  export namespace FetchResponse {
132
176
  export interface Loose extends Response {
@@ -137,13 +181,9 @@ export namespace FetchResponse {
137
181
  }
138
182
 
139
183
  export type FetchRequestConstructor<Schema extends HttpSchema> = new <
140
- Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
141
184
  Method extends HttpSchemaMethod<Schema>,
185
+ Path extends HttpSchemaPath.NonLiteral<Schema, Method>,
142
186
  >(
143
- input: FetchInput<Schema, Path, Method>,
144
- init: FetchRequestInit<Schema, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>, Method>,
145
- ) => FetchRequest<
146
- LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>,
147
- Method,
148
- Default<Schema[LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>][Method]>
149
- >;
187
+ input: FetchInput<Schema, Method, Path>,
188
+ init: FetchRequestInit<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>,
189
+ ) => FetchRequest<Schema, Method, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path>>;
package/src/index.ts CHANGED
@@ -1,12 +1,8 @@
1
- export type {
2
- Fetch,
3
- FetchFunction,
4
- FetchClient,
5
- FetchOptions as FetchClientOptions,
6
- FetchInput,
7
- } from './client/types/public';
8
-
9
- export type { FetchRequestInit, FetchRequest, FetchRequestConstructor, FetchResponse } from './client/types/requests';
1
+ export type { JSONStringified } from './client/types/json';
2
+
3
+ export type { Fetch, InferFetchSchema, FetchOptions, FetchDefaults, FetchInput } from './client/types/public';
4
+
5
+ export type { FetchRequest, FetchRequestInit, FetchResponse, FetchRequestConstructor } from './client/types/requests';
10
6
 
11
7
  export { default as FetchResponseError } from './client/errors/FetchResponseError';
12
8
 
@@ -9,8 +9,7 @@ import {
9
9
  JSONValue,
10
10
  HttpStatusCode,
11
11
  } from '@zimic/http';
12
-
13
- import { ReplaceBy } from '@/types/utils';
12
+ import { ReplaceBy } from '@zimic/utils/types';
14
13
 
15
14
  /** The body type for HTTP requests and responses. */
16
15
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -0,0 +1,3 @@
1
+ export function isClientSide() {
2
+ return typeof window !== 'undefined';
3
+ }
@@ -1,23 +1,8 @@
1
- import { createCachedDynamicImport } from './imports';
2
-
3
- export const importBuffer = createCachedDynamicImport(
4
- /* istanbul ignore next -- @preserve
5
- * Ignoring as Node.js >=20 provides a global file and the buffer import won't run. */
6
- () => import('buffer'),
7
- );
8
-
9
- let FileSingleton: typeof File | undefined;
10
-
11
- export async function importFile() {
12
- /* istanbul ignore if -- @preserve
13
- * Ignoring as this will only run if this function is called more than once. */
14
- if (FileSingleton) {
15
- return FileSingleton;
16
- }
1
+ import createCachedDynamicImport from '@zimic/utils/import/createCachedDynamicImport';
17
2
 
3
+ export const importFile = createCachedDynamicImport(
18
4
  /* istanbul ignore next -- @preserve
19
5
  * Ignoring as Node.js >=20 provides a global File and the import fallback won't run. */
20
6
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
21
- FileSingleton = globalThis.File ?? (await importBuffer()).File;
22
- return FileSingleton;
23
- }
7
+ async () => globalThis.File ?? (await import('buffer')).File,
8
+ );
@@ -1,9 +0,0 @@
1
- interface String {
2
- // Using the original method signature style to correctly apply the overload.
3
- // eslint-disable-next-line @typescript-eslint/method-signature-style
4
- toLowerCase<Type = string>(): Lowercase<Type>;
5
-
6
- // Using the original method signature style to correctly apply the overload.
7
- // eslint-disable-next-line @typescript-eslint/method-signature-style
8
- toUpperCase<Type = string>(): Uppercase<Type>;
9
- }
@@ -1,11 +0,0 @@
1
- export type Default<Type, IfEmpty = never> = [undefined | void] extends [Type]
2
- ? IfEmpty
3
- : Exclude<Type, undefined | void>;
4
-
5
- export type DefaultNoExclude<Type, IfEmpty = never> = [undefined | void] extends Type ? IfEmpty : Type;
6
-
7
- export type IfNever<Type, Yes, No = Type> = [Type] extends [never] ? Yes : No;
8
-
9
- export type PossiblePromise<Type> = Type | PromiseLike<Type>;
10
-
11
- export type ReplaceBy<Type, Source, Target> = Type extends Source ? Target : Type;
@@ -1,14 +0,0 @@
1
- /* istanbul ignore next -- @preserve
2
- * Ignoring as Node.js >=20 provides globals that may cause this dynamic import to not run. */
3
- export function createCachedDynamicImport<ImportType>(
4
- importModuleDynamically: () => Promise<ImportType>,
5
- ): () => Promise<ImportType> {
6
- let cachedImportResult: ImportType | undefined;
7
-
8
- return async function importModuleDynamicallyWithCache() {
9
- if (cachedImportResult === undefined) {
10
- cachedImportResult = await importModuleDynamically();
11
- }
12
- return cachedImportResult;
13
- };
14
- }
package/src/utils/urls.ts DELETED
@@ -1,43 +0,0 @@
1
- export function excludeNonPathParams(url: URL) {
2
- url.hash = '';
3
- url.search = '';
4
- url.username = '';
5
- url.password = '';
6
- return url;
7
- }
8
-
9
- function prepareURLForRegex(url: string) {
10
- const encodedURL = encodeURI(url);
11
- return encodedURL.replace(/([.()*?+$\\])/g, '\\$1');
12
- }
13
-
14
- const URL_PATH_PARAM_REGEX = /\/:([^/]+)/g;
15
-
16
- export function createRegexFromURL(url: string) {
17
- const urlWithReplacedPathParams = prepareURLForRegex(url)
18
- .replace(URL_PATH_PARAM_REGEX, '/(?<$1>[^/]+)')
19
- .replace(/(\/+)$/, '(?:/+)?');
20
-
21
- return new RegExp(`^${urlWithReplacedPathParams}$`);
22
- }
23
-
24
- export function joinURL(...parts: (string | URL)[]) {
25
- return parts
26
- .map((part, index) => {
27
- const isFirstPart = index === 0;
28
- const isLastPart = index === parts.length - 1;
29
-
30
- let partAsString = part.toString();
31
-
32
- if (!isFirstPart) {
33
- partAsString = partAsString.replace(/^\//, '');
34
- }
35
- if (!isLastPart) {
36
- partAsString = partAsString.replace(/\/$/, '');
37
- }
38
-
39
- return partAsString;
40
- })
41
- .filter((part) => part.length > 0)
42
- .join('/');
43
- }