spiceflow 1.1.8 → 1.1.9

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 (58) hide show
  1. package/README.md +177 -92
  2. package/dist/benchmark.benchmark.js.map +1 -1
  3. package/dist/client/errors.d.ts.map +1 -1
  4. package/dist/client/errors.js.map +1 -1
  5. package/dist/client/index.d.ts.map +1 -1
  6. package/dist/client/index.js +8 -12
  7. package/dist/client/index.js.map +1 -1
  8. package/dist/client/types.d.ts.map +1 -1
  9. package/dist/client/utils.js.map +1 -1
  10. package/dist/client/ws.d.ts.map +1 -1
  11. package/dist/client/ws.js +1 -3
  12. package/dist/client/ws.js.map +1 -1
  13. package/dist/client.test.js.map +1 -1
  14. package/dist/context.d.ts.map +1 -1
  15. package/dist/cors.d.ts.map +1 -1
  16. package/dist/cors.js.map +1 -1
  17. package/dist/cors.test.js.map +1 -1
  18. package/dist/error.d.ts.map +1 -1
  19. package/dist/error.js.map +1 -1
  20. package/dist/middleware.test.js.map +1 -1
  21. package/dist/openapi.d.ts.map +1 -1
  22. package/dist/openapi.js +1 -1
  23. package/dist/openapi.js.map +1 -1
  24. package/dist/openapi.test.js.map +1 -1
  25. package/dist/spiceflow.d.ts.map +1 -1
  26. package/dist/spiceflow.js +4 -2
  27. package/dist/spiceflow.js.map +1 -1
  28. package/dist/spiceflow.test.js.map +1 -1
  29. package/dist/stream.test.js.map +1 -1
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/types.js.map +1 -1
  32. package/dist/types.test.js +2 -6
  33. package/dist/types.test.js.map +1 -1
  34. package/dist/utils.d.ts.map +1 -1
  35. package/dist/utils.js.map +1 -1
  36. package/dist/zod.test.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/benchmark.benchmark.ts +8 -8
  39. package/src/client/errors.ts +17 -17
  40. package/src/client/index.ts +437 -469
  41. package/src/client/types.ts +168 -191
  42. package/src/client/utils.ts +5 -5
  43. package/src/client/ws.ts +87 -89
  44. package/src/client.test.ts +176 -183
  45. package/src/context.ts +82 -82
  46. package/src/cors.test.ts +38 -38
  47. package/src/cors.ts +87 -92
  48. package/src/error.ts +13 -13
  49. package/src/middleware.test.ts +201 -201
  50. package/src/openapi.test.ts +97 -97
  51. package/src/openapi.ts +365 -365
  52. package/src/spiceflow.test.ts +461 -467
  53. package/src/spiceflow.ts +1117 -1161
  54. package/src/stream.test.ts +310 -310
  55. package/src/types.test.ts +46 -50
  56. package/src/types.ts +698 -701
  57. package/src/utils.ts +79 -79
  58. package/src/zod.test.ts +64 -64
@@ -4,96 +4,96 @@ import { bfs, Spiceflow } from './spiceflow.js'
4
4
  import { z } from 'zod'
5
5
 
6
6
  test('middleware with next changes the response', async () => {
7
- const res = await new Spiceflow()
8
- .use(async ({ request }, next) => {
9
- expect(request.method).toBe('GET')
10
- const res = await next()
11
- expect(res).toBeInstanceOf(Response)
12
- if (res) {
13
- res.headers.set('x-test', 'ok')
14
- }
15
- return res
16
- })
17
- .get('/ids/:id', () => 'hi')
18
- .post('/ids/:id', ({ params: { id } }) => id, {
19
- params: z.object({ id: z.string() }),
20
- })
21
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
22
- expect(res.status).toBe(200)
23
- expect(await res.json()).toEqual('hi')
24
- expect(res.headers.get('x-test')).toBe('ok')
7
+ const res = await new Spiceflow()
8
+ .use(async ({ request }, next) => {
9
+ expect(request.method).toBe('GET')
10
+ const res = await next()
11
+ expect(res).toBeInstanceOf(Response)
12
+ if (res) {
13
+ res.headers.set('x-test', 'ok')
14
+ }
15
+ return res
16
+ })
17
+ .get('/ids/:id', () => 'hi')
18
+ .post('/ids/:id', ({ params: { id } }) => id, {
19
+ params: z.object({ id: z.string() }),
20
+ })
21
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
22
+ expect(res.status).toBe(200)
23
+ expect(await res.json()).toEqual('hi')
24
+ expect(res.headers.get('x-test')).toBe('ok')
25
25
  })
