spiceflow 1.1.7 → 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 (61) 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 +65 -0
  21. package/dist/middleware.test.js.map +1 -1
  22. package/dist/openapi.d.ts.map +1 -1
  23. package/dist/openapi.js +1 -1
  24. package/dist/openapi.js.map +1 -1
  25. package/dist/openapi.test.js.map +1 -1
  26. package/dist/spiceflow.d.ts.map +1 -1
  27. package/dist/spiceflow.js +12 -5
  28. package/dist/spiceflow.js.map +1 -1
  29. package/dist/spiceflow.test.js.map +1 -1
  30. package/dist/stream.test.js +6 -6
  31. package/dist/stream.test.js.map +1 -1
  32. package/dist/types.d.ts +1 -1
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/types.js.map +1 -1
  35. package/dist/types.test.js +56 -6
  36. package/dist/types.test.js.map +1 -1
  37. package/dist/utils.d.ts.map +1 -1
  38. package/dist/utils.js.map +1 -1
  39. package/dist/zod.test.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/benchmark.benchmark.ts +8 -8
  42. package/src/client/errors.ts +17 -17
  43. package/src/client/index.ts +437 -469
  44. package/src/client/types.ts +168 -191
  45. package/src/client/utils.ts +5 -5
  46. package/src/client/ws.ts +87 -89
  47. package/src/client.test.ts +176 -183
  48. package/src/context.ts +82 -82
  49. package/src/cors.test.ts +38 -38
  50. package/src/cors.ts +87 -92
  51. package/src/error.ts +13 -13
  52. package/src/middleware.test.ts +221 -149
  53. package/src/openapi.test.ts +97 -97
  54. package/src/openapi.ts +365 -365
  55. package/src/spiceflow.test.ts +461 -467
  56. package/src/spiceflow.ts +1117 -1157
  57. package/src/stream.test.ts +310 -310
  58. package/src/types.test.ts +59 -39
  59. package/src/types.ts +698 -701
  60. package/src/utils.ts +79 -79
  61. package/src/zod.test.ts +64 -64
@@ -4,371 +4,369 @@ import { bfs, Spiceflow } from './spiceflow.js'
4
4
  import { z } from 'zod'
5
5
 
6
6
  test('works', async () => {
7
- const res = await new Spiceflow()
8
- .post('/xxx', () => 'hi')
9
- .handle(new Request('http://localhost/xxx', { method: 'POST' }))
10
- expect(res.status).toBe(200)
11
- expect(await res.json()).toEqual('hi')
7
+ const res = await new Spiceflow()
8
+ .post('/xxx', () => 'hi')
9
+ .handle(new Request('http://localhost/xxx', { method: 'POST' }))
10
+ expect(res.status).toBe(200)
11
+ expect(await res.json()).toEqual('hi')
12
12
  })
13
13
  test('dynamic route', async () => {
14
- const res = await new Spiceflow()
15
- .post('/ids/:id', () => 'hi')
16
- .handle(new Request('http://localhost/ids/xxx', { method: 'POST' }))
17
- expect(res.status).toBe(200)
18
- expect(await res.json()).toEqual('hi')
14
+ const res = await new Spiceflow()
15
+ .post('/ids/:id', () => 'hi')
16
+ .handle(new Request('http://localhost/ids/xxx', { method: 'POST' }))
17
+ expect(res.status).toBe(200)
18
+ expect(await res.json()).toEqual('hi')
19
19
  })
20
20
  test('GET dynamic route', async () => {
21
- const res = await new Spiceflow()
22
- .get('/ids/:id', () => 'hi')
23
- .post('/ids/:id', ({ params: { id } }) => id, {
24
- params: z.object({ id: z.string() }),
25
- })
26
- .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
27
- expect(res.status).toBe(200)
28
- expect(await res.json()).toEqual('hi')
21
+ const res = await new Spiceflow()
22
+ .get('/ids/:id', () => 'hi')
23
+ .post('/ids/:id', ({ params: { id } }) => id, {
24
+ params: z.object({ id: z.string() }),
25
+ })
26
+ .handle(new Request('http://localhost/ids/xxx', { method: 'GET' }))
27
+ expect(res.status).toBe(200)
28
+ expect(await res.json()).toEqual('hi')
29
29
  })
30
30
 
