galbe 0.11.0 → 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,24 +318,24 @@ 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
- for (let { p, expected } of cases) {
304
- let search = new URLSearchParams()
305
- for (const [k, v] of Object.entries(p)) search.append(k, v as string)
328
+ for (let { p, expected } of cases) {
329
+ let search = new URLSearchParams()
330
+ for (const [k, v] of Object.entries(p)) search.append(k, v as string)
306
331
 
307
- let resp = await fetch(`http://localhost:${port}/query/params/schema?${search.toString()}`)
308
- let body = await resp.json()
332
+ let resp = await fetch(`http://localhost:${port}/query/params/schema?${search.toString()}`)
333
+ let body = await resp.json()
309
334
 
310
- expect(resp.status).toBe(expected.status ?? 200)
311
- expect(body).toEqual(expected.body)
312
- }
313
- })
335
+ expect(resp.status).toBe(expected.status ?? 200)
336
+ expect(body).toEqual(expected.body)
337
+ }
338
+ })
314
339
 
315
340
  test('query params, duplicates', async () => {
316
341
  const search = new URLSearchParams()
@@ -342,7 +367,7 @@ describe('parser', () => {
342
367
  any: false,
343
368
  null: null,
344
369
  nullable: null,
345
- nullish: 42
370
+ nullish: 42,
346
371
  }),
347
372
  type,
348
373
  schema,
@@ -359,9 +384,9 @@ describe('parser', () => {
359
384
  any: false,
360
385
  null: null,
361
386
  nullable: null,
362
- nullish: 42
363
- }
364
- }
387
+ nullish: 42,
388
+ },
389
+ },
365
390
  },
366
391
  {
367
392
  body: JSON.stringify({
@@ -375,7 +400,7 @@ describe('parser', () => {
375
400
  optional: 'optional',
376
401
  null: null,
377
402
  nullable: 'test',
378
- nullish: null
403
+ nullish: null,
379
404
  }),
380
405
  type,
381
406
  schema,
@@ -393,9 +418,9 @@ describe('parser', () => {
393
418
  optional: 'optional',
394
419
  null: null,
395
420
  nullable: 'test',
396
- nullish: null
397
- }
398
- }
421
+ nullish: null,
422
+ },
423
+ },
399
424
  },
400
425
  {
401
426
  body: JSON.stringify({
@@ -406,7 +431,7 @@ describe('parser', () => {
406
431
  object: [],
407
432
  array: {},
408
433
  any: {},
409
- null: ''
434
+ null: '',
410
435
  }),
411
436
  type,
412
437
  schema,
@@ -421,17 +446,17 @@ describe('parser', () => {
421
446
  object: 'Expected an object, not an array',
422
447
  array: 'Not a valid array',
423
448
  null: 'Expected null value got ',
424
- nullable: 'Required'
425
- }
426
- }
427
- }
428
- }
449
+ nullable: 'Required',
450
+ },
451
+ },
452
+ },
453
+ },
429
454
  ]
430
455
  for (let { body, type, schema, expected } of cases) {
431
456
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
432
457
  method: 'POST',
433
458
  body,
434
- headers: { ...(type ? { 'content-type': type } : {}) }
459
+ headers: { ...(type ? { 'content-type': type } : {}) },
435
460
  })
436
461
  let respBody = (await resp.json()) as { type: string; content: any }
437
462
 
@@ -460,15 +485,15 @@ describe('parser', () => {
460
485
  status: 200,
461
486
  type: 'object',
462
487
  resp: {
463
- ba: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
488
+ ba: EMPTY_BA_STR,
464
489
  string: '',
465
490
  number: 0,
466
491
  bool: false,
467
492
  any: 'false',
468
493
  union: true,
469
- array: []
470
- }
471
- }
494
+ array: [],
495
+ },
496
+ },
472
497
  },