26
26
 
27
27
  test('middleware with no handlers works', async () => {
28
- const res = await new Spiceflow()
29
- .use(async ({ request }, next) => {
30
- expect(request.method).toBe('GET')
31
- // expect(res).toBeInstanceOf(Response)
32
- return new Response('ok')
33
- })
28
+ const res = await new Spiceflow()
29
+ .use(async ({ request }, next) => {
30
+ expect(request.method).toBe('GET')
31
+ // expect(res).toBeInstanceOf(Response)
32
+ return new Response('ok')
33
+ })
34
34
 
35
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
36
- expect(res.status).toBe(200)
37
- expect(await res.text()).toEqual('ok')
35
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
36
+ expect(res.status).toBe(200)
37
+ expect(await res.text()).toEqual('ok')
38
38
  })
39
39
  test('middleware calling next() without returning it works', async () => {
40
- const res = await new Spiceflow()
41
- .use(async ({ request }, next) => {
42
- expect(request.method).toBe('GET')
43
- // expect(res).toBeInstanceOf(Response)
44
- await next()
45
- })
46
- .use(async ({ request }, next) => {
47
- expect(request.method).toBe('GET')
48
- // expect(res).toBeInstanceOf(Response)
49
- return new Response('"hi"')
50
- })
51
- .get('/ids/:id', () => 'not hi')
40
+ const res = await new Spiceflow()
41
+ .use(async ({ request }, next) => {
42
+ expect(request.method).toBe('GET')
43
+ // expect(res).toBeInstanceOf(Response)
44
+ await next()
45
+ })
46
+ .use(async ({ request }, next) => {
47
+ expect(request.method).toBe('GET')
48
+ // expect(res).toBeInstanceOf(Response)
49
+ return new Response('"hi"')
50
+ })
51
+ .get('/ids/:id', () => 'not hi')
52
52
 
53
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
54
- expect(res.status).toBe(200)
55
- expect(await res.json()).toEqual('hi')
53
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
54
+ expect(res.status).toBe(200)
55
+ expect(await res.json()).toEqual('hi')
56
56
  })
57
57
  test('middleware calling next() without returning it, calls handler', async () => {
58
- const res = await new Spiceflow()
59
- .use(async ({ request }, next) => {
60
- expect(request.method).toBe('GET')
61
- // expect(res).toBeInstanceOf(Response)
62
- await next()
63
- })
58
+ const res = await new Spiceflow()
59
+ .use(async ({ request }, next) => {
60
+ expect(request.method).toBe('GET')
61
+ // expect(res).toBeInstanceOf(Response)
62
+ await next()
63
+ })
64
64
 
65
- .get('/ids/:id', () => 'hi')
65
+ .get('/ids/:id', () => 'hi')
66
66
 
67
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
68
- expect(res.status).toBe(200)
69
- expect(await res.json()).toEqual('hi')
67
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
68
+ expect(res.status).toBe(200)
69
+ expect(await res.json()).toEqual('hi')
70
70
  })
71
71
 