31
31
  test('onError does not fire on 404', async () => {
32
- let errorFired = false
33
- const app = new Spiceflow()
34
- .get('/test', () => 'Hello')
35
- .onError(() => {
36
- errorFired = true
37
- return new Response('Error', { status: 500 })
38
- })
39
-
40
- const res = await app.handle(
41
- new Request('http://localhost/non-existent', { method: 'GET' }),
42
- )
43
-
44
- expect(res.status).toBe(404)
45
- expect(errorFired).toBe(false)
46
- expect(await res.text()).toBe('Not Found')
32
+ let errorFired = false
33
+ const app = new Spiceflow()
34
+ .get('/test', () => 'Hello')
35
+ .onError(() => {
36
+ errorFired = true
37
+ return new Response('Error', { status: 500 })
38
+ })
39
+
40
+ const res = await app.handle(
41
+ new Request('http://localhost/non-existent', { method: 'GET' }),
42
+ )
43
+
44
+ expect(res.status).toBe(404)
45
+ expect(errorFired).toBe(false)
46
+ expect(await res.text()).toBe('Not Found')
47
47
  })
48
48
 
49
49
  test('onError fires on validation errors', async () => {
50
- let errorMessage = ''
51
- const app = new Spiceflow()
52
- .post(
53
- '/test',
54
- async ({ request }) => {
55
- await request.json()
56
- return 'Success'
57
- },
58
- {
59
- body: z.object({
60
- name: z.string(),
61
- }),
62
- },
63
- )
64
- .onError(({ error }) => {
65
- errorMessage = error.message
66
- return new Response('Error', { status: 400 })
67
- })
68
-
69
- const res = await app.handle(
70
- new Request('http://localhost/test', {
71
- method: 'POST',
72
- headers: {
73
- 'Content-Type': 'application/json',
74
- },
75
- body: JSON.stringify({ name: 1 }), // Invalid type for 'name'
76
- }),
77
- )
78
-
79
- expect(res.status).toBe(400)
80
- expect(errorMessage).toContain('data/name must be string')
81
- expect(await res.text()).toBe('Error')
50
+ let errorMessage = ''
51
+ const app = new Spiceflow()
52
+ .post(
53
+ '/test',
54
+ async ({ request }) => {
55
+ await request.json()
56
+ return 'Success'
57
+ },
58
+ {
59
+ body: z.object({
60
+ name: z.string(),
61
+ }),
62
+ },
63
+ )
64
+ .onError(({ error }) => {
65
+ errorMessage = error.message
66
+ return new Response('Error', { status: 400 })
67
+ })
68
+
69
+ const res = await app.handle(
70
+ new Request('http://localhost/test', {
71
+ method: 'POST',
72
+ headers: {
73
+ 'Content-Type': 'application/json',
74
+ },
75
+ body: JSON.stringify({ name: 1 }), // Invalid type for 'name'
76
+ }),
77
+ )
78
+
79
+ expect(res.status).toBe(400)
80
+ expect(errorMessage).toContain('data/name must be string')
81
+ expect(await res.text()).toBe('Error')
82
82
  })
83
83
 
84
84
  test.todo('HEAD uses GET route, does not add body', async () => {
85
- const app = new Spiceflow().get('/ids/:id', () => {
86
- console.trace('GET')
87
- return {
88
- message: 'hi',
89
- length: 10,
90
- }
91
- })
92
-
93
- const res = await app.handle(
94
- new Request('http://localhost/ids/xxx', { method: 'HEAD' }),
95
- )
96
- expect(res.status).toBe(200)
97
- // expect(res.headers.get('Content-Length')).toBe('10')
98
- expect(await res.text()).toBe('')
99
-
100
- // Compare with GET to ensure HEAD is using GET route
101
- const getRes = await app.handle(
102
- new Request('http://localhost/ids/xxx', { method: 'GET' }),
103
- )
104
- expect(getRes.status).toBe(200)
105
- expect(await getRes.json()).toEqual({ message: 'hi', length: 10 })
85
+ const app = new Spiceflow().get('/ids/:id', () => {
86
+ console.trace('GET')
87
+ return {
88
+ message: 'hi',
89
+ length: 10,
90
+ }
91
+ })
92
+
93
+ const res = await app.handle(
94
+ new Request('http://localhost/ids/xxx', { method: 'HEAD' }),
95
+ )
96
+ expect(res.status).toBe(200)
97
+ // expect(res.headers.get('Content-Length')).toBe('10')
98
+ expect(await res.text()).toBe('')
99
+
100
+ // Compare with GET to ensure HEAD is using GET route
101
+ const getRes = await app.handle(
102
+ new Request('http://localhost/ids/xxx', { method: 'GET' }),
103
+ )
104
+ expect(getRes.status).toBe(200)
105
+ expect(await getRes.json()).toEqual({ message: 'hi', length: 10 })
106
106
  })
107
107
 
108
108
  test('GET with query, untyped', async () => {
109
- const res = await new Spiceflow()
110
- .get('/query', ({ query }) => {
111
- return query.id
112
- })
113
- .handle(new Request('http://localhost/query?id=hi', { method: 'GET' }))
114
- expect(res.status).toBe(200)
115
- expect(await res.json()).toEqual('hi')
109
+ const res = await new Spiceflow()
110
+ .get('/query', ({ query }) => {
111
+ return query.id
112
+ })
113
+ .handle(new Request('http://localhost/query?id=hi', { method: 'GET' }))
114
+ expect(res.status).toBe(200)
115
+ expect(await res.json()).toEqual('hi')
116
116
  })
