galbe 0.10.1 → 0.12.0

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.
@@ -7,7 +7,8 @@ import {
7
7
  handleBody,
8
8
  schema_objectBase,
9
9
  handleUrlFormStream,
10
- isAsyncIterator
10
+ isAsyncIterator,
11
+ EMPTY_BA_STR,
11
12
  } from './test.utils'
12
13
  import { Galbe, $T } from '../src'
13
14
  import { schemaToTypeStr } from '../src/schema'
@@ -29,8 +30,8 @@ describe('parser', () => {
29
30
  float: $T.number(),
30
31
  integer: $T.integer(),
31
32
  'boolean-true': $T.boolean(),
32
- 'boolean-false': $T.boolean()
33
- }
33
+ 'boolean-false': $T.boolean(),
34
+ },
34
35
  },
35
36
  ctx => {
36
37
  return ctx.headers
@@ -44,8 +45,8 @@ describe('parser', () => {
44
45
  p1: $T.string(),
45
46
  p2: $T.number(),
46
47
  p3: $T.integer(),
47
- p4: $T.boolean()
48
- }
48
+ p4: $T.boolean(),
49
+ },
49
50
  },
50
51
  ctx => {
51
52
  return ctx.params
@@ -60,8 +61,8 @@ describe('parser', () => {
60
61
  p2: $T.number(),
61
62
  p3: $T.boolean(),
62
63
  p4: $T.union([$T.number(), $T.boolean()]),
63
- p5: $T.optional($T.string())
64
- }
64
+ p5: $T.optional($T.string()),
65
+ },
65
66
  },
66
67
  ctx => {
67
68
  return ctx.query
@@ -74,66 +75,86 @@ describe('parser', () => {
74
75
  default: $T.optional($T.string({ default: 'DEFAULT_VALUE' })),
75
76
  int: $T.integer({ exclusiveMin: 10, max: 42 }),
76
77
  num: $T.number({ min: 10, exclusiveMax: 42 }),
77
- str: $T.string({ minLength: 4, maxLength: 8, pattern: /^a.*z/ })
78
- }
78
+ str: $T.string({ minLength: 4, maxLength: 8, pattern: /^a.*z/ }),
79
+ },
79
80
  },
80
81
  ctx => {
81
82
  return ctx.query
82
83
  }
83
84
  )
84
85
 
85
- galbe.post('/obj/schema/base', { body: $T.object(schema_object) }, handleBody)
86
+ galbe.post('/obj/schema/base', { body: { json: $T.object(schema_object) } }, handleBody)
86
87
 
87
88
  galbe.post(
88
89
  '/form/schema/base',
89
90
  {
90
- body: $T.urlForm({
91
- ...schema_objectBase,
92
- union: $T.optional($T.union([$T.number(), $T.boolean()])),
93
- literal: $T.optional($T.literal('x')),
94
- array: $T.array()
95
- })
91
+ body: {
92
+ urlForm: $T.object({
93
+ ...schema_objectBase,
94
+ object: $T.optional($T.object({ nested: $T.object({ foo: $T.literal('bar') }), baz: $T.number() })),
95
+ union: $T.optional($T.union([$T.number(), $T.boolean()])),
96
+ literal: $T.optional($T.literal('x')),
97
+ array: $T.array(),
98
+ }),
99
+ },
96
100
  },
97
101
  handleBody
98
102
  )
99
103
  galbe.post(
100
104
  '/form/stream/schema/base',
101
105
  {
102
- body: $T.stream(
103
- $T.urlForm({
106
+ body: {
107
+ urlForm: $T.stream(
108
+ $T.object({
109
+ ...schema_objectBase,
110
+ union: $T.optional($T.union([$T.number(), $T.boolean()])),
111
+ literal: $T.optional($T.literal('x')),
112
+ array: $T.array($T.any()),
113
+ numArray: $T.optional($T.array($T.number())),
114
+ })
115
+ ),
116
+ },
117
+ },
118
+ handleUrlFormStream
119
+ )
120
+ galbe.post(
121
+ '/mp/schema/base',
122
+ {
123
+ body: {
124
+ multipart: $T.multipartForm({
104
125
  ...schema_objectBase,
105
126
  union: $T.optional($T.union([$T.number(), $T.boolean()])),
106
127
  literal: $T.optional($T.literal('x')),
107
128
  array: $T.array($T.any()),
108
- numArray: $T.optional($T.array($T.number()))
109
- })
110
- )
129
+ }),
130
+ },
111
131
  },
112
- handleUrlFormStream
132
+ handleBody
113
133
  )
114
134
  galbe.post(
115
- '/mp/schema/base',
135
+ '/mp/schema/file',
116
136
  {
117
- body: $T.multipartForm({
118
- ...schema_objectBase,
119
- union: $T.optional($T.union([$T.number(), $T.boolean()])),
120
- literal: $T.optional($T.literal('x')),
121
- array: $T.array($T.any())
122
- })
137
+ body: {
138
+ multipart: $T.multipartForm({
139
+ foo: $T.byteArray(),
140
+ }),
141
+ },
123
142
  },
124
143
  handleBody
125
144
  )
