galbe 0.12.0 → 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 (42) hide show
  1. package/bin/commands/generate/code/openapi.parser.ts +2 -2
  2. package/package.json +6 -1
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -35
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
  5. package/.github/workflows/build_test.yml +0 -17
  6. package/.github/workflows/deploy_website.yml +0 -20
  7. package/.github/workflows/release.yml +0 -39
  8. package/.prettierrc +0 -10
  9. package/bun.lock +0 -904
  10. package/bunfig.toml +0 -2
  11. package/docs/CONTRIBUTING.md +0 -105
  12. package/docs/cli.md +0 -343
  13. package/docs/configuration.md +0 -80
  14. package/docs/context.md +0 -104
  15. package/docs/error-handler.md +0 -54
  16. package/docs/getting-started.md +0 -164
  17. package/docs/handler.md +0 -119
  18. package/docs/hooks.md +0 -90
  19. package/docs/plugins.md +0 -146
  20. package/docs/router.md +0 -10
  21. package/docs/routes.md +0 -133
  22. package/docs/schemas.md +0 -327
  23. package/test/hooks.test.ts +0 -200
  24. package/test/parser.test.ts +0 -1358
  25. package/test/plugins.test.ts +0 -239
  26. package/test/requests.test.ts +0 -917
  27. package/test/resources/image.png +0 -0
  28. package/test/resources/object.badSyntax.json +0 -8
  29. package/test/resources/object.json +0 -8
  30. package/test/resources/object.missing.json +0 -6
  31. package/test/resources/static/chameleon.png +0 -0
  32. package/test/resources/static/index.html +0 -13
  33. package/test/resources/static/sub/index.html +0 -13
  34. package/test/resources/static/sub/other.html +0 -13
  35. package/test/resources/test.route.comment.ts +0 -58
  36. package/test/resources/test.route.empty.ts +0 -9
  37. package/test/responses.test.ts +0 -483
  38. package/test/routeFiles.test.ts +0 -239
  39. package/test/router.test.ts +0 -231
  40. package/test/test.utils.ts +0 -109
  41. package/test/types.test.ts +0 -909
  42. 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
- })