@swapkit/api-sdk-typescript 1.0.3 → 1.1.0-nightly.20260701161042
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 +6 -0
- package/dist/index.cjs +148 -164
- package/dist/index.d.cts +1661 -1455
- package/dist/index.d.ts +1661 -1455
- package/dist/index.js +139 -155
- package/package.json +4 -2
- package/src/client.ts +3 -3
- package/src/core/auth.ts +7 -0
- package/src/core/bodySerializer.ts +6 -8
- package/src/core/params.ts +24 -15
- package/src/core/pathSerializer.ts +6 -6
- package/src/core/queryKeySerializer.ts +1 -1
- package/src/core/serverSentEvents.ts +4 -5
- package/src/core/types.ts +7 -1
- package/src/core/utils.ts +5 -5
- package/src/http/client.ts +129 -140
- package/src/http/index.ts +2 -0
- package/src/http/types.ts +10 -6
- package/src/http/utils.ts +13 -13
- package/src/index.ts +28 -28
- package/src/sdk.ts +18 -18
- package/src/types.ts +1597 -1387
|
@@ -25,7 +25,7 @@ interface SerializePrimitiveParam extends SerializePrimitiveOptions {
|
|
|
25
25
|
value: string;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
|
|
28
|
+
export const separatorArrayExplode = (style: ArraySeparatorStyle): '.' | ';' | ',' | '&' => {
|
|
29
29
|
switch (style) {
|
|
30
30
|
case 'label':
|
|
31
31
|
return '.';
|
|
@@ -38,7 +38,7 @@ export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
-
export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
|
|
41
|
+
export const separatorArrayNoExplode = (style: ArraySeparatorStyle): ',' | '|' | '%20' => {
|
|
42
42
|
switch (style) {
|
|
43
43
|
case 'form':
|
|
44
44
|
return ',';
|
|
@@ -51,7 +51,7 @@ export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
|
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
export const separatorObjectExplode = (style: ObjectSeparatorStyle) => {
|
|
54
|
+
export const separatorObjectExplode = (style: ObjectSeparatorStyle): '.' | ';' | ',' | '&' => {
|
|
55
55
|
switch (style) {
|
|
56
56
|
case 'label':
|
|
57
57
|
return '.';
|
|
@@ -72,7 +72,7 @@ export const serializeArrayParam = ({
|
|
|
72
72
|
value,
|
|
73
73
|
}: SerializeOptions<ArraySeparatorStyle> & {
|
|
74
74
|
value: unknown[];
|
|
75
|
-
}) => {
|
|
75
|
+
}): string => {
|
|
76
76
|
if (!explode) {
|
|
77
77
|
const joinedValues = (
|
|
78
78
|
allowReserved ? value : value.map((v) => encodeURIComponent(v as string))
|
|
@@ -110,7 +110,7 @@ export const serializePrimitiveParam = ({
|
|
|
110
110
|
allowReserved,
|
|
111
111
|
name,
|
|
112
112
|
value,
|
|
113
|
-
}: SerializePrimitiveParam) => {
|
|
113
|
+
}: SerializePrimitiveParam): string => {
|
|
114
114
|
if (value === undefined || value === null) {
|
|
115
115
|
return '';
|
|
116
116
|
}
|
|
@@ -134,7 +134,7 @@ export const serializeObjectParam = ({
|
|
|
134
134
|
}: SerializeOptions<ObjectSeparatorStyle> & {
|
|
135
135
|
value: Record<string, unknown> | Date;
|
|
136
136
|
valueOnly?: boolean;
|
|
137
|
-
}) => {
|
|
137
|
+
}): string => {
|
|
138
138
|
if (value instanceof Date) {
|
|
139
139
|
return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
|
|
140
140
|
}
|
|
@@ -14,7 +14,7 @@ export type JsonValue =
|
|
|
14
14
|
/**
|
|
15
15
|
* Replacer that converts non-JSON values (bigint, Date, etc.) to safe substitutes.
|
|
16
16
|
*/
|
|
17
|
-
export const queryKeyJsonReplacer = (_key: string, value: unknown) => {
|
|
17
|
+
export const queryKeyJsonReplacer = (_key: string, value: unknown): unknown | undefined => {
|
|
18
18
|
if (value === undefined || typeof value === 'function' || typeof value === 'symbol') {
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
@@ -79,7 +79,7 @@ export type ServerSentEventsResult<TData = unknown, TReturn = void, TNext = unkn
|
|
|
79
79
|
>;
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
export
|
|
82
|
+
export function createSseClient<TData = unknown>({
|
|
83
83
|
onRequest,
|
|
84
84
|
onSseError,
|
|
85
85
|
onSseEvent,
|
|
@@ -91,7 +91,7 @@ export const createSseClient = <TData = unknown>({
|
|
|
91
91
|
sseSleepFn,
|
|
92
92
|
url,
|
|
93
93
|
...options
|
|
94
|
-
}: ServerSentEventsOptions): ServerSentEventsResult<TData>
|
|
94
|
+
}: ServerSentEventsOptions): ServerSentEventsResult<TData> {
|
|
95
95
|
let lastEventId: string | undefined;
|
|
96
96
|
|
|
97
97
|
const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
@@ -155,8 +155,7 @@ export const createSseClient = <TData = unknown>({
|
|
|
155
155
|
const { done, value } = await reader.read();
|
|
156
156
|
if (done) break;
|
|
157
157
|
buffer += value;
|
|
158
|
-
|
|
159
|
-
buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
158
|
+
buffer = buffer.replace(/\r\n?/g, '\n'); // normalize line endings
|
|
160
159
|
|
|
161
160
|
const chunks = buffer.split('\n\n');
|
|
162
161
|
buffer = chunks.pop() ?? '';
|
|
@@ -240,4 +239,4 @@ export const createSseClient = <TData = unknown>({
|
|
|
240
239
|
const stream = createStream();
|
|
241
240
|
|
|
242
241
|
return { stream };
|
|
243
|
-
}
|
|
242
|
+
}
|
package/src/core/types.ts
CHANGED
|
@@ -80,7 +80,7 @@ export interface Config {
|
|
|
80
80
|
requestValidator?: (data: unknown) => Promise<unknown>;
|
|
81
81
|
/**
|
|
82
82
|
* A function transforming response data before it's returned. This is useful
|
|
83
|
-
* for post-processing data, e.g
|
|
83
|
+
* for post-processing data, e.g., converting ISO strings into Date objects.
|
|
84
84
|
*/
|
|
85
85
|
responseTransformer?: (data: unknown) => Promise<unknown>;
|
|
86
86
|
/**
|
|
@@ -91,6 +91,12 @@ export interface Config {
|
|
|
91
91
|
responseValidator?: (data: unknown) => Promise<unknown>;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Arbitrary metadata passed through the `meta` request option.
|
|
96
|
+
*/
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
98
|
+
export interface ClientMeta {}
|
|
99
|
+
|
|
94
100
|
type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
|
|
95
101
|
? true
|
|
96
102
|
: [T] extends [never | undefined]
|
package/src/core/utils.ts
CHANGED
|
@@ -13,9 +13,9 @@ export interface PathSerializer {
|
|
|
13
13
|
url: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
16
|
+
export const PATH_PARAM_RE: RegExp = /\{[^{}]+\}/g;
|
|
17
17
|
|
|
18
|
-
export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
|
|
18
|
+
export const defaultPathSerializer = ({ path, url: _url }: PathSerializer): string => {
|
|
19
19
|
let url = _url;
|
|
20
20
|
const matches = _url.match(PATH_PARAM_RE);
|
|
21
21
|
if (matches) {
|
|
@@ -94,7 +94,7 @@ export const getUrl = ({
|
|
|
94
94
|
query?: Record<string, unknown>;
|
|
95
95
|
querySerializer: QuerySerializer;
|
|
96
96
|
url: string;
|
|
97
|
-
}) => {
|
|
97
|
+
}): string => {
|
|
98
98
|
const pathUrl = _url.startsWith('/') ? _url : `/${_url}`;
|
|
99
99
|
let url = (baseUrl ?? '') + pathUrl;
|
|
100
100
|
if (path) {
|
|
@@ -114,7 +114,7 @@ export function getValidRequestBody(options: {
|
|
|
114
114
|
body?: unknown;
|
|
115
115
|
bodySerializer?: BodySerializer | null;
|
|
116
116
|
serializedBody?: unknown;
|
|
117
|
-
}) {
|
|
117
|
+
}): unknown {
|
|
118
118
|
const hasBody = options.body !== undefined;
|
|
119
119
|
const isSerializedBody = hasBody && options.bodySerializer;
|
|
120
120
|
|
|
@@ -126,7 +126,7 @@ export function getValidRequestBody(options: {
|
|
|
126
126
|
return hasSerializedBody ? options.serializedBody : null;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
// not all clients implement a serializedBody property (i.e
|
|
129
|
+
// not all clients implement a serializedBody property (i.e., client-axios)
|
|
130
130
|
return options.body !== '' ? options.body : null;
|
|
131
131
|
}
|
|
132
132
|
|
package/src/http/client.ts
CHANGED
|
@@ -31,20 +31,24 @@ export const createClient = (config: Config = {}): Client => {
|
|
|
31
31
|
|
|
32
32
|
const interceptors = createInterceptors<Request, Response, unknown, ResolvedRequestOptions>();
|
|
33
33
|
|
|
34
|
-
const beforeRequest = async
|
|
34
|
+
const beforeRequest = async <
|
|
35
|
+
TData = unknown,
|
|
36
|
+
TResponseStyle extends 'data' | 'fields' = 'fields',
|
|
37
|
+
ThrowOnError extends boolean = boolean,
|
|
38
|
+
Url extends string = string,
|
|
39
|
+
>(
|
|
40
|
+
options: RequestOptions<TData, TResponseStyle, ThrowOnError, Url>,
|
|
41
|
+
) => {
|
|
35
42
|
const opts = {
|
|
36
43
|
..._config,
|
|
37
44
|
...options,
|
|
38
45
|
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
|
|
39
46
|
headers: mergeHeaders(_config.headers, options.headers),
|
|
40
|
-
serializedBody: undefined,
|
|
47
|
+
serializedBody: undefined as string | undefined,
|
|
41
48
|
};
|
|
42
49
|
|
|
43
50
|
if (opts.security) {
|
|
44
|
-
await setAuthParams(
|
|
45
|
-
...opts,
|
|
46
|
-
security: opts.security,
|
|
47
|
-
});
|
|
51
|
+
await setAuthParams(opts);
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
if (opts.requestValidator) {
|
|
@@ -52,7 +56,7 @@ export const createClient = (config: Config = {}): Client => {
|
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
if (opts.body !== undefined && opts.bodySerializer) {
|
|
55
|
-
opts.serializedBody = opts.bodySerializer(opts.body);
|
|
59
|
+
opts.serializedBody = opts.bodySerializer(opts.body) as string | undefined;
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
// remove Content-Type header if body is empty to avoid sending invalid requests
|
|
@@ -60,178 +64,162 @@ export const createClient = (config: Config = {}): Client => {
|
|
|
60
64
|
opts.headers.delete('Content-Type');
|
|
61
65
|
}
|
|
62
66
|
|
|
63
|
-
const
|
|
67
|
+
const resolvedOpts = opts as typeof opts &
|
|
68
|
+
ResolvedRequestOptions<TResponseStyle, ThrowOnError, Url>;
|
|
69
|
+
const url = buildUrl(resolvedOpts);
|
|
64
70
|
|
|
65
|
-
return { opts, url };
|
|
71
|
+
return { opts: resolvedOpts, url };
|
|
66
72
|
};
|
|
67
73
|
|
|
68
74
|
const request: Client['request'] = async (options) => {
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
const requestInit: ReqInit = {
|
|
72
|
-
redirect: 'follow',
|
|
73
|
-
...opts,
|
|
74
|
-
body: getValidRequestBody(opts),
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
let request = new Request(url, requestInit);
|
|
75
|
+
const throwOnError = options.throwOnError ?? _config.throwOnError;
|
|
76
|
+
const responseStyle = options.responseStyle ?? _config.responseStyle;
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
request = await fn(request, opts);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// fetch must be assigned here, otherwise it would throw the error:
|
|
86
|
-
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
|
|
87
|
-
const _fetch = opts.fetch!;
|
|
88
|
-
let response: Response;
|
|
78
|
+
let request: Request | undefined;
|
|
79
|
+
let response: Response | undefined;
|
|
89
80
|
|
|
90
81
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
const { opts, url } = await beforeRequest(options);
|
|
83
|
+
const requestInit: ReqInit = {
|
|
84
|
+
redirect: 'follow',
|
|
85
|
+
...opts,
|
|
86
|
+
body: getValidRequestBody(opts),
|
|
87
|
+
};
|
|
95
88
|
|
|
96
|
-
|
|
89
|
+
request = new Request(url, requestInit);
|
|
90
|
+
|
|
91
|
+
for (const fn of interceptors.request.fns) {
|
|
97
92
|
if (fn) {
|
|
98
|
-
|
|
93
|
+
request = await fn(request, opts);
|
|
99
94
|
}
|
|
100
95
|
}
|
|
101
96
|
|
|
102
|
-
|
|
97
|
+
// fetch must be assigned here, otherwise it would throw the error:
|
|
98
|
+
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
|
|
99
|
+
const _fetch = opts.fetch!;
|
|
103
100
|
|
|
104
|
-
|
|
105
|
-
throw finalError;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Return error response
|
|
109
|
-
return opts.responseStyle === 'data'
|
|
110
|
-
? undefined
|
|
111
|
-
: {
|
|
112
|
-
error: finalError,
|
|
113
|
-
request,
|
|
114
|
-
response: undefined as any,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
101
|
+
response = await _fetch(request);
|
|
117
102
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
103
|
+
for (const fn of interceptors.response.fns) {
|
|
104
|
+
if (fn) {
|
|
105
|
+
response = await fn(response, request, opts);
|
|
106
|
+
}
|
|
121
107
|
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const result = {
|
|
125
|
-
request,
|
|
126
|
-
response,
|
|
127
|
-
};
|
|
128
108
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
109
|
+
const result = {
|
|
110
|
+
request,
|
|
111
|
+
response,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (response.ok) {
|
|
115
|
+
const parseAs =
|
|
116
|
+
(opts.parseAs === 'auto'
|
|
117
|
+
? getParseAs(response.headers.get('Content-Type'))
|
|
118
|
+
: opts.parseAs) ?? 'json';
|
|
119
|
+
|
|
120
|
+
if (response.status === 204 || response.headers.get('Content-Length') === '0') {
|
|
121
|
+
let emptyData: any;
|
|
122
|
+
switch (parseAs) {
|
|
123
|
+
case 'arrayBuffer':
|
|
124
|
+
case 'blob':
|
|
125
|
+
case 'text':
|
|
126
|
+
emptyData = await response[parseAs]();
|
|
127
|
+
break;
|
|
128
|
+
case 'formData':
|
|
129
|
+
emptyData = new FormData();
|
|
130
|
+
break;
|
|
131
|
+
case 'stream':
|
|
132
|
+
emptyData = response.body;
|
|
133
|
+
break;
|
|
134
|
+
case 'json':
|
|
135
|
+
default:
|
|
136
|
+
emptyData = {};
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
return opts.responseStyle === 'data'
|
|
140
|
+
? emptyData
|
|
141
|
+
: {
|
|
142
|
+
data: emptyData,
|
|
143
|
+
...result,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
134
146
|
|
|
135
|
-
|
|
136
|
-
let emptyData: any;
|
|
147
|
+
let data: any;
|
|
137
148
|
switch (parseAs) {
|
|
138
149
|
case 'arrayBuffer':
|
|
139
150
|
case 'blob':
|
|
151
|
+
case 'formData':
|
|
140
152
|
case 'text':
|
|
141
|
-
|
|
153
|
+
data = await response[parseAs]();
|
|
142
154
|
break;
|
|
143
|
-
case '
|
|
144
|
-
|
|
155
|
+
case 'json': {
|
|
156
|
+
// Some servers return 200 with no Content-Length and empty body.
|
|
157
|
+
// response.json() would throw; read as text and parse if non-empty.
|
|
158
|
+
const text = await response.text();
|
|
159
|
+
data = text ? JSON.parse(text) : {};
|
|
145
160
|
break;
|
|
161
|
+
}
|
|
146
162
|
case 'stream':
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
163
|
+
return opts.responseStyle === 'data'
|
|
164
|
+
? response.body
|
|
165
|
+
: {
|
|
166
|
+
data: response.body,
|
|
167
|
+
...result,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (parseAs === 'json') {
|
|
172
|
+
if (opts.responseValidator) {
|
|
173
|
+
await opts.responseValidator(data);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (opts.responseTransformer) {
|
|
177
|
+
data = await opts.responseTransformer(data);
|
|
178
|
+
}
|
|
153
179
|
}
|
|
180
|
+
|
|
154
181
|
return opts.responseStyle === 'data'
|
|
155
|
-
?
|
|
182
|
+
? data
|
|
156
183
|
: {
|
|
157
|
-
data
|
|
184
|
+
data,
|
|
158
185
|
...result,
|
|
159
186
|
};
|
|
160
187
|
}
|
|
161
188
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
break;
|
|
170
|
-
case 'json': {
|
|
171
|
-
// Some servers return 200 with no Content-Length and empty body.
|
|
172
|
-
// response.json() would throw; read as text and parse if non-empty.
|
|
173
|
-
const text = await response.text();
|
|
174
|
-
data = text ? JSON.parse(text) : {};
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
case 'stream':
|
|
178
|
-
return opts.responseStyle === 'data'
|
|
179
|
-
? response.body
|
|
180
|
-
: {
|
|
181
|
-
data: response.body,
|
|
182
|
-
...result,
|
|
183
|
-
};
|
|
189
|
+
const textError = await response.text();
|
|
190
|
+
let jsonError: unknown;
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
jsonError = JSON.parse(textError);
|
|
194
|
+
} catch {
|
|
195
|
+
// noop
|
|
184
196
|
}
|
|
185
197
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
198
|
+
throw jsonError ?? textError;
|
|
199
|
+
} catch (error) {
|
|
200
|
+
let finalError = error;
|
|
190
201
|
|
|
191
|
-
|
|
192
|
-
|
|
202
|
+
for (const fn of interceptors.error.fns) {
|
|
203
|
+
if (fn) {
|
|
204
|
+
finalError = await fn(finalError, response, request, options as ResolvedRequestOptions);
|
|
193
205
|
}
|
|
194
206
|
}
|
|
195
207
|
|
|
196
|
-
|
|
197
|
-
? data
|
|
198
|
-
: {
|
|
199
|
-
data,
|
|
200
|
-
...result,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
208
|
+
finalError = finalError || {};
|
|
203
209
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
jsonError = JSON.parse(textError);
|
|
209
|
-
} catch {
|
|
210
|
-
// noop
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const error = jsonError ?? textError;
|
|
214
|
-
let finalError = error;
|
|
215
|
-
|
|
216
|
-
for (const fn of interceptors.error.fns) {
|
|
217
|
-
if (fn) {
|
|
218
|
-
finalError = (await fn(error, response, request, opts)) as string;
|
|
210
|
+
if (throwOnError) {
|
|
211
|
+
throw finalError;
|
|
219
212
|
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
finalError = finalError || ({} as string);
|
|
223
213
|
|
|
224
|
-
|
|
225
|
-
|
|
214
|
+
// TODO: we probably want to return error and improve types
|
|
215
|
+
return responseStyle === 'data'
|
|
216
|
+
? undefined
|
|
217
|
+
: {
|
|
218
|
+
error: finalError,
|
|
219
|
+
request,
|
|
220
|
+
response,
|
|
221
|
+
};
|
|
226
222
|
}
|
|
227
|
-
|
|
228
|
-
// TODO: we probably want to return error and improve types
|
|
229
|
-
return opts.responseStyle === 'data'
|
|
230
|
-
? undefined
|
|
231
|
-
: {
|
|
232
|
-
error: finalError,
|
|
233
|
-
...result,
|
|
234
|
-
};
|
|
235
223
|
};
|
|
236
224
|
|
|
237
225
|
const makeMethodFn = (method: Uppercase<HttpMethod>) => (options: RequestOptions) =>
|
|
@@ -242,7 +230,6 @@ export const createClient = (config: Config = {}): Client => {
|
|
|
242
230
|
return createSseClient({
|
|
243
231
|
...opts,
|
|
244
232
|
body: opts.body as BodyInit | null | undefined,
|
|
245
|
-
headers: opts.headers as unknown as Record<string, string>,
|
|
246
233
|
method,
|
|
247
234
|
onRequest: async (url, init) => {
|
|
248
235
|
let request = new Request(url, init);
|
|
@@ -258,8 +245,10 @@ export const createClient = (config: Config = {}): Client => {
|
|
|
258
245
|
});
|
|
259
246
|
};
|
|
260
247
|
|
|
248
|
+
const _buildUrl: Client['buildUrl'] = (options) => buildUrl({ ..._config, ...options });
|
|
249
|
+
|
|
261
250
|
return {
|
|
262
|
-
buildUrl,
|
|
251
|
+
buildUrl: _buildUrl,
|
|
263
252
|
connect: makeMethodFn('CONNECT'),
|
|
264
253
|
delete: makeMethodFn('DELETE'),
|
|
265
254
|
get: makeMethodFn('GET'),
|
package/src/http/index.ts
CHANGED
|
@@ -9,6 +9,8 @@ export {
|
|
|
9
9
|
} from '../core/bodySerializer';
|
|
10
10
|
export { buildClientParams } from '../core/params';
|
|
11
11
|
export { serializeQueryKeyValue } from '../core/queryKeySerializer';
|
|
12
|
+
export type { ServerSentEventsResult } from '../core/serverSentEvents';
|
|
13
|
+
export type { ClientMeta } from '../core/types';
|
|
12
14
|
export { createClient } from './client';
|
|
13
15
|
export type {
|
|
14
16
|
Client,
|
package/src/http/types.ts
CHANGED
|
@@ -93,6 +93,7 @@ export interface ResolvedRequestOptions<
|
|
|
93
93
|
ThrowOnError extends boolean = boolean,
|
|
94
94
|
Url extends string = string,
|
|
95
95
|
> extends RequestOptions<unknown, TResponseStyle, ThrowOnError, Url> {
|
|
96
|
+
headers: Headers;
|
|
96
97
|
serializedBody?: string;
|
|
97
98
|
}
|
|
98
99
|
|
|
@@ -126,8 +127,10 @@ export type RequestResult<
|
|
|
126
127
|
error: TError extends Record<string, unknown> ? TError[keyof TError] : TError;
|
|
127
128
|
}
|
|
128
129
|
) & {
|
|
129
|
-
request
|
|
130
|
-
|
|
130
|
+
/** request may be undefined, because error may be from building the request object itself */
|
|
131
|
+
request?: Request;
|
|
132
|
+
/** response may be undefined, because error may be from building the request object itself or from a network error */
|
|
133
|
+
response?: Response;
|
|
131
134
|
}
|
|
132
135
|
>;
|
|
133
136
|
|
|
@@ -148,12 +151,13 @@ type MethodFn = <
|
|
|
148
151
|
|
|
149
152
|
type SseFn = <
|
|
150
153
|
TData = unknown,
|
|
151
|
-
|
|
154
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
155
|
+
_TError = unknown,
|
|
152
156
|
ThrowOnError extends boolean = false,
|
|
153
157
|
TResponseStyle extends ResponseStyle = 'fields',
|
|
154
158
|
>(
|
|
155
|
-
options: Omit<RequestOptions<
|
|
156
|
-
) => Promise<ServerSentEventsResult<TData
|
|
159
|
+
options: Omit<RequestOptions<never, TResponseStyle, ThrowOnError>, 'method'>,
|
|
160
|
+
) => Promise<ServerSentEventsResult<TData>>;
|
|
157
161
|
|
|
158
162
|
type RequestFn = <
|
|
159
163
|
TData = unknown,
|
|
@@ -190,7 +194,7 @@ export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn, SseFn>
|
|
|
190
194
|
*/
|
|
191
195
|
export type CreateClientConfig<T extends ClientOptions = ClientOptions> = (
|
|
192
196
|
override?: Config<ClientOptions & T>,
|
|
193
|
-
) => Config<Required<ClientOptions> & T
|
|
197
|
+
) => Config<Required<ClientOptions> & T>;
|
|
194
198
|
|
|
195
199
|
export interface TDataShape {
|
|
196
200
|
body?: unknown;
|
package/src/http/utils.ts
CHANGED
|
@@ -14,8 +14,8 @@ import type { Client, ClientOptions, Config, RequestOptions } from './types';
|
|
|
14
14
|
export const createQuerySerializer = <T = unknown>({
|
|
15
15
|
parameters = {},
|
|
16
16
|
...args
|
|
17
|
-
}: QuerySerializerOptions = {}) => {
|
|
18
|
-
const querySerializer = (queryParams: T) => {
|
|
17
|
+
}: QuerySerializerOptions = {}): ((queryParams: T) => string) => {
|
|
18
|
+
const querySerializer = (queryParams: T): string => {
|
|
19
19
|
const search: string[] = [];
|
|
20
20
|
if (queryParams && typeof queryParams === 'object') {
|
|
21
21
|
for (const name in queryParams) {
|
|
@@ -118,14 +118,12 @@ const checkForExistence = (
|
|
|
118
118
|
return false;
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
-
export
|
|
122
|
-
security
|
|
123
|
-
...options
|
|
124
|
-
}: Pick<Required<RequestOptions>, 'security'> &
|
|
125
|
-
Pick<RequestOptions, 'auth' | 'query'> & {
|
|
121
|
+
export async function setAuthParams(
|
|
122
|
+
options: Pick<RequestOptions, 'auth' | 'query' | 'security'> & {
|
|
126
123
|
headers: Headers;
|
|
127
|
-
}
|
|
128
|
-
|
|
124
|
+
},
|
|
125
|
+
): Promise<void> {
|
|
126
|
+
for (const auth of options.security ?? []) {
|
|
129
127
|
if (checkForExistence(options, auth.name)) {
|
|
130
128
|
continue;
|
|
131
129
|
}
|
|
@@ -154,7 +152,7 @@ export const setAuthParams = async ({
|
|
|
154
152
|
break;
|
|
155
153
|
}
|
|
156
154
|
}
|
|
157
|
-
}
|
|
155
|
+
}
|
|
158
156
|
|
|
159
157
|
export const buildUrl: Client['buildUrl'] = (options) =>
|
|
160
158
|
getUrl({
|
|
@@ -204,7 +202,7 @@ export const mergeHeaders = (
|
|
|
204
202
|
mergedHeaders.append(key, v as string);
|
|
205
203
|
}
|
|
206
204
|
} else if (value !== undefined) {
|
|
207
|
-
// assume object headers are meant to be JSON stringified, i.e
|
|
205
|
+
// assume object headers are meant to be JSON stringified, i.e., their
|
|
208
206
|
// content value in OpenAPI specification is 'application/json'
|
|
209
207
|
mergedHeaders.set(
|
|
210
208
|
key,
|
|
@@ -218,8 +216,10 @@ export const mergeHeaders = (
|
|
|
218
216
|
|
|
219
217
|
type ErrInterceptor<Err, Res, Req, Options> = (
|
|
220
218
|
error: Err,
|
|
221
|
-
response
|
|
222
|
-
|
|
219
|
+
/** response may be undefined due to a network error where no response object is produced */
|
|
220
|
+
response: Res | undefined,
|
|
221
|
+
/** request may be undefined, because error may be from building the request object itself */
|
|
222
|
+
request: Req | undefined,
|
|
223
223
|
options: Options,
|
|
224
224
|
) => Err | Promise<Err>;
|
|
225
225
|
|