473
498
  {
474
499
  body: 'ba=Hello&string=Mom!&number=42&bool=true&any=36&optional=optional&array=1&array=2&literal=x&union=42',
@@ -486,9 +511,9 @@ describe('parser', () => {
486
511
  optional: 'optional',
487
512
  literal: 'x',
488
513
  union: 42,
489
- array: ['1', '2']
490
- }
491
- }
514
+ array: ['1', '2'],
515
+ },
516
+ },
492
517
  },
493
518
  {
494
519
  body: 'optional=optional',
@@ -498,9 +523,9 @@ describe('parser', () => {
498
523
  status: 400,
499
524
  type: 'object',
500
525
  resp: {
501
- body: 'Missing fields: ba, string, number, bool, any'
502
- }
503
- }
526
+ body: 'Missing fields: ba, string, number, bool, any',
527
+ },
528
+ },
504
529
  },
505
530
  {
506
531
  body: 'ba=&string=Hello&string=Mom!&number=aaa&bool=1&any=36&literal=y&union=X',
@@ -514,20 +539,60 @@ describe('parser', () => {
514
539
  number: 'Not a valid number',
515
540
  bool: "Not a valid boolean. Should be 'true' or 'false'",
516
541
  literal: 'Not a valid value',
517
- union: 'Could not be parsed to any of [number, boolean]'
518
- }
519
- }
520
- }
521
- }
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
+ },
522
586
  ]
523
587
  for (let { body, type, schema, expected } of cases) {
524
588
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
525
589
  method: 'POST',
526
590
  body,
527
- headers: { ...(type ? { 'content-type': type } : {}) }
591
+ headers: { ...(type ? { 'content-type': type } : {}) },
528
592
  })
529
593
  let respBody = (await resp.json()) as { type: string; content: any }
530
594
 
595
+ console.log(respBody)
531
596
  expect(resp.status).toBe(expected.status)
532
597
  if (resp.status === 200) {
533
598
  if (expected.type) expect(respBody.type).toEqual(expected.type)
@@ -559,9 +624,9 @@ describe('parser', () => {
559
624
  bool: false,
560
625
  any: 'false',
561
626
  union: true,
562
- array: []
563
- }
564
- }
627
+ array: [],
628
+ },
629
+ },
565
630
  },
566
631
  {
567
632
  body: 'ba=Hello&string=Mom!&number=42&bool=true&any=36&optional=optional&array=1&array=2&literal=x&union=42',
@@ -579,9 +644,9 @@ describe('parser', () => {
579
644
  optional: 'optional',
580
645
  literal: 'x',
581
646
  union: 42,
582
- array: ['1', '2']
583
- }
584
- }
647
+ array: ['1', '2'],
648
+ },
649
+ },
585
650
  },
586
651
  {
587
652
  body: 'ba=Hello&string=Mom!&number=42&bool=true&any=36&optional=optional&array=1&array=2&literal=x&union=42&numArray=x',
@@ -591,9 +656,9 @@ describe('parser', () => {
591
656
  status: 400,
592
657
  type: 'object',
593
658
  resp: {
594
- body: { numArray: 'Not a valid number' }
595
- }
596
- }
659
+ body: { numArray: 'Not a valid number' },
660
+ },
661
+ },
597
662
  },
598
663
  {
599
664
  body: 'ba=&string=Hello&string=Mom!&number=1&bool=true&any=36&literal=y&union=X',
@@ -603,10 +668,10 @@ describe('parser', () => {
603
668
  status: 400,
604
669
  resp: {
605
670
  body: {
606
- literal: 'Not a valid value'
607
- }
608
- }
609
- }
671
+ literal: 'Not a valid value',
672
+ },
673
+ },
674
+ },
610
675
  },
611
676
  {
612
677
  body: 'optional=otpional',
@@ -615,16 +680,16 @@ describe('parser', () => {
615
680
  expected: {
616
681
  status: 400,
617
682
  resp: {
618
- body: 'Missing fields: ba, string, number, bool, any'
619
- }
620
- }
621
- }
683
+ body: 'Missing fields: ba, string, number, bool, any',
684
+ },
685
+ },
686
+ },
622
687
  ]