117
117
 
118
118
  test('GET with query, zod, fails validation', async () => {
119
- const res = await new Spiceflow()
120
- .get(
121
- '/query',
122
- ({ query }) => {
123
- return query.id
124
- },
125
- {
126
- query: z.object({
127
- id: z.number(),
128
- }),
129
- },
130
- )
131
- .handle(new Request('http://localhost/query?id=hi', { method: 'GET' }))
132
- expect(res.status).toBe(422)
119
+ const res = await new Spiceflow()
120
+ .get(
121
+ '/query',
122
+ ({ query }) => {
123
+ return query.id
124
+ },
125
+ {
126
+ query: z.object({
127
+ id: z.number(),
128
+ }),
129
+ },
130
+ )
131
+ .handle(new Request('http://localhost/query?id=hi', { method: 'GET' }))
132
+ expect(res.status).toBe(422)
133
133
  })
134
134
 
135
135
  test('GET with query and zod', async () => {
136
- const res = await new Spiceflow()
137
- .get(
138
- '/query',
139
- ({ query }) => {
140
- return query.id
141
- // @ts-expect-error
142
- void query.sdfsd
143
- },
144
- {
145
- query: z.object({
146
- id: z.string(),
147
- }),
148
- },
149
- )
150
- .handle(new Request('http://localhost/query?id=hi', { method: 'GET' }))
151
- expect(res.status).toBe(200)
152
- expect(await res.json()).toEqual('hi')
136
+ const res = await new Spiceflow()
137
+ .get(
138
+ '/query',
139
+ ({ query }) => {
140
+ return query.id
141
+ // @ts-expect-error
142
+ void query.sdfsd
143
+ },
144
+ {
145
+ query: z.object({
146
+ id: z.string(),
147
+ }),
148
+ },
149
+ )
150
+ .handle(new Request('http://localhost/query?id=hi', { method: 'GET' }))
151
+ expect(res.status).toBe(200)
152
+ expect(await res.json()).toEqual('hi')
153
153
  })
154
154
 
155
155
  test('GET dynamic route, params are typed', async () => {
156
- const res = await new Spiceflow()
157
- .get('/ids/:id', ({ params }) => {
158
- let id = params.id
159
- // @ts-expect-error
160
- params.sdfsd
161
- return id
162
- })
163
- .handle(new Request('http://localhost/ids/hi', { method: 'GET' }))
164
- expect(res.status).toBe(200)
165
- expect(await res.json()).toEqual('hi')
156
+ const res = await new Spiceflow()
157
+ .get('/ids/:id', ({ params }) => {
158
+ let id = params.id
159
+ // @ts-expect-error
160
+ params.sdfsd
161
+ return id
162
+ })
163
+ .handle(new Request('http://localhost/ids/hi', { method: 'GET' }))
164
+ expect(res.status).toBe(200)
165
+ expect(await res.json()).toEqual('hi')
166
166
  })
167
167
 
168
168
  test('GET dynamic route, params are typed with schema', async () => {
169
- const res = await new Spiceflow()
170
- .get(
171
- '/ids/:id',
172
- ({ params }) => {
173
- let id = params.id
174
- // @ts-expect-error
175
- params.sdfsd
176
- return id
177
- },
178
- {
179
- params: z.object({
180
- id: z.string(),
181
- }),
182
- },
183
- )
184
- .handle(new Request('http://localhost/ids/hi', { method: 'GET' }))
185
- expect(res.status).toBe(200)
186
- expect(await res.json()).toEqual('hi')
169
+ const res = await new Spiceflow()
170
+ .get(
171
+ '/ids/:id',
172
+ ({ params }) => {
173
+ let id = params.id
174
+ // @ts-expect-error
175
+ params.sdfsd
176
+ return id
177
+ },
178
+ {
179
+ params: z.object({
180
+ id: z.string(),
181
+ }),
182
+ },
183
+ )
184
+ .handle(new Request('http://localhost/ids/hi', { method: 'GET' }))
185
+ expect(res.status).toBe(200)
186
+ expect(await res.json()).toEqual('hi')
187
187
  })
188
188
 
189
189
  test('missing route is not found', async () => {
190
- const res = await new Spiceflow()
191
- .get('/ids/:id', () => 'hi')
192
- .handle(new Request('http://localhost/zxxx', { method: 'GET' }))
193
- expect(res.status).toBe(404)
190
+ const res = await new Spiceflow()
191
+ .get('/ids/:id', () => 'hi')
192
+ .handle(new Request('http://localhost/zxxx', { method: 'GET' }))
193
+ expect(res.status).toBe(404)
194
194
  })