126
145
  galbe.post(
127
146
  '/mp/stream/schema/base',
128
147
  {
129
- body: $T.stream(
130
- $T.multipartForm({
131
- ...schema_objectBase,
132
- union: $T.optional($T.union([$T.number(), $T.boolean()])),
133
- literal: $T.optional($T.literal('x')),
134
- array: $T.array($T.any())
135
- })
136
- )
148
+ body: {
149
+ multipart: $T.stream(
150
+ $T.multipartForm({
151
+ ...schema_objectBase,
152
+ union: $T.optional($T.union([$T.number(), $T.boolean()])),
153
+ literal: $T.optional($T.literal('x')),
154
+ array: $T.array($T.any()),
155
+ })
156
+ ),
157
+ },
137
158
  },
138
159
  handleBody
139
160
  )
@@ -144,17 +165,21 @@ describe('parser', () => {
144
165
  bool: $T.boolean(),
145
166
  arrayStr: $T.array($T.string()),
146
167
  arrayNumber: $T.array($T.number()),
147
- arrayBool: $T.array($T.boolean())
168
+ arrayBool: $T.array($T.boolean()),
148
169
  }
149
170
 
150
171
  galbe.post(
151
172
  '/mp/file',
152
- { body: $T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) }) },
173
+ { body: { multipart: $T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) }) } },
153
174
  handleBody
154
175
  )