623
688
  for (let { body, type, schema, expected } of cases) {
624
689
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
625
690
  method: 'POST',
626
691
  body,
627
- headers: { ...(type ? { 'content-type': type } : {}) }
692
+ headers: { ...(type ? { 'content-type': type } : {}) },
628
693
  })
629
694
  let respBody = (await resp.json()) as any
630
695
 
@@ -643,6 +708,9 @@ describe('parser', () => {
643
708
  test('body, MultipartForm, schema object', async () => {
644
709
  const schema = 'mp/schema/base'
645
710
 
711
+ const formWithHeader = formdata({})
712
+ formWithHeader.append('foo', new Blob([new Uint8Array()], { type: 'image/png' }), 'foo.png')
713
+
646
714
  const cases: Case[] = [
647
715
  {
648
716
  body: formdata({ ba: '', string: '', number: '0', bool: 'false', any: 'false', union: 'true' }),
@@ -652,49 +720,67 @@ describe('parser', () => {
652
720
  type: 'object',
653
721
  resp: {
654
722
  ba: {
655
- content: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
723
+ content: EMPTY_BA_STR,
656
724
  headers: {
657
- name: 'ba'
658
- }
725
+ name: 'ba',
726
+ },
659
727
  },
660
728
  string: {
661
729
  content: '',
662
730
  headers: {
663
- name: 'string'
664
- }
731
+ name: 'string',
732
+ },
665
733
  },
666
734
  number: {
667
735
  content: 0,
668
736
  headers: {
669
- name: 'number'
670
- }
737
+ name: 'number',
738
+ },
671
739
  },
672
740
  bool: {
673
741
  content: false,
674
742
  headers: {
675
- name: 'bool'
676
- }
743
+ name: 'bool',
744
+ },
677
745
  },
678
746
  any: {
679
747
  content: 'false',
680
748
  headers: {
681
- name: 'any'
682
- }
749
+ name: 'any',
750
+ },
683
751
  },
684
752
  union: {
685
753
  content: true,
686
754
  headers: {
687
- name: 'union'
688
- }
755
+ name: 'union',
756
+ },
689
757
  },
690
758
  array: {
691
759
  content: [],
692
760
  headers: {
693
- name: 'array'
694
- }
695
- }
696
- }
697
- }
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
+ },
698
784
  },
699
785
  {
700
786
  body: formdata({
@@ -706,7 +792,7 @@ describe('parser', () => {
706
792
  optional: 'optional',
707
793
  array: ['1', '2'],
708
794
  literal: 'x',
709
- union: '42'
795
+ union: '42',
710
796
  }),
711
797
  schema,
712
798
  expected: {
@@ -716,59 +802,59 @@ describe('parser', () => {
716
802
  ba: {
717
803
  content: '185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969',
718
804
  headers: {
719
- name: 'ba'
720
- }
805
+ name: 'ba',
806
+ },
721
807
  },
722
808
  string: {
723
809
  content: 'Mom!',
724
810
  headers: {
725
- name: 'string'
726
- }
811
+ name: 'string',
812
+ },
727
813
  },
728
814
  number: {
729
815
  content: 42,
730
816
  headers: {
731
- name: 'number'
732
- }
817
+ name: 'number',
818
+ },
733
819
  },
734
820
  bool: {
735
821
  content: true,
736
822
  headers: {
737
- name: 'bool'
738
- }
823
+ name: 'bool',
824
+ },
739
825
  },
740
826
  any: {
741
827
  content: '36',
742
828
  headers: {
743
- name: 'any'
744
- }
829
+ name: 'any',
830
+ },
745
831
  },
746
832
  optional: {
747
833
  content: 'optional',
748
834
  headers: {
749
- name: 'optional'
750
- }
835
+ name: 'optional',
836
+ },
751
837
  },
752
838
  array: {
753
839
  content: ['1', '2'],
754
840
  headers: {
755
- name: 'array'
756
- }
841
+ name: 'array',
842
+ },
757
843
  },
