@mpen/routekit 0.1.0 → 0.1.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.
Files changed (133) hide show
  1. package/dist/bin.d.mts +4 -0
  2. package/dist/client/react.d.mts +178 -0
  3. package/dist/client/react.mjs +142 -0
  4. package/dist/client.d.mts +433 -0
  5. package/dist/client.mjs +264 -0
  6. package/dist/content-BuDOmhH_.mjs +102 -0
  7. package/dist/core-CzUCxvGk.d.mts +140 -0
  8. package/dist/core-DbmQauwS.mjs +81 -0
  9. package/dist/handlers.d.mts +72 -0
  10. package/dist/handlers.mjs +153 -0
  11. package/dist/index.d.mts +3 -0
  12. package/dist/index.mjs +1152 -0
  13. package/dist/middleware.d.mts +388 -0
  14. package/dist/middleware.mjs +1222 -0
  15. package/dist/request-Dn0zc-xm.mjs +1025 -0
  16. package/dist/response/content.d.mts +79 -0
  17. package/dist/response/content.mjs +2 -0
  18. package/dist/response/json-rpc.d.mts +1 -0
  19. package/dist/response/json-rpc.mjs +1 -0
  20. package/dist/response/problem/valibot.d.mts +230 -0
  21. package/dist/response/problem/valibot.mjs +258 -0
  22. package/dist/response/problem.d.mts +415 -0
  23. package/dist/response/problem.mjs +183 -0
  24. package/dist/response/status.d.mts +45 -0
  25. package/dist/response/status.mjs +2 -0
  26. package/dist/responses-B379Ep9Y.d.mts +296 -0
  27. package/dist/responses-BpVrgeYi.mjs +101 -0
  28. package/dist/router-Cwb7ak0J.d.mts +1819 -0
  29. package/dist/routes.d.mts +282 -0
  30. package/dist/routes.mjs +311 -0
  31. package/dist/status-C-8mw-FB.mjs +59 -0
  32. package/dist/valibot-D7liFYyB.d.mts +290 -0
  33. package/dist/valibot-Du97X-TS.mjs +326 -0
  34. package/package.json +8 -2
  35. package/src/bin/gen-api-client.test.ts +0 -70
  36. package/src/bin/gen-api-client.ts +0 -986
  37. package/src/client/headers.ts +0 -31
  38. package/src/client/index.ts +0 -8
  39. package/src/client/promise.ts +0 -11
  40. package/src/client/react/index.test.tsx +0 -266
  41. package/src/client/react/index.ts +0 -431
  42. package/src/client/responses.test.ts +0 -151
  43. package/src/client/responses.ts +0 -278
  44. package/src/client/transport.ts +0 -74
  45. package/src/client/transports/body-codec.ts +0 -61
  46. package/src/client/transports/fetch.ts +0 -113
  47. package/src/client/tsconfig.json +0 -9
  48. package/src/client/types.ts +0 -15
  49. package/src/client/url.ts +0 -31
  50. package/src/index.ts +0 -63
  51. package/src/router/fetch-types.ts +0 -13
  52. package/src/router/handlers/index.ts +0 -2
  53. package/src/router/handlers/openapi/index.ts +0 -2
  54. package/src/router/handlers/openapi/openapi.ts +0 -293
  55. package/src/router/integration/zod-openapi.test.ts +0 -74
  56. package/src/router/lib/charset.test.ts +0 -22
  57. package/src/router/lib/charset.ts +0 -133
  58. package/src/router/lib/collections.ts +0 -3
  59. package/src/router/lib/format.test.ts +0 -67
  60. package/src/router/lib/format.ts +0 -35
  61. package/src/router/lib/host.ts +0 -4
  62. package/src/router/lib/json-schema.ts +0 -6
  63. package/src/router/lib/media-type.test.ts +0 -122
  64. package/src/router/lib/media-type.ts +0 -289
  65. package/src/router/lib/pathname.test.ts +0 -18
  66. package/src/router/lib/pathname.ts +0 -19
  67. package/src/router/lib/route-names.ts +0 -70
  68. package/src/router/lib/route-normalize.test.ts +0 -36
  69. package/src/router/lib/route-normalize.ts +0 -67
  70. package/src/router/lib/schema-merge.ts +0 -56
  71. package/src/router/middleware/accept-ctx.test.ts +0 -33
  72. package/src/router/middleware/accept-ctx.ts +0 -12
  73. package/src/router/middleware/body-limit.test.ts +0 -112
  74. package/src/router/middleware/body-limit.ts +0 -121
  75. package/src/router/middleware/content-type-context.ts +0 -0
  76. package/src/router/middleware/cors.test.ts +0 -269
  77. package/src/router/middleware/cors.ts +0 -490
  78. package/src/router/middleware/csrf.test.ts +0 -106
  79. package/src/router/middleware/csrf.ts +0 -192
  80. package/src/router/middleware/define.ts +0 -249
  81. package/src/router/middleware/index.ts +0 -34
  82. package/src/router/middleware/jsxhtml-response.ts +0 -0
  83. package/src/router/middleware/oas-swagger.ts +0 -0
  84. package/src/router/middleware/rate-limit.test.ts +0 -886
  85. package/src/router/middleware/rate-limit.ts +0 -920
  86. package/src/router/middleware/request-id-ctx.test.ts +0 -183
  87. package/src/router/middleware/request-id-ctx.ts +0 -135
  88. package/src/router/middleware/request-logger-format.test.ts +0 -16
  89. package/src/router/middleware/request-logger-format.ts +0 -269
  90. package/src/router/middleware/request-logger.test.ts +0 -267
  91. package/src/router/middleware/request-logger.ts +0 -131
  92. package/src/router/middleware/start-time-ctx.ts +0 -5
  93. package/src/router/request.ts +0 -611
  94. package/src/router/response/core.ts +0 -181
  95. package/src/router/response/directives.ts +0 -233
  96. package/src/router/response/formats/content/bodyless.ts +0 -54
  97. package/src/router/response/formats/content/content.ts +0 -79
  98. package/src/router/response/formats/content/index.ts +0 -2
  99. package/src/router/response/formats/json-rpc/index.ts +0 -2
  100. package/src/router/response/formats/problem/badRequest.ts +0 -90
  101. package/src/router/response/formats/problem/conflict.ts +0 -90
  102. package/src/router/response/formats/problem/created.ts +0 -40
  103. package/src/router/response/formats/problem/index.ts +0 -27
  104. package/src/router/response/formats/problem/notFound.ts +0 -90
  105. package/src/router/response/formats/problem/permissionDenied.ts +0 -90
  106. package/src/router/response/formats/problem/problem.test.ts +0 -888
  107. package/src/router/response/formats/problem/rateLimited.ts +0 -90
  108. package/src/router/response/formats/problem/responses.ts +0 -219
  109. package/src/router/response/formats/problem/root-errors.ts +0 -48
  110. package/src/router/response/formats/problem/sessionExpired.ts +0 -90
  111. package/src/router/response/formats/problem/types.ts +0 -170
  112. package/src/router/response/formats/problem/unauthenticated.ts +0 -90
  113. package/src/router/response/formats/problem/valibot.ts +0 -410
  114. package/src/router/response/formats/status/index.ts +0 -1
  115. package/src/router/response/formats/status/responses.ts +0 -59
  116. package/src/router/response/formats/status/status.test.ts +0 -21
  117. package/src/router/response/framers.ts +0 -85
  118. package/src/router/response/index.ts +0 -28
  119. package/src/router/response/openapi.test.ts +0 -96
  120. package/src/router/response/openapi.ts +0 -1
  121. package/src/router/response/serializers.ts +0 -66
  122. package/src/router/response/stream.ts +0 -35
  123. package/src/router/router.test.ts +0 -1571
  124. package/src/router/router.ts +0 -1965
  125. package/src/router/routes/index.ts +0 -46
  126. package/src/router/routes/valibot/index.ts +0 -18
  127. package/src/router/routes/valibot/valibot.ts +0 -1393
  128. package/src/router/routes/valibot.test.ts +0 -286
  129. package/src/router/routes/zod/index.ts +0 -18
  130. package/src/router/routes/zod/zod.ts +0 -1318
  131. package/src/router/routes/zod.test.ts +0 -280
  132. package/src/router/server-interface.ts +0 -31
  133. package/src/router/types.ts +0 -657
