galbe 0.12.1 → 0.12.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.
Files changed (41) hide show
  1. package/package.json +6 -1
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
  4. package/.github/workflows/build_test.yml +0 -17
  5. package/.github/workflows/deploy_website.yml +0 -20
  6. package/.github/workflows/release.yml +0 -39
  7. package/.prettierrc +0 -10
  8. package/bun.lock +0 -904
  9. package/bunfig.toml +0 -2
  10. package/docs/CONTRIBUTING.md +0 -105
  11. package/docs/cli.md +0 -343
  12. package/docs/configuration.md +0 -80
  13. package/docs/context.md +0 -104
  14. package/docs/error-handler.md +0 -54
  15. package/docs/getting-started.md +0 -164
  16. package/docs/handler.md +0 -119
  17. package/docs/hooks.md +0 -90
  18. package/docs/plugins.md +0 -146
  19. package/docs/router.md +0 -10
  20. package/docs/routes.md +0 -133
  21. package/docs/schemas.md +0 -327
  22. package/test/hooks.test.ts +0 -200
  23. package/test/parser.test.ts +0 -1358
  24. package/test/plugins.test.ts +0 -239
  25. package/test/requests.test.ts +0 -917
  26. package/test/resources/image.png +0 -0
  27. package/test/resources/object.badSyntax.json +0 -8
  28. package/test/resources/object.json +0 -8
  29. package/test/resources/object.missing.json +0 -6
  30. package/test/resources/static/chameleon.png +0 -0
  31. package/test/resources/static/index.html +0 -13
  32. package/test/resources/static/sub/index.html +0 -13
  33. package/test/resources/static/sub/other.html +0 -13
  34. package/test/resources/test.route.comment.ts +0 -58
  35. package/test/resources/test.route.empty.ts +0 -9
  36. package/test/responses.test.ts +0 -483
  37. package/test/routeFiles.test.ts +0 -239
  38. package/test/router.test.ts +0 -231
  39. package/test/test.utils.ts +0 -109
  40. package/test/types.test.ts +0 -909
  41. package/tsconfig.json +0 -23