758
844
  literal: {
759
845
  content: 'x',
760
846
  headers: {
761
- name: 'literal'
762
- }
847
+ name: 'literal',
848
+ },
763
849
  },
764
850
  union: {
765
851
  content: 42,
766
852
  headers: {
767
- name: 'union'
768
- }
769
- }
770
- }
771
- }
853
+ name: 'union',
854
+ },
855
+ },
856
+ },
857
+ },
772
858
  },
773
859
  {
774
860
  body: formdata({ optional: 'optional' }),
@@ -777,9 +863,9 @@ describe('parser', () => {
777
863
  status: 400,
778
864
  type: 'object',
779
865
  resp: {
780
- body: 'Missing fields: ba, string, number, bool, any'
781
- }
782
- }
866
+ body: 'Missing fields: ba, string, number, bool, any',
867
+ },
868
+ },
783
869
  },
784
870
  {
785
871
  body: formdata({
@@ -789,7 +875,7 @@ describe('parser', () => {
789
875
  bool: '1',
790
876
  any: '36',
791
877
  literal: 'y',
792
- union: 'X'
878
+ union: 'X',
793
879
  }),
794
880
  schema,
795
881
  expected: {
@@ -799,18 +885,18 @@ describe('parser', () => {
799
885
  string: 'Multiple values found',
800
886
  number: 'Not a valid number',
801
887
  bool: "Not a valid boolean. Should be 'true' or 'false'",
802
- literal: 'Not a valid value',
803
- union: 'Could not be parsed to any of [number, boolean]'
804
- }
805
- }
806
- }
807
- }
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
+ },
808
894
  ]
809
895
  for (let { body, type, schema, expected } of cases) {
810
896
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
811
897
  method: 'POST',
812
898
  body,
813
- headers: { ...(type ? { 'content-type': type } : {}) }
899
+ headers: { ...(type ? { 'content-type': type } : {}) },
814
900
  })
815
901
  let respBody = (await resp.json()) as { type: string; content: any }
816
902
 
@@ -840,47 +926,47 @@ describe('parser', () => {
840
926
  {
841
927
  content: {},
842
928
  headers: {
843
- name: 'ba'
844
- }
929
+ name: 'ba',
930
+ },
845
931
  },
846
932
  {
847
933
  content: '',
848
934
  headers: {
849
- name: 'string'
850
- }
935
+ name: 'string',
936
+ },
851
937
  },
852
938
  {
853
939
  content: 0,
854
940
  headers: {
855
- name: 'number'
856
- }
941
+ name: 'number',
942
+ },
857
943
  },
858
944
  {
859
945
  content: false,
860
946
  headers: {
861
- name: 'bool'
862
- }
947
+ name: 'bool',
948
+ },
863
949
  },
864
950
  {
865
951
  content: 'false',
866
952
  headers: {
867
- name: 'any'
868
- }
953
+ name: 'any',
954
+ },
869
955
  },
870
956
  {
871
957
  content: true,
872
958
  headers: {
873
- name: 'union'
874
- }
959
+ name: 'union',
960
+ },
875
961
  },
876
962
  {
877
963
  content: [],
878
964
  headers: {
879
- name: 'array'
880
- }
881
- }
882
- ]
883
- }
965
+ name: 'array',
966
+ },
967
+ },
968
+ ],
969
+ },
884
970
  },