155
176
  galbe.post(
156
177
  '/mp/stream/file',
157
- { body: $T.stream($T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) })) },
178
+ {
179
+ body: {
180
+ multipart: $T.stream($T.multipartForm({ imgFile: $T.byteArray(), jsonFile: $T.object(schema_jsonFile) })),
181
+ },
182
+ },
158
183
  async ctx => {
159
184
  if (isAsyncIterator(ctx.body)) {
160
185
  const chunks: any[] = []
@@ -169,14 +194,14 @@ describe('parser', () => {
169
194
  }
170
195
  }
171
196
  )
172
- galbe.post('/ba/file', { body: $T.byteArray() }, async ctx => {
197
+ galbe.post('/ba/file', { body: { byteArray: $T.byteArray() } }, async ctx => {
173
198
  if (ctx?.body instanceof Uint8Array) {
174
199
  return { type: 'byteArray', content: await fileHash(ctx.body) }
175
200
  } else {
176
201
  return { type: null, content: 'error' }
177
202
  }
178
203
  })
179
- galbe.post('/ba/stream/file', { body: $T.stream($T.byteArray()) }, async ctx => {
204
+ galbe.post('/ba/stream/file', { body: { byteArray: $T.stream($T.byteArray()) } }, async ctx => {
180
205
  if (isAsyncIterator(ctx.body)) {
181
206
  let bytes = new Uint8Array()
182
207
  for await (const b of ctx.body) {
@@ -202,7 +227,7 @@ describe('parser', () => {
202
227
  float: '3.14',
203
228
  integer: '42',
204
229
  'boolean-true': 'true',
205
- 'boolean-false': 'false'
230
+ 'boolean-false': 'false',
206
231
  },
207
232
  expected: {
208
233
  body: {
@@ -213,9 +238,9 @@ describe('parser', () => {
213
238
  float: 3.14,
214
239
  integer: 42,
215
240
  'boolean-true': true,
216
- 'boolean-false': false
217
- }
218
- }
241
+ 'boolean-false': false,
242
+ },
243
+ },
219
244
  },
220
245
  {
221
246
  h: {
@@ -225,18 +250,18 @@ describe('parser', () => {
225
250
  float: '3.14',
226
251
  integer: '42',
227
252
  'boolean-true': 'a',
228
- 'boolean-false': 'false'
253
+ 'boolean-false': 'false',
229
254
  },
230
255
  expected: {
231
256
  status: 400,
232
257
  body: {
233
258
  headers: {
234
259
  'neg-number': 'Required',
235
- 'boolean-true': "Not a valid boolean. Should be 'true' or 'false'"
236
- }
237
- }
238
- }
239
- }
260
+ 'boolean-true': "Not a valid boolean. Should be 'true' or 'false'",
261
+ },
262
+ },
263
+ },
264
+ },
240
265
  ]
241
266
 
242
267
  for (let { h, expected } of cases) {
@@ -251,7 +276,7 @@ describe('parser', () => {
251
276
  const cases: any = [
252
277
  {
253
278
  p: { p1: 'one', p2: '3.14', p3: '42', p4: 'true' },
254
- expected: { body: { p1: 'one', p2: 3.14, p3: 42, p4: true } }
279
+ expected: { body: { p1: 'one', p2: 3.14, p3: 42, p4: true } },
255
280
  },
256
281
  {
257
282
  p: { p1: '_', p2: 'test', p3: '42.5', p4: 'a' },
@@ -261,11 +286,11 @@ describe('parser', () => {
261
286
  params: {
262
287
  p2: 'Not a valid number',
263
288
  p3: 'Not a valid integer',
264
- p4: "Not a valid boolean. Should be 'true' or 'false'"
265
- }
266
- }
267
- }
268
- }
289
+ p4: "Not a valid boolean. Should be 'true' or 'false'",
290
+ },
291
+ },
292
+ },
293
+ },
269
294
  ]
270
295
  for (let { p, expected } of cases) {
271
296
  let resp = await fetch(`http://localhost:${port}/params/schema/${p.p1}/${p.p2}/${p.p3}/${p.p4}`)
@@ -279,11 +304,11 @@ describe('parser', () => {
279
304
  const cases: any = [
280
305
  {
281
306
  p: { p1: 'one', p2: '3.14', p3: 'false', p4: '42' },
282
- expected: { body: { p1: 'one', p2: 3.14, p3: false, p4: 42 } }
307
+ expected: { body: { p1: 'one', p2: 3.14, p3: false, p4: 42 } },
283
308
  },
284
309
  {
285
310
  p: { p1: 'one', p2: '3.14', p3: 'true', p4: 'true', p5: 'hello' },
286
- expected: { body: { p1: 'one', p2: 3.14, p3: true, p4: true, p5: 'hello' } }
311
+ expected: { body: { p1: 'one', p2: 3.14, p3: true, p4: true, p5: 'hello' } },
287
312
  },
288
313
  {
289
314
  p: { p1: '36', p2: 'a', p3: '0' },
@@ -293,11 +318,11 @@ describe('parser', () => {
293
318
  query: {
294
319
  p2: 'Not a valid number',
295
320
  p3: "Not a valid boolean. Should be 'true' or 'false'",
296
- p4: 'Required'
297
- }
298
- }
299
- }
300
- }
321
+ p4: 'Required',
322
+ },
323
+ },
324
+ },
325
+ },
301
326
  ]
302
327
 
303
328
  for (let { p, expected } of cases) {
@@ -312,6 +337,21 @@ describe('parser', () => {
312
337
  }
313
338
  })
314
339
 
340
+ test('query params, duplicates', async () => {
341
+ const search = new URLSearchParams()
342
+ search.append('p1', 'one')
343
+ search.append('p1', 'two')
344
+ search.append('p2', '3.14')
345
+ search.append('p3', 'true')
346
+ search.append('p4', '42')
347
+
348
+ let resp = await fetch(`http://localhost:${port}/query/params/schema?${search.toString()}`)
349
+ let body = await resp.json()
350
+
351
+ expect(resp.status).toBe(400)
352
+ expect(body).toEqual({ query: { p1: 'Multiple values found' } })
353
+ })
354
+
315
355
  test('body, json, schema object', async () => {
316
356
  const type = 'application/json'
317
357
  const schema = 'obj/schema/base'
@@ -327,7 +367,7 @@ describe('parser', () => {
327
367
  any: false,
328
368
  null: null,
329
369
  nullable: null,
330
- nullish: 42
370
+ nullish: 42,
331
371
  }),
332
372
  type,
333
373
  schema,
@@ -344,9 +384,9 @@ describe('parser', () => {
344
384
  any: false,
345
385
  null: null,
346
386
  nullable: null,
347
- nullish: 42
348
- }
349
- }
387
+ nullish: 42,
388
+ },
389
+ },
350
390
  },
351
391
  {
352
392
  body: JSON.stringify({
@@ -360,7 +400,7 @@ describe('parser', () => {
360
400
  optional: 'optional',
361
401
  null: null,
362
402
  nullable: 'test',
363
- nullish: null
403
+ nullish: null,
364
404
  }),
365
405
  type,
366
406
  schema,
@@ -378,9 +418,9 @@ describe('parser', () => {
378
418
  optional: 'optional',
379
419
  null: null,
380
420
  nullable: 'test',
381
- nullish: null
382
- }
383
- }
421
+ nullish: null,
422
+ },
423
+ },
384
424
  },
385
425
  {
386
426
  body: JSON.stringify({
@@ -391,7 +431,7 @@ describe('parser', () => {
391
431
  object: [],
392
432
  array: {},
393
433
  any: {},
394
- null: ''
434
+ null: '',
395
435
  }),
396
436
  type,
397
437
  schema,
@@ -406,17 +446,17 @@ describe('parser', () => {
406
446
  object: 'Expected an object, not an array',
407
447
  array: 'Not a valid array',
408
448
  null: 'Expected null value got ',
409
- nullable: 'Required'
410
- }
411
- }
412
- }
413
- }
449
+ nullable: 'Required',
450
+ },
451
+ },
452
+ },
453
+ },
414
454
  ]
415
455
  for (let { body, type, schema, expected } of cases) {
416
456
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
417
457
  method: 'POST',
418
458
  body,
419
- headers: { ...(type ? { 'content-type': type } : {}) }
459
+ headers: { ...(type ? { 'content-type': type } : {}) },
420
460
  })
421
461
  let respBody = (await resp.json()) as { type: string; content: any }
422
462
 
@@ -445,15 +485,15 @@ describe('parser', () => {
445
485
  status: 200,
446
486
  type: 'object',
447
487
  resp: {
448
- ba: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
488
+ ba: EMPTY_BA_STR,
449
489
  string: '',
450
490
  number: 0,
451
491
  bool: false,
452
492
  any: 'false',
453
493
  union: true,
454
- array: []
455
- }
456
- }
494
+ array: [],
495
+ },
496
+ },
457
497
  },