Binary file
@@ -1,8 +0,0 @@
1
- {
2
- "string": "test"
3
- "number": 3.14,
4
- "bool": true,
5
- "arrayStr": ["un", "deux", "trois"],
6
- "arrayNumber": [0],
7
- "arrayBool": [true, false]
8
- }
@@ -1,8 +0,0 @@
1
- {
2
- "string": "test",
3
- "number": 3.14,
4
- "bool": true,
5
- "arrayStr": ["un", "deux", "trois"],
6
- "arrayNumber": [0],
7
- "arrayBool": [true, false]
8
- }
@@ -1,6 +0,0 @@
1
- {
2
- "string": "test",
3
- "number": 3.14,
4
- "bool": true,
5
- "arrayNumber": [0]
6
- }
Binary file
@@ -1,13 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Galbe test</title>
7
- <!-- <link rel="stylesheet" href="styles.css" /> -->
8
- </head>
9
- <body>
10
- <h1>Bonjour</h1>
11
- <p>This is a test page.</p>
12
- </body>
13
- </html>
@@ -1,13 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Galbe test: sub page</title>
7
- <!-- <link rel="stylesheet" href="styles.css" /> -->
8
- </head>
9
- <body>
10
- <h1>Hello</h1>
11
- <p>This is a sub test page.</p>
12
- </body>
13
- </html>
@@ -1,13 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Galbe test: other page</title>
7
- <!-- <link rel="stylesheet" href="styles.css" /> -->
8
- </head>
9
- <body>
10
- <h1>Hola</h1>
11
- <p>This is another test page.</p>
12
- </body>
13
- </html>
@@ -1,58 +0,0 @@
1
- import type { Galbe } from '../../src'
2
- import { $T } from '../../src'
3
-
4
- /**
5
- * description
6
- * multiline
7
- * @tag test
8
- * ok
9
- */
10
- export default (g: Galbe) => {
11
- /**
12
- * This part
13
- * here
14
- * @tags tag1, tag2, tag3
15
- * @summary short summary
16
- * @description longer description example
17
- * @deprecated
18
- * @param {path} param1 description
19
- * @param {query} param2 description
20
- */
21
- g.get('/test/:param1', _ => {})
22
-
23
- // Comment between enpoints
24
-
25
- /**
26
- * @tags tag1, tag2, tag3
27
- * @summary short summary
28
- * @description longer description example
29
- * @body body descripton
30
- */
31
- g.post('/test', { body: $T.object({ foo: $T.string() }) }, _ => {})
32
-
33
- /**
34
- * @tags tag1, tag2
35
- * @other Hello Mom!
36
- */
37
- g.put('/test', { body: $T.object({ foo: $T.string() }) }, [() => {}], _ => {})
38
-
39
- /**
40
- * patch method
41
- */
42
- g.patch('/test', _ => {})
43
-
44
- /**
45
- * options method
46
- */
47
- g.options('/test', _ => {})
48
-
49
- /**
50
- * delete method
51
- */
52
- g.delete('/test', _ => {})
53
-
54
- /**
55
- * head method
56
- */
57
- g.head('/test', _ => {})
58
- }
@@ -1,9 +0,0 @@
1
- import type { Galbe } from '../../src'
2
-
3
- export default (g: Galbe) => {
4
- g.get('/one', _ => {})
5
- // Comment between enpoints
6
- g.post('/two', _ => {})
7
-
8
- g.put('/three', _ => {})
9
- }
@@ -1,483 +0,0 @@
1
- import { expect, test, describe, beforeAll } from 'bun:test'
2
- import { Galbe, $T, type Context } from '../src'
3
- import { decoder } from './test.utils'
4
-
5
- const port = 7359
6
-
7
- const UUID_RGX = '[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}'
8
-
9
- function* genTxt(text: string) {
10
- const words = text.split(' ')
11
- for (const w of words) yield w
12
- }
13
-
14
- const rsTxt = (text: string) => {
15
- return new ReadableStream({
16
- async start(controller) {
17
- const words = text.split(' ')
18
- for (const w of words) controller.enqueue(w)
19
- controller.close()
20
- },
21
- })
22
- }
23
-
24
- const handleResp = (ctx: Context) => ctx.body
25
-
26
- describe('responses', () => {
27
- beforeAll(async () => {
28
- const galbe = new Galbe()
29
-
30
- galbe.post(
31
- '/none',
32
- {
33
- body: { json: $T.optional($T.object($T.any())) },
34
- query: { text: $T.optional($T.string()), stream: $T.optional($T.string()) },
35
- },
36
- ctx => {
37
- if (ctx.query.text) {
38
- if (ctx.query.stream === 'generatorFunction') return genTxt(ctx.query.text)
39
- if (ctx.query.stream === 'readableStream') return rsTxt(ctx.query.text)
40
- else return ctx.query.text
41
- } else if (ctx.body) return ctx.body
42
-
43
- return null
44
- }
45
- )
46
-
47
- galbe.post('', { response: { test: '' } }, () => {})
48
-
49
- galbe.post('/ba', { response: { 200: $T.byteArray() } }, handleResp)
50
- galbe.post('/bool', { response: { 200: $T.boolean() } }, handleResp)
51
- galbe.post('/num', { response: { 200: $T.number() } }, handleResp)
52
- galbe.post('/str', { response: { 200: $T.string() } }, handleResp)
53
- galbe.post('/json/bool', { response: { 200: $T.json($T.boolean()) } }, handleResp)
54
- galbe.post('/json/num', { response: { 200: $T.json($T.number()) } }, handleResp)
55
- galbe.post('/json/str', { response: { 200: $T.json($T.string()) } }, handleResp)
56
- galbe.post('/json/obj', { response: { 200: $T.json($T.object()) } }, handleResp)
57
- galbe.post('/arr', { response: { 200: $T.array() } }, handleResp)
58
- galbe.post('/obj', { response: { 200: $T.object($T.any()) } }, handleResp)
59
- galbe.post('/stream/ba', { response: { 200: $T.stream($T.byteArray()) } }, ctx =>
60
- ctx.body ? genTxt(ctx.body) : ''
61
- )
62
- galbe.post('/stream/str', { response: { 200: $T.stream($T.string()) } }, ctx => (ctx.body ? genTxt(ctx.body) : 42))
63
-
64
- await galbe.listen(port)
65
- })
66
-
67
- test('response, no schema, string', async () => {
68
- const reqTxt = 'Hello Mom!'
69
- let resp = await fetch(`http://localhost:${port}/none?text=${reqTxt}`, {
70
- method: 'POST',
71
- })
72
-
73
- const body = await resp.text()
74
-
75
- expect(resp.status).toBe(200)
76
- expect(resp.headers.get('content-type')).toBe('text/plain')
77
- expect(body).toBe(reqTxt)
78
- })
79
-
80
- test('response, no schema, object', async () => {
81
- const reqBody = { foo: 'bar' }
82
- let resp = await fetch(`http://localhost:${port}/none`, {
83
- method: 'POST',
84
- body: JSON.stringify(reqBody),
85
- headers: {
86
- 'content-type': 'application/json',
87
- },
88
- })
89
-
90
- const body = await resp.json()
91
-
92
- expect(resp.status).toBe(200)
93
- expect(resp.headers.get('content-type')).toBe('application/json')
94
- expect(body).toEqual(reqBody)
95
- })
96
-
97
- test('response, no schema, stream', async () => {
98
- const reqTxt = 'Hello Mom!'
99
- const cases = [{ stream: 'generatorFunction' }, { stream: 'readableStream' }]
100
-
101
- for (const c of cases) {
102
- let resp = await fetch(`http://localhost:${port}/none?text=${reqTxt}&stream=${c.stream}`, {
103
- method: 'POST',
104
- headers: {
105
- 'content-type': 'application/json',
106
- },
107
- })
108
- const reader = resp.body?.getReader()
109
- let body = ''
110
- while (reader) {
111
- const { value, done } = await reader.read()
112
- if (done) break
113
- body += decoder.decode(value)
114
- }
115
- expect(resp.status).toBe(200)
116
- expect(resp.headers.get('content-type')).toBe('text/event-stream')
117
- expect(body).toMatch(new RegExp(`id:${UUID_RGX}\ndata:Hello\n\nid:${UUID_RGX}\ndata:Mom!\n\n`))
118
- }
119
- })
120
-
121
- test('response, ba, validation OK', async () => {
122
- let bodyStr = 'Hello mom!'
123
- let reqBody = new TextEncoder().encode(bodyStr)
124
-
125
- let resp = await fetch(`http://localhost:${port}/ba`, {
126
- method: 'POST',
127
- body: bodyStr,
128
- headers: {
129
- 'content-type': 'application/octet-stream',
130
- },
131
- })
132
-
133
- const reader = resp.body?.getReader()
134
- let body = new Uint8Array()
135
- while (reader) {
136
- const { value, done } = await reader.read()
137
- if (done) break
138
- let buff = new Uint8Array(body.length + value.length)
139
- buff.set(body)
140
- buff.set(value, body.length)
141
- body = buff
142
- }
143
-
144
- expect(resp.status).toBe(200)
145
- expect(resp.headers.get('content-type')).toBe('application/octet-stream')
146
- //@ts-ignore
147
- expect(body).toEqual(reqBody)
148
- })
149
-
150
- test('response, ba, validation error', async () => {
151
- let bodyStr = 'Hello mom!'
152
-
153
- let resp = await fetch(`http://localhost:${port}/ba`, {
154
- method: 'POST',
155
- body: bodyStr,
156
- headers: {
157
- 'content-type': 'text/plain',
158
- },
159
- })
160
-
161
- expect(resp.status).toBe(500)
162
- })
163
-
164
- test('response, bool, validation OK', async () => {
165
- let bodyStr = 'true'
166
- let reqBody = true
167
-
168
- let resp = await fetch(`http://localhost:${port}/bool`, {
169
- method: 'POST',
170
- body: bodyStr,
171
- headers: {
172
- 'content-type': 'application/json',
173
- },
174
- })
175
-
176
- const body = await resp.json()
177
-
178
- expect(resp.status).toBe(200)
179
- expect(resp.headers.get('content-type')).toBe('application/json')
180
- expect(body).toEqual(reqBody)
181
- })
182
-
183
- test('response, bool, validation error', async () => {
184
- let bodyStr = 'true'
185
-
186
- let resp = await fetch(`http://localhost:${port}/bool`, {
187
- method: 'POST',
188
- body: bodyStr,
189
- headers: {
190
- 'content-type': 'text/plain',
191
- },
192
- })
193
-
194
- expect(resp.status).toBe(500)
195
- })
196
-
197
- test('response, num, validation OK', async () => {
198
- let bodyStr = '42'
199
- let reqBody = 42
200
-
201
- let resp = await fetch(`http://localhost:${port}/num`, {
202
- method: 'POST',
203
- body: bodyStr,
204
- headers: {
205
- 'content-type': 'application/json',
206
- },
207
- })
208
-
209
- const body = await resp.json()
210
-
211
- expect(resp.status).toBe(200)
212
- expect(resp.headers.get('content-type')).toBe('application/json')
213
- expect(body).toEqual(reqBody)
214
- })
215
-
216
- test('response, num, validation error', async () => {
217
- let bodyStr = '"test"'
218
-
219
- let resp = await fetch(`http://localhost:${port}/num`, {
220
- method: 'POST',
221
- body: bodyStr,
222
- headers: {
223
- 'content-type': 'application/json',
224
- },
225
- })
226
-
227
- expect(resp.status).toBe(500)
228
- })
229
-
230
- test('response, str, validation OK', async () => {
231
- let bodyStr = 'Hello Mom!'
232
-
233
- let resp = await fetch(`http://localhost:${port}/str`, {
234
- method: 'POST',
235
- body: bodyStr,
236
- headers: {
237
- 'content-type': 'text/plain',
238
- },
239
- })
240
-
241
- const body = await resp.text()
242
-
243
- expect(resp.status).toBe(200)
244
- expect(resp.headers.get('content-type')).toBe('text/plain')
245
- expect(body).toEqual(bodyStr)
246
- })
247
-
248
- test('response, json bool, validation OK', async () => {
249
- let bodyStr = 'false'
250
- let reqBody = false
251
-
252
- let resp = await fetch(`http://localhost:${port}/json/bool`, {
253
- method: 'POST',
254
- body: bodyStr,
255
- headers: {
256
- 'content-type': 'application/json',
257
- },
258
- })
259
-
260
- const body = await resp.json()
261
-
262
- expect(resp.status).toBe(200)
263
- expect(resp.headers.get('content-type')).toBe('application/json')
264
- expect(body).toEqual(reqBody)
265
- })
266
-
267
- test('response, json bool, validation error', async () => {
268
- let bodyStr = '3.14'
269
-
270
- let resp = await fetch(`http://localhost:${port}/json/bool`, {
271
- method: 'POST',
272
- body: bodyStr,
273
- headers: {
274
- 'content-type': 'application/json',
275
- },
276
- })
277
-
278
- expect(resp.status).toBe(500)
279
- })
280
-
281
- test('response, json num, validation OK', async () => {
282
- let bodyStr = '42'
283
- let reqBody = 42
284
-
285
- let resp = await fetch(`http://localhost:${port}/json/num`, {
286
- method: 'POST',
287
- body: bodyStr,
288
- headers: {
289
- 'content-type': 'application/json',
290
- },
291
- })
292
-
293
- const body = await resp.json()
294
-
295
- expect(resp.status).toBe(200)
296
- expect(resp.headers.get('content-type')).toBe('application/json')
297
- expect(body).toEqual(reqBody)
298
- })
299
-
300
- test('response, json num, validation error', async () => {
301
- let bodyStr = '"Hi"'
302
-
303
- let resp = await fetch(`http://localhost:${port}/json/bool`, {
304
- method: 'POST',
305
- body: bodyStr,
306
- headers: {
307
- 'content-type': 'application/json',
308
- },
309
- })
310
-
311
- expect(resp.status).toBe(500)
312
- })
313
-
314
- test('response, json str, validation OK', async () => {
315
- let bodyStr = '"Hello Mom!"'
316
- let reqBody = 'Hello Mom!'
317
-
318
- let resp = await fetch(`http://localhost:${port}/json/str`, {
319
- method: 'POST',
320
- body: bodyStr,
321
- headers: {
322
- 'content-type': 'application/json',
323
- },
324
- })
325
-
326
- const body = await resp.json()
327
-
328
- expect(resp.status).toBe(200)
329
- expect(resp.headers.get('content-type')).toBe('application/json')
330
- expect(body).toEqual(reqBody)
331
- })
332
-
333
- test('response, json str, validation error', async () => {
334
- let bodyStr = '3.14'
335
-
336
- let resp = await fetch(`http://localhost:${port}/json/str`, {
337
- method: 'POST',
338
- body: bodyStr,
339
- headers: {
340
- 'content-type': 'application/json',
341
- },
342
- })
343
-
344
- expect(resp.status).toBe(500)
345
- })
346
-
347
- test('response, array, validation OK', async () => {
348
- let bodyStr = '[false, "one", 2]'
349
- let reqBody = [false, 'one', 2]
350
-
351
- let resp = await fetch(`http://localhost:${port}/arr`, {
352
- method: 'POST',
353
- body: bodyStr,
354
- headers: {
355
- 'content-type': 'application/json',
356
- },
357
- })
358
-
359
- const body = await resp.json()
360
-
361
- expect(resp.status).toBe(200)
362
- expect(resp.headers.get('content-type')).toBe('application/json')
363
- expect(body).toEqual(reqBody)
364
- })
365
-
366
- test('response, array, validation error', async () => {
367
- let bodyStr = '0'
368
-
369
- let resp = await fetch(`http://localhost:${port}/arr`, {
370
- method: 'POST',
371
- body: bodyStr,
372
- headers: {
373
- 'content-type': 'application/json',
374
- },
375
- })
376
-
377
- expect(resp.status).toBe(500)
378
- })
379
-
380
- test('response, object, validation OK', async () => {
381
- let bodyStr = '{"str":"str", "num":0, "arr":[1,2,3], "nested": {"foo":"bar"}}'
382
- let reqBody = { str: 'str', num: 0, arr: [1, 2, 3], nested: { foo: 'bar' } }
383
-
384
- let resp = await fetch(`http://localhost:${port}/obj`, {
385
- method: 'POST',
386
- body: bodyStr,
387
- headers: {
388
- 'content-type': 'application/json',
389
- },
390
- })
391
-
392
- const body = await resp.json()
393
-
394
- expect(resp.status).toBe(200)
395
- expect(resp.headers.get('content-type')).toBe('application/json')
396
- expect(body).toEqual(reqBody)
397
- })
398
-
399
- test('response, object, validation error', async () => {
400
- let bodyStr = '"This"'
401
-
402
- let resp = await fetch(`http://localhost:${port}/obj`, {
403
- method: 'POST',
404
- body: bodyStr,
405
- headers: {
406
- 'content-type': 'application/json',
407
- },
408
- })
409
-
410
- expect(resp.status).toBe(500)
411
- })
412
-
413
- test('response, stream ba, validation OK', async () => {
414
- let bodyStr = 'Hello Mom!'
415
-
416
- let resp = await fetch(`http://localhost:${port}/stream/ba`, {
417
- method: 'POST',
418
- body: bodyStr,
419
- headers: {
420
- 'content-type': 'text/plain',
421
- },
422
- })
423
-
424
- const reader = resp.body?.getReader()
425
- let body = ''
426
- while (reader) {
427
- const { value, done } = await reader.read()
428
- if (done) break
429
- body += decoder.decode(value)
430
- }
431
- expect(resp.status).toBe(200)
432
- expect(resp.headers.get('content-type')).toBe('text/event-stream')
433
- expect(body).toMatch(new RegExp(`id:${UUID_RGX}\ndata:Hello\n\nid:${UUID_RGX}\ndata:Mom!\n\n`))
434
- })
435
-
436
- test('response, stream ba, validation error', async () => {
437
- let bodyStr = ''
438
-
439
- let resp = await fetch(`http://localhost:${port}/stream/ba`, {
440
- method: 'POST',
441
- body: bodyStr,
442
- })
443
-
444
- expect(resp.status).toBe(500)
445
- })
446
-
447
- test('response, stream str, validation OK', async () => {
448
- let bodyStr = 'Hello Mom!'
449
-
450
- let resp = await fetch(`http://localhost:${port}/stream/str`, {
451
- method: 'POST',
452
- body: bodyStr,
453
- headers: {
454
- 'content-type': 'text/plain',
455
- },
456
- })
457
-
458
- const reader = resp.body?.getReader()
459
- let body = ''
460
- while (reader) {
461
- const { value, done } = await reader.read()
462
- if (done) break
463
- body += decoder.decode(value)
464
- }
465
- expect(resp.status).toBe(200)
466
- expect(resp.headers.get('content-type')).toBe('text/event-stream')
467
- expect(body).toMatch(new RegExp(`id:${UUID_RGX}\ndata:Hello\n\nid:${UUID_RGX}\ndata:Mom!\n\n`))
468
- })
469
-
470
- test('response, stream str, validation error', async () => {
471
- let bodyStr = '0'
472
-
473
- let resp = await fetch(`http://localhost:${port}/stream/str`, {
474
- method: 'POST',
475
- body: bodyStr,
476
- headers: {
477
- 'content-type': 'application/json',
478
- },
479
- })
480
-
481
- expect(resp.status).toBe(500)
482
- })
483
- })