885
971
  {
886
972
  body: formdata({
@@ -892,7 +978,7 @@ describe('parser', () => {
892
978
  optional: 'optional',
893
979
  array: ['1', '2'],
894
980
  literal: 'x',
895
- union: '42'
981
+ union: '42',
896
982
  }),
897
983
  schema,
898
984
  expected: {
@@ -902,65 +988,65 @@ describe('parser', () => {
902
988
  {
903
989
  content: Object.fromEntries(Uint8Array.from('Hello', c => c.charCodeAt(0)).entries()),
904
990
  headers: {
905
- name: 'ba'
906
- }
991
+ name: 'ba',
992
+ },
907
993
  },
908
994
  {
909
995
  content: 'Mom!',
910
996
  headers: {
911
- name: 'string'
912
- }
997
+ name: 'string',
998
+ },
913
999
  },
914
1000
  {
915
1001
  content: 42,
916
1002
  headers: {
917
- name: 'number'
918
- }
1003
+ name: 'number',
1004
+ },
919
1005
  },
920
1006
  {
921
1007
  content: true,
922
1008
  headers: {
923
- name: 'bool'
924
- }
1009
+ name: 'bool',
1010
+ },
925
1011
  },
926
1012
  {
927
1013
  content: '36',
928
1014
  headers: {
929
- name: 'any'
930
- }
1015
+ name: 'any',
1016
+ },
931
1017
  },
932
1018
  {
933
1019
  content: 'optional',
934
1020
  headers: {
935
- name: 'optional'
936
- }
1021
+ name: 'optional',
1022
+ },
937
1023
  },
938
1024
  {
939
1025
  content: '1',
940
1026
  headers: {
941
- name: 'array'
942
- }
1027
+ name: 'array',
1028
+ },
943
1029
  },
944
1030
  {
945
1031
  content: '2',
946
1032
  headers: {
947
- name: 'array'
948
- }
1033
+ name: 'array',
1034
+ },
949
1035
  },
950
1036
  {
951
1037
  content: 'x',
952
1038
  headers: {
953
- name: 'literal'
954
- }
1039
+ name: 'literal',
1040
+ },
955
1041
  },
956
1042
  {
957
1043
  content: 42,
958
1044
  headers: {
959
- name: 'union'
960
- }
961
- }
962
- ]
963
- }
1045
+ name: 'union',
1046
+ },
1047
+ },
1048
+ ],
1049
+ },
964
1050
  },
965
1051
  {
966
1052
  body: formdata({ optional: 'optional' }),
@@ -969,9 +1055,9 @@ describe('parser', () => {
969
1055
  status: 400,
970
1056
  type: 'object',
971
1057
  resp: {
972
- body: 'Missing fields: ba, string, number, bool, any'
973
- }
974
- }
1058
+ body: 'Missing fields: ba, string, number, bool, any',
1059
+ },
1060
+ },
975
1061
  },
976
1062
  {
977
1063
  body: formdata({
@@ -981,24 +1067,24 @@ describe('parser', () => {
981
1067
  bool: '1',
982
1068
  any: '36',
983
1069
  literal: 'y',
984
- union: 'X'
1070
+ union: 'X',
985
1071
  }),
986
1072
  schema,
987
1073
  expected: {
988
1074
  status: 400,
989
1075
  resp: {
990
1076
  body: {
991
- number: 'Not a valid number'
992
- }
993
- }
994
- }
995
- }
1077
+ number: 'Not a valid number',
1078
+ },
1079
+ },
1080
+ },
1081
+ },
996
1082
  ]
997
1083
  for (let { body, type, schema, expected } of cases) {
998
1084
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
999
1085
  method: 'POST',
1000
1086
  body,
1001
- headers: { ...(type ? { 'content-type': type } : {}) }
1087
+ headers: { ...(type ? { 'content-type': type } : {}) },
1002
1088
  })
1003
1089
  let respBody = (await resp.json()) as { type: string; content: any }
1004
1090
 
@@ -1035,8 +1121,8 @@ describe('parser', () => {
1035
1121
  headers: {
1036
1122
  name: 'imgFile',
1037
1123
  filename: 'test/resources/image.png',
1038
- type: 'image/png'
1039
- }
1124
+ type: 'image/png',
1125
+ },
1040
1126
  },