458
498
  {
459
499
  body: 'ba=Hello&string=Mom!&number=42&bool=true&any=36&optional=optional&array=1&array=2&literal=x&union=42',
@@ -471,9 +511,9 @@ describe('parser', () => {
471
511
  optional: 'optional',
472
512
  literal: 'x',
473
513
  union: 42,
474
- array: ['1', '2']
475
- }
476
- }
514
+ array: ['1', '2'],
515
+ },
516
+ },
477
517
  },
478
518
  {
479
519
  body: 'optional=optional',
@@ -483,9 +523,9 @@ describe('parser', () => {
483
523
  status: 400,
484
524
  type: 'object',
485
525
  resp: {
486
- body: 'Missing fields: ba, string, number, bool, any'
487
- }
488
- }
526
+ body: 'Missing fields: ba, string, number, bool, any',
527
+ },
528
+ },
489
529
  },
490
530
  {
491
531
  body: 'ba=&string=Hello&string=Mom!&number=aaa&bool=1&any=36&literal=y&union=X',
@@ -499,20 +539,60 @@ describe('parser', () => {
499
539
  number: 'Not a valid number',
500
540
  bool: "Not a valid boolean. Should be 'true' or 'false'",
501
541
  literal: 'Not a valid value',
502
- union: 'Could not be parsed to any of [number, boolean]'
503
- }
504
- }
505
- }
506
- }
542
+ union: 'Could not be parsed to any of [number, boolean]',
543
+ },
544
+ },
545
+ },
546
+ },
547
+ {
548
+ body: 'object=%7B%22nested%22%3A%7B%22foo%22%3A%22bar%22%7D%2C%22baz%22%3A42%7D&ba=&string=&number=0&bool=false&any=any',
549
+ type,
550
+ schema,
551
+ expected: {
552
+ status: 200,
553
+ resp: {
554
+ object: { nested: { foo: 'bar' }, baz: 42 },
555
+ any: 'any',
556
+ string: '',
557
+ array: [],
558
+ ba: EMPTY_BA_STR,
559
+ bool: false,
560
+ number: 0,
561
+ },
562
+ },
563
+ },
564
+ {
565
+ body: 'object=&ba=&string=&number=0&bool=false&any=any',
566
+ type,
567
+ schema,
568
+ expected: {
569
+ status: 400,
570
+ resp: {
571
+ body: { object: 'Not a valid object' },
572
+ },
573
+ },
574
+ },
575
+ {
576
+ body: 'object=%7B%22nested%22%3A%7B%22foo%22%3A%22toto%22%7D%2C%22baz%22%3A42%7D&ba=&string=&number=0&bool=false&any=any',
577
+ type,
578
+ schema,
579
+ expected: {
580
+ status: 400,
581
+ resp: {
582
+ body: { object: { nested: { foo: 'Not a valid value. Found "toto" but expected "bar"' } } },
583
+ },
584
+ },
585
+ },
507
586
  ]
508
587
  for (let { body, type, schema, expected } of cases) {
509
588
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
510
589
  method: 'POST',
511
590
  body,
512
- headers: { ...(type ? { 'content-type': type } : {}) }
591
+ headers: { ...(type ? { 'content-type': type } : {}) },
513
592
  })
514
593
  let respBody = (await resp.json()) as { type: string; content: any }
515
594
 
595
+ console.log(respBody)
516
596
  expect(resp.status).toBe(expected.status)
517
597
  if (resp.status === 200) {
518
598
  if (expected.type) expect(respBody.type).toEqual(expected.type)
@@ -544,9 +624,9 @@ describe('parser', () => {
544
624
  bool: false,
545
625
  any: 'false',
546
626
  union: true,
547
- array: []
548
- }
549
- }
627
+ array: [],
628
+ },
629
+ },
550
630
  },
551
631
  {
552
632
  body: 'ba=Hello&string=Mom!&number=42&bool=true&any=36&optional=optional&array=1&array=2&literal=x&union=42',
@@ -564,9 +644,9 @@ describe('parser', () => {
564
644
  optional: 'optional',
565
645
  literal: 'x',
566
646
  union: 42,
567
- array: ['1', '2']
568
- }
569
- }
647
+ array: ['1', '2'],
648
+ },
649
+ },
570
650
  },
571
651
  {
572
652
  body: 'ba=Hello&string=Mom!&number=42&bool=true&any=36&optional=optional&array=1&array=2&literal=x&union=42&numArray=x',
@@ -576,9 +656,9 @@ describe('parser', () => {
576
656
  status: 400,
577
657
  type: 'object',
578
658
  resp: {
579
- body: { numArray: 'Not a valid number' }
580
- }
581
- }
659
+ body: { numArray: 'Not a valid number' },
660
+ },
661
+ },
582
662
  },
583
663
  {
584
664
  body: 'ba=&string=Hello&string=Mom!&number=1&bool=true&any=36&literal=y&union=X',
@@ -588,10 +668,10 @@ describe('parser', () => {
588
668
  status: 400,
589
669
  resp: {
590
670
  body: {
591
- literal: 'Not a valid value'
592
- }
593
- }
594
- }
671
+ literal: 'Not a valid value',
672
+ },
673
+ },
674
+ },
595
675
  },
596
676
  {
597
677
  body: 'optional=otpional',
@@ -600,16 +680,16 @@ describe('parser', () => {
600
680
  expected: {
601
681
  status: 400,
602
682
  resp: {
603
- body: 'Missing fields: ba, string, number, bool, any'
604
- }
605
- }
606
- }
683
+ body: 'Missing fields: ba, string, number, bool, any',
684
+ },
685
+ },
686
+ },
607
687
  ]