@@ -1,31 +0,0 @@
1
- import type { MaybePromise } from './promise'
2
-
3
- type ClientHeadersInit = NonNullable<ConstructorParameters<typeof Headers>[0]>
4
-
5
- /**
6
- * Context passed to global header providers.
7
- *
8
- * @example
9
- * ```ts
10
- * const headers = (context: ClientHeaderContext) =>
11
- * context.url.startsWith('/admin') ? { authorization: `Bearer ${token}` } : undefined
12
- * ```
13
- */
14
- export interface ClientHeaderContext {
15
- /** The request URL before base URL resolution. */
16
- url: string
17
- /** The request init object before execution. */
18
- init: RequestInit
19
- }
20
-
21
- /**
22
- * Headers or a function that provides headers for each request.
23
- *
24
- * @example
25
- * ```ts
26
- * const headers: ClientHeaders = () => ({ authorization: `Bearer ${token}` })
27
- * ```
28
- */
29
- export type ClientHeaders =
30
- | ClientHeadersInit
31
- | ((context: ClientHeaderContext) => MaybePromise<ClientHeadersInit | undefined>)
@@ -1,8 +0,0 @@
1
- export * from './headers'
2
- export * from './promise'
3
- export * from './responses'
4
- export * from './transport'
5
- export * from './types'
6
- export * from './transports/body-codec'
7
- export * from './transports/fetch'
8
- export * from './url'
@@ -1,11 +0,0 @@
1
- /**
2
- * A value that may be returned immediately or through a promise.
3
- *
4
- * @example
5
- * ```ts
6
- * const headers: MaybePromise<HeadersInit> = { authorization: 'Bearer token' }
7
- * ```
8
- *
9
- * @typeParam T - The resolved value type.
10
- */
11
- export type MaybePromise<T> = T | Promise<T>
@@ -1,266 +0,0 @@
1
- import { afterEach, describe, expect, test } from 'bun:test'
2
- import { expectType, type TypeEqual } from '@mpen/ts-types'
3
- import { Window } from 'happy-dom'
4
- import type { ReactNode } from 'react'
5
- import type { ApiResponse } from '../responses'
6
-
7
- const testWindow = new Window({ url: 'http://localhost/' })
8
-
9
- testWindow.SyntaxError = SyntaxError
10
-
11
- Object.assign(globalThis, {
12
- IS_REACT_ACT_ENVIRONMENT: true,
13
- window: testWindow,
14
- document: testWindow.document,
15
- navigator: testWindow.navigator,
16
- HTMLElement: testWindow.HTMLElement,
17
- SyntaxError,
18
- })
19
-
20
- const { act } = await import('react')
21
- const { createRoot } = await import('react-dom/client')
22
- const { useQuery } = await import('./index')
23
-
24
- const roots: Array<ReturnType<typeof createRoot>> = []
25
-
26
- function render(children: ReactNode) {
27
- const container = document.createElement('div')
28
- document.body.append(container)
29
-
30
- const root = createRoot(container)
31
- roots.push(root)
32
-
33
- act(() => {
34
- root.render(children)
35
- })
36
-
37
- return { container, root }
38
- }
39
-
40
- function text(container: Element, testId: string): string | undefined {
41
- return container.querySelector(`[data-testid="${testId}"]`)?.textContent ?? undefined
42
- }
43
-
44
- function waitFrame(): Promise<void> {
45
- return new Promise((resolve) => setTimeout(resolve, 0))
46
- }
47
-
48
- async function waitFor(assertion: () => void): Promise<void> {
49
- let lastError: unknown
50
-
51
- for (let attempt = 0; attempt < 30; attempt += 1) {
52
- try {
53
- assertion()
54
- return
55
- } catch (error) {
56
- lastError = error
57
- }
58
-
59
- await act(async () => {
60
- await waitFrame()
61
- })
62
- }
63
-
64
- throw lastError
65
- }
66
-
67
- afterEach(() => {
68
- for (const root of roots.splice(0)) {
69
- act(() => {
70
- root.unmount()
71
- })
72
- }
73
-
74
- document.body.replaceChildren()
75
- })
76
-
77
- describe(useQuery.name, () => {
78
- test('runs endpoint methods and refetches when arguments change', async () => {
79
- type UserResponse = ApiResponse<{ enabled: boolean; id: number }>
80
- const calls: Array<{ id: number; request: { body: boolean } }> = []
81
- const endpoint = async (id: number, request: { body: boolean }): Promise<UserResponse> => {
82
- calls.push({ id, request })
83
- return {
84
- ok: true,
85
- status: 200,
86
- headers: new Headers(),
87
- body: { enabled: request.body, id },
88
- }
89
- }
90
-
91
- function Reader({ id }: { id: number }) {
92
- const query = useQuery(endpoint, id, { body: true })
93
-
94
- expectType<TypeEqual<typeof query.data, { enabled: boolean; id: number } | undefined>>(
95
- true,
96
- )
97
-
98
- return (
99
- <span data-testid="state">{`${query.status}:${query.data?.id ?? 'none'}:${String(query.isFetching)}`}</span>
100
- )
101
- }
102
-
103
- const { container, root } = render(<Reader id={1} />)
104
-
105
- await waitFor(() => {
106
- expect(text(container, 'state')).toBe('success:1:false')
107
- })
108
- expect(calls).toEqual([{ id: 1, request: { body: true } }])
109
-
110
- act(() => {
111
- root.render(<Reader id={1} />)
112
- })
113
-
114
- expect(calls).toHaveLength(1)
115
-
116
- act(() => {
117
- root.render(<Reader id={2} />)
118
- })
119
-
120
- await waitFor(() => {
121
- expect(text(container, 'state')).toBe('success:2:false')
122
- })
123
- expect(calls).toEqual([
124
- { id: 1, request: { body: true } },
125
- { id: 2, request: { body: true } },
126
- ])
127
- })
128
-
129
- test('supports options-first calls, selected data, and manual refetching', async () => {
130
- type UserResponse = ApiResponse<{ id: number; label: string }>
131
- const calls: number[] = []
132
- const endpoint = async (id: number): Promise<UserResponse> => {
133
- calls.push(id)
134
- return {
135
- ok: true,
136
- status: 200,
137
- headers: new Headers(),
138
- body: { id, label: `user-${calls.length}` },
139
- }
140
- }
141
- function Reader({ enabled }: { enabled: boolean }) {
142
- const query = useQuery(
143
- { enabled, select: (response) => response.body.label },
144
- endpoint,
145
- 123,
146
- )
147
-
148
- expectType<TypeEqual<typeof query.data, string | undefined>>(true)
149
-
150
- return (
151
- <>
152
- <span data-testid="label">{`${query.status}:${query.data ?? 'none'}`}</span>
153
- <button type="button" onClick={() => void query.refetch()}>
154
- Refetch
155
- </button>
156
- </>
157
- )
158
- }
159
-
160
- const { container, root } = render(<Reader enabled={false} />)
161
-
162
- expect(text(container, 'label')).toBe('idle:none')
163
- expect(calls).toEqual([])
164
-
165
- act(() => {
166
- root.render(<Reader enabled />)
167
- })
168
-
169
- await waitFor(() => {
170
- expect(text(container, 'label')).toBe('success:user-1')
171
- })
172
- expect(calls).toEqual([123])
173
-
174
- act(() => {
175
- container.querySelector('button')?.click()
176
- })
177
-
178
- await waitFor(() => {
179
- expect(text(container, 'label')).toBe('success:user-2')
180
- })
181
- expect(calls).toEqual([123, 123])
182
- })
183
-
184
- test('keeps previous data by default while refetching', async () => {
185
- type UserResponse = ApiResponse<{ id: number }>
186
- let resolveSecond: ((response: UserResponse) => void) | undefined
187
- const endpoint = (id: number): Promise<UserResponse> => {
188
- if (id === 1) {
189
- return Promise.resolve({
190
- ok: true,
191
- status: 200,
192
- headers: new Headers(),
193
- body: { id },
194
- })
195
- }
196
-
197
- return new Promise((resolve) => {
198
- resolveSecond = resolve
199
- })
200
- }
201
-
202
- function Reader({ id }: { id: number }) {
203
- const query = useQuery(endpoint, id)
204
-
205
- return (
206
- <span data-testid="state">{`${query.status}:${query.data?.id ?? 'none'}:${String(query.isFetching)}`}</span>
207
- )
208
- }
209
-
210
- const { container, root } = render(<Reader id={1} />)
211
-
212
- await waitFor(() => {
213
- expect(text(container, 'state')).toBe('success:1:false')
214
- })
215
-
216
- act(() => {
217
- root.render(<Reader id={2} />)
218
- })
219
-
220
- await waitFor(() => {
221
- expect(text(container, 'state')).toBe('success:1:true')
222
- })
223
-
224
- await act(async () => {
225
- resolveSecond?.({
226
- ok: true,
227
- status: 200,
228
- headers: new Headers(),
229
- body: { id: 2 },
230
- })
231
- await waitFrame()
232
- })
233
-
234
- await waitFor(() => {
235
- expect(text(container, 'state')).toBe('success:2:false')
236
- })
237
- })
238
-
239
- test('accepts generated-style endpoint properties with required object arguments', async () => {
240
- type TodoResponse = ApiResponse<{ todos: string[] }>
241
- const apiClient = {
242
- todos: {
243
- list: {
244
- get: async (query: { filter: 'all' | 'active' }): Promise<TodoResponse> => ({
245
- ok: true,
246
- status: 200,
247
- headers: new Headers(),
248
- body: { todos: [query.filter] },
249
- }),
250
- },
251
- },
252
- }
253
-
254
- function Reader() {
255
- const query = useQuery({ enabled: false }, apiClient.todos.list.get, { filter: 'all' })
256
-
257
- expectType<TypeEqual<typeof query.data, { todos: string[] } | undefined>>(true)
258
-
259
- return <span data-testid="state">{query.status}</span>
260
- }
261
-
262
- const { container } = render(<Reader />)
263
-
264
- expect(text(container, 'state')).toBe('idle')
265
- })
266
- })