@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.
- package/README.md +3 -7
- package/dist/index.d.ts +61 -44
- package/dist/index.js +77 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -11
- package/src/client/FetchClient.ts +113 -66
- package/src/client/errors/FetchResponseError.ts +6 -6
- package/src/client/factory.ts +3 -5
- package/src/client/types/public.ts +42 -50
- package/src/client/types/requests.ts +89 -49
- package/src/index.ts +5 -9
- package/src/types/requests.ts +1 -2
- package/src/utils/environment.ts +3 -0
- package/src/utils/files.ts +4 -19
- package/src/types/strings.d.ts +0 -9
- package/src/types/utils.ts +0 -11
- package/src/utils/imports.ts +0 -14
- package/src/utils/urls.ts +0 -43
|
@@ -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?:
|
|
32
|
-
: { 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?:
|
|
40
|
-
: { 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
|
-
:
|
|
45
|
-
?
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
88
|
-
Method extends
|
|
89
|
-
|
|
90
|
-
> extends HttpRequest<
|
|
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
|
-
|
|
105
|
-
Method extends
|
|
106
|
-
|
|
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<
|
|
151
|
+
HttpResponseBodySchema<Default<Schema[Path][Method]>, StatusCode>,
|
|
110
152
|
StatusCode,
|
|
111
|
-
HttpResponseHeadersSchema<
|
|
153
|
+
HttpResponseHeadersSchema<Default<Schema[Path][Method]>, StatusCode>
|
|
112
154
|
> {
|
|
113
|
-
request: FetchRequest<
|
|
155
|
+
request: FetchRequest<Schema, Method, Path>;
|
|
114
156
|
|
|
115
157
|
error: StatusCode extends HttpStatusCode.ClientError | HttpStatusCode.ServerError
|
|
116
|
-
? FetchResponseError<
|
|
158
|
+
? FetchResponseError<Schema, Method, Path>
|
|
117
159
|
: null;
|
|
118
160
|
}
|
|
119
161
|
|
|
120
162
|
export type FetchResponse<
|
|
121
|
-
|
|
122
|
-
Method extends
|
|
123
|
-
|
|
163
|
+
Schema extends HttpSchema,
|
|
164
|
+
Method extends HttpSchemaMethod<Schema>,
|
|
165
|
+
Path extends HttpSchemaPath.Literal<Schema, Method>,
|
|
124
166
|
ErrorOnly extends boolean = false,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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,
|
|
144
|
-
init: FetchRequestInit<Schema, LiteralHttpSchemaPathFromNonLiteral<Schema, Method, Path
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
package/src/types/requests.ts
CHANGED
|
@@ -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
|
package/src/utils/files.ts
CHANGED
|
@@ -1,23 +1,8 @@
|
|
|
1
|
-
import
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
7
|
+
async () => globalThis.File ?? (await import('buffer')).File,
|
|
8
|
+
);
|
package/src/types/strings.d.ts
DELETED
|
@@ -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
|
-
}
|
package/src/types/utils.ts
DELETED
|
@@ -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;
|
package/src/utils/imports.ts
DELETED
|
@@ -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
|
-
}
|