@mpen/routekit 0.1.0 → 0.1.2
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/bin.d.mts +4 -0
- package/dist/client/react.d.mts +178 -0
- package/dist/client/react.mjs +142 -0
- package/dist/client.d.mts +433 -0
- package/dist/client.mjs +264 -0
- package/dist/content-BuDOmhH_.mjs +102 -0
- package/dist/core-CzUCxvGk.d.mts +140 -0
- package/dist/core-DbmQauwS.mjs +81 -0
- package/dist/handlers.d.mts +72 -0
- package/dist/handlers.mjs +153 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +1152 -0
- package/dist/middleware.d.mts +388 -0
- package/dist/middleware.mjs +1222 -0
- package/dist/request-Dn0zc-xm.mjs +1025 -0
- package/dist/response/content.d.mts +79 -0
- package/dist/response/content.mjs +2 -0
- package/dist/response/json-rpc.d.mts +1 -0
- package/dist/response/json-rpc.mjs +1 -0
- package/dist/response/problem/valibot.d.mts +230 -0
- package/dist/response/problem/valibot.mjs +258 -0
- package/dist/response/problem.d.mts +415 -0
- package/dist/response/problem.mjs +183 -0
- package/dist/response/status.d.mts +45 -0
- package/dist/response/status.mjs +2 -0
- package/dist/responses-B379Ep9Y.d.mts +296 -0
- package/dist/responses-BpVrgeYi.mjs +101 -0
- package/dist/router-Cwb7ak0J.d.mts +1819 -0
- package/dist/routes.d.mts +282 -0
- package/dist/routes.mjs +311 -0
- package/dist/status-C-8mw-FB.mjs +59 -0
- package/dist/valibot-D7liFYyB.d.mts +290 -0
- package/dist/valibot-Du97X-TS.mjs +326 -0
- package/package.json +8 -2
- package/src/bin/gen-api-client.test.ts +0 -70
- package/src/bin/gen-api-client.ts +0 -986
- package/src/client/headers.ts +0 -31
- package/src/client/index.ts +0 -8
- package/src/client/promise.ts +0 -11
- package/src/client/react/index.test.tsx +0 -266
- package/src/client/react/index.ts +0 -431
- package/src/client/responses.test.ts +0 -151
- package/src/client/responses.ts +0 -278
- package/src/client/transport.ts +0 -74
- package/src/client/transports/body-codec.ts +0 -61
- package/src/client/transports/fetch.ts +0 -113
- package/src/client/tsconfig.json +0 -9
- package/src/client/types.ts +0 -15
- package/src/client/url.ts +0 -31
- package/src/index.ts +0 -63
- package/src/router/fetch-types.ts +0 -13
- package/src/router/handlers/index.ts +0 -2
- package/src/router/handlers/openapi/index.ts +0 -2
- package/src/router/handlers/openapi/openapi.ts +0 -293
- package/src/router/integration/zod-openapi.test.ts +0 -74
- package/src/router/lib/charset.test.ts +0 -22
- package/src/router/lib/charset.ts +0 -133
- package/src/router/lib/collections.ts +0 -3
- package/src/router/lib/format.test.ts +0 -67
- package/src/router/lib/format.ts +0 -35
- package/src/router/lib/host.ts +0 -4
- package/src/router/lib/json-schema.ts +0 -6
- package/src/router/lib/media-type.test.ts +0 -122
- package/src/router/lib/media-type.ts +0 -289
- package/src/router/lib/pathname.test.ts +0 -18
- package/src/router/lib/pathname.ts +0 -19
- package/src/router/lib/route-names.ts +0 -70
- package/src/router/lib/route-normalize.test.ts +0 -36
- package/src/router/lib/route-normalize.ts +0 -67
- package/src/router/lib/schema-merge.ts +0 -56
- package/src/router/middleware/accept-ctx.test.ts +0 -33
- package/src/router/middleware/accept-ctx.ts +0 -12
- package/src/router/middleware/body-limit.test.ts +0 -112
- package/src/router/middleware/body-limit.ts +0 -121
- package/src/router/middleware/content-type-context.ts +0 -0
- package/src/router/middleware/cors.test.ts +0 -269
- package/src/router/middleware/cors.ts +0 -490
- package/src/router/middleware/csrf.test.ts +0 -106
- package/src/router/middleware/csrf.ts +0 -192
- package/src/router/middleware/define.ts +0 -249
- package/src/router/middleware/index.ts +0 -34
- package/src/router/middleware/jsxhtml-response.ts +0 -0
- package/src/router/middleware/oas-swagger.ts +0 -0
- package/src/router/middleware/rate-limit.test.ts +0 -886
- package/src/router/middleware/rate-limit.ts +0 -920
- package/src/router/middleware/request-id-ctx.test.ts +0 -183
- package/src/router/middleware/request-id-ctx.ts +0 -135
- package/src/router/middleware/request-logger-format.test.ts +0 -16
- package/src/router/middleware/request-logger-format.ts +0 -269
- package/src/router/middleware/request-logger.test.ts +0 -267
- package/src/router/middleware/request-logger.ts +0 -131
- package/src/router/middleware/start-time-ctx.ts +0 -5
- package/src/router/request.ts +0 -611
- package/src/router/response/core.ts +0 -181
- package/src/router/response/directives.ts +0 -233
- package/src/router/response/formats/content/bodyless.ts +0 -54
- package/src/router/response/formats/content/content.ts +0 -79
- package/src/router/response/formats/content/index.ts +0 -2
- package/src/router/response/formats/json-rpc/index.ts +0 -2
- package/src/router/response/formats/problem/badRequest.ts +0 -90
- package/src/router/response/formats/problem/conflict.ts +0 -90
- package/src/router/response/formats/problem/created.ts +0 -40
- package/src/router/response/formats/problem/index.ts +0 -27
- package/src/router/response/formats/problem/notFound.ts +0 -90
- package/src/router/response/formats/problem/permissionDenied.ts +0 -90
- package/src/router/response/formats/problem/problem.test.ts +0 -888
- package/src/router/response/formats/problem/rateLimited.ts +0 -90
- package/src/router/response/formats/problem/responses.ts +0 -219
- package/src/router/response/formats/problem/root-errors.ts +0 -48
- package/src/router/response/formats/problem/sessionExpired.ts +0 -90
- package/src/router/response/formats/problem/types.ts +0 -170
- package/src/router/response/formats/problem/unauthenticated.ts +0 -90
- package/src/router/response/formats/problem/valibot.ts +0 -410
- package/src/router/response/formats/status/index.ts +0 -1
- package/src/router/response/formats/status/responses.ts +0 -59
- package/src/router/response/formats/status/status.test.ts +0 -21
- package/src/router/response/framers.ts +0 -85
- package/src/router/response/index.ts +0 -28
- package/src/router/response/openapi.test.ts +0 -96
- package/src/router/response/openapi.ts +0 -1
- package/src/router/response/serializers.ts +0 -66
- package/src/router/response/stream.ts +0 -35
- package/src/router/router.test.ts +0 -1571
- package/src/router/router.ts +0 -1965
- package/src/router/routes/index.ts +0 -46
- package/src/router/routes/valibot/index.ts +0 -18
- package/src/router/routes/valibot/valibot.ts +0 -1393
- package/src/router/routes/valibot.test.ts +0 -286
- package/src/router/routes/zod/index.ts +0 -18
- package/src/router/routes/zod/zod.ts +0 -1318
- package/src/router/routes/zod.test.ts +0 -280
- package/src/router/server-interface.ts +0 -31
- package/src/router/types.ts +0 -657
package/src/client/responses.ts
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import type { ApiTransportResponse, ApiTransportResponsePromise } from './transport'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A typed response returned by generated API clients.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```ts
|
|
8
|
-
* const response: ApiResponse<{ ok: true }> = await client.health.get()
|
|
9
|
-
* if (response.status === 200) {
|
|
10
|
-
* response.body.ok
|
|
11
|
-
* }
|
|
12
|
-
* ```
|
|
13
|
-
*
|
|
14
|
-
* @typeParam T - The parsed response body type.
|
|
15
|
-
*/
|
|
16
|
-
export interface ApiResponse<T> {
|
|
17
|
-
/** Whether the response status is in the successful 200-299 range. */
|
|
18
|
-
ok: boolean
|
|
19
|
-
/** The response status code. */
|
|
20
|
-
status: number
|
|
21
|
-
/** The response headers. */
|
|
22
|
-
headers: Headers
|
|
23
|
-
/** The parsed response body. */
|
|
24
|
-
body: T
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
type ApiResponseStatus<TStatus> = TStatus extends number
|
|
28
|
-
? TStatus
|
|
29
|
-
: TStatus extends `${infer TNumber extends number}`
|
|
30
|
-
? TNumber
|
|
31
|
-
: number
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* A typed response union keyed by HTTP status code.
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* ```ts
|
|
38
|
-
* type WidgetResponse = ApiResponseByStatus<{
|
|
39
|
-
* 200: { id: number }
|
|
40
|
-
* 400: { message: string }
|
|
41
|
-
* }>
|
|
42
|
-
*
|
|
43
|
-
* if (response.status === 400) {
|
|
44
|
-
* response.body.message
|
|
45
|
-
* }
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @typeParam T - A map from response status codes to parsed response body types.
|
|
49
|
-
*/
|
|
50
|
-
export type ApiResponseByStatus<T extends object> = {
|
|
51
|
-
[TStatus in keyof T]: Omit<ApiResponse<T[TStatus]>, 'status'> & {
|
|
52
|
-
/** The narrowed response status code. */
|
|
53
|
-
status: ApiResponseStatus<TStatus>
|
|
54
|
-
}
|
|
55
|
-
}[keyof T]
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The default async response wrapper used by generated API clients.
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* ```ts
|
|
62
|
-
* const response: ApiResponsePromise<{ id: number }> = client.items.byId.get(123)
|
|
63
|
-
* ```
|
|
64
|
-
*
|
|
65
|
-
* @typeParam T - The parsed response body type.
|
|
66
|
-
*/
|
|
67
|
-
export type ApiResponsePromise<T> = Promise<ApiResponse<T>>
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* The async response wrapper used by generated API clients for routes with response body types
|
|
71
|
-
* keyed by HTTP status code.
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* ```ts
|
|
75
|
-
* const response: ApiResponseByStatusPromise<{ 200: { ok: true } }> = client.health.get()
|
|
76
|
-
* ```
|
|
77
|
-
*
|
|
78
|
-
* @typeParam T - A map from response status codes to parsed response body types.
|
|
79
|
-
*/
|
|
80
|
-
export type ApiResponseByStatusPromise<T extends object> = Promise<ApiResponseByStatus<T>>
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Extracts the successful `data` payload from a Routekit Problem-style success envelope.
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* ```ts
|
|
87
|
-
* type Body = { success: true; data: { id: string } }
|
|
88
|
-
* type Data = RoutekitProblemSuccessData<Body> // { id: string }
|
|
89
|
-
* ```
|
|
90
|
-
*
|
|
91
|
-
* @typeParam TSuccessBody - Routekit Problem-style successful response body.
|
|
92
|
-
*/
|
|
93
|
-
export type RoutekitProblemSuccessData<TSuccessBody> = TSuccessBody extends {
|
|
94
|
-
success: true
|
|
95
|
-
data: infer Data
|
|
96
|
-
}
|
|
97
|
-
? Data
|
|
98
|
-
: unknown
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Error thrown for Routekit Problem-style response bodies.
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* ```ts
|
|
105
|
-
* try {
|
|
106
|
-
* await resolveRoutekitProblemData(response)
|
|
107
|
-
* } catch (error) {
|
|
108
|
-
* if (isRoutekitProblemError(error)) {
|
|
109
|
-
* console.error(error.status, error.body.error.code)
|
|
110
|
-
* }
|
|
111
|
-
* }
|
|
112
|
-
* ```
|
|
113
|
-
*
|
|
114
|
-
* @typeParam TProblem - Routekit Problem-style error response body.
|
|
115
|
-
*/
|
|
116
|
-
export class RoutekitProblemError<TProblem> extends Error {
|
|
117
|
-
/**
|
|
118
|
-
* The response status code.
|
|
119
|
-
*/
|
|
120
|
-
readonly status: number
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* The response headers.
|
|
124
|
-
*/
|
|
125
|
-
readonly headers: Headers
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* The Routekit Problem-style response body.
|
|
129
|
-
*/
|
|
130
|
-
readonly body: TProblem
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* The full normalized API response.
|
|
134
|
-
*/
|
|
135
|
-
readonly response: ApiResponse<TProblem>
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Create an error for a Routekit Problem-style response.
|
|
139
|
-
*
|
|
140
|
-
* @param response - Normalized API response containing a problem body.
|
|
141
|
-
*/
|
|
142
|
-
constructor(response: ApiResponse<TProblem>) {
|
|
143
|
-
super(getRoutekitProblemMessage(response.body))
|
|
144
|
-
this.name = 'RoutekitProblemError'
|
|
145
|
-
this.status = response.status
|
|
146
|
-
this.headers = response.headers
|
|
147
|
-
this.body = response.body
|
|
148
|
-
this.response = response
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Checks whether a value is a [`RoutekitProblemError`]{@link RoutekitProblemError}.
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* ```ts
|
|
157
|
-
* if (isRoutekitProblemError(error)) {
|
|
158
|
-
* error.body
|
|
159
|
-
* }
|
|
160
|
-
* ```
|
|
161
|
-
*
|
|
162
|
-
* @param value - Value to inspect.
|
|
163
|
-
* @returns Whether the value is a Routekit Problem error.
|
|
164
|
-
* @typeParam TProblem - Routekit Problem-style error response body.
|
|
165
|
-
*/
|
|
166
|
-
export function isRoutekitProblemError<TProblem = unknown>(
|
|
167
|
-
value: unknown,
|
|
168
|
-
): value is RoutekitProblemError<TProblem> {
|
|
169
|
-
return value instanceof RoutekitProblemError
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function getRoutekitProblemMessage(body: unknown): string {
|
|
173
|
-
if (!body || typeof body !== 'object') return 'Routekit problem response'
|
|
174
|
-
const error = (body as { error?: { message?: unknown } }).error
|
|
175
|
-
return typeof error?.message === 'string' ? error.message : 'Routekit problem response'
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function isRoutekitProblemSuccessBody<TSuccessBody>(
|
|
179
|
-
body: TSuccessBody | unknown,
|
|
180
|
-
): body is TSuccessBody & { success: true; data: RoutekitProblemSuccessData<TSuccessBody> } {
|
|
181
|
-
return (
|
|
182
|
-
!!body &&
|
|
183
|
-
typeof body === 'object' &&
|
|
184
|
-
(body as { success?: unknown }).success === true &&
|
|
185
|
-
'data' in body
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function isApiResponse<T>(
|
|
190
|
-
response: ApiResponse<T> | ApiTransportResponse,
|
|
191
|
-
): response is ApiResponse<T> {
|
|
192
|
-
return (
|
|
193
|
-
'ok' in response && typeof response.ok === 'boolean' && response.headers instanceof Headers
|
|
194
|
-
)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Normalize a transport response into the public generated API response shape.
|
|
199
|
-
*
|
|
200
|
-
* @example
|
|
201
|
-
* ```ts
|
|
202
|
-
* const response = await resolveApiResponse(transport.request(request))
|
|
203
|
-
* ```
|
|
204
|
-
*
|
|
205
|
-
* @param response - A transport response or transport response promise.
|
|
206
|
-
* @returns The normalized API response.
|
|
207
|
-
* @typeParam T - The parsed response body type.
|
|
208
|
-
*/
|
|
209
|
-
export async function resolveApiResponse<T>(
|
|
210
|
-
response: ApiTransportResponse | ApiTransportResponsePromise,
|
|
211
|
-
): ApiResponsePromise<T> {
|
|
212
|
-
const resolved = await response
|
|
213
|
-
return {
|
|
214
|
-
ok: resolved.status >= 200 && resolved.status < 300,
|
|
215
|
-
status: resolved.status,
|
|
216
|
-
headers: new Headers(resolved.headers),
|
|
217
|
-
body: resolved.body as T,
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Normalize a transport response into a generated API response union keyed by status code.
|
|
223
|
-
*
|
|
224
|
-
* @example
|
|
225
|
-
* ```ts
|
|
226
|
-
* const response = await resolveApiResponseByStatus<{ 200: { ok: true } }>(
|
|
227
|
-
* transport.request(request),
|
|
228
|
-
* )
|
|
229
|
-
* ```
|
|
230
|
-
*
|
|
231
|
-
* @param response - A transport response or transport response promise.
|
|
232
|
-
* @returns The normalized API response.
|
|
233
|
-
* @typeParam T - A map from response status codes to parsed response body types.
|
|
234
|
-
*/
|
|
235
|
-
export function resolveApiResponseByStatus<T extends object>(
|
|
236
|
-
response: ApiTransportResponse | ApiTransportResponsePromise,
|
|
237
|
-
): ApiResponseByStatusPromise<T> {
|
|
238
|
-
return resolveApiResponse(response) as ApiResponseByStatusPromise<T>
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Resolve a Routekit Problem-style API response into its successful data payload.
|
|
243
|
-
*
|
|
244
|
-
* This helper unwraps `{ success: true, data }` bodies and throws
|
|
245
|
-
* [`RoutekitProblemError`]{@link RoutekitProblemError} for non-success problem bodies, which lets
|
|
246
|
-
* TanStack Query use its built-in success and error states while preserving rich problem details.
|
|
247
|
-
*
|
|
248
|
-
* @example
|
|
249
|
-
* ```ts
|
|
250
|
-
* const data = await resolveRoutekitProblemData<
|
|
251
|
-
* { success: true; data: { id: string } },
|
|
252
|
-
* { success: false; error: { code: 'not_found'; message: string } }
|
|
253
|
-
* >(transport.request(request))
|
|
254
|
-
* ```
|
|
255
|
-
*
|
|
256
|
-
* @param response - A transport response, normalized API response, or promise for either.
|
|
257
|
-
* @returns The unwrapped successful response `data` payload.
|
|
258
|
-
* @typeParam TSuccessBody - Routekit Problem-style successful response body.
|
|
259
|
-
* @typeParam TProblemBody - Routekit Problem-style problem response body.
|
|
260
|
-
*/
|
|
261
|
-
export async function resolveRoutekitProblemData<TSuccessBody, TProblemBody>(
|
|
262
|
-
response:
|
|
263
|
-
| ApiResponse<TSuccessBody | TProblemBody>
|
|
264
|
-
| ApiTransportResponse
|
|
265
|
-
| ApiTransportResponsePromise
|
|
266
|
-
| Promise<ApiResponse<TSuccessBody | TProblemBody>>,
|
|
267
|
-
): Promise<RoutekitProblemSuccessData<TSuccessBody>> {
|
|
268
|
-
const resolvedResponse = await response
|
|
269
|
-
const apiResponse = isApiResponse<TSuccessBody | TProblemBody>(resolvedResponse)
|
|
270
|
-
? resolvedResponse
|
|
271
|
-
: await resolveApiResponse<TSuccessBody | TProblemBody>(resolvedResponse)
|
|
272
|
-
|
|
273
|
-
if (apiResponse.ok && isRoutekitProblemSuccessBody<TSuccessBody>(apiResponse.body)) {
|
|
274
|
-
return apiResponse.body.data
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
throw new RoutekitProblemError(apiResponse as ApiResponse<TProblemBody>)
|
|
278
|
-
}
|
package/src/client/transport.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
type ClientHeadersInit = NonNullable<ConstructorParameters<typeof Headers>[0]>
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* A generated client request before it is executed by a transport.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```ts
|
|
8
|
-
* const request: ClientRequest = {
|
|
9
|
-
* url: '/widgets',
|
|
10
|
-
* init: { method: 'POST' },
|
|
11
|
-
* body: { name: 'demo' },
|
|
12
|
-
* }
|
|
13
|
-
* ```
|
|
14
|
-
*/
|
|
15
|
-
export interface ClientRequest {
|
|
16
|
-
/** The URL path generated for the route. */
|
|
17
|
-
url: string
|
|
18
|
-
/** Fetch-compatible request initialization. */
|
|
19
|
-
init: RequestInit
|
|
20
|
-
/** The unencoded request body value. */
|
|
21
|
-
body?: unknown
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* A minimal response returned by client transports.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```ts
|
|
29
|
-
* const response: ApiTransportResponse = {
|
|
30
|
-
* status: 200,
|
|
31
|
-
* body: { ok: true },
|
|
32
|
-
* }
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export interface ApiTransportResponse {
|
|
36
|
-
/** The response status code. */
|
|
37
|
-
status: number
|
|
38
|
-
/** The response headers, when available. */
|
|
39
|
-
headers?: ClientHeadersInit
|
|
40
|
-
/** The parsed response body. */
|
|
41
|
-
body: unknown
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The async response wrapper returned by client transports.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```ts
|
|
49
|
-
* const response: ApiTransportResponsePromise = transport.request(request)
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
export type ApiTransportResponsePromise = Promise<ApiTransportResponse>
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Transport used by generated API clients to execute typed requests.
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```ts
|
|
59
|
-
* class AxiosTransport implements ClientTransport {
|
|
60
|
-
* async request(request: ClientRequest): ApiTransportResponsePromise {
|
|
61
|
-
* throw new Error('Adapt Axios into a Response-shaped object here')
|
|
62
|
-
* }
|
|
63
|
-
* }
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export interface ClientTransport {
|
|
67
|
-
/**
|
|
68
|
-
* Execute a generated client request.
|
|
69
|
-
*
|
|
70
|
-
* @param request - The generated request metadata and init.
|
|
71
|
-
* @returns A transport response promise.
|
|
72
|
-
*/
|
|
73
|
-
request(request: ClientRequest): ApiTransportResponsePromise
|
|
74
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
type ClientBodyInit = NonNullable<RequestInit['body']>
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The response body stream exposed to response body codecs.
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* ```ts
|
|
8
|
-
* const text = await new Response(body).text()
|
|
9
|
-
* ```
|
|
10
|
-
*/
|
|
11
|
-
export type ResponseBodyReader = ReadableStream<Uint8Array<ArrayBufferLike>> | null
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Serializes request bodies and deserializes response bodies for generated clients.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```ts
|
|
18
|
-
* const textJsonCodec: BodyCodec = {
|
|
19
|
-
* serialize: (value) => JSON.stringify(value),
|
|
20
|
-
* deserialize: async (body) => JSON.parse(await new Response(body).text()),
|
|
21
|
-
* }
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
export interface BodyCodec {
|
|
25
|
-
/**
|
|
26
|
-
* Serialize a generated client body value into a Fetch-compatible body.
|
|
27
|
-
*
|
|
28
|
-
* @param value - The generated client body value.
|
|
29
|
-
* @returns A Fetch-compatible body, or nullish to omit the request body.
|
|
30
|
-
*/
|
|
31
|
-
serialize(value: unknown): ClientBodyInit | null | undefined
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Deserialize a response body for generated `response.body` values.
|
|
35
|
-
*
|
|
36
|
-
* @param body - The response body stream.
|
|
37
|
-
* @param contentType - The response content type, when present.
|
|
38
|
-
* @returns The deserialized response body.
|
|
39
|
-
* @typeParam T - The expected response body type.
|
|
40
|
-
*/
|
|
41
|
-
deserialize<T>(body: ResponseBodyReader, contentType: string | null): Promise<T>
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The default JSON codec used by generated API clients.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```ts
|
|
49
|
-
* const client = new ApiClient(new FetchTransport({ bodyCodec: jsonBodyCodec }))
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
export const jsonBodyCodec: BodyCodec = {
|
|
53
|
-
serialize: (value) => JSON.stringify(value),
|
|
54
|
-
deserialize: async <T>(body: ResponseBodyReader, contentType: string | null) => {
|
|
55
|
-
if (!body) return undefined as T
|
|
56
|
-
const text = await new Response(body).text()
|
|
57
|
-
if (text.length === 0) return undefined as T
|
|
58
|
-
if (contentType?.includes('json')) return JSON.parse(text) as T
|
|
59
|
-
return text as T
|
|
60
|
-
},
|
|
61
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import type { ClientHeaders } from '../headers'
|
|
2
|
-
import type { ApiTransportResponsePromise, ClientRequest, ClientTransport } from '../transport'
|
|
3
|
-
import { jsonBodyCodec, type BodyCodec } from './body-codec'
|
|
4
|
-
|
|
5
|
-
type ClientHeadersInit = NonNullable<ConstructorParameters<typeof Headers>[0]>
|
|
6
|
-
type FetchFn = NonNullable<FetchTransportOptions['fetch']>
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Options for [`FetchTransport`]{@link FetchTransport}.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```ts
|
|
13
|
-
* const transport = new FetchTransport({
|
|
14
|
-
* baseUrl: 'https://api.example.com',
|
|
15
|
-
* headers: () => ({ authorization: `Bearer ${token}` }),
|
|
16
|
-
* })
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
export interface FetchTransportOptions {
|
|
20
|
-
/** Base URL used to resolve generated relative route URLs. */
|
|
21
|
-
baseUrl?: string | URL
|
|
22
|
-
/** Fetch implementation to call. Defaults to `globalThis.fetch`. */
|
|
23
|
-
fetch?: (url: string | URL | Request, init?: RequestInit) => Promise<Response>
|
|
24
|
-
/** Global headers, or a function that returns headers for each request. */
|
|
25
|
-
headers?: ClientHeaders
|
|
26
|
-
/** Default body codec. Defaults to [`jsonBodyCodec`]{@link jsonBodyCodec}. */
|
|
27
|
-
bodyCodec?: BodyCodec
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function mergeHeaders(...sources: Array<ClientHeadersInit | undefined>): Headers {
|
|
31
|
-
const headers = new Headers()
|
|
32
|
-
for (const source of sources) {
|
|
33
|
-
if (!source) continue
|
|
34
|
-
new Headers(source).forEach((value, key) => {
|
|
35
|
-
headers.set(key, value)
|
|
36
|
-
})
|
|
37
|
-
}
|
|
38
|
-
return headers
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function resolveUrl(url: string, baseUrl: string | URL | undefined): string {
|
|
42
|
-
return baseUrl ? new URL(url, baseUrl).toString() : url
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Fetch-based transport for generated API clients.
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* ```ts
|
|
50
|
-
* const client = new ApiClient(
|
|
51
|
-
* new FetchTransport({
|
|
52
|
-
* baseUrl: 'https://api.example.com',
|
|
53
|
-
* headers: { authorization: 'Bearer token' },
|
|
54
|
-
* }),
|
|
55
|
-
* )
|
|
56
|
-
* ```
|
|
57
|
-
*/
|
|
58
|
-
export class FetchTransport implements ClientTransport {
|
|
59
|
-
readonly #baseUrl: string | URL | undefined
|
|
60
|
-
readonly #bodyCodec: BodyCodec
|
|
61
|
-
readonly #fetch: FetchFn
|
|
62
|
-
readonly #headers: ClientHeaders | undefined
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Create a Fetch-backed generated client transport.
|
|
66
|
-
*
|
|
67
|
-
* @param options - Transport configuration.
|
|
68
|
-
*/
|
|
69
|
-
constructor(options: FetchTransportOptions = {}) {
|
|
70
|
-
this.#baseUrl = options.baseUrl
|
|
71
|
-
this.#bodyCodec = options.bodyCodec ?? jsonBodyCodec
|
|
72
|
-
this.#fetch = options.fetch ?? globalThis.fetch.bind(globalThis)
|
|
73
|
-
this.#headers = options.headers
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Execute a generated client request with Fetch.
|
|
78
|
-
*
|
|
79
|
-
* @param request - The generated client request.
|
|
80
|
-
* @returns A transport response promise.
|
|
81
|
-
*/
|
|
82
|
-
async request(request: ClientRequest): ApiTransportResponsePromise {
|
|
83
|
-
const codec = this.#bodyCodec
|
|
84
|
-
const init: RequestInit = { ...request.init }
|
|
85
|
-
const headerContext = { url: request.url, init }
|
|
86
|
-
const providedHeaders =
|
|
87
|
-
typeof this.#headers === 'function' ? await this.#headers(headerContext) : this.#headers
|
|
88
|
-
const headers = mergeHeaders(providedHeaders, init.headers)
|
|
89
|
-
|
|
90
|
-
if (Object.hasOwn(request, 'body')) {
|
|
91
|
-
const body = codec.serialize(request.body)
|
|
92
|
-
if (body != null) {
|
|
93
|
-
init.body = body
|
|
94
|
-
if (!headers.has('content-type')) {
|
|
95
|
-
headers.set('content-type', 'application/json')
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if ([...headers].length > 0) {
|
|
101
|
-
init.headers = headers
|
|
102
|
-
} else {
|
|
103
|
-
delete init.headers
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const response = await this.#fetch(resolveUrl(request.url, this.#baseUrl), init)
|
|
107
|
-
return {
|
|
108
|
-
status: response.status,
|
|
109
|
-
headers: response.headers,
|
|
110
|
-
body: await codec.deserialize(response.body, response.headers.get('content-type')),
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
package/src/client/tsconfig.json
DELETED
package/src/client/types.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extracts the type of a single path parameter from a path parameter object type.
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* type Params = { id: string }
|
|
7
|
-
* type IdParam = SinglePathParam<Params, 'id'> // string
|
|
8
|
-
* ```
|
|
9
|
-
*
|
|
10
|
-
* @typeParam TParams - The path parameter object type.
|
|
11
|
-
* @typeParam TKey - The parameter key to extract.
|
|
12
|
-
*/
|
|
13
|
-
export type SinglePathParam<TParams, TKey extends string> = TParams extends { [K in TKey]: infer V }
|
|
14
|
-
? V
|
|
15
|
-
: unknown
|
package/src/client/url.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Append an object of query values to a URL.
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* withQuery('/widgets', { view: 'full', tag: ['a', 'b'] })
|
|
7
|
-
* ```
|
|
8
|
-
*
|
|
9
|
-
* @param url - URL without generated query parameters.
|
|
10
|
-
* @param query - Query parameter object.
|
|
11
|
-
* @returns The URL with serialized query parameters.
|
|
12
|
-
*/
|
|
13
|
-
export function withQuery(url: string, query: object): string {
|
|
14
|
-
const searchParams = new URLSearchParams()
|
|
15
|
-
for (const [key, value] of Object.entries(query)) {
|
|
16
|
-
if (value == null) continue
|
|
17
|
-
if (Array.isArray(value)) {
|
|
18
|
-
for (const item of value) {
|
|
19
|
-
if (item != null)
|
|
20
|
-
searchParams.append(
|
|
21
|
-
key,
|
|
22
|
-
typeof item === 'object' ? JSON.stringify(item) : String(item),
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
continue
|
|
26
|
-
}
|
|
27
|
-
searchParams.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value))
|
|
28
|
-
}
|
|
29
|
-
const search = searchParams.toString()
|
|
30
|
-
return search.length > 0 ? `${url}?${search}` : url
|
|
31
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export { Router } from './router/router'
|
|
2
|
-
export {
|
|
3
|
-
createRoutekitRequest,
|
|
4
|
-
defaultRequestBodyParsers,
|
|
5
|
-
formDataRequestBodyParser,
|
|
6
|
-
jsonRequestBodyParser,
|
|
7
|
-
RequestBodyError,
|
|
8
|
-
RequestBodyLengthMismatchError,
|
|
9
|
-
RequestBodyTooLargeError,
|
|
10
|
-
responseFromRequestBodyError,
|
|
11
|
-
textRequestBodyParser,
|
|
12
|
-
UnsupportedRequestBodyMediaTypeError,
|
|
13
|
-
urlEncodedRequestBodyParser,
|
|
14
|
-
} from './router/request'
|
|
15
|
-
export type {
|
|
16
|
-
RequestBodyFormData,
|
|
17
|
-
RequestBodyParseContext,
|
|
18
|
-
RequestBodyParser,
|
|
19
|
-
RequestBodyStream,
|
|
20
|
-
RoutekitRequest,
|
|
21
|
-
RoutekitRequestBody,
|
|
22
|
-
} from './router/request'
|
|
23
|
-
export * from './router/response'
|
|
24
|
-
export { defineMiddleware } from './router/middleware/define'
|
|
25
|
-
export type {
|
|
26
|
-
DeclaredMiddleware,
|
|
27
|
-
DefineMiddlewareOptions,
|
|
28
|
-
MiddlewareControls,
|
|
29
|
-
MiddlewareResponseDeclaration,
|
|
30
|
-
MiddlewareResponseDeclarations,
|
|
31
|
-
} from './router/middleware/define'
|
|
32
|
-
export type {
|
|
33
|
-
AcceptMediaRange,
|
|
34
|
-
AddedContextFromMiddlewareInput,
|
|
35
|
-
AnyContext,
|
|
36
|
-
ContentType,
|
|
37
|
-
ContextFromMiddlewareInput,
|
|
38
|
-
ContextMiddleware,
|
|
39
|
-
Handler,
|
|
40
|
-
HandlerContext,
|
|
41
|
-
JsonObjectSchema,
|
|
42
|
-
JsonSchema,
|
|
43
|
-
MediaType,
|
|
44
|
-
Middleware,
|
|
45
|
-
MiddlewareEntry,
|
|
46
|
-
MiddlewareList,
|
|
47
|
-
NormalizedRoute,
|
|
48
|
-
RequestContext,
|
|
49
|
-
RequestMiddleware,
|
|
50
|
-
RequestMiddlewareEntry,
|
|
51
|
-
RequestMiddlewareInput,
|
|
52
|
-
Route,
|
|
53
|
-
RouteMatch,
|
|
54
|
-
RouteMeta,
|
|
55
|
-
RouteOptions,
|
|
56
|
-
RoutePath,
|
|
57
|
-
RouteSchema,
|
|
58
|
-
RouterExtension,
|
|
59
|
-
RouterMountOptions,
|
|
60
|
-
MiddlewareInput,
|
|
61
|
-
RequestBodyParserInput,
|
|
62
|
-
ResponseBodySerializerInput,
|
|
63
|
-
} from './router/types'
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Headers initializer accepted by the active Fetch runtime.
|
|
3
|
-
*
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
export type RouterHeadersInit = NonNullable<ConstructorParameters<typeof Headers>[0]>
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Response body initializer accepted by the active Fetch runtime.
|
|
10
|
-
*
|
|
11
|
-
* @internal
|
|
12
|
-
*/
|
|
13
|
-
export type RouterBodyInit = NonNullable<ConstructorParameters<typeof Response>[0]>
|