608
688
  for (let { body, type, schema, expected } of cases) {
609
689
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
610
690
  method: 'POST',
611
691
  body,
612
- headers: { ...(type ? { 'content-type': type } : {}) }
692
+ headers: { ...(type ? { 'content-type': type } : {}) },
613
693
  })
614
694
  let respBody = (await resp.json()) as any
615
695
 
@@ -628,6 +708,9 @@ describe('parser', () => {
628
708
  test('body, MultipartForm, schema object', async () => {
629
709
  const schema = 'mp/schema/base'
630
710
 
711
+ const formWithHeader = formdata({})
712
+ formWithHeader.append('foo', new Blob([new Uint8Array()], { type: 'image/png' }), 'foo.png')
713
+
631
714
  const cases: Case[] = [
632
715
  {
633
716
  body: formdata({ ba: '', string: '', number: '0', bool: 'false', any: 'false', union: 'true' }),
@@ -637,49 +720,67 @@ describe('parser', () => {
637
720
  type: 'object',
638
721
  resp: {
639
722
  ba: {
640
- content: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
723
+ content: EMPTY_BA_STR,
641
724
  headers: {
642
- name: 'ba'
643
- }
725
+ name: 'ba',
726
+ },
644
727
  },
645
728
  string: {
646
729
  content: '',
647
730
  headers: {
648
- name: 'string'
649
- }
731
+ name: 'string',
732
+ },
650
733
  },
651
734
  number: {
652
735
  content: 0,
653
736
  headers: {
654
- name: 'number'
655
- }
737
+ name: 'number',
738
+ },
656
739
  },
657
740
  bool: {
658
741
  content: false,
659
742
  headers: {
660
- name: 'bool'
661
- }
743
+ name: 'bool',
744
+ },
662
745
  },
663
746
  any: {
664
747
  content: 'false',
665
748
  headers: {
666
- name: 'any'
667
- }
749
+ name: 'any',
750
+ },
668
751
  },
669
752
  union: {
670
753
  content: true,
671
754
  headers: {
672
- name: 'union'
673
- }
755
+ name: 'union',
756
+ },
674
757
  },
675
758
  array: {
676
759
  content: [],
677
760
  headers: {
678
- name: 'array'
679
- }
680
- }
681
- }
682
- }
761
+ name: 'array',
762
+ },
763
+ },
764
+ },
765
+ },
766
+ },
767
+ {
768
+ body: formWithHeader,
769
+ schema: 'mp/schema/file',
770
+ expected: {
771
+ status: 200,
772
+ type: 'object',
773
+ resp: {
774
+ foo: {
775
+ content: EMPTY_BA_STR,
776
+ headers: {
777
+ name: 'foo',
778
+ filename: 'foo.png',
779
+ type: 'image/png',
780
+ },
781
+ },
782
+ },
783
+ },
683
784
  },
684
785
  {
685
786
  body: formdata({
@@ -691,7 +792,7 @@ describe('parser', () => {
691
792
  optional: 'optional',
692
793
  array: ['1', '2'],
693
794
  literal: 'x',
694
- union: '42'
795
+ union: '42',
695
796
  }),
696
797
  schema,
697
798
  expected: {
@@ -701,59 +802,59 @@ describe('parser', () => {
701
802
  ba: {
702
803
  content: '185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969',
703
804
  headers: {
704
- name: 'ba'
705
- }
805
+ name: 'ba',
806
+ },
706
807
  },
707
808
  string: {
708
809
  content: 'Mom!',
709
810
  headers: {
710
- name: 'string'
711
- }
811
+ name: 'string',
812
+ },
712
813
  },
713
814
  number: {
714
815
  content: 42,
715
816
  headers: {
716
- name: 'number'
717
- }
817
+ name: 'number',
818
+ },
718
819
  },
719
820
  bool: {
720
821
  content: true,
721
822
  headers: {
722
- name: 'bool'
723
- }
823
+ name: 'bool',
824
+ },
724
825
  },
725
826
  any: {
726
827
  content: '36',
727
828
  headers: {
728
- name: 'any'
729
- }
829
+ name: 'any',
830
+ },
730
831
  },
731
832
  optional: {
732
833
  content: 'optional',
733
834
  headers: {
734
- name: 'optional'
735
- }
835
+ name: 'optional',
836
+ },
736
837
  },
737
838
  array: {
738
839
  content: ['1', '2'],
739
840
  headers: {
740
- name: 'array'
741
- }
841
+ name: 'array',
842
+ },
742
843
  },
743
844
  literal: {
744
845
  content: 'x',
745
846
  headers: {
746
- name: 'literal'
747
- }
847
+ name: 'literal',
848
+ },
748
849
  },
749
850
  union: {
750
851
  content: 42,
751
852
  headers: {
752
- name: 'union'
753
- }
754
- }
755
- }
756
- }
853
+ name: 'union',
854
+ },
855
+ },
856
+ },
857
+ },
757
858
  },