1041
1127
  jsonFile: {
1042
1128
  content: {
@@ -1045,16 +1131,16 @@ describe('parser', () => {
1045
1131
  bool: true,
1046
1132
  arrayStr: ['un', 'deux', 'trois'],
1047
1133
  arrayNumber: [0],
1048
- arrayBool: [true, false]
1134
+ arrayBool: [true, false],
1049
1135
  },
1050
1136
  headers: {
1051
1137
  name: 'jsonFile',
1052
1138
  filename: 'test/resources/object.json',
1053
- type: 'application/json'
1054
- }
1055
- }
1056
- }
1057
- }
1139
+ type: 'application/json',
1140
+ },
1141
+ },
1142
+ },
1143
+ },
1058
1144
  },
1059
1145
  {
1060
1146
  body: formdata({ imgFile, jsonFile: missingJsonFile }),
@@ -1062,9 +1148,9 @@ describe('parser', () => {
1062
1148
  expected: {
1063
1149
  status: 400,
1064
1150
  resp: {
1065
- body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } }
1066
- }
1067
- }
1151
+ body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } },
1152
+ },
1153
+ },
1068
1154
  },
1069
1155
  {
1070
1156
  body: formdata({ imgFile, jsonFile: badSyntaxJsonFile }),
@@ -1072,25 +1158,26 @@ describe('parser', () => {
1072
1158
  expected: {
1073
1159
  status: 400,
1074
1160
  resp: {
1075
- body: { jsonFile: "JSON Parse error: Expected '}'" }
1076
- }
1077
- }
1161
+ body: { jsonFile: "JSON Parse error: Expected '}'" },
1162
+ },
1163
+ },
1078
1164
  },
1079
1165
  {
1080
1166
  body: imgFileBytes,
1081
1167
  schema: '/ba/file',
1168
+ type: 'application/octet-stream',
1082
1169
  expected: {
1083
1170
  status: 200,
1084
1171
  type: 'byteArray',
1085
- resp: await fileHash(imgFileBytes)
1086
- }
1087
- }
1172
+ resp: await fileHash(imgFileBytes),
1173
+ },
1174
+ },
1088
1175
  ]
1089
1176
  for (let { body, type, schema, expected } of cases) {
1090
1177
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
1091
1178
  method: 'POST',
1092
1179
  body,
1093
- headers: { ...(type ? { 'content-type': type } : {}) }
1180
+ headers: { ...(type ? { 'content-type': type } : {}) },
1094
1181
  })
1095
1182
  let respBody = (await resp.json()) as { type: string; content: any }
1096
1183
 
@@ -1127,8 +1214,8 @@ describe('parser', () => {
1127
1214
  headers: {
1128
1215
  name: 'imgFile',
1129
1216
  filename: 'test/resources/image.png',
1130
- type: 'image/png'
1131
- }
1217
+ type: 'image/png',
1218
+ },
1132
1219
  },
1133
1220
  {
1134
1221
  content: {
@@ -1137,16 +1224,16 @@ describe('parser', () => {
1137
1224
  bool: true,
1138
1225
  arrayStr: ['un', 'deux', 'trois'],
1139
1226
  arrayNumber: [0],
1140
- arrayBool: [true, false]
1227
+ arrayBool: [true, false],
1141
1228
  },
1142
1229
  headers: {
1143
1230
  name: 'jsonFile',
1144
1231
  filename: 'test/resources/object.json',
1145
- type: 'application/json'
1146
- }
1147
- }
1148
- ]
1149
- }
1232
+ type: 'application/json',
1233
+ },
1234
+ },
1235
+ ],
1236
+ },
1150
1237
  },
1151
1238
  {
1152
1239
  body: formdata({ imgFile, jsonFile: missingJsonFile }),
@@ -1154,9 +1241,9 @@ describe('parser', () => {
1154
1241
  expected: {
1155
1242
  status: 400,
1156
1243
  resp: {
1157
- body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } }
1158
- }
1159
- }
1244
+ body: { jsonFile: { arrayBool: 'Required', arrayStr: 'Required' } },
1245
+ },
1246
+ },
1160
1247
  },