72
72
  test('middleware state is not shared between requests', async () => {
73
- const app = await new Spiceflow()
74
- .state('x', -1)
75
- .use(async ({ request, state, query }, next) => {
76
- state.x = Number(query?.x || -1)
77
- })
78
- .get('/get', ({ state }) => {
79
- return state.x
80
- })
81
- async function first() {
82
- const res = await app.handle(new Request('http://localhost/get?x=1'))
83
- expect(res.status).toBe(200)
84
- expect(await res.json()).toEqual(1)
85
- }
86
- async function second() {
87
- const res = await app.handle(new Request('http://localhost/get?x=2'))
88
- expect(res.status).toBe(200)
89
- expect(await res.json()).toEqual(2)
90
- }
91
- await Promise.all(
92
- new Array(100).fill(0).map((_, i) => {
93
- if (i % 2 === 0) return first()
94
- return second()
95
- }),
96
- )
73
+ const app = await new Spiceflow()
74
+ .state('x', -1)
75
+ .use(async ({ request, state, query }, next) => {
76
+ state.x = Number(query?.x || -1)
77
+ })
78
+ .get('/get', ({ state }) => {
79
+ return state.x
80
+ })
81
+ async function first() {
82
+ const res = await app.handle(new Request('http://localhost/get?x=1'))
83
+ expect(res.status).toBe(200)
84
+ expect(await res.json()).toEqual(1)
85
+ }
86
+ async function second() {
87
+ const res = await app.handle(new Request('http://localhost/get?x=2'))
88
+ expect(res.status).toBe(200)
89
+ expect(await res.json()).toEqual(2)
90
+ }
91
+ await Promise.all(
92
+ new Array(100).fill(0).map((_, i) => {
93
+ if (i % 2 === 0) return first()
94
+ return second()
95
+ }),
96
+ )
97
97
  })
98
98
 
99
99
  // test('child app that adds state also adds state in the parent app', async () => {