195
195
  test('state works', async () => {
196
- const res = await new Spiceflow()
197
- .state('id', '')
198
- .use(({ state, request }) => {
199
- state.id = 'xxx'
200
- })
201
- .get('/get', ({ state: state }) => {
202
- expect(state.id).toBe('xxx')
203
- })
204
- .handle(new Request('http://localhost/get'))
205
- expect(res.status).toBe(200)
196
+ const res = await new Spiceflow()
197
+ .state('id', '')
198
+ .use(({ state, request }) => {
199
+ state.id = 'xxx'
200
+ })
201
+ .get('/get', ({ state: state }) => {
202
+ expect(state.id).toBe('xxx')
203
+ })
204
+ .handle(new Request('http://localhost/get'))
205
+ expect(res.status).toBe(200)
206
206
  })
207
207
 
208
208
  test('body is parsed as json', async () => {
209
- let body
210
- const res = await new Spiceflow()
211
- .state('id', '')
212
-
213
- .post('/post', async (c) => {
214
- body = await c.request.json()
215
- // console.log({request})
216
- return body
217
- })
218
- .handle(
219
- new Request('http://localhost/post', {
220
- method: 'POST',
221
- headers: {
222
- 'content-type': 'application/json',
223
- },
224
- body: JSON.stringify({ name: 'John' }),
225
- }),
226
- )
227
- expect(res.status).toBe(200)
228
- expect(await res.json()).toEqual({ name: 'John' })
209
+ let body
210
+ const res = await new Spiceflow()
211
+ .state('id', '')
212
+
213
+ .post('/post', async (c) => {
214
+ body = await c.request.json()
215
+ // console.log({request})
216
+ return body
217
+ })
218
+ .handle(
219
+ new Request('http://localhost/post', {
220
+ method: 'POST',
221
+ headers: {
222
+ 'content-type': 'application/json',
223
+ },
224
+ body: JSON.stringify({ name: 'John' }),
225
+ }),
226
+ )
227
+ expect(res.status).toBe(200)
228
+ expect(await res.json()).toEqual({ name: 'John' })
229
229
  })
230
230
 
231
231
  test('validate body works, request success', async () => {
232
- const res = await new Spiceflow()
233
-
234
- .post(
235
- '/post',
236
- async ({ request }) => {
237
- // console.log({request})
238
- let body = await request.json()
239
- expect(body).toEqual({ name: 'John' })
240
- return 'ok'
241
- },
242
- {
243
- body: Type.Object({
244
- name: Type.String(),
245
- }),
246
- },
247
- )
248
- .handle(
249
- new Request('http://localhost/post', {
250
- method: 'POST',
251
- headers: {
252
- 'content-type': 'application/json',
253
- },
254
- body: JSON.stringify({ name: 'John' }),
255
- }),
256
- )
257
- expect(res.status).toBe(200)
258
- expect(await res.text()).toMatchInlineSnapshot(`""ok""`)
232
+ const res = await new Spiceflow()
233
+
234
+ .post(
235
+ '/post',
236
+ async ({ request }) => {
237
+ // console.log({request})
238
+ let body = await request.json()
239
+ expect(body).toEqual({ name: 'John' })
240
+ return 'ok'
241
+ },
242
+ {
243
+ body: Type.Object({
244
+ name: Type.String(),
245
+ }),
246
+ },
247
+ )
248
+ .handle(
249
+ new Request('http://localhost/post', {
250
+ method: 'POST',
251
+ headers: {
252
+ 'content-type': 'application/json',
253
+ },
254
+ body: JSON.stringify({ name: 'John' }),
255
+ }),
256
+ )
257
+ expect(res.status).toBe(200)
258
+ expect(await res.text()).toMatchInlineSnapshot(`""ok""`)
259
259
  })
260
260
 
261
261
  test('validate body works, request fails', async () => {
262
- const res = await new Spiceflow()
263
-
264
- .post(
265
- '/post',
266
- async ({ request, redirect }) => {
267
- // console.log({request})
268
- let body = await request.json()
269
- expect(body).toEqual({ name: 'John' })
270
- },
271
- {
272
- body: Type.Object({
273
- name: Type.String(),
274
- requiredField: Type.String(),
275
- }),
276
- },
277
- )
278
- .handle(
279
- new Request('http://localhost/post', {
280
- method: 'POST',
281
- headers: {
282
- 'content-type': 'application/json',
283
- },
284
- body: JSON.stringify({ name: 'John' }),
285
- }),
286
- )
287
- expect(res.status).toBe(422)
288
- expect(await res.text()).toMatchInlineSnapshot(
289
- `"data must have required property 'requiredField'"`,
290
- )
262
+ const res = await new Spiceflow()
263
+
264
+ .post(
265
+ '/post',
266
+ async ({ request, redirect }) => {
267
+ // console.log({request})
268
+ let body = await request.json()
269
+ expect(body).toEqual({ name: 'John' })
270
+ },
271
+ {
272
+ body: Type.Object({
273
+ name: Type.String(),
274
+ requiredField: Type.String(),
275
+ }),
276
+ },
277
+ )
278
+ .handle(
279
+ new Request('http://localhost/post', {
280
+ method: 'POST',
281
+ headers: {
282
+ 'content-type': 'application/json',
283
+ },
284
+ body: JSON.stringify({ name: 'John' }),
285
+ }),
286
+ )
287
+ expect(res.status).toBe(422)
288
+ expect(await res.text()).toMatchInlineSnapshot(
289
+ `"data must have required property 'requiredField'"`,
290
+ )
291
291
  })