758
859
  {
759
860
  body: formdata({ optional: 'optional' }),
@@ -762,9 +863,9 @@ describe('parser', () => {
762
863
  status: 400,
763
864
  type: 'object',
764
865
  resp: {
765
- body: 'Missing fields: ba, string, number, bool, any'
766
- }
767
- }
866
+ body: 'Missing fields: ba, string, number, bool, any',
867
+ },
868
+ },
768
869
  },
769
870
  {
770
871
  body: formdata({
@@ -774,7 +875,7 @@ describe('parser', () => {
774
875
  bool: '1',
775
876
  any: '36',
776
877
  literal: 'y',
777
- union: 'X'
878
+ union: 'X',
778
879
  }),
779
880
  schema,
780
881
  expected: {
@@ -784,18 +885,18 @@ describe('parser', () => {
784
885
  string: 'Multiple values found',
785
886
  number: 'Not a valid number',
786
887
  bool: "Not a valid boolean. Should be 'true' or 'false'",
787
- literal: 'Not a valid value',
788
- union: 'Could not be parsed to any of [number, boolean]'
789
- }
790
- }
791
- }
792
- }
888
+ literal: 'Not a valid value. Found "y" but expected "x"',
889
+ union: 'Could not be parsed to any of [number, boolean]',
890
+ },
891
+ },
892
+ },
893
+ },
793
894
  ]
794
895
  for (let { body, type, schema, expected } of cases) {
795
896
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
796
897
  method: 'POST',
797
898
  body,
798
- headers: { ...(type ? { 'content-type': type } : {}) }
899
+ headers: { ...(type ? { 'content-type': type } : {}) },
799
900
  })
800
901
  let respBody = (await resp.json()) as { type: string; content: any }
801
902
 
@@ -825,47 +926,47 @@ describe('parser', () => {
825
926
  {
826
927
  content: {},
827
928
  headers: {
828
- name: 'ba'
829
- }
929
+ name: 'ba',
930
+ },
830
931
  },
831
932
  {
832
933
  content: '',
833
934
  headers: {
834
- name: 'string'
835
- }
935
+ name: 'string',
936
+ },
836
937
  },
837
938
  {
838
939
  content: 0,
839
940
  headers: {
840
- name: 'number'
841
- }
941
+ name: 'number',
942
+ },
842
943
  },
843
944
  {
844
945
  content: false,
845
946
  headers: {
846
- name: 'bool'
847
- }
947
+ name: 'bool',
948
+ },
848
949
  },
849
950
  {
850
951
  content: 'false',
851
952
  headers: {
852
- name: 'any'
853
- }
953
+ name: 'any',
954
+ },
854
955
  },
855
956
  {
856
957
  content: true,
857
958
  headers: {
858
- name: 'union'
859
- }
959
+ name: 'union',
960
+ },
860
961
  },
861
962
  {
862
963
  content: [],
863
964
  headers: {
864
- name: 'array'
865
- }
866
- }
867
- ]
868
- }
965
+ name: 'array',
966
+ },
967
+ },
968
+ ],
969
+ },
869
970
  },
870
971
  {
871
972
  body: formdata({
@@ -877,7 +978,7 @@ describe('parser', () => {
877
978
  optional: 'optional',
878
979
  array: ['1', '2'],
879
980
  literal: 'x',
880
- union: '42'
981
+ union: '42',
881
982
  }),
882
983
  schema,
883
984
  expected: {
@@ -887,65 +988,65 @@ describe('parser', () => {
887
988
  {
888
989
  content: Object.fromEntries(Uint8Array.from('Hello', c => c.charCodeAt(0)).entries()),
889
990
  headers: {
890
- name: 'ba'
891
- }
991
+ name: 'ba',
992
+ },
892
993
  },
893
994
  {
894
995
  content: 'Mom!',
895
996
  headers: {
896
- name: 'string'
897
- }
997
+ name: 'string',
998
+ },
898
999
  },
899
1000
  {
900
1001
  content: 42,
901
1002
  headers: {
902
- name: 'number'
903
- }
1003
+ name: 'number',
1004
+ },
904
1005
  },
905
1006
  {
906
1007
  content: true,
907
1008
  headers: {
908
- name: 'bool'
909
- }
1009
+ name: 'bool',
1010
+ },
910
1011
  },
911
1012
  {
912
1013
  content: '36',
913
1014
  headers: {
914
- name: 'any'
915
- }
1015
+ name: 'any',
1016
+ },
916
1017
  },
917
1018
  {
918
1019
  content: 'optional',
919
1020
  headers: {
920
- name: 'optional'
921
- }
1021
+ name: 'optional',
1022
+ },
922
1023
  },
923
1024
  {
924
1025
  content: '1',
925
1026
  headers: {
926
- name: 'array'
927
- }
1027
+ name: 'array',
1028
+ },
928
1029
  },
929
1030
  {
930
1031
  content: '2',
931
1032
  headers: {
932
- name: 'array'
933
- }
1033
+ name: 'array',
1034
+ },
934
1035
  },
935
1036
  {
936
1037
  content: 'x',
937
1038
  headers: {
938
- name: 'literal'
939
- }
1039
+ name: 'literal',
1040
+ },
940
1041
  },