1161
1248
  {
1162
1249
  body: formdata({ imgFile, jsonFile: badSyntaxJsonFile }),
@@ -1164,25 +1251,26 @@ describe('parser', () => {
1164
1251
  expected: {
1165
1252
  status: 400,
1166
1253
  resp: {
1167
- body: { jsonFile: "JSON Parse error: Expected '}'" }
1168
- }
1169
- }
1254
+ body: { jsonFile: "JSON Parse error: Expected '}'" },
1255
+ },
1256
+ },
1170
1257
  },
1171
1258
  {
1172
1259
  body: imgFileBytes,
1173
1260
  schema: '/ba/stream/file',
1261
+ type: 'application/octet-stream',
1174
1262
  expected: {
1175
1263
  status: 200,
1176
1264
  type: 'AsyncIterator',
1177
- resp: await fileHash(imgFileBytes)
1178
- }
1179
- }
1265
+ resp: await fileHash(imgFileBytes),
1266
+ },
1267
+ },
1180
1268
  ]
1181
1269
  for (let { body, type, schema, expected } of cases) {
1182
1270
  let resp = await fetch(`http://localhost:${port}/${schema}`, {
1183
1271
  method: 'POST',
1184
1272
  body,
1185
- headers: { ...(type ? { 'content-type': type } : {}) }
1273
+ headers: { ...(type ? { 'content-type': type } : {}) },
1186
1274
  })
1187
1275
  let respBody = (await resp.json()) as { type: string; content: any }
1188
1276
 
@@ -1202,11 +1290,11 @@ describe('parser', () => {
1202
1290
  const cases: any = [
1203
1291
  {
1204
1292
  p: { int: '11', num: '10', str: 'aaaz' },
1205
- expected: { body: { default: 'DEFAULT_VALUE', int: 11, num: 10, str: 'aaaz' } }
1293
+ expected: { body: { default: 'DEFAULT_VALUE', int: 11, num: 10, str: 'aaaz' } },
1206
1294
  },
1207
1295
  {
1208
1296
  p: { default: '', int: '42', num: '41.5', str: 'a______z' },
1209
- expected: { body: { default: '', int: 42, num: 41.5, str: 'a______z' } }
1297
+ expected: { body: { default: '', int: 42, num: 41.5, str: 'a______z' } },
1210
1298
  },
1211
1299
  {
1212
1300
  p: { int: '10', num: '42.01', str: 'xxxxxxxxxx' },
@@ -1216,11 +1304,11 @@ describe('parser', () => {
1216
1304
  query: {
1217
1305
  int: 'Is less or equal to 10',
1218
1306
  num: 'Is greater or equal to 42',
1219
- str: ['Length is too large (8 char max)', 'Does not match pattern /^a.*z/']
1220
- }
1221
- }
1222
- }
1223
- }
1307
+ str: ['Length is too large (8 char max)', 'Does not match pattern /^a.*z/'],
1308
+ },
1309
+ },
1310
+ },
1311
+ },
1224
1312
  ]
1225
1313
 
1226
1314
  for (let { p, expected } of cases) {
@@ -1247,24 +1335,24 @@ describe('parser', () => {
1247
1335
  literal: $T.literal('literal'),
1248
1336
  array: $T.array($T.string()),
1249
1337
  object: $T.object({
1250
- foo: $T.string()
1338
+ foo: $T.string(),
1251
1339
  }),
1252
- union: $T.union([$T.number(), $T.string()])
1340
+ union: $T.union([$T.number(), $T.string()]),
1253
1341
  })
1254
1342
  )
1255
1343
  expect(type).toBe(
1256
1344
  `{` +
1257
- `'boolean':boolean;` +
1258
- `'byteArray':Uint8Array;` +
1259
- `'number':number;` +
1260
- `'integer':number;` +
1261
- `'string':string;` +
1262
- `'any':any;` +
1263
- `'literal':'literal';` +
1264
- `'array':Array<string>;` +
1265
- `'object':{'foo':string};` +
1266
- `'union':number|string` +
1267
- `}`
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
+ `}`
1268
1356
  )
1269
1357
  })
1270
1358
  })