292
292
 
293
293
  test('run use', async () => {
294
- const res = await new Spiceflow()
295
- .use(({ request }) => {
296
- expect(request.method).toBe('HEAD')
297
- return new Response('ok', { status: 401 })
298
- })
299
- .use(({ request }) => {
300
- expect(request.method).toBe('HEAD')
301
- return 'second one'
302
- })
303
- .head('/ids/:id', () => 'hi')
304
- .handle(new Request('http://localhost/ids/zxxx', { method: 'HEAD' }))
305
- expect(res.status).toBe(401)
306
- expect(await res.text()).toBe('ok')
294
+ const res = await new Spiceflow()
295
+ .use(({ request }) => {
296
+ expect(request.method).toBe('HEAD')
297
+ return new Response('ok', { status: 401 })
298
+ })
299
+ .use(({ request }) => {
300
+ expect(request.method).toBe('HEAD')
301
+ return 'second one'
302
+ })
303
+ .head('/ids/:id', () => 'hi')
304
+ .handle(new Request('http://localhost/ids/zxxx', { method: 'HEAD' }))
305
+ expect(res.status).toBe(401)
306
+ expect(await res.text()).toBe('ok')
307
307
  })
308
308
 
309
309
  test('run use', async () => {
310
- const res = await new Spiceflow()
311
- .use(({ request }) => {
312
- expect(request.method).toBe('HEAD')
313
- return new Response('ok', { status: 401 })
314
- })
315
- .use(({ request }) => {
316
- expect(request.method).toBe('HEAD')
317
- return 'second one'
318
- })
319
- .head('/ids/:id', () => 'hi')
320
- .handle(new Request('http://localhost/ids/zxxx', { method: 'HEAD' }))
321
- expect(res.status).toBe(401)
322
- expect(await res.text()).toBe('ok')
310
+ const res = await new Spiceflow()
311
+ .use(({ request }) => {
312
+ expect(request.method).toBe('HEAD')
313
+ return new Response('ok', { status: 401 })
314
+ })
315
+ .use(({ request }) => {
316
+ expect(request.method).toBe('HEAD')
317
+ return 'second one'
318
+ })
319
+ .head('/ids/:id', () => 'hi')
320
+ .handle(new Request('http://localhost/ids/zxxx', { method: 'HEAD' }))
321
+ expect(res.status).toBe(401)
322
+ expect(await res.text()).toBe('ok')
323
323
  })
324
324
 
325
325
  test('basPath works', async () => {
326
- const res = await new Spiceflow({ basePath: '/one' })
327
- .get('/ids/:id', () => 'hi')
328
- .handle(new Request('http://localhost/one/ids/xxx', { method: 'GET' }))
329
- expect(res.status).toBe(200)
330
- expect(await res.json()).toEqual('hi')
326
+ const res = await new Spiceflow({ basePath: '/one' })
327
+ .get('/ids/:id', () => 'hi')
328
+ .handle(new Request('http://localhost/one/ids/xxx', { method: 'GET' }))
329
+ expect(res.status).toBe(200)
330
+ expect(await res.json()).toEqual('hi')
331
331
  })
332
332
 
333
333
  test('basPath works with use', async () => {
334
- let app = new Spiceflow({ basePath: '/one' }).use(
335
- new Spiceflow({})
336
- .get('/two', () => 'hi')
337
- .use(
338
- new Spiceflow({ basePath: '/three' }).get('/four', () => 'hi'),
339
- ),
340
- )
341
- {
342
- const res = await app.handle(
343
- new Request('http://localhost/one/two', { method: 'GET' }),
344
- )
345
-
346
- expect(res.status).toBe(200)
347
- expect(await res.json()).toEqual('hi')
348
- }
349
- {
350
- const res = await app.handle(
351
- new Request('http://localhost/one/three/four', { method: 'GET' }),
352
- )
353
- expect(res.status).toBe(200)
354
- expect(await res.json()).toEqual('hi')
355
- }
334
+ let app = new Spiceflow({ basePath: '/one' }).use(
335
+ new Spiceflow({})
336
+ .get('/two', () => 'hi')
337
+ .use(new Spiceflow({ basePath: '/three' }).get('/four', () => 'hi')),
338
+ )
339
+ {
340
+ const res = await app.handle(
341
+ new Request('http://localhost/one/two', { method: 'GET' }),
342
+ )
343
+
344
+ expect(res.status).toBe(200)
345
+ expect(await res.json()).toEqual('hi')
346
+ }
347
+ {
348
+ const res = await app.handle(
349
+ new Request('http://localhost/one/three/four', { method: 'GET' }),
350
+ )
351
+ expect(res.status).toBe(200)
352
+ expect(await res.json()).toEqual('hi')
353
+ }
356
354
  })