941
1042
  {
942
1043
  content: 42,
943
1044
  headers: {
944
- name: 'union'
945
- }
946
- }
947
- ]
948
- }
1045
+ name: 'union',
1046
+ },
1047
+ },
1048
+ ],
1049
+ },
949
1050
  },
950
1051
  {
951
1052
  body: formdata({ optional: 'optional' }),
@@ -954,9 +1055,9 @@ describe('parser', () => {
954
1055
  status: 400,
955
1056
  type: 'object',
956
1057
  resp: {
957
- body: 'Missing fields: ba, string, number, bool, any'
958
- }
959
- }
1058
+ body: 'Missing fields: ba, string, number, bool, any',
1059
+ },
1060
+ },
960
1061
  },
961
1062
  {
962
1063
  body: formdata({
@@ -966,24 +1067,24 @@ describe('parser', () => {
966
1067
  bool: '1',
967
1068
  any: '36',
968
1069
  literal: 'y',
969
- union: 'X'
1070
+ union: 'X',
970
1071
  }),
971
1072
  schema,
972
1073
  expected: {
973
1074
  status: 400,
974
1075
  resp: {
975
1076
  body: {
976
- number: 'Not a valid number'
977
- }
978
- }
979
- }
980
- }
1077
+ number: 'Not a valid number',
1078
+ },
1079
+ },
1080
+ },
1081
+ },
981
1082
  ]
982
1083
  for (let { body, type, schema, expected } of cases) {
983
1084
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
984
1085
  method: 'POST',
985
1086
  body,
986
- headers: { ...(type ? { 'content-type': type } : {}) }
1087
+ headers: { ...(type ? { 'content-type': type } : {}) },
987
1088
  })
988
1089
  let respBody = (await resp.json()) as { type: string; content: any }
989
1090
 
@@ -1020,8 +1121,8 @@ describe('parser', () => {
1020
1121
  headers: {
1021
1122
  name: 'imgFile',
1022
1123
  filename: 'test/resources/image.png',
1023
- type: 'image/png'
1024
- }
1124
+ type: 'image/png',
1125
+ },
1025
1126
  },
1026
1127
  jsonFile: {
1027
1128
  content: {
@@ -1030,16 +1131,16 @@ describe('parser', () => {
1030
1131
  bool: true,
1031
1132
  arrayStr: ['un', 'deux', 'trois'],
1032
1133
  arrayNumber: [0],
1033
- arrayBool: [true, false]
1134
+ arrayBool: [true, false],
1034
1135
  },
1035
1136
  headers: {
1036
1137
  name: 'jsonFile',
1037
1138
  filename: 'test/resources/object.json',
1038
- type: 'application/json'
1039
- }
1040
- }
1041
- }
1042
- }
1139
+ type: 'application/json',
1140
+ },
1141
+ },
1142
+ },
1143
+ },
1043
1144
  },
1044
1145
  {
1045
1146
  body: formdata({ imgFile, jsonFile: missingJsonFile }),
@@ -1047,9 +1148,9 @@ describe('parser', () => {
1047
1148
  expected: {
1048
1149
  status: 400,
1049
1150
  resp: {
1050
- body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } }
1051
- }
1052
- }
1151
+ body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } },
1152
+ },
1153
+ },
1053
1154
  },
1054
1155
  {
1055
1156
  body: formdata({ imgFile, jsonFile: badSyntaxJsonFile }),
@@ -1057,25 +1158,26 @@ describe('parser', () => {
1057
1158
  expected: {
1058
1159
  status: 400,
1059
1160
  resp: {
1060
- body: { jsonFile: "JSON Parse error: Expected '}'" }
1061
- }
1062
- }
1161
+ body: { jsonFile: "JSON Parse error: Expected '}'" },
1162
+ },
1163
+ },
1063
1164
  },
1064
1165
  {
1065
1166
  body: imgFileBytes,
1066
1167
  schema: '/ba/file',
1168
+ type: 'application/octet-stream',
1067
1169
  expected: {
1068
1170
  status: 200,
1069
1171
  type: 'byteArray',
1070
- resp: await fileHash(imgFileBytes)
1071
- }
1072
- }
1172
+ resp: await fileHash(imgFileBytes),
1173
+ },
1174
+ },
1073
1175
  ]
1074
1176
  for (let { body, type, schema, expected } of cases) {
1075
1177
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
1076
1178
  method: 'POST',
1077
1179
  body,
1078
- headers: { ...(type ? { 'content-type': type } : {}) }
1180
+ headers: { ...(type ? { 'content-type': type } : {}) },
1079
1181
  })
1080
1182
  let respBody = (await resp.json()) as { type: string; content: any }
1081
1183
 
@@ -1112,8 +1214,8 @@ describe('parser', () => {
1112
1214
  headers: {
1113
1215
  name: 'imgFile',
1114
1216
  filename: 'test/resources/image.png',
1115
- type: 'image/png'
1116
- }
1217
+ type: 'image/png',
1218
+ },
1117
1219
  },