@@ -127,152 +127,152 @@ test('middleware state is not shared between requests', async () => {
127
127
  // })
128
128
 
129
129
  test('middleware next returns a response even for 404, if there are no routes', async () => {
130
- const res = await new Spiceflow()
131
- .use(async ({ request }, next) => {
132
- expect(request.method).toBe('GET')
133
- const res = await next()
134
- expect(res).toBeInstanceOf(Response)
135
- if (res) {
136
- res.headers.set('x-test', 'ok')
137
- }
138
- return res
139
- })
140
- .handle(new Request('http://localhost/non-existent', { method: 'GET' }))
141
- expect(res.status).toBe(404)
142
- expect(res.headers.get('x-test')).toBe('ok')
143
- expect(await res.text()).toContain('Not Found')
130
+ const res = await new Spiceflow()
131
+ .use(async ({ request }, next) => {
132
+ expect(request.method).toBe('GET')
133
+ const res = await next()
134
+ expect(res).toBeInstanceOf(Response)
135
+ if (res) {
136
+ res.headers.set('x-test', 'ok')
137
+ }
138
+ return res
139
+ })
140
+ .handle(new Request('http://localhost/non-existent', { method: 'GET' }))
141
+ expect(res.status).toBe(404)
142
+ expect(res.headers.get('x-test')).toBe('ok')
143
+ expect(await res.text()).toContain('Not Found')
144
144
  })
145
145
 
146
146
  test('middleware without next runs the next middleware and handler', async () => {
147
- let middlewaresCalled = [] as string[]
148
- const res = await new Spiceflow()
149
- .use(async ({ request }) => {
150
- middlewaresCalled.push('first')
151
- })
152
- .use(async ({ request }, next) => {
153
- middlewaresCalled.push('second')
154
- const res = await next()
155
- if (res instanceof Response) {
156
- res.headers.set('x-test', 'ok')
157
- }
158
- return res
159
- })
160
- .get('/ids/:id', () => 'hi')
147
+ let middlewaresCalled = [] as string[]
148
+ const res = await new Spiceflow()
149
+ .use(async ({ request }) => {
150
+ middlewaresCalled.push('first')
151
+ })
152
+ .use(async ({ request }, next) => {
153
+ middlewaresCalled.push('second')
154
+ const res = await next()
155
+ if (res instanceof Response) {
156
+ res.headers.set('x-test', 'ok')
157
+ }
158
+ return res
159
+ })
160
+ .get('/ids/:id', () => 'hi')
161
161
 
162
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
163
- expect(res.status).toBe(200)
164
- expect(middlewaresCalled).toEqual(['first', 'second'])
165
- expect(await res.json()).toEqual('hi')
166
- expect(res.headers.get('x-test')).toBe('ok')
162
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
163
+ expect(res.status).toBe(200)
164
+ expect(middlewaresCalled).toEqual(['first', 'second'])
165
+ expect(await res.json()).toEqual('hi')
166
+ expect(res.headers.get('x-test')).toBe('ok')
167
167
  })
168
168
  test('middleware throws response', async () => {
169
- let middlewaresCalled = [] as string[]
170
- const res = await new Spiceflow()
171
- .use(async ({ request }) => {
172
- middlewaresCalled.push('first')
173
- })
174
- .use(async ({ request }, next) => {
175
- middlewaresCalled.push('second')
176
- throw new Response('ok')
177
- })
178
- .get('/ids/:id', () => 'hi')
169
+ let middlewaresCalled = [] as string[]
170
+ const res = await new Spiceflow()
171
+ .use(async ({ request }) => {
172
+ middlewaresCalled.push('first')
173
+ })
174
+ .use(async ({ request }, next) => {
175
+ middlewaresCalled.push('second')
176
+ throw new Response('ok')
177
+ })
178
+ .get('/ids/:id', () => 'hi')
179
179
 
180
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
181
- expect(res.status).toBe(200)
182
- expect(middlewaresCalled).toEqual(['first', 'second'])
183
- expect(await res.text()).toEqual('ok')
180
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
181
+ expect(res.status).toBe(200)
182
+ expect(middlewaresCalled).toEqual(['first', 'second'])
183
+ expect(await res.text()).toEqual('ok')
184
184
  })
185
185
 
186
186
  test('middleware stops other middlewares', async () => {
187
- let middlewaresCalled = [] as string[]
188
- const res = await new Spiceflow()
189
- .use(async ({ request }) => {
190
- middlewaresCalled.push('first')
191
- return new Response('ok')
192
- })
193
- .use(async ({ request }) => {
194
- middlewaresCalled.push('second')
195
- })
196
- .get('/ids/:id', () => 'hi')
187
+ let middlewaresCalled = [] as string[]
188
+ const res = await new Spiceflow()
189
+ .use(async ({ request }) => {
190
+ middlewaresCalled.push('first')
191
+ return new Response('ok')
192
+ })
193
+ .use(async ({ request }) => {
194
+ middlewaresCalled.push('second')
195
+ })
196
+ .get('/ids/:id', () => 'hi')
197
197
 
198
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
199
- expect(res.status).toBe(200)
200
- expect(middlewaresCalled).toEqual(['first'])
201
- expect(await res.text()).toEqual('ok')
198
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
199
+ expect(res.status).toBe(200)
200
+ expect(middlewaresCalled).toEqual(['first'])
201
+ expect(await res.text()).toEqual('ok')
202
202
  })
203
203
 
204
204
  test('calling next and then returning a new response works', async () => {
205
- let middlewaresCalled = [] as string[]
206
- const res = await new Spiceflow()
207
- .use(async (ctx, next) => {
208
- middlewaresCalled.push('first')
209
- await next()
210
- return new Response('middleware response')
211
- })
212
- .use(async (ctx, next) => {
213
- middlewaresCalled.push('second')
214
- return next()
215
- })
216
- .get('/ids/:id', () => {
217
- middlewaresCalled.push('handler')
218
- return 'handler response'
219
- })
205
+ let middlewaresCalled = [] as string[]
206
+ const res = await new Spiceflow()
207
+ .use(async (ctx, next) => {
208
+ middlewaresCalled.push('first')
209
+ await next()
210
+ return new Response('middleware response')
211
+ })
212
+ .use(async (ctx, next) => {
213
+ middlewaresCalled.push('second')
214
+ return next()
215
+ })
216
+ .get('/ids/:id', () => {
217
+ middlewaresCalled.push('handler')
218
+ return 'handler response'
219
+ })
220
220
 
221
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
222
- expect(res.status).toBe(200)
223
- expect(middlewaresCalled).toEqual(['first', 'second', 'handler'])
224
- expect(await res.text()).toEqual('middleware response')
221
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
222
+ expect(res.status).toBe(200)
223
+ expect(middlewaresCalled).toEqual(['first', 'second', 'handler'])
224
+ expect(await res.text()).toEqual('middleware response')
225
225
  })
226
226
 
227
227
  test('middleware changes handler response body', async () => {
228
- let middlewaresCalled = [] as string[]
229
- const res = await new Spiceflow()
230
- .use(async (ctx, next) => {
231
- middlewaresCalled.push('first')
232
- const response = await next()
233
- if (response) {
234
- const body = await response.text()
235
- return new Response(body.toUpperCase(), response)
236
- }
237
- return response
238
- })
239
- .use(async (ctx, next) => {
240
- middlewaresCalled.push('second')
241
- return next()
242
- })
243
- .get('/test', () => 'hello world')
244
- .handle(new Request('http://localhost/test'))
228
+ let middlewaresCalled = [] as string[]
229
+ const res = await new Spiceflow()
230
+ .use(async (ctx, next) => {
231
+ middlewaresCalled.push('first')
232
+ const response = await next()
233
+ if (response) {
234
+ const body = await response.text()
235
+ return new Response(body.toUpperCase(), response)
236
+ }
237
+ return response
238
+ })
239
+ .use(async (ctx, next) => {
240
+ middlewaresCalled.push('second')
241
+ return next()
242
+ })
243
+ .get('/test', () => 'hello world')
244
+ .handle(new Request('http://localhost/test'))
245
245
 
246
- expect(res.status).toBe(200)
247
- expect(middlewaresCalled).toEqual(['first', 'second'])
248
- expect(await res.json()).toEqual('HELLO WORLD')
246
+ expect(res.status).toBe(200)
247
+ expect(middlewaresCalled).toEqual(['first', 'second'])
248
+ expect(await res.json()).toEqual('HELLO WORLD')
249
249
  })
250
250
 
251
251
  test('mutating response returned by next without returning it works', async () => {
252
- let handlerCalledTimes = 0
253
- const res = await new Spiceflow()
254
- .use(async (ctx, next) => {
255
- const response = await next()
256
- if (response) {
257
- response.headers.set('X-Custom-Header', 'Modified')
258
- }
259
- // Not returning the response, letting it pass through
260
- })
261
- .use(async (ctx, next) => {
262
- const response = await next()
263
- if (response) {
264
- response.headers.set('X-Another-Header', 'Added')
265
- }
266
- })
267
- .get('/test', () => {
268
- handlerCalledTimes++
269
- return 'hello world'
270
- })
271
- .handle(new Request('http://localhost/test'))
252
+ let handlerCalledTimes = 0
253
+ const res = await new Spiceflow()
254
+ .use(async (ctx, next) => {
255
+ const response = await next()
256
+ if (response) {
257
+ response.headers.set('X-Custom-Header', 'Modified')
258
+ }
259
+ // Not returning the response, letting it pass through
260
+ })
261
+ .use(async (ctx, next) => {
262
+ const response = await next()
263
+ if (response) {
264
+ response.headers.set('X-Another-Header', 'Added')
265
+ }
266
+ })
267
+ .get('/test', () => {
268
+ handlerCalledTimes++
269
+ return 'hello world'
270
+ })
271
+ .handle(new Request('http://localhost/test'))
272
272
 
273
- expect(res.status).toBe(200)
274
- expect(handlerCalledTimes).toBe(1)
275
- expect(await res.json()).toBe('hello world')
276
- expect(res.headers.get('X-Custom-Header')).toBe('Modified')
277
- expect(res.headers.get('X-Another-Header')).toBe('Added')
273
+ expect(res.status).toBe(200)
274
+ expect(handlerCalledTimes).toBe(1)
275
+ expect(await res.json()).toBe('hello world')
276
+ expect(res.headers.get('X-Custom-Header')).toBe('Modified')
277
+ expect(res.headers.get('X-Another-Header')).toBe('Added')
278
278
  })
@@ -4,104 +4,104 @@ import { openapi } from './openapi.js'
4
4
  import { z } from 'zod'
5
5
 
6
6
  test('openapi response', async () => {
7
- const app = await new Spiceflow()
8
- .use(
9
- openapi({
10
- documentation: {
11
- info: {
12
- title: 'Spiceflow Docs',
13
- version: '0.0.0',
14
- },
15
- },
16
- }),
17
- )
18
- .use(
19
- new Spiceflow({ basePath: '/one' }).get(
20
- '/ids/:id',
21
- ({ params }) => {
22
- if (Math.random() < 0.5) {
23
- // TODO add a way to set status
7
+ const app = await new Spiceflow()
8
+ .use(
9
+ openapi({
10
+ documentation: {
11
+ info: {
12
+ title: 'Spiceflow Docs',
13
+ version: '0.0.0',
14
+ },
15
+ },
16
+ }),
17
+ )
18
+ .use(
19
+ new Spiceflow({ basePath: '/one' }).get(
20
+ '/ids/:id',
21
+ ({ params }) => {
22
+ if (Math.random() < 0.5) {
23
+ // TODO add a way to set status
24
24
 
25
- return {
26
- message: 'sdf',
27
- }
28
- }
29
- return params.id
30
- },
31
- {
32
- response: {
33
- 200: z.string(),
34
- 404: z.object({
35
- message: z.string(),
36
- }),
37
- },
38
- },
39
- ),
40
- )
41
- .patch(
42
- '/addBody',
43
- async (c) => {
44
- let body = await c.request.json()
45
- return body
46
- },
47
- {
48
- body: z.object({
49
- name: z.string(),
50
- }),
51
- response: z.object({
52
- name: z.string().optional(),
53
- }),
54
- },
55
- )
56
- .get(
57
- '/queryParams',
58
- async (c) => {
59
- const query = c.query
60
- return query
61
- },
62
- {
63
- query: z.object({
64
- name: z.string(),
65
- }),
66
- response: z.object({
67
- name: z.string().optional(),
68
- }),
69
- },
70
- )
71
- .post(
72
- '/queryParams',
73
- async (c) => {
74
- const query = c.query
75
- return query
76
- },
77
- {
78
- detail: {
79
- description: 'This is a post',
80
- operationId: 'postQueryParamsXXX',
81
- },
82
- body: z.object({
83
- name: z.string(),
84
- }),
85
- response: z.object({
86
- name: z.string().optional(),
87
- }),
88
- },
89
- )
90
- .use(
91
- new Spiceflow({ basePath: '/two' }).get(
92
- '/ids/:id',
93
- ({ params }) => params.id,
94
- {
95
- params: z.object({
96
- id: z.string(),
97
- }),
98
- },
99
- ),
100
- )
101
- const openapiSchema = await app
102
- .handle(new Request('http://localhost/openapi'))
103
- .then((x) => x.json())
104
- expect(openapiSchema).toMatchInlineSnapshot(`
25
+ return {
26
+ message: 'sdf',
27
+ }
28
+ }
29
+ return params.id
30
+ },
31
+ {
32
+ response: {
33
+ 200: z.string(),
34
+ 404: z.object({
35
+ message: z.string(),
36
+ }),
37
+ },
38
+ },
39
+ ),
40
+ )
41
+ .patch(
42
+ '/addBody',
43
+ async (c) => {
44
+ let body = await c.request.json()
45
+ return body
46
+ },
47
+ {
48
+ body: z.object({
49
+ name: z.string(),
50
+ }),
51
+ response: z.object({
52
+ name: z.string().optional(),
53
+ }),
54
+ },
55
+ )
56
+ .get(
57
+ '/queryParams',
58
+ async (c) => {
59
+ const query = c.query
60
+ return query
61
+ },
62
+ {
63
+ query: z.object({
64
+ name: z.string(),
65
+ }),
66
+ response: z.object({
67
+ name: z.string().optional(),
68
+ }),
69
+ },
70
+ )
71
+ .post(
72
+ '/queryParams',
73
+ async (c) => {
74
+ const query = c.query
75
+ return query
76
+ },
77
+ {
78
+ detail: {
79
+ description: 'This is a post',
80
+ operationId: 'postQueryParamsXXX',
81
+ },
82
+ body: z.object({
83
+ name: z.string(),
84
+ }),
85
+ response: z.object({
86
+ name: z.string().optional(),
87
+ }),
88
+ },
89
+ )
90
+ .use(
91
+ new Spiceflow({ basePath: '/two' }).get(
92
+ '/ids/:id',
93
+ ({ params }) => params.id,
94
+ {
95
+ params: z.object({
96
+ id: z.string(),
97
+ }),
98
+ },
99
+ ),
100
+ )
101
+ const openapiSchema = await app
102
+ .handle(new Request('http://localhost/openapi'))
103
+ .then((x) => x.json())
104
+ expect(openapiSchema).toMatchInlineSnapshot(`
105
105
  {
106
106
  "components": {
107
107
  "schemas": {},