357
355
 
358
356
  test('getRouteAndParents', async () => {
359
- let app = new Spiceflow({ basePath: '/one' })
360
- .get('/ids/:id', () => 'hi')
361
- .use(
362
- new Spiceflow({ basePath: '/two' }).use(
363
- new Spiceflow({ basePath: '/three' }).get('/four', () => 'hi'),
364
- ),
365
- )
366
-
367
- let routers = bfs(app)
368
- let last = routers[routers.length - 1]
369
-
370
- expect(app['getAppAndParents'](last).map((x) => x.prefix))
371
- .toMatchInlineSnapshot(`
357
+ let app = new Spiceflow({ basePath: '/one' })
358
+ .get('/ids/:id', () => 'hi')
359
+ .use(
360
+ new Spiceflow({ basePath: '/two' }).use(
361
+ new Spiceflow({ basePath: '/three' }).get('/four', () => 'hi'),
362
+ ),
363
+ )
364
+
365
+ let routers = bfs(app)
366
+ let last = routers[routers.length - 1]
367
+
368
+ expect(app['getAppAndParents'](last).map((x) => x.prefix))
369
+ .toMatchInlineSnapshot(`
372
370
  [
373
371
  "/one",
374
372
  "/two",
@@ -378,23 +376,23 @@ test('getRouteAndParents', async () => {
378
376
  })
379
377
 
380
378
  test('getAppsInScope include all parent apps', async () => {
381
- let app = new Spiceflow({ basePath: '/one' })
382
- .get('/ids/:id', () => 'hi')
383
- .use(
384
- new Spiceflow({ basePath: '/two' }).use(
385
- new Spiceflow({ basePath: '/three' }).use(
386
- new Spiceflow({ basePath: '/four' })
387
- .get('/five', () => 'hi')
388
- .use(({ request }) => {}),
389
- ),
390
- ),
391
- )
392
-
393
- let routers = bfs(app)
394
- let secondLast = routers[routers.length - 2]
395
-
396
- expect(app['getAppsInScope'](secondLast).map((x) => x.prefix))
397
- .toMatchInlineSnapshot(`
379
+ let app = new Spiceflow({ basePath: '/one' })
380
+ .get('/ids/:id', () => 'hi')
381
+ .use(
382
+ new Spiceflow({ basePath: '/two' }).use(
383
+ new Spiceflow({ basePath: '/three' }).use(
384
+ new Spiceflow({ basePath: '/four' })
385
+ .get('/five', () => 'hi')
386
+ .use(({ request }) => {}),
387
+ ),
388
+ ),
389
+ )
390
+
391
+ let routers = bfs(app)
392
+ let secondLast = routers[routers.length - 2]
393
+
394
+ expect(app['getAppsInScope'](secondLast).map((x) => x.prefix))
395
+ .toMatchInlineSnapshot(`
398
396
  [
399
397
  "/one",
400
398
  "/two",
@@ -404,23 +402,23 @@ test('getAppsInScope include all parent apps', async () => {
404
402
  })
405
403
 
406
404
  test('getAppsInScope include all parent apps and non scoped apps', async () => {
407
- let app = new Spiceflow({ basePath: '/one' })
408
- .get('/ids/:id', () => 'hi')
409
- .use(
410
- new Spiceflow({ basePath: '/two' }).use(
411
- new Spiceflow({ basePath: '/three' }).use(
412
- new Spiceflow({ basePath: '/four', scoped: false })
413
- .get('/five', () => 'hi')
414
- .use(({ request }) => {}),
415
- ),
416
- ),
417
- )
418
-
419
- let routers = bfs(app)
420
- let secondLast = routers[routers.length - 2]
421
-
422
- expect(app['getAppsInScope'](secondLast).map((x) => x.prefix))
423
- .toMatchInlineSnapshot(`
405
+ let app = new Spiceflow({ basePath: '/one' })
406
+ .get('/ids/:id', () => 'hi')
407
+ .use(
408
+ new Spiceflow({ basePath: '/two' }).use(
409
+ new Spiceflow({ basePath: '/three' }).use(
410
+ new Spiceflow({ basePath: '/four', scoped: false })
411
+ .get('/five', () => 'hi')
412
+ .use(({ request }) => {}),
413
+ ),
414
+ ),
415
+ )
416
+
417
+ let routers = bfs(app)
418
+ let secondLast = routers[routers.length - 2]
419
+
420
+ expect(app['getAppsInScope'](secondLast).map((x) => x.prefix))
421
+ .toMatchInlineSnapshot(`
424
422
  [
425
423
  "/one",
426
424
  "/two",
@@ -431,135 +429,131 @@ test('getAppsInScope include all parent apps and non scoped apps', async () => {
431
429
  })
432
430
 
433
431
  test('use with 2 basPath works', async () => {
434
- let oneOnReq = false
435
- let twoOnReq = false
436
- let onReqCalled: string[] = []
437
- const app = await new Spiceflow()
438
- .use(({ request }) => {
439
- onReqCalled.push('root')
440
- })
441
- .use(
442
- new Spiceflow({ basePath: '/one' })
443
-
444
- .use(({ request }) => {
445
- oneOnReq = true
446
- onReqCalled.push('one')
447
- })
448
- .get('/ids/:id', ({ params }) => params.id),
449
- )
450
- .use(
451
- new Spiceflow({ basePath: '/two' })
452
- .use((c) => {
453
- twoOnReq = true
454
- onReqCalled.push('two')
455
- })
456
- .get('/ids/:id', ({ params }) => params.id, {}),
457
- )
458
-
459
- {
460
- const res = await app.handle(
461
- new Request('http://localhost/one/ids/one'),
462
- )
463
- expect(res.status).toBe(200)
464
-
465
- expect(await res.json()).toEqual('one')
466
- }
467
- expect(onReqCalled).toEqual(['root', 'one'])
468
- {
469
- const res = await app.handle(
470
- new Request('http://localhost/two/ids/two'),
471
- )
472
- expect(res.status).toBe(200)
473
-
474
- expect(await res.json()).toEqual('two')
475
- }
476
- expect(oneOnReq).toBe(true)
477
- expect(twoOnReq).toBe(true)
432
+ let oneOnReq = false
433
+ let twoOnReq = false
434
+ let onReqCalled: string[] = []
435
+ const app = await new Spiceflow()
436
+ .use(({ request }) => {
437
+ onReqCalled.push('root')
438
+ })
439
+ .use(
440
+ new Spiceflow({ basePath: '/one' })
441
+
442
+ .use(({ request }) => {
443
+ oneOnReq = true
444
+ onReqCalled.push('one')
445
+ })
446
+ .get('/ids/:id', ({ params }) => params.id),
447
+ )
448
+ .use(
449
+ new Spiceflow({ basePath: '/two' })
450
+ .use((c) => {
451
+ twoOnReq = true
452
+ onReqCalled.push('two')
453
+ })
454
+ .get('/ids/:id', ({ params }) => params.id, {}),
455
+ )
456
+
457
+ {
458
+ const res = await app.handle(new Request('http://localhost/one/ids/one'))
459
+ expect(res.status).toBe(200)
460
+
461
+ expect(await res.json()).toEqual('one')
462
+ }
463
+ expect(onReqCalled).toEqual(['root', 'one'])
464
+ {
465
+ const res = await app.handle(new Request('http://localhost/two/ids/two'))
466
+ expect(res.status).toBe(200)
467
+
468
+ expect(await res.json()).toEqual('two')
469
+ }
470
+ expect(oneOnReq).toBe(true)
471
+ expect(twoOnReq).toBe(true)
478
472
  })
479
473
 
480
474
  test('use with nested basPath works', async () => {
481
- const app = await new Spiceflow({ basePath: '/zero' })
482
- .use(
483
- new Spiceflow({ basePath: '/one' }).get(
484
- '/ids/:id',
485
- ({ params }) => params.id,
486
- ),
487
- )
488
- .use(
489
- new Spiceflow({ basePath: '/two' }).use(
490
- new Spiceflow({ basePath: '/nested' }).get(
491
- '/ids/:id',
492
- ({ params }) => params.id,
493
- ),
494
- ),
495
- )
496
- {
497
- const res = await app.handle(
498
- new Request('http://localhost/zero/one/ids/one'),
499
- )
500
- expect(res.status).toBe(200)
501
- expect(await res.json()).toEqual('one')
502
- }
503
-
504
- {
505
- const res = await app.handle(
506
- new Request('http://localhost/zero/two/nested/ids/nested'),
507
- )
508
- expect(res.status).toBe(200)
509
- expect(await res.json()).toEqual('nested')
510
- }
475
+ const app = await new Spiceflow({ basePath: '/zero' })
476
+ .use(
477
+ new Spiceflow({ basePath: '/one' }).get(
478
+ '/ids/:id',
479
+ ({ params }) => params.id,
480
+ ),
481
+ )
482
+ .use(
483
+ new Spiceflow({ basePath: '/two' }).use(
484
+ new Spiceflow({ basePath: '/nested' }).get(
485
+ '/ids/:id',
486
+ ({ params }) => params.id,
487
+ ),
488
+ ),
489
+ )
490
+ {
491
+ const res = await app.handle(
492
+ new Request('http://localhost/zero/one/ids/one'),
493
+ )
494
+ expect(res.status).toBe(200)
495
+ expect(await res.json()).toEqual('one')
496
+ }
497
+
498
+ {
499
+ const res = await app.handle(
500
+ new Request('http://localhost/zero/two/nested/ids/nested'),
501
+ )
502
+ expect(res.status).toBe(200)
503
+ expect(await res.json()).toEqual('nested')
504
+ }
511
505
  })
512
506
 
513
507
  test('errors inside basPath works', async () => {
514
- let onErrorTriggered = [] as string[]
515
- let onReqTriggered = [] as string[]
516
- let handlerCalledNTimes = 0
517
- const app = await new Spiceflow({ basePath: '/zero' })
518
- .onError(({ error }) => {
519
- onErrorTriggered.push('root')
520
- // return new Response('root', { status: 500 })
521
- })
522
- .use(({ request }) => {
523
- onReqTriggered.push('root')
524
- // return new Response('root', { status: 500 })
525
- })
526
-
527
- .use(
528
- new Spiceflow({ basePath: '/two' })
529
- .onError(({ error }) => {
530
- onErrorTriggered.push('two')
531
- // return new Response('two', { status: 500 })
532
- })
533
- .use(({ request }) => {
534
- onReqTriggered.push('two')
535
- // return new Response('two', { status: 500 })
536
- })
537
- .use(
538
- new Spiceflow({ basePath: '/nested' })
539
- .onError(({ error }) => {
540
- onErrorTriggered.push('nested')
541
- // return new Response('nested', { status: 500 })
542
- })
543
- .use(({ request }) => {
544
- onReqTriggered.push('nested')
545
- // return new Response('nested', { status: 500 })
546
- })
547
- .get('/ids/:id', ({ params }) => {
548
- handlerCalledNTimes++
549
- throw new Error('error message')
550
- }),
551
- ),
552
- )
553
-
554
- {
555
- const res = await app.handle(
556
- new Request('http://localhost/zero/two/nested/ids/nested'),
557
- )
558
- expect(handlerCalledNTimes).toBe(1)
559
- expect(onErrorTriggered).toEqual(['root', 'two', 'nested'])
560
- expect(onReqTriggered).toEqual(['root', 'two', 'nested'])
561
- expect(res.status).toBe(500)
562
- expect(await res.text()).toBe('error message')
563
- // expect(await res.json()).toEqual('nested'))
564
- }
508
+ let onErrorTriggered = [] as string[]
509
+ let onReqTriggered = [] as string[]
510
+ let handlerCalledNTimes = 0
511
+ const app = await new Spiceflow({ basePath: '/zero' })
512
+ .onError(({ error }) => {
513
+ onErrorTriggered.push('root')
514
+ // return new Response('root', { status: 500 })
515
+ })
516
+ .use(({ request }) => {
517
+ onReqTriggered.push('root')
518
+ // return new Response('root', { status: 500 })
519
+ })
520
+
521
+ .use(
522
+ new Spiceflow({ basePath: '/two' })
523
+ .onError(({ error }) => {
524
+ onErrorTriggered.push('two')
525
+ // return new Response('two', { status: 500 })
526
+ })
527
+ .use(({ request }) => {
528
+ onReqTriggered.push('two')
529
+ // return new Response('two', { status: 500 })
530
+ })
531
+ .use(
532
+ new Spiceflow({ basePath: '/nested' })
533
+ .onError(({ error }) => {
534
+ onErrorTriggered.push('nested')
535
+ // return new Response('nested', { status: 500 })
536
+ })
537
+ .use(({ request }) => {
538
+ onReqTriggered.push('nested')
539
+ // return new Response('nested', { status: 500 })
540
+ })
541
+ .get('/ids/:id', ({ params }) => {
542
+ handlerCalledNTimes++
543
+ throw new Error('error message')
544
+ }),
545
+ ),
546
+ )
547
+
548
+ {
549
+ const res = await app.handle(
550
+ new Request('http://localhost/zero/two/nested/ids/nested'),
551
+ )
552
+ expect(handlerCalledNTimes).toBe(1)
553
+ expect(onErrorTriggered).toEqual(['root', 'two', 'nested'])
554
+ expect(onReqTriggered).toEqual(['root', 'two', 'nested'])
555
+ expect(res.status).toBe(500)
556
+ expect(await res.text()).toBe('error message')
557
+ // expect(await res.json()).toEqual('nested'))
558
+ }
565
559
  })