1118
1220
  {
1119
1221
  content: {
@@ -1122,16 +1224,16 @@ describe('parser', () => {
1122
1224
  bool: true,
1123
1225
  arrayStr: ['un', 'deux', 'trois'],
1124
1226
  arrayNumber: [0],
1125
- arrayBool: [true, false]
1227
+ arrayBool: [true, false],
1126
1228
  },
1127
1229
  headers: {
1128
1230
  name: 'jsonFile',
1129
1231
  filename: 'test/resources/object.json',
1130
- type: 'application/json'
1131
- }
1132
- }
1133
- ]
1134
- }
1232
+ type: 'application/json',
1233
+ },
1234
+ },
1235
+ ],
1236
+ },
1135
1237
  },
1136
1238
  {
1137
1239
  body: formdata({ imgFile, jsonFile: missingJsonFile }),
@@ -1139,9 +1241,9 @@ describe('parser', () => {
1139
1241
  expected: {
1140
1242
  status: 400,
1141
1243
  resp: {
1142
- body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } }
1143
- }
1144
- }
1244
+ body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } },
1245
+ },
1246
+ },
1145
1247
  },
1146
1248
  {
1147
1249
  body: formdata({ imgFile, jsonFile: badSyntaxJsonFile }),
@@ -1149,25 +1251,26 @@ describe('parser', () => {
1149
1251
  expected: {
1150
1252
  status: 400,
1151
1253
  resp: {
1152
- body: { jsonFile: "JSON Parse error: Expected '}'" }
1153
- }
1154
- }
1254
+ body: { jsonFile: "JSON Parse error: Expected '}'" },
1255
+ },
1256
+ },
1155
1257
  },
1156
1258
  {
1157
1259
  body: imgFileBytes,
1158
1260
  schema: '/ba/stream/file',
1261
+ type: 'application/octet-stream',
1159
1262
  expected: {
1160
1263
  status: 200,
1161
1264
  type: 'AsyncIterator',
1162
- resp: await fileHash(imgFileBytes)
1163
- }
1164
- }
1265
+ resp: await fileHash(imgFileBytes),
1266
+ },
1267
+ },
1165
1268
  ]
1166
1269
  for (let { body, type, schema, expected } of cases) {
1167
1270
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
1168
1271
  method: 'POST',
1169
1272
  body,
1170
- headers: { ...(type ? { 'content-type': type } : {}) }
1273
+ headers: { ...(type ? { 'content-type': type } : {}) },
1171
1274
  })
1172
1275
  let respBody = (await resp.json()) as { type: string; content: any }
1173
1276
 
@@ -1187,11 +1290,11 @@ describe('parser', () => {
1187
1290
  const cases: any = [
1188
1291
  {
1189
1292
  p: { int: '11', num: '10', str: 'aaaz' },
1190
- expected: { body: { default: 'DEFAULT_VALUE', int: 11, num: 10, str: 'aaaz' } }
1293
+ expected: { body: { default: 'DEFAULT_VALUE', int: 11, num: 10, str: 'aaaz' } },
1191
1294
  },
1192
1295
  {
1193
1296
  p: { default: '', int: '42', num: '41.5', str: 'a______z' },
1194
- expected: { body: { default: '', int: 42, num: 41.5, str: 'a______z' } }
1297
+ expected: { body: { default: '', int: 42, num: 41.5, str: 'a______z' } },
1195
1298
  },
1196
1299
  {
1197
1300
  p: { int: '10', num: '42.01', str: 'xxxxxxxxxx' },
@@ -1201,11 +1304,11 @@ describe('parser', () => {
1201
1304
  query: {
1202
1305
  int: 'Is less or equal to 10',
1203
1306
  num: 'Is greater or equal to 42',
1204
- str: ['Length is too large (8 char max)', 'Does not match pattern /^a.*z/']
1205
- }
1206
- }
1207
- }
1208
- }
1307
+ str: ['Length is too large (8 char max)', 'Does not match pattern /^a.*z/'],
1308
+ },
1309
+ },
1310
+ },
1311
+ },
1209
1312
  ]
1210
1313
 
1211
1314
  for (let { p, expected } of cases) {
@@ -1232,24 +1335,24 @@ describe('parser', () => {
1232
1335
  literal: $T.literal('literal'),
1233
1336
  array: $T.array($T.string()),
1234
1337
  object: $T.object({
1235
- foo: $T.string()
1338
+ foo: $T.string(),
1236
1339
  }),
1237
- union: $T.union([$T.number(), $T.string()])
1340
+ union: $T.union([$T.number(), $T.string()]),
1238
1341
  })
1239
1342
  )
1240
1343
  expect(type).toBe(
1241
1344
  `{` +
1242
- `'boolean':boolean;` +
1243
- `'byteArray':Uint8Array;` +
1244
- `'number':number;` +
1245
- `'integer':number;` +
1246
- `'string':string;` +
1247
- `'any':any;` +
1248
- `'literal':'literal';` +
1249
- `'array':Array<string>;` +
1250
- `'object':{'foo':string};` +
1251
- `'union':number|string` +
1252
- `}`
1345
+ `'boolean':boolean;` +
1346
+ `'byteArray':Uint8Array;` +
1347
+ `'number':number;` +
1348
+ `'integer':number;` +
1349
+ `'string':string;` +
1350
+ `'any':any;` +
1351
+ `'literal':'literal';` +
1352
+ `'array':Array<string>;` +
1353
+ `'object':{'foo':string};` +
1354
+ `'union':number|string` +
1355
+ `}`
1253
1356
  )
1254
1357
  })
1255
1358
  })