@tellescope/validation 1.4.0 → 1.4.1
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.
- package/lib/cjs/validation.d.ts +168 -143
- package/lib/cjs/validation.d.ts.map +1 -1
- package/lib/cjs/validation.js +971 -699
- package/lib/cjs/validation.js.map +1 -1
- package/lib/esm/validation.d.ts +168 -143
- package/lib/esm/validation.d.ts.map +1 -1
- package/lib/esm/validation.js +952 -664
- package/lib/esm/validation.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/validation.ts +946 -664
package/src/validation.ts
CHANGED
|
@@ -192,8 +192,22 @@ export type EscapeBuilder <R=any> = {
|
|
|
192
192
|
}
|
|
193
193
|
export type ComplexEscapeBuilder <C,R=any> = (customization: C) => EscapeBuilder<R>
|
|
194
194
|
|
|
195
|
+
export type ValidatorDefinition <R=any> = {
|
|
196
|
+
validate: EscapeBuilder<R>,
|
|
197
|
+
getType: () => string | object,
|
|
198
|
+
getExample: () => string | object,
|
|
199
|
+
}
|
|
200
|
+
export type ValidatorBuilder <R=any, C={}> = (options: ValidatorOptions & C) => ValidatorDefinition<R>
|
|
201
|
+
|
|
202
|
+
const EXAMPLE_OBJECT_ID = '60398b0231a295e64f084fd9'
|
|
203
|
+
const getTypeString = () => "string"
|
|
204
|
+
const getTypeNumber = () => "number"
|
|
205
|
+
const getExampleString = () => 'example string'
|
|
206
|
+
const getExampleObjectId = () => EXAMPLE_OBJECT_ID
|
|
207
|
+
|
|
195
208
|
export type InputValues <T> = { [K in keyof T]: JSONType }
|
|
196
|
-
export type InputValidation<T> = { [K in keyof T]:
|
|
209
|
+
export type InputValidation<T> = { [K in keyof T]: ValidatorDefinition }
|
|
210
|
+
export type InputValidationOld<T> = { [K in keyof T]: EscapeFunction }
|
|
197
211
|
|
|
198
212
|
export const MAX_FILE_SIZE = 25000000 // 25 megabytes in bytes
|
|
199
213
|
const DEFAULT_MAX_LENGTH = 5000
|
|
@@ -282,16 +296,17 @@ export const build_validator: BuildValidator_T = (escapeFunction, options={} as
|
|
|
282
296
|
}
|
|
283
297
|
}
|
|
284
298
|
|
|
285
|
-
export const
|
|
286
|
-
const validation = {} as
|
|
299
|
+
export const fieldsToValidationOld = <T>(fs: { [K in keyof T]: { validator: ValidatorDefinition, required?: boolean } }): InputValidationOld<T> => {
|
|
300
|
+
const validation = {} as InputValidationOld<T>
|
|
287
301
|
|
|
288
302
|
for (const f in fs) {
|
|
289
|
-
validation[f] =
|
|
303
|
+
validation[f] = fs[f].validator.validate({ isOptional: !fs[f].required })
|
|
290
304
|
}
|
|
291
305
|
|
|
292
306
|
return validation
|
|
293
307
|
}
|
|
294
308
|
|
|
309
|
+
|
|
295
310
|
/********************************* VALIDATORS *********************************/
|
|
296
311
|
const optionsWithDefaults = (options={} as ValidatorOptions) => {
|
|
297
312
|
return {
|
|
@@ -319,20 +334,24 @@ export const binaryOrValidator = <A, B>(f1: EscapeFunction<A>, f2: EscapeFunctio
|
|
|
319
334
|
},
|
|
320
335
|
{ ...o, listOf: false }
|
|
321
336
|
)
|
|
322
|
-
export const orValidator = <T>(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
337
|
+
export const orValidator = <T>(validators: { [K in keyof T]: ValidatorDefinition<T[K]> }): ValidatorDefinition<T[keyof T]> => ({
|
|
338
|
+
validate: (o={}) => build_validator(
|
|
339
|
+
value => {
|
|
340
|
+
for (const field in validators) {
|
|
341
|
+
const escape = validators[field]
|
|
342
|
+
try {
|
|
343
|
+
return escape.validate()(value)
|
|
344
|
+
} catch(err) {
|
|
345
|
+
continue
|
|
346
|
+
}
|
|
330
347
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
)
|
|
348
|
+
throw `Value does not match any of the expected options`
|
|
349
|
+
},
|
|
350
|
+
{ ...o, listOf: false }
|
|
351
|
+
),
|
|
352
|
+
getExample: () => (Object.values(validators)[0] as ValidatorDefinition).getExample(),
|
|
353
|
+
getType: () => [Object.values(validators).map(v => (v as ValidatorDefinition).getType())]
|
|
354
|
+
})
|
|
336
355
|
|
|
337
356
|
export const filterCommandsValidator: EscapeBuilder<FilterType> = (o={}) => build_validator(
|
|
338
357
|
(value: any) => {
|
|
@@ -389,9 +408,11 @@ export const convertCommands = (operators: Indexable<any>) => {
|
|
|
389
408
|
|
|
390
409
|
interface ObjectOptions {
|
|
391
410
|
emptyOk?: boolean,
|
|
411
|
+
isOptional?: boolean,
|
|
392
412
|
throwOnUnrecognizedField?: boolean,
|
|
393
413
|
}
|
|
394
|
-
|
|
414
|
+
|
|
415
|
+
export const objectValidatorOld = <T extends object>(i: InputValidationOld<Required<T>>, objectOptions={ emptyOk: true } as ObjectOptions): EscapeBuilder<T> => (o={}) => build_validator(
|
|
395
416
|
(object: any) => {
|
|
396
417
|
const emptyOk = objectOptions.emptyOk ?? true
|
|
397
418
|
const validated = {} as T
|
|
@@ -427,68 +448,140 @@ export const objectValidator = <T extends object>(i: InputValidation<Required<T>
|
|
|
427
448
|
return validated
|
|
428
449
|
}, { ...o, isObject: true, listOf: false }
|
|
429
450
|
)
|
|
430
|
-
export const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const validated = {} as T
|
|
451
|
+
export const listValidatorOld = <T>(b: EscapeFunction<T>): EscapeBuilder<T[]> => o => build_validator(
|
|
452
|
+
b, { ...o, listOf: true }
|
|
453
|
+
)
|
|
434
454
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
if (!emptyOk && object_is_empty(object)) {
|
|
439
|
-
throw new Error(`Expected a non-empty object`)
|
|
440
|
-
}
|
|
455
|
+
const exampleObject = (fields: InputValidation<any>) => {
|
|
456
|
+
const examples = {} as Indexable<string | object>
|
|
441
457
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
// if (!(i as Indexable)[field]) {
|
|
446
|
-
// unrecognizedFields.push(field)
|
|
447
|
-
// }
|
|
448
|
-
// }
|
|
449
|
-
// if (unrecognizedFields.length > 0) {
|
|
450
|
-
// throw new Error(`Got unexpected field(s) [${unrecognizedFields.join(', ')}]`)
|
|
451
|
-
// }
|
|
458
|
+
for (const field in fields) {
|
|
459
|
+
examples[field] = fields[field].getExample()
|
|
460
|
+
}
|
|
452
461
|
|
|
453
|
-
|
|
454
|
-
|
|
462
|
+
return examples
|
|
463
|
+
}
|
|
464
|
+
const typeObject = (fields: InputValidation<any>) => {
|
|
465
|
+
const types = {} as Indexable<string | object>
|
|
455
466
|
|
|
456
|
-
|
|
457
|
-
|
|
467
|
+
for (const field in fields) {
|
|
468
|
+
types[field] = fields[field].getType()
|
|
469
|
+
}
|
|
458
470
|
|
|
459
|
-
|
|
460
|
-
|
|
471
|
+
return types
|
|
472
|
+
}
|
|
461
473
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
)
|
|
474
|
+
export const objectValidator = <T extends object>(i: InputValidation<Required<T>>, objectOptions={ emptyOk: true } as ObjectOptions): ValidatorDefinition<T> => ({
|
|
475
|
+
validate: (o={}) => build_validator(
|
|
476
|
+
(object: any) => {
|
|
477
|
+
const emptyOk = objectOptions.emptyOk ?? true
|
|
478
|
+
const validated = {} as T
|
|
465
479
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
480
|
+
if (!is_object(object)) {
|
|
481
|
+
throw new Error(`Expected a non-null object by got ${object}`)
|
|
482
|
+
}
|
|
483
|
+
if (!emptyOk && object_is_empty(object)) {
|
|
484
|
+
throw new Error(`Expected a non-empty object`)
|
|
485
|
+
}
|
|
469
486
|
|
|
470
|
-
|
|
487
|
+
// don't throw on unrecognized fields, just ignore/don't validate them
|
|
488
|
+
if (objectOptions.throwOnUnrecognizedField) {
|
|
489
|
+
const unrecognizedFields = []
|
|
490
|
+
for (const field in object) {
|
|
491
|
+
if (!(i as Indexable)[field]) {
|
|
492
|
+
unrecognizedFields.push(field)
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
if (unrecognizedFields.length > 0) {
|
|
496
|
+
throw new Error(`Got unexpected field(s) [${unrecognizedFields.join(', ')}]`)
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
for (const field in i) {
|
|
501
|
+
const value = (object as Indexable)[field]
|
|
502
|
+
const escaped = i[field].validate()(value) // may be required
|
|
503
|
+
if (escaped === undefined) continue
|
|
471
504
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
505
|
+
validated[field] = escaped
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return validated
|
|
509
|
+
}, { ...o, isObject: true, listOf: false, isOptional: !!objectOptions.isOptional || o.isOptional }
|
|
510
|
+
),
|
|
511
|
+
getExample: () => exampleObject(i),
|
|
512
|
+
getType: () => typeObject(i),
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
export const listOfObjectsValidator = <T extends object>(i: InputValidation<Required<T>>, objectOptions={ emptyOk: true }): ValidatorDefinition<T[]> => ({
|
|
516
|
+
validate: (o={}) => build_validator(
|
|
517
|
+
(object: any) => {
|
|
518
|
+
const emptyOk = !!objectOptions.emptyOk || o.emptyListOk
|
|
519
|
+
const validated = {} as T
|
|
520
|
+
|
|
521
|
+
if (!is_object(object)) {
|
|
522
|
+
throw new Error(`Expected a non-null object by got ${object}`)
|
|
523
|
+
}
|
|
524
|
+
if (!emptyOk && object_is_empty(object)) {
|
|
525
|
+
throw new Error(`Expected a non-empty object`)
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// don't throw on unrecognized fields, just ignore/don't validate them
|
|
529
|
+
// const unrecognizedFields = []
|
|
530
|
+
// for (const field in object) {
|
|
531
|
+
// if (!(i as Indexable)[field]) {
|
|
532
|
+
// unrecognizedFields.push(field)
|
|
533
|
+
// }
|
|
534
|
+
// }
|
|
535
|
+
// if (unrecognizedFields.length > 0) {
|
|
536
|
+
// throw new Error(`Got unexpected field(s) [${unrecognizedFields.join(', ')}]`)
|
|
537
|
+
// }
|
|
538
|
+
|
|
539
|
+
for (const field in i) {
|
|
540
|
+
const value = (object as Indexable)[field]
|
|
541
|
+
|
|
542
|
+
const escaped = i[field].validate()(value) // may be required
|
|
543
|
+
if (escaped === undefined) continue
|
|
544
|
+
|
|
545
|
+
validated[field] = escaped
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return validated
|
|
549
|
+
}, { ...o, isObject: true, listOf: true, emptyListOk: !!objectOptions.emptyOk || o.emptyListOk }
|
|
550
|
+
),
|
|
551
|
+
getExample: () => [exampleObject(i)], // don't forget list
|
|
552
|
+
getType: () => [typeObject(i)] // don't forget list
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
export const objectAnyFieldsValidator = <T>(valueValidator?: ValidatorDefinition<T>): ValidatorDefinition<Indexable<T>> => ({
|
|
556
|
+
validate: (o={}) => build_validator(
|
|
557
|
+
(object: any) => {
|
|
558
|
+
if (!is_object(object)) { throw new Error("Expected a non-null object by got ${object}") }
|
|
559
|
+
|
|
560
|
+
const validated = {} as Indexable
|
|
561
|
+
|
|
562
|
+
for (const field in object) {
|
|
482
563
|
if (valueValidator) {
|
|
483
|
-
|
|
564
|
+
validated[field] = valueValidator.validate()(object[field])
|
|
565
|
+
} else if (typeof object[field] === 'number') {
|
|
566
|
+
validated[field] = numberValidator.validate()(object[field])
|
|
567
|
+
} else if (typeof object[field] === 'string') {
|
|
568
|
+
validated[field] = stringValidator.validate()(object[field])
|
|
569
|
+
} else if (object[field] === null) {
|
|
570
|
+
validated[field] = null
|
|
571
|
+
} else {
|
|
572
|
+
if (valueValidator) {
|
|
573
|
+
throw new Error(`Field ${field} is not a string or number`)
|
|
574
|
+
}
|
|
575
|
+
validated[field] = object[field]
|
|
484
576
|
}
|
|
485
|
-
validated[field] = object[field]
|
|
486
577
|
}
|
|
487
|
-
}
|
|
488
578
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
)
|
|
579
|
+
return validated
|
|
580
|
+
}, { ...o, isObject: true, listOf: false }
|
|
581
|
+
),
|
|
582
|
+
getExample: () => `{ "key": ${valueValidator?.getExample?.() ?? '"value"'} }`,
|
|
583
|
+
getType: () => `{ "key": ${valueValidator?.getType?.() ?? 'string'} }`,
|
|
584
|
+
})
|
|
492
585
|
|
|
493
586
|
export const objectAnyFieldsAnyValuesValidator = objectAnyFieldsValidator()
|
|
494
587
|
|
|
@@ -504,51 +597,125 @@ export const escapeString: EscapeWithOptions<string> = (o={}) => string => {
|
|
|
504
597
|
}
|
|
505
598
|
return string
|
|
506
599
|
}
|
|
507
|
-
export const stringValidator: EscapeBuilder<string> = (o={}) => build_validator(
|
|
508
|
-
escapeString(o), { ...o, maxLength: o.maxLength ?? 1000, listOf: false }
|
|
509
|
-
)
|
|
510
|
-
export const stringValidator100: EscapeBuilder<string> = (o={}) => build_validator(
|
|
511
|
-
escapeString(o), { ...o, maxLength: 100, listOf: false }
|
|
512
|
-
)
|
|
513
|
-
export const stringValidator250: EscapeBuilder<string> = (o={}) => build_validator(
|
|
514
|
-
escapeString(o), { ...o, maxLength: 250, listOf: false }
|
|
515
|
-
)
|
|
516
|
-
export const stringValidator1000: EscapeBuilder<string> = (o={}) => build_validator(
|
|
517
|
-
escapeString(o), { ...o, maxLength: 1000, listOf: false }
|
|
518
|
-
)
|
|
519
|
-
export const stringValidator5000: EscapeBuilder<string> = (o={}) => build_validator(
|
|
520
|
-
escapeString(o), { ...o, maxLength: 5000, listOf: false }
|
|
521
|
-
)
|
|
522
|
-
export const stringValidator25000: EscapeBuilder<string> = (o={}) => build_validator(
|
|
523
|
-
escapeString(o), { ...o, maxLength: 25000, listOf: false }
|
|
524
|
-
)
|
|
525
|
-
export const SMSMessageValidator: EscapeBuilder<string> = (o={}) => build_validator(
|
|
526
|
-
escapeString(o), { ...o, maxLength: 630, listOf: false }
|
|
527
|
-
)
|
|
528
600
|
|
|
529
|
-
export const
|
|
530
|
-
|
|
531
|
-
)
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
601
|
+
export const stringValidator: ValidatorDefinition<string> = {
|
|
602
|
+
validate: (o={}) => build_validator(
|
|
603
|
+
escapeString(o), { ...o, maxLength: o.maxLength ?? 1000, listOf: false }
|
|
604
|
+
),
|
|
605
|
+
getExample: getExampleString,
|
|
606
|
+
getType: getTypeString,
|
|
607
|
+
}
|
|
608
|
+
export const stringValidatorOptional: ValidatorDefinition<string> = {
|
|
609
|
+
validate: (o={}) => build_validator(
|
|
610
|
+
escapeString(o), { ...o, maxLength: o.maxLength ?? 1000, listOf: false, isOptional: true }
|
|
611
|
+
),
|
|
612
|
+
getExample: getExampleString,
|
|
613
|
+
getType: getTypeString,
|
|
614
|
+
}
|
|
615
|
+
export const stringValidator100: ValidatorDefinition<string> = {
|
|
616
|
+
validate: (o={}) => build_validator(
|
|
617
|
+
escapeString(o), { ...o, maxLength: 100, listOf: false }
|
|
618
|
+
),
|
|
619
|
+
getExample: () => 'example string',
|
|
620
|
+
getType: () => 'string'
|
|
621
|
+
}
|
|
535
622
|
|
|
536
|
-
export const
|
|
537
|
-
|
|
538
|
-
|
|
623
|
+
export const stringValidator250: ValidatorDefinition<string> = {
|
|
624
|
+
validate: (o={}) => build_validator(
|
|
625
|
+
escapeString(o), { ...o, maxLength: 250, listOf: false }
|
|
626
|
+
),
|
|
627
|
+
getExample: getExampleString,
|
|
628
|
+
getType: getTypeString,
|
|
629
|
+
}
|
|
630
|
+
export const stringValidator1000: ValidatorDefinition<string> = {
|
|
631
|
+
validate: (o={}) => build_validator(
|
|
632
|
+
escapeString(o), { ...o, maxLength: 1000, listOf: false }
|
|
633
|
+
),
|
|
634
|
+
getExample: getExampleString,
|
|
635
|
+
getType: getTypeString,
|
|
636
|
+
}
|
|
637
|
+
export const stringValidator5000: ValidatorDefinition<string> = {
|
|
638
|
+
validate: (o={}) => build_validator(
|
|
639
|
+
escapeString(o), { ...o, maxLength: 5000, listOf: false }
|
|
640
|
+
),
|
|
641
|
+
getExample: getExampleString,
|
|
642
|
+
getType: getTypeString,
|
|
643
|
+
}
|
|
644
|
+
export const stringValidator5000EmptyOkay: ValidatorDefinition<string> = {
|
|
645
|
+
validate: (o={}) => build_validator(
|
|
646
|
+
escapeString(o), { ...o, maxLength: 5000, listOf: false, emptyStringOk: true }
|
|
647
|
+
),
|
|
648
|
+
getExample: getExampleString,
|
|
649
|
+
getType: getTypeString,
|
|
650
|
+
}
|
|
651
|
+
export const stringValidator5000Optional: ValidatorDefinition<string> = {
|
|
652
|
+
validate: (o={}) => build_validator(
|
|
653
|
+
escapeString(o), { ...o, maxLength: 5000, listOf: false, isOptional: true, emptyStringOk: true }
|
|
654
|
+
),
|
|
655
|
+
getExample: getExampleString,
|
|
656
|
+
getType: getTypeString,
|
|
657
|
+
}
|
|
658
|
+
export const stringValidator25000: ValidatorDefinition<string> = {
|
|
659
|
+
validate: (o={}) => build_validator(
|
|
660
|
+
escapeString(o), { ...o, maxLength: 25000, listOf: false }
|
|
661
|
+
),
|
|
662
|
+
getExample: getExampleString,
|
|
663
|
+
getType: getTypeString,
|
|
664
|
+
}
|
|
665
|
+
export const stringValidator25000EmptyOkay: ValidatorDefinition<string> = {
|
|
666
|
+
validate: (o={}) => build_validator(
|
|
667
|
+
escapeString(o), { ...o, maxLength: 25000, listOf: false, emptyStringOk: true }
|
|
668
|
+
),
|
|
669
|
+
getExample: getExampleString,
|
|
670
|
+
getType: getTypeString,
|
|
671
|
+
}
|
|
672
|
+
export const SMSMessageValidator: ValidatorDefinition<string> = {
|
|
673
|
+
validate: (o={}) => build_validator(
|
|
674
|
+
escapeString(o), { ...o, maxLength: 630, listOf: false }
|
|
675
|
+
),
|
|
676
|
+
getExample: getExampleString,
|
|
677
|
+
getType: getTypeString,
|
|
678
|
+
}
|
|
539
679
|
|
|
540
|
-
export const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
680
|
+
export const listValidator = <T>(b: ValidatorDefinition<T>, o?: ValidatorOptions | ValidatorOptionsForList): ValidatorDefinition<T[]> => ({
|
|
681
|
+
validate: o => build_validator(b.validate(o as any), { ...o, listOf: true }),
|
|
682
|
+
getExample: () => [b.getExample()],
|
|
683
|
+
getType: () => [b.getExample()],
|
|
684
|
+
})
|
|
685
|
+
export const listValidatorEmptyOk = <T>(b: ValidatorDefinition<T>, o?: ValidatorOptions): ValidatorDefinition<T[]> => ({
|
|
686
|
+
validate: o => build_validator(b.validate(o as any), { ...o, listOf: true, emptyListOk: true }),
|
|
687
|
+
getExample: () => [b.getExample()],
|
|
688
|
+
getType: () => [b.getExample()],
|
|
689
|
+
})
|
|
690
|
+
export const listValidatorOptionalOrEmptyOk = <T>(b: ValidatorDefinition<T>, o?: ValidatorOptions): ValidatorDefinition<T[]> => ({
|
|
691
|
+
validate: o => build_validator(b.validate(o as any), { ...o, listOf: true, emptyListOk: true, isOptional: true }),
|
|
692
|
+
getExample: () => [b.getExample()],
|
|
693
|
+
getType: () => [b.getExample()],
|
|
694
|
+
})
|
|
544
695
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
)
|
|
696
|
+
export const listOfStringsValidator = listValidator(stringValidator)
|
|
697
|
+
export const listOfStringsValidatorOptionalOrEmptyOk = listValidatorOptionalOrEmptyOk(stringValidator)
|
|
698
|
+
export const listOfStringsValidatorEmptyOk = listValidatorEmptyOk(stringValidator)
|
|
699
|
+
export const listOfObjectAnyFieldsAnyValuesValidator = listValidator(objectAnyFieldsAnyValuesValidator)
|
|
700
|
+
|
|
701
|
+
export const booleanValidatorBuilder: ValidatorBuilder<boolean> = (defaults) => ({
|
|
702
|
+
validate: (options={}) => build_validator(
|
|
703
|
+
boolean => {
|
|
704
|
+
if (boolean === 'true') return true
|
|
705
|
+
if (boolean === 'false') return false
|
|
706
|
+
|
|
707
|
+
if (typeof boolean !== 'boolean') {
|
|
708
|
+
throw new Error(options.errorMessage || "Invalid boolean")
|
|
709
|
+
}
|
|
710
|
+
return boolean
|
|
711
|
+
},
|
|
712
|
+
{ ...defaults, ...options, isBoolean: true, listOf: false }
|
|
713
|
+
),
|
|
714
|
+
getExample: () => "false",
|
|
715
|
+
getType: () => "boolean",
|
|
716
|
+
})
|
|
717
|
+
export const booleanValidator = booleanValidatorBuilder({ })
|
|
718
|
+
export const booleanValidatorOptional = booleanValidatorBuilder({ isOptional: true })
|
|
552
719
|
|
|
553
720
|
export const escapeMongoId: EscapeFunction<string> = (mongoId: any) => {
|
|
554
721
|
if (typeof mongoId !== 'string') throw new Error('Expecting string id')
|
|
@@ -557,12 +724,20 @@ export const escapeMongoId: EscapeFunction<string> = (mongoId: any) => {
|
|
|
557
724
|
}
|
|
558
725
|
return mongoId
|
|
559
726
|
}
|
|
560
|
-
export const mongoIdValidator:
|
|
561
|
-
|
|
562
|
-
)
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
727
|
+
export const mongoIdValidator: ValidatorDefinition<ObjectId> = {
|
|
728
|
+
validate: (o={}) => build_validator(
|
|
729
|
+
s => to_object_id(escapeMongoId(s)), { ...optionsWithDefaults(o), maxLength: 100, listOf: false }
|
|
730
|
+
),
|
|
731
|
+
getType: getTypeString,
|
|
732
|
+
getExample: getExampleObjectId,
|
|
733
|
+
}
|
|
734
|
+
export const buildMongoIdStringValidator: ValidatorBuilder<string> = (options) => ({
|
|
735
|
+
validate: (o={}) => build_validator(
|
|
736
|
+
escapeMongoId, { ...optionsWithDefaults({ ...options, ...o }), maxLength: 100, listOf: false }
|
|
737
|
+
),
|
|
738
|
+
getType: getTypeString,
|
|
739
|
+
getExample: getExampleObjectId,
|
|
740
|
+
})
|
|
566
741
|
|
|
567
742
|
export const nullValidator: EscapeBuilder<null> = (o={}) => build_validator(
|
|
568
743
|
v => {
|
|
@@ -573,215 +748,296 @@ export const nullValidator: EscapeBuilder<null> = (o={}) => build_validator(
|
|
|
573
748
|
{ ...o, listOf: false }
|
|
574
749
|
)
|
|
575
750
|
|
|
576
|
-
export const mongoIdRequired = mongoIdValidator()
|
|
577
|
-
export const mongoIdOptional = mongoIdValidator({ isOptional: true })
|
|
578
|
-
export const
|
|
579
|
-
|
|
580
|
-
export const
|
|
581
|
-
export const
|
|
582
|
-
export const
|
|
751
|
+
export const mongoIdRequired = mongoIdValidator.validate()
|
|
752
|
+
export const mongoIdOptional = mongoIdValidator.validate({ isOptional: true })
|
|
753
|
+
export const listOfMongoIdValidator = listValidator(mongoIdValidator)
|
|
754
|
+
|
|
755
|
+
export const mongoIdStringRequired = buildMongoIdStringValidator({ isOptional: false })
|
|
756
|
+
export const mongoIdStringOptional = buildMongoIdStringValidator({ isOptional: true })
|
|
757
|
+
export const listOfMongoIdStringValidator = listValidator(mongoIdStringRequired)
|
|
758
|
+
export const listOfMongoIdStringValidatorEmptyOk = listValidatorEmptyOk(mongoIdStringRequired)
|
|
583
759
|
|
|
584
760
|
export const first_letter_capitalized = (s='') => s.charAt(0).toUpperCase() + s.slice(1)
|
|
585
761
|
export const escape_name = (namestring: string) => namestring.replace(/[^a-zA-Z0-9-_ /.]/, '').substring(0, 100)
|
|
586
762
|
|
|
587
763
|
// enforces first-letter capitalization
|
|
588
|
-
export const nameValidator:
|
|
589
|
-
|
|
590
|
-
|
|
764
|
+
export const nameValidator: ValidatorDefinition<string> = {
|
|
765
|
+
validate: (options={}) => build_validator(
|
|
766
|
+
name => {
|
|
767
|
+
if (typeof name !== 'string') throw new Error('Expecting string value')
|
|
591
768
|
|
|
592
|
-
|
|
593
|
-
|
|
769
|
+
name = escape_name(name)
|
|
770
|
+
if (!name) throw new Error("Invalid name")
|
|
594
771
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
)
|
|
772
|
+
return first_letter_capitalized(name)
|
|
773
|
+
},
|
|
774
|
+
{ ...options, maxLength: 100, trim: true, listOf: false }
|
|
775
|
+
),
|
|
776
|
+
getExample: () => 'John',
|
|
777
|
+
getType: getTypeString,
|
|
778
|
+
}
|
|
599
779
|
|
|
780
|
+
export const emailValidator: ValidatorDefinition<string> = {
|
|
781
|
+
validate: (options={}) => build_validator(
|
|
782
|
+
(email) => {
|
|
783
|
+
if (typeof email !== 'string') throw new Error('Expecting string value')
|
|
784
|
+
if (!isEmail(email)) { throw new Error(options.errorMessage || "Invalid email") }
|
|
600
785
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
786
|
+
return email.toLowerCase()
|
|
787
|
+
},
|
|
788
|
+
{ ...options, maxLength: 250, listOf: false }
|
|
789
|
+
),
|
|
790
|
+
getExample: () => "example@tellescope.com",
|
|
791
|
+
getType: getTypeString,
|
|
792
|
+
}
|
|
793
|
+
export const emailValidatorOptional: ValidatorDefinition<string> = {
|
|
794
|
+
validate: (options={}) => build_validator(
|
|
795
|
+
(email) => {
|
|
796
|
+
if (typeof email !== 'string') throw new Error('Expecting string value')
|
|
797
|
+
if (!isEmail(email)) { throw new Error(options.errorMessage || "Invalid email") }
|
|
605
798
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
)
|
|
799
|
+
return email.toLowerCase()
|
|
800
|
+
},
|
|
801
|
+
{ ...options, maxLength: 250, listOf: false, isOptional: true, emptyStringOk: true }
|
|
802
|
+
),
|
|
803
|
+
getExample: () => "example@tellescope.com",
|
|
804
|
+
getType: getTypeString,
|
|
805
|
+
}
|
|
610
806
|
|
|
611
|
-
export const emailValidatorEmptyOkay:
|
|
612
|
-
(
|
|
613
|
-
|
|
614
|
-
|
|
807
|
+
export const emailValidatorEmptyOkay: ValidatorDefinition<string> = {
|
|
808
|
+
validate: (options={}) => build_validator(
|
|
809
|
+
(email) => {
|
|
810
|
+
if (typeof email !== 'string') throw new Error('Expecting string value')
|
|
811
|
+
if (!isEmail(email)) { throw new Error(options.errorMessage || "Invalid email") }
|
|
615
812
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
)
|
|
813
|
+
return email.toLowerCase()
|
|
814
|
+
},
|
|
815
|
+
{ ...options, maxLength: 250, emptyStringOk: true, listOf: false }
|
|
816
|
+
),
|
|
817
|
+
getExample: () => "example@tellescope.com",
|
|
818
|
+
getType: getTypeString,
|
|
819
|
+
}
|
|
620
820
|
|
|
621
821
|
|
|
622
|
-
export const numberValidatorBuilder:
|
|
623
|
-
options
|
|
822
|
+
export const numberValidatorBuilder: ValidatorBuilder<number, { lower: number, upper: number }> = ({ lower, upper, ...higherOptions }) => ({
|
|
823
|
+
validate: (options={}) => {
|
|
824
|
+
options.isNumber = true
|
|
624
825
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
826
|
+
return build_validator(
|
|
827
|
+
(number: any) => {
|
|
828
|
+
number = Number(number) // ok to throw error!
|
|
829
|
+
if (typeof number !== "number" || isNaN(number)) {
|
|
830
|
+
throw new Error(options.errorMessage || `Not a valid number`)
|
|
831
|
+
}
|
|
832
|
+
if (!(lower || upper)) return number
|
|
632
833
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
}
|
|
834
|
+
if (!(number >= lower && number <= upper)) {
|
|
835
|
+
throw new Error(options.errorMessage || `Not a valid number for [${lower}-${upper}]`)
|
|
836
|
+
}
|
|
837
|
+
return number
|
|
838
|
+
},
|
|
839
|
+
{ ...optionsWithDefaults({ ...higherOptions, ...options }), listOf: false, }
|
|
840
|
+
)
|
|
841
|
+
},
|
|
842
|
+
getExample: () => `${lower}`, // `a number from ${lower} to ${upper}`,
|
|
843
|
+
getType: getTypeNumber,
|
|
844
|
+
})
|
|
641
845
|
|
|
642
846
|
export const nonNegNumberValidator = numberValidatorBuilder({ lower: 0, upper: 10000000000000 }) // max is 2286 in UTC MS
|
|
643
847
|
export const numberValidator = numberValidatorBuilder({ lower: -100000000, upper: 10000000000000 }) // max is 2286 in UTC MS
|
|
848
|
+
export const numberValidatorOptional = numberValidatorBuilder({ lower: -100000000, upper: 10000000000000, isOptional: true, emptyStringOk: true }) // max is 2286 in UTC MS
|
|
644
849
|
export const fileSizeValidator = numberValidatorBuilder({ lower: 0, upper: MAX_FILE_SIZE })
|
|
645
850
|
|
|
646
|
-
export const dateValidator:
|
|
647
|
-
|
|
648
|
-
|
|
851
|
+
export const dateValidator: ValidatorDefinition<Date> = {
|
|
852
|
+
validate: (options={}) => build_validator(
|
|
853
|
+
(date: any) => {
|
|
854
|
+
if (isDate(date)) throw new Error(options.errorMessage || "Invalid date")
|
|
649
855
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
)
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
},
|
|
662
|
-
{ ...o, listOf: false }
|
|
663
|
-
)
|
|
664
|
-
export const exactMatchListValidator = <T extends string>(matches: T[]): EscapeBuilder<T[]> => (o={}) => build_validator(
|
|
665
|
-
(match: JSONType) => {
|
|
666
|
-
if (matches.filter(m => m === match).length === 0) {
|
|
667
|
-
throw new Error(`Value must match one of ${matches}`)
|
|
668
|
-
}
|
|
669
|
-
return match
|
|
670
|
-
},
|
|
671
|
-
{ ...o, listOf: true }
|
|
672
|
-
)
|
|
856
|
+
return new Date(date)
|
|
857
|
+
},
|
|
858
|
+
{ ...options, maxLength: 250, listOf: false }
|
|
859
|
+
),
|
|
860
|
+
getExample: () => new Date().toISOString(),
|
|
861
|
+
getType: () => "Date",
|
|
862
|
+
}
|
|
863
|
+
export const dateValidatorOptional: ValidatorDefinition<Date> = {
|
|
864
|
+
validate: (options={}) => build_validator(
|
|
865
|
+
(date: any) => {
|
|
866
|
+
if (isDate(date)) throw new Error(options.errorMessage || "Invalid date")
|
|
673
867
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
868
|
+
return new Date(date)
|
|
869
|
+
},
|
|
870
|
+
{ ...options, maxLength: 250, listOf: false, isOptional: true, emptyStringOk: true }
|
|
871
|
+
),
|
|
872
|
+
getExample: () => new Date().toISOString(),
|
|
873
|
+
getType: () => "Date",
|
|
874
|
+
}
|
|
679
875
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
)
|
|
876
|
+
export const exactMatchValidator = <T extends string>(matches: T[]): ValidatorDefinition<T> => ({
|
|
877
|
+
validate: (o={}) => build_validator(
|
|
878
|
+
(match: JSONType) => {
|
|
879
|
+
if (matches.filter(m => m === match).length === 0) {
|
|
880
|
+
throw new Error(`Value must match one of ${matches}`)
|
|
881
|
+
}
|
|
882
|
+
return match
|
|
883
|
+
},
|
|
884
|
+
{ ...o, listOf: false }
|
|
885
|
+
),
|
|
886
|
+
getExample: () => matches[0],
|
|
887
|
+
getType: getTypeString,
|
|
888
|
+
})
|
|
889
|
+
export const exactMatchValidatorOptional = <T extends string>(matches: T[]): ValidatorDefinition<T> => ({
|
|
890
|
+
validate: (o={}) => build_validator(
|
|
891
|
+
(match: JSONType) => {
|
|
892
|
+
if (matches.filter(m => m === match).length === 0) {
|
|
893
|
+
throw new Error(`Value must match one of ${matches}`)
|
|
894
|
+
}
|
|
895
|
+
return match
|
|
896
|
+
},
|
|
897
|
+
{ ...o, listOf: false, isOptional: true }
|
|
898
|
+
),
|
|
899
|
+
getExample: () => matches[0],
|
|
900
|
+
getType: getTypeString,
|
|
901
|
+
})
|
|
902
|
+
export const exactMatchListValidator = <T extends string>(matches: T[]) => listValidator(exactMatchValidator(matches))
|
|
690
903
|
|
|
691
|
-
export const
|
|
904
|
+
export const journeysValidator: ValidatorDefinition<Indexable> = {
|
|
905
|
+
validate: (options={}) => build_validator(
|
|
906
|
+
(journeys) => {
|
|
907
|
+
if (typeof journeys !== 'object') {
|
|
908
|
+
throw new Error('Expecting an object')
|
|
909
|
+
}
|
|
692
910
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
911
|
+
const mIdValidator = mongoIdValidator.validate()
|
|
912
|
+
const stateValidator = stringValidator.validate({ isOptional: true, maxLength: 75, errorMessage: "Journey state names may not exceed 75 characters" })
|
|
913
|
+
for (const j in journeys) {
|
|
914
|
+
mIdValidator(j);
|
|
915
|
+
(journeys as Indexable)[j] = stateValidator(journeys[j as keyof typeof journeys]);
|
|
916
|
+
}
|
|
917
|
+
return journeys
|
|
918
|
+
},
|
|
919
|
+
{ ...options, isObject: true, listOf: false }
|
|
920
|
+
),
|
|
921
|
+
getExample: () => `{ ${EXAMPLE_OBJECT_ID}: "status" }`,
|
|
922
|
+
getType: () => `{ string: string }`,
|
|
923
|
+
}
|
|
696
924
|
|
|
697
|
-
|
|
698
|
-
if (escaped.length < 10) throw new Error(`Phone number must be at least 10 digits`)
|
|
925
|
+
export const escape_phone_number = (p='') => p.replace(/[^\d+]/g, '')
|
|
699
926
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
927
|
+
export const phoneValidator: ValidatorDefinition<string> = {
|
|
928
|
+
validate: (options={}) => build_validator(
|
|
929
|
+
phone => {
|
|
930
|
+
if (typeof phone !== "string") throw new Error(`Expecting phone to be string but got ${phone}`)
|
|
703
931
|
|
|
704
|
-
|
|
705
|
-
throw `
|
|
706
|
-
}
|
|
932
|
+
let escaped = escape_phone_number(phone)
|
|
933
|
+
if (escaped.length < 10) throw new Error(`Phone number must be at least 10 digits`)
|
|
707
934
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
)
|
|
935
|
+
escaped = escaped.startsWith('+') ? escaped
|
|
936
|
+
: escaped.length === 10 ? '+1' + escaped // assume US country code for now
|
|
937
|
+
: "+" + escaped // assume country code provided, but missing leading +
|
|
712
938
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
939
|
+
if (!isMobilePhone(escaped, 'any', { strictMode: true })) {
|
|
940
|
+
throw `Invalid phone number`
|
|
941
|
+
}
|
|
716
942
|
|
|
717
|
-
|
|
718
|
-
|
|
943
|
+
return escaped
|
|
944
|
+
},
|
|
945
|
+
{ ...options, maxLength: 25, listOf: false }
|
|
946
|
+
),
|
|
947
|
+
getExample: () => "+15555555555",
|
|
948
|
+
getType: getTypeString,
|
|
949
|
+
}
|
|
950
|
+
export const phoneValidatorOptional: ValidatorDefinition<string> = {
|
|
951
|
+
validate: (options={}) => build_validator(
|
|
952
|
+
phone => {
|
|
953
|
+
if (typeof phone !== "string") throw new Error(`Expecting phone to be string but got ${phone}`)
|
|
719
954
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
: "+" + escaped // assume country code provided, but missing leading +
|
|
955
|
+
let escaped = escape_phone_number(phone)
|
|
956
|
+
if (escaped.length < 10) throw new Error(`Phone number must be at least 10 digits`)
|
|
723
957
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
958
|
+
escaped = escaped.startsWith('+') ? escaped
|
|
959
|
+
: escaped.length === 10 ? '+1' + escaped // assume US country code for now
|
|
960
|
+
: "+" + escaped // assume country code provided, but missing leading +
|
|
727
961
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
)
|
|
962
|
+
if (!isMobilePhone(escaped, 'any', { strictMode: true })) {
|
|
963
|
+
throw `Invalid phone number`
|
|
964
|
+
}
|
|
732
965
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
966
|
+
return escaped
|
|
967
|
+
},
|
|
968
|
+
{ ...options, maxLength: 25, listOf: false, isOptional: true, emptyStringOk: true }
|
|
969
|
+
),
|
|
970
|
+
getExample: () => "+15555555555",
|
|
971
|
+
getType: getTypeString,
|
|
972
|
+
}
|
|
737
973
|
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
)
|
|
974
|
+
export const fileTypeValidator: ValidatorDefinition<string> = {
|
|
975
|
+
validate: (options={}) => build_validator(
|
|
976
|
+
(s: any) => {
|
|
977
|
+
if (typeof s !== 'string') throw new Error("fileType must be a string")
|
|
978
|
+
if (!isMimeType(s)) throw new Error(`${s} is not a valid file type`)
|
|
742
979
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
980
|
+
return s
|
|
981
|
+
},
|
|
982
|
+
{ ...options, listOf: false }
|
|
983
|
+
),
|
|
984
|
+
getExample: () => 'text/plain',
|
|
985
|
+
getType: getTypeString,
|
|
986
|
+
}
|
|
987
|
+
export const urlValidator: ValidatorDefinition<string> = {
|
|
988
|
+
validate: (options={}) => build_validator(
|
|
989
|
+
(s: any) => {
|
|
990
|
+
if (typeof s !== 'string') throw new Error("URL must be a string")
|
|
991
|
+
if (!isURL(s)) throw new Error(`${s} is not a valid URL`)
|
|
747
992
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
)
|
|
993
|
+
return s
|
|
994
|
+
},
|
|
995
|
+
{ ...options, listOf: false }
|
|
996
|
+
),
|
|
997
|
+
getExample: () => '"https://www.tellescope.com"',
|
|
998
|
+
getType: getTypeString,
|
|
999
|
+
}
|
|
752
1000
|
|
|
753
|
-
export const safeBase64Validator =
|
|
754
|
-
|
|
755
|
-
|
|
1001
|
+
export const safeBase64Validator: ValidatorDefinition<string> = {
|
|
1002
|
+
validate: (options={}) => build_validator(
|
|
1003
|
+
(sb64: any) => {
|
|
1004
|
+
if (typeof sb64 !== 'string') throw new Error("Expecting string")
|
|
756
1005
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
)
|
|
1006
|
+
// https://stackoverflow.com/questions/12930007/how-to-validate-base64-string-using-regex-in-javascript
|
|
1007
|
+
// regex with = + and / replaced as get_random_base64_URL_safe
|
|
1008
|
+
if (!/^(?:[A-Za-z0-9_-]{4})*(?:[A-Za-z0-9_-]{2}..|[A-Za-z0-9_-]{3}.)?$/.test(sb64)) {
|
|
1009
|
+
throw `Invalid safe base64`
|
|
1010
|
+
}
|
|
1011
|
+
return sb64
|
|
1012
|
+
},
|
|
1013
|
+
{ ...options, listOf: false }
|
|
1014
|
+
),
|
|
1015
|
+
getExample: () => '129vjas0fkj1234jgfmnaef',
|
|
1016
|
+
getType: getTypeString,
|
|
1017
|
+
}
|
|
766
1018
|
|
|
767
|
-
export const subdomainValidator =
|
|
768
|
-
|
|
769
|
-
|
|
1019
|
+
export const subdomainValidator: ValidatorDefinition<string> = {
|
|
1020
|
+
validate: (options={}) => build_validator(
|
|
1021
|
+
subdomain => {
|
|
1022
|
+
if (typeof subdomain !== 'string') throw new Error("Expecting string value")
|
|
770
1023
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
1024
|
+
subdomain = subdomain.toLowerCase()
|
|
1025
|
+
if (subdomain.startsWith('-')) {
|
|
1026
|
+
subdomain = subdomain.substring(1)
|
|
1027
|
+
}
|
|
1028
|
+
while (subdomain.endsWith('-')) {
|
|
1029
|
+
subdomain = subdomain.substring(0, subdomain.length - 1)
|
|
1030
|
+
}
|
|
778
1031
|
|
|
779
|
-
|
|
1032
|
+
subdomain = subdomain.replace(/[^a-zA-Z\d-]/g, '')
|
|
780
1033
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
)
|
|
1034
|
+
return subdomain
|
|
1035
|
+
},
|
|
1036
|
+
{ ...options, maxLength: 50, listOf: false }
|
|
1037
|
+
),
|
|
1038
|
+
getExample: () => 'example',
|
|
1039
|
+
getType: getTypeString,
|
|
1040
|
+
}
|
|
785
1041
|
|
|
786
1042
|
type FileResponse = { type: 'file', name: string, secureName: string }
|
|
787
1043
|
// export const fileResponseValidator: EscapeBuilder<FileResponse> = (options={}) => build_validator(
|
|
@@ -796,16 +1052,16 @@ type FileResponse = { type: 'file', name: string, secureName: string }
|
|
|
796
1052
|
// { ...options, isObject: true, listOf: false }
|
|
797
1053
|
// )
|
|
798
1054
|
export const fileResponseValidator = objectValidator<FileResponse>({
|
|
799
|
-
type: exactMatchValidator(['file'])
|
|
800
|
-
name:
|
|
801
|
-
secureName: stringValidator250
|
|
1055
|
+
type: exactMatchValidator(['file']),
|
|
1056
|
+
name: stringValidator1000,
|
|
1057
|
+
secureName: stringValidator250,
|
|
802
1058
|
})
|
|
803
1059
|
|
|
804
1060
|
type SignatureResponse = { type: 'signature', signed: string | null, fullName: string }
|
|
805
1061
|
export const signatureResponseValidator = objectValidator<SignatureResponse>({
|
|
806
|
-
type: exactMatchValidator(['signature'])
|
|
807
|
-
fullName:
|
|
808
|
-
signed: booleanValidator
|
|
1062
|
+
type: exactMatchValidator(['signature']),
|
|
1063
|
+
fullName: stringValidator100,
|
|
1064
|
+
signed: booleanValidator,
|
|
809
1065
|
})
|
|
810
1066
|
|
|
811
1067
|
|
|
@@ -845,22 +1101,25 @@ const _FORM_FIELD_TYPES: { [K in FormFieldType]: any } = {
|
|
|
845
1101
|
export const FORM_FIELD_TYPES = Object.keys(_FORM_FIELD_TYPES) as FormFieldType[]
|
|
846
1102
|
export const formFieldTypeValidator = exactMatchValidator<FormFieldType>(FORM_FIELD_TYPES)
|
|
847
1103
|
|
|
848
|
-
export const FORM_FIELD_VALIDATORS_BY_TYPE: { [K in FormFieldType]: (value?: FormResponseValueAnswer[keyof FormResponseValueAnswer], options?: any, isOptional?: boolean) => any } = {
|
|
849
|
-
'string': stringValidator({ maxLength: 5000, emptyStringOk: true, errorMessage: "Response must not exceed 5000 characters" }),
|
|
850
|
-
'number': numberValidator({ errorMessage: "Response must be a number" }),
|
|
851
|
-
'email': emailValidator(),
|
|
1104
|
+
export const FORM_FIELD_VALIDATORS_BY_TYPE: { [K in FormFieldType | 'userEmail' | 'phoneNumber']: (value?: FormResponseValueAnswer[keyof FormResponseValueAnswer], options?: any, isOptional?: boolean) => any } = {
|
|
1105
|
+
'string': stringValidator.validate({ maxLength: 5000, emptyStringOk: true, errorMessage: "Response must not exceed 5000 characters" }),
|
|
1106
|
+
'number': numberValidator.validate({ errorMessage: "Response must be a number" }),
|
|
1107
|
+
'email': emailValidator.validate(),
|
|
1108
|
+
|
|
1109
|
+
'userEmail': emailValidator.validate(),
|
|
1110
|
+
'phone': phoneValidator.validate(),
|
|
1111
|
+
'phoneNumber': phoneValidator.validate(), // backwards compatibility with old field name for phone
|
|
852
1112
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
'phoneNumber': phoneValidator(), // backwards compatibility with old field name for phone
|
|
1113
|
+
"date": dateValidator.validate(),
|
|
1114
|
+
"ranking": listOfStringsValidator.validate(),
|
|
1115
|
+
"rating": numberValidator.validate(),
|
|
857
1116
|
|
|
858
1117
|
// fileInfo: FileResponse
|
|
859
1118
|
'file': (fileInfo: any, _, isOptional) => {
|
|
860
1119
|
if (isOptional && (!fileInfo || object_is_empty(fileInfo))) {
|
|
861
1120
|
return { type: 'file', secureName: null }
|
|
862
1121
|
}
|
|
863
|
-
return fileResponseValidator()(fileInfo)
|
|
1122
|
+
return fileResponseValidator.validate()(fileInfo)
|
|
864
1123
|
},
|
|
865
1124
|
// sigInfo: SignatureResponse
|
|
866
1125
|
|
|
@@ -868,7 +1127,7 @@ export const FORM_FIELD_VALIDATORS_BY_TYPE: { [K in FormFieldType]: (value?: For
|
|
|
868
1127
|
if (isOptional && (!sigInfo || object_is_empty(sigInfo))) {
|
|
869
1128
|
return { type: 'signature', signed: null }
|
|
870
1129
|
}
|
|
871
|
-
return signatureResponseValidator()(sigInfo)
|
|
1130
|
+
return signatureResponseValidator.validate()(sigInfo)
|
|
872
1131
|
},
|
|
873
1132
|
|
|
874
1133
|
// choiceInfo: { indexes: [], otherText?: string }
|
|
@@ -898,82 +1157,87 @@ export const FORM_FIELD_VALIDATORS_BY_TYPE: { [K in FormFieldType]: (value?: For
|
|
|
898
1157
|
return parsed
|
|
899
1158
|
},
|
|
900
1159
|
}
|
|
901
|
-
export const fieldsValidator:
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1160
|
+
export const fieldsValidator: ValidatorDefinition<Indexable<string | CustomField>> = {
|
|
1161
|
+
validate: (options={}) => build_validator(
|
|
1162
|
+
(fields: any) => {
|
|
1163
|
+
if (!is_object(fields)) throw new Error("Expecting an object")
|
|
1164
|
+
|
|
1165
|
+
for (const k in fields) {
|
|
1166
|
+
if (DEFAULT_ENDUSER_FIELDS.includes(k)) throw new Error(`key ${k} conflicts with a built-in field.`)
|
|
1167
|
+
if (k.startsWith('_')) throw new Error("Fields that start with '_' are not allowed")
|
|
1168
|
+
if (is_whitespace(k)) {
|
|
1169
|
+
delete fields[k]
|
|
1170
|
+
continue
|
|
1171
|
+
}
|
|
912
1172
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1173
|
+
if (k.length > 32) throw new Error(`key ${k} is greater than 32 characters`)
|
|
1174
|
+
|
|
1175
|
+
const val = fields[k]
|
|
1176
|
+
if (typeof val === 'string') {
|
|
1177
|
+
if (val.length > 512) fields[k] = val.substring(0, 512)
|
|
1178
|
+
continue
|
|
1179
|
+
} else if (typeof val === 'number' || val === null || typeof val === 'boolean') {
|
|
1180
|
+
continue // nothing to restrict on number type yet
|
|
1181
|
+
} else if (typeof val === 'object') {
|
|
1182
|
+
if (JSON.stringify(val).length > 1024) throw new Error(`object value for key ${k} exceeds the maximum length of 1024 characters in string representation`)
|
|
1183
|
+
// previous restricted structure for fields object
|
|
1184
|
+
// try {
|
|
1185
|
+
// if (val.type && typeof val.type === 'string') { // form responses can be stored as custom fields (form responses is simple array)
|
|
1186
|
+
// FORM_FIELD_VALIDATORS_BY_TYPE[val.type as keyof typeof FORM_FIELD_VALIDATORS_BY_TYPE](val, undefined as never, undefined as never)
|
|
1187
|
+
// continue
|
|
1188
|
+
// }
|
|
1189
|
+
// if (val.length && typeof val.length === 'number') { // array of strings is ok too, (inclusive of multiple-choice responses)
|
|
1190
|
+
// if (val.find((s: any) => typeof s !== 'string') !== undefined) {
|
|
1191
|
+
// throw new Error('List must contain only strings')
|
|
1192
|
+
// }
|
|
1193
|
+
// continue
|
|
1194
|
+
// }
|
|
1195
|
+
|
|
1196
|
+
// if (val.value === undefined) throw new Error(`value field is undefined for key ${k}`)
|
|
1197
|
+
// if (JSON.stringify(val).length > 1024) throw new Error(`object value for key ${k} exceeds the maximum length of 1024 characters in string representation`)
|
|
1198
|
+
|
|
1199
|
+
// const escaped = { value: val.value } as Indexable // create new object to omit unrecognized fields
|
|
1200
|
+
// escaped.title = val.title // optional
|
|
1201
|
+
// escaped.description = val.description // optional
|
|
1202
|
+
// fields[k] = escaped
|
|
1203
|
+
// } catch(err) {
|
|
1204
|
+
// throw new Error(`object value is invalid JSON for key ${k}`)
|
|
1205
|
+
// }
|
|
1206
|
+
} else {
|
|
1207
|
+
throw new Error(`Expecting value to be a string or object but got ${typeof val} for key {k}`)
|
|
1208
|
+
}
|
|
948
1209
|
}
|
|
949
|
-
}
|
|
950
1210
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
)
|
|
1211
|
+
return fields
|
|
1212
|
+
},
|
|
1213
|
+
{ ...options, isObject: true, listOf: false }
|
|
1214
|
+
),
|
|
1215
|
+
getExample: () => `{}`,
|
|
1216
|
+
getType: () => `{}`,
|
|
1217
|
+
}
|
|
955
1218
|
|
|
956
1219
|
export const preferenceValidator = exactMatchValidator<Preference>(['email', 'sms', 'call', 'chat'])
|
|
957
1220
|
|
|
958
1221
|
export const updateOptionsValidator = objectValidator<CustomUpdateOptions>({
|
|
959
|
-
replaceObjectFields:
|
|
960
|
-
})
|
|
1222
|
+
replaceObjectFields: booleanValidatorOptional,
|
|
1223
|
+
}, { isOptional: true })
|
|
961
1224
|
|
|
962
1225
|
export const journeyStatePriorityValidator = exactMatchValidator<JourneyStatePriority>(["Disengaged", "N/A", "Engaged"])
|
|
963
1226
|
|
|
964
1227
|
export const journeyStateValidator = objectValidator<JourneyState>({
|
|
965
|
-
name: stringValidator100
|
|
966
|
-
priority: journeyStatePriorityValidator
|
|
967
|
-
description:
|
|
968
|
-
requiresFollowup:
|
|
969
|
-
})
|
|
970
|
-
export const journeyStateUpdateValidator = objectValidator<JourneyState>({
|
|
971
|
-
name: stringValidator100({ isOptional: true }),
|
|
972
|
-
priority: journeyStatePriorityValidator({ isOptional: true }),
|
|
973
|
-
description: stringValidator({ isOptional: true }),
|
|
974
|
-
requiresFollowup: booleanValidator({ isOptional: true }),
|
|
1228
|
+
name: stringValidator100,
|
|
1229
|
+
priority: journeyStatePriorityValidator, // deprecated
|
|
1230
|
+
description: stringValidatorOptional, // deprecated
|
|
1231
|
+
requiresFollowup: booleanValidatorOptional, // deprecated
|
|
975
1232
|
})
|
|
976
|
-
|
|
1233
|
+
// deprecated
|
|
1234
|
+
// export const journeyStateUpdateValidator = objectValidator<JourneyState>({
|
|
1235
|
+
// name: stringValidator100({ isOptional: true }),
|
|
1236
|
+
// priority: journeyStatePriorityValidator({ isOptional: true }),
|
|
1237
|
+
// description: stringValidator({ isOptional: true }),
|
|
1238
|
+
// requiresFollowup: booleanValidator({ isOptional: true }),
|
|
1239
|
+
// })
|
|
1240
|
+
export const journeyStatesValidator = listValidator(journeyStateValidator)
|
|
977
1241
|
|
|
978
1242
|
export const emailEncodingValidator = exactMatchValidator<EmailEncoding>(['', 'base64'])
|
|
979
1243
|
|
|
@@ -991,28 +1255,32 @@ export const validateIndexable = <V>(keyValidator: EscapeFunction<string | numbe
|
|
|
991
1255
|
},
|
|
992
1256
|
{ ...o, isObject: true, listOf: false }
|
|
993
1257
|
)
|
|
994
|
-
export const indexableValidator = <V>(keyValidator:
|
|
995
|
-
validateIndexable(keyValidator, valueValidator)
|
|
996
|
-
)
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
)
|
|
1258
|
+
export const indexableValidator = <V>(keyValidator: ValidatorDefinition<string>, valueValidator: ValidatorDefinition<V>): ValidatorDefinition<{ [index: string]: V }> => ({
|
|
1259
|
+
validate: validateIndexable(keyValidator.validate(), valueValidator.validate()),
|
|
1260
|
+
getExample: () => `{ ${keyValidator.getExample()}: ${valueValidator.getExample()} }`,
|
|
1261
|
+
getType: () => `{ ${keyValidator.getType()}: ${valueValidator.getType()} }`,
|
|
1262
|
+
})
|
|
1263
|
+
export const indexableNumberValidator = <V>(keyValidator: ValidatorDefinition<number>, valueValidator: ValidatorDefinition<V>): ValidatorDefinition<{ [index: number]: V }> => ({
|
|
1264
|
+
validate: validateIndexable(keyValidator.validate(), valueValidator.validate()),
|
|
1265
|
+
getExample: () => `{ ${keyValidator.getExample()}: ${valueValidator.getExample()} }`,
|
|
1266
|
+
getType: () => `{ ${keyValidator.getType()}: ${valueValidator.getType()} }`,
|
|
1267
|
+
})
|
|
1000
1268
|
|
|
1001
1269
|
export const rejectionWithMessage: EscapeBuilder<undefined> = o => build_validator(
|
|
1002
1270
|
v => { throw new Error(o?.errorMessage || 'This field is not valid') },
|
|
1003
1271
|
{ ...o, isOptional: true, listOf: false, }
|
|
1004
1272
|
)
|
|
1005
1273
|
|
|
1006
|
-
export const numberToDateValidator = indexableNumberValidator(numberValidator
|
|
1007
|
-
export const idStringToDateValidator = indexableValidator(
|
|
1274
|
+
export const numberToDateValidator = indexableNumberValidator(numberValidator, dateValidator)
|
|
1275
|
+
export const idStringToDateValidator = indexableValidator(mongoIdStringRequired, dateValidator)
|
|
1008
1276
|
|
|
1009
1277
|
// todo: move preference to FIELD_TYPES with drop-down option in user-facing forms
|
|
1010
1278
|
const FIELD_TYPES = ['string', 'number', 'email', 'phone', 'multiple_choice', 'file', 'signature']
|
|
1011
1279
|
const VALIDATE_OPTIONS_FOR_FIELD_TYPES = {
|
|
1012
1280
|
'multiple_choice': {
|
|
1013
|
-
choices: listOfStringsValidator
|
|
1014
|
-
radio: booleanValidator
|
|
1015
|
-
other:
|
|
1281
|
+
choices: listOfStringsValidator,
|
|
1282
|
+
radio: booleanValidator,
|
|
1283
|
+
other: booleanValidatorOptional,
|
|
1016
1284
|
REQUIRED: ['choices', 'radio'],
|
|
1017
1285
|
}
|
|
1018
1286
|
}
|
|
@@ -1055,18 +1323,18 @@ const isFormField = (f: JSONType, fieldOptions={ forUpdate: false }) => {
|
|
|
1055
1323
|
|
|
1056
1324
|
|
|
1057
1325
|
if (!forUpdate && !field.type) throw `field.type is required` // fieldName otherwise given as 'field' in validation for every subfield
|
|
1058
|
-
if (field.type) exactMatchValidator(FIELD_TYPES)(field.type)
|
|
1326
|
+
if (field.type) exactMatchValidator(FIELD_TYPES).validate(field.type)
|
|
1059
1327
|
|
|
1060
1328
|
if (!forUpdate && !field.title) throw `field.title is required` // fieldName otherwise given as 'field' in validation for every subfield
|
|
1061
1329
|
if (field.title) {
|
|
1062
|
-
field.title = stringValidator({
|
|
1330
|
+
field.title = stringValidator.validate({
|
|
1063
1331
|
maxLength: 100,
|
|
1064
1332
|
errorMessage: "field title is required and must not exceed 100 characters"
|
|
1065
1333
|
})(field.title)
|
|
1066
1334
|
}
|
|
1067
1335
|
|
|
1068
1336
|
if (!forUpdate || field.description !== undefined){ // don't overwrite description on update with ''
|
|
1069
|
-
field.description = stringValidator({
|
|
1337
|
+
field.description = stringValidator.validate({
|
|
1070
1338
|
isOptional: true,
|
|
1071
1339
|
maxLength: 500,
|
|
1072
1340
|
errorMessage: "field description must be under 500 characters"
|
|
@@ -1091,7 +1359,7 @@ const isFormField = (f: JSONType, fieldOptions={ forUpdate: false }) => {
|
|
|
1091
1359
|
if (validators[k as keyof typeof validators] === undefined) {
|
|
1092
1360
|
throw new Error(`Got unexpected option ${k} for field of type ${INTERNAL_NAME_TO_DISPLAY_FIELD[field.type as keyof typeof INTERNAL_NAME_TO_DISPLAY_FIELD] || 'Text'}`)
|
|
1093
1361
|
}
|
|
1094
|
-
field.options[k] = (validators[k as keyof typeof validators] as
|
|
1362
|
+
field.options[k] = (validators[k as keyof typeof validators] as ValidatorDefinition).validate(field.options[k])
|
|
1095
1363
|
}
|
|
1096
1364
|
}
|
|
1097
1365
|
|
|
@@ -1114,59 +1382,60 @@ const isFormField = (f: JSONType, fieldOptions={ forUpdate: false }) => {
|
|
|
1114
1382
|
// validate optional vs not at endpoint-level
|
|
1115
1383
|
export const formResponseAnswerValidator = orValidator<{ [K in FormFieldType]: FormResponseValueAnswer & { type: K } } >({
|
|
1116
1384
|
email: objectValidator<FormResponseAnswerEmail>({
|
|
1117
|
-
type: exactMatchValidator(['email'])
|
|
1118
|
-
value:
|
|
1119
|
-
})
|
|
1385
|
+
type: exactMatchValidator(['email']),
|
|
1386
|
+
value: emailValidatorOptional,
|
|
1387
|
+
}),
|
|
1120
1388
|
number: objectValidator<FormResponseAnswerNumber>({
|
|
1121
|
-
type: exactMatchValidator(['number'])
|
|
1122
|
-
value:
|
|
1123
|
-
})
|
|
1389
|
+
type: exactMatchValidator(['number']),
|
|
1390
|
+
value: numberValidatorOptional,
|
|
1391
|
+
}),
|
|
1124
1392
|
rating: objectValidator<FormResponseAnswerRating>({
|
|
1125
|
-
type: exactMatchValidator(['rating'])
|
|
1126
|
-
value:
|
|
1127
|
-
})
|
|
1393
|
+
type: exactMatchValidator(['rating']),
|
|
1394
|
+
value: numberValidatorOptional,
|
|
1395
|
+
}),
|
|
1128
1396
|
phone: objectValidator<FormResponseAnswerPhone>({
|
|
1129
|
-
type: exactMatchValidator(['phone'])
|
|
1130
|
-
value:
|
|
1131
|
-
})
|
|
1397
|
+
type: exactMatchValidator(['phone']),
|
|
1398
|
+
value: phoneValidatorOptional,
|
|
1399
|
+
}),
|
|
1132
1400
|
string: objectValidator<FormResponseAnswerString>({
|
|
1133
|
-
type: exactMatchValidator(['string'])
|
|
1134
|
-
value:
|
|
1135
|
-
})
|
|
1401
|
+
type: exactMatchValidator(['string']),
|
|
1402
|
+
value: stringValidator5000Optional,
|
|
1403
|
+
}),
|
|
1136
1404
|
date: objectValidator<FormResponseAnswerDate>({
|
|
1137
|
-
type: exactMatchValidator(['date'])
|
|
1138
|
-
value:
|
|
1139
|
-
})
|
|
1405
|
+
type: exactMatchValidator(['date']),
|
|
1406
|
+
value: dateValidatorOptional,
|
|
1407
|
+
}),
|
|
1140
1408
|
file: objectValidator<FormResponseAnswerFile>({
|
|
1141
|
-
type: exactMatchValidator(['file'])
|
|
1409
|
+
type: exactMatchValidator(['file']),
|
|
1142
1410
|
value: objectValidator<FormResponseAnswerFileValue>({
|
|
1143
|
-
name: stringValidator5000
|
|
1144
|
-
secureName: stringValidator250
|
|
1145
|
-
}, { emptyOk: false
|
|
1146
|
-
})
|
|
1411
|
+
name: stringValidator5000,
|
|
1412
|
+
secureName: stringValidator250,
|
|
1413
|
+
}, { emptyOk: false, isOptional: true }),
|
|
1414
|
+
}),
|
|
1147
1415
|
multiple_choice: objectValidator<FormResponseAnswerMultipleChoice>({
|
|
1148
|
-
type: exactMatchValidator(['multiple_choice'])
|
|
1149
|
-
value:
|
|
1150
|
-
})
|
|
1416
|
+
type: exactMatchValidator(['multiple_choice']),
|
|
1417
|
+
value: listOfStringsValidatorEmptyOk,
|
|
1418
|
+
}),
|
|
1151
1419
|
ranking: objectValidator<FormResponseAnswerRanking>({
|
|
1152
|
-
type: exactMatchValidator(['ranking'])
|
|
1153
|
-
value:
|
|
1154
|
-
})
|
|
1420
|
+
type: exactMatchValidator(['ranking']),
|
|
1421
|
+
value: listOfStringsValidatorOptionalOrEmptyOk,
|
|
1422
|
+
}),
|
|
1155
1423
|
signature: objectValidator<FormResponseAnswerSignature>({
|
|
1156
|
-
type: exactMatchValidator(['signature'])
|
|
1424
|
+
type: exactMatchValidator(['signature']),
|
|
1157
1425
|
value: objectValidator<FormResponseAnswerSignatureValue>({
|
|
1158
|
-
fullName: stringValidator250
|
|
1159
|
-
signed: booleanValidator
|
|
1160
|
-
}, { emptyOk: false
|
|
1161
|
-
})
|
|
1426
|
+
fullName: stringValidator250,
|
|
1427
|
+
signed: booleanValidator,
|
|
1428
|
+
}, { emptyOk: false, isOptional: true }),
|
|
1429
|
+
}),
|
|
1162
1430
|
})
|
|
1163
1431
|
|
|
1164
1432
|
export const formResponseValidator = objectValidator<FormResponseValue>({
|
|
1165
1433
|
fieldId: mongoIdStringRequired,
|
|
1166
|
-
fieldTitle: stringValidator5000
|
|
1167
|
-
|
|
1434
|
+
fieldTitle: stringValidator5000,
|
|
1435
|
+
fieldDescription: stringValidator5000Optional,
|
|
1436
|
+
answer: formResponseAnswerValidator,
|
|
1168
1437
|
})
|
|
1169
|
-
export const formResponsesValidator = listValidator(formResponseValidator
|
|
1438
|
+
export const formResponsesValidator = listValidator(formResponseValidator)
|
|
1170
1439
|
|
|
1171
1440
|
export const intakePhoneValidator = exactMatchValidator<'optional' | 'required'>(['optional', 'required'])
|
|
1172
1441
|
|
|
@@ -1228,10 +1497,10 @@ export const CUD = Object.keys(_CUD) as CUDType[]
|
|
|
1228
1497
|
export const CUDStringValidator = exactMatchValidator<CUDType>(CUD)
|
|
1229
1498
|
|
|
1230
1499
|
export const CUDValidator = objectValidator<CUDSubscription>({
|
|
1231
|
-
create:
|
|
1232
|
-
update:
|
|
1233
|
-
delete:
|
|
1234
|
-
})
|
|
1500
|
+
create: booleanValidatorOptional,
|
|
1501
|
+
update: booleanValidatorOptional,
|
|
1502
|
+
delete: booleanValidatorOptional,
|
|
1503
|
+
}, { isOptional: true })
|
|
1235
1504
|
|
|
1236
1505
|
const _UNIT_OF_TIME: { [K in UnitOfTime]: any } = {
|
|
1237
1506
|
Days: '',
|
|
@@ -1243,9 +1512,9 @@ export const UNITS_OF_TIME = Object.keys(_UNIT_OF_TIME) as UnitOfTime[]
|
|
|
1243
1512
|
|
|
1244
1513
|
export const UnitOfTimeValidator = exactMatchValidator<UnitOfTime>(UNITS_OF_TIME)
|
|
1245
1514
|
|
|
1246
|
-
const WebhookSubscriptionValidatorObject = {} as { [K in WebhookSupportedModel]:
|
|
1515
|
+
const WebhookSubscriptionValidatorObject = {} as { [K in WebhookSupportedModel]: ValidatorDefinition<CUDSubscription> }
|
|
1247
1516
|
for (const model in WEBHOOK_MODELS) {
|
|
1248
|
-
WebhookSubscriptionValidatorObject[model as WebhookSupportedModel] = CUDValidator
|
|
1517
|
+
WebhookSubscriptionValidatorObject[model as WebhookSupportedModel] = CUDValidator
|
|
1249
1518
|
}
|
|
1250
1519
|
export const WebhookSubscriptionValidator = objectValidator<{ [K in WebhookSupportedModel]: CUDSubscription}>(
|
|
1251
1520
|
WebhookSubscriptionValidatorObject,
|
|
@@ -1255,15 +1524,15 @@ export const WebhookSubscriptionValidator = objectValidator<{ [K in WebhookSuppo
|
|
|
1255
1524
|
export const sessionTypeValidator = exactMatchValidator<SessionType>(['user', 'enduser'])
|
|
1256
1525
|
|
|
1257
1526
|
export const listOfDisplayNameInfo = listValidator(objectValidator<{ fname: string, lname: string, id: string }>({
|
|
1258
|
-
fname: nameValidator
|
|
1259
|
-
lname: nameValidator
|
|
1260
|
-
id: listOfMongoIdStringValidator
|
|
1261
|
-
})
|
|
1527
|
+
fname: nameValidator,
|
|
1528
|
+
lname: nameValidator,
|
|
1529
|
+
id: listOfMongoIdStringValidator,
|
|
1530
|
+
}))
|
|
1262
1531
|
|
|
1263
1532
|
export const attendeeInfoValidator = objectValidator<AttendeeInfo>({
|
|
1264
|
-
AttendeeId: stringValidator
|
|
1265
|
-
ExternalUserId:
|
|
1266
|
-
JoinToken: stringValidator
|
|
1533
|
+
AttendeeId: stringValidator,
|
|
1534
|
+
ExternalUserId: mongoIdStringRequired,
|
|
1535
|
+
JoinToken: stringValidator,
|
|
1267
1536
|
})
|
|
1268
1537
|
|
|
1269
1538
|
export const attendeeValidator = objectValidator<{
|
|
@@ -1271,55 +1540,55 @@ export const attendeeValidator = objectValidator<{
|
|
|
1271
1540
|
id: string,
|
|
1272
1541
|
info: AttendeeInfo,
|
|
1273
1542
|
}>({
|
|
1274
|
-
type: sessionTypeValidator
|
|
1275
|
-
id:
|
|
1276
|
-
info: attendeeInfoValidator
|
|
1543
|
+
type: sessionTypeValidator,
|
|
1544
|
+
id: mongoIdStringRequired,
|
|
1545
|
+
info: attendeeInfoValidator,
|
|
1277
1546
|
})
|
|
1278
|
-
export const listOfAttendeesValidator = listValidator(attendeeValidator
|
|
1547
|
+
export const listOfAttendeesValidator = listValidator(attendeeValidator)
|
|
1279
1548
|
export const meetingInfoValidator = objectValidator<{ Meeting: MeetingInfo }>({
|
|
1280
|
-
Meeting: objectAnyFieldsAnyValuesValidator
|
|
1549
|
+
Meeting: objectAnyFieldsAnyValuesValidator,
|
|
1281
1550
|
})
|
|
1282
1551
|
|
|
1283
1552
|
export const userIdentityValidator = objectValidator<{
|
|
1284
1553
|
type: SessionType,
|
|
1285
1554
|
id: string,
|
|
1286
1555
|
}>({
|
|
1287
|
-
type: sessionTypeValidator
|
|
1288
|
-
id:
|
|
1556
|
+
type: sessionTypeValidator,
|
|
1557
|
+
id: mongoIdStringRequired,
|
|
1289
1558
|
})
|
|
1290
|
-
export const listOfUserIndentitiesValidator = listValidator(userIdentityValidator
|
|
1559
|
+
export const listOfUserIndentitiesValidator = listValidator(userIdentityValidator)
|
|
1291
1560
|
|
|
1292
1561
|
export const chatAttachmentValidator = objectValidator<ChatAttachment>({
|
|
1293
|
-
type: exactMatchValidator<ChatAttachmentType>(['image', 'video', 'file'])
|
|
1294
|
-
secureName: stringValidator250
|
|
1562
|
+
type: exactMatchValidator<ChatAttachmentType>(['image', 'video', 'file']),
|
|
1563
|
+
secureName: stringValidator250,
|
|
1295
1564
|
})
|
|
1296
|
-
export const listOfChatAttachmentsValidator = listValidatorEmptyOk(chatAttachmentValidator
|
|
1565
|
+
export const listOfChatAttachmentsValidator = listValidatorEmptyOk(chatAttachmentValidator)
|
|
1297
1566
|
|
|
1298
1567
|
export const meetingsListValidator = listValidator(objectValidator<{
|
|
1299
1568
|
id: string,
|
|
1300
1569
|
updatedAt: string,
|
|
1301
1570
|
status: MeetingStatus,
|
|
1302
1571
|
}>({
|
|
1303
|
-
id:
|
|
1304
|
-
updatedAt: stringValidator
|
|
1305
|
-
status: meetingStatusValidator
|
|
1306
|
-
})
|
|
1572
|
+
id: mongoIdStringRequired,
|
|
1573
|
+
updatedAt: stringValidator,
|
|
1574
|
+
status: meetingStatusValidator,
|
|
1575
|
+
}))
|
|
1307
1576
|
|
|
1308
1577
|
export const userDisplayInfoValidator = objectValidator<UserDisplayInfo>({
|
|
1309
|
-
id:
|
|
1310
|
-
createdAt: dateValidator
|
|
1311
|
-
avatar: stringValidator
|
|
1312
|
-
fname: nameValidator
|
|
1313
|
-
lname: nameValidator
|
|
1314
|
-
lastActive: dateValidator
|
|
1315
|
-
lastLogout: dateValidator
|
|
1316
|
-
email: emailValidator
|
|
1578
|
+
id: mongoIdStringRequired,
|
|
1579
|
+
createdAt: dateValidator,
|
|
1580
|
+
avatar: stringValidator,
|
|
1581
|
+
fname: nameValidator,
|
|
1582
|
+
lname: nameValidator,
|
|
1583
|
+
lastActive: dateValidator,
|
|
1584
|
+
lastLogout: dateValidator,
|
|
1585
|
+
email: emailValidator,
|
|
1317
1586
|
})
|
|
1318
|
-
export const meetingDisplayInfoValidator = indexableValidator(mongoIdStringRequired, userDisplayInfoValidator
|
|
1587
|
+
export const meetingDisplayInfoValidator = indexableValidator(mongoIdStringRequired, userDisplayInfoValidator)
|
|
1319
1588
|
|
|
1320
1589
|
export const chatRoomUserInfoValidator = objectAnyFieldsValidator(objectValidator<ChatRoomUserInfo>({
|
|
1321
|
-
unreadCount: nonNegNumberValidator
|
|
1322
|
-
})
|
|
1590
|
+
unreadCount: nonNegNumberValidator,
|
|
1591
|
+
}))
|
|
1323
1592
|
|
|
1324
1593
|
const _AUTOMATION_ENDUSER_STATUS: { [K in AutomatedActionStatus]: any } = {
|
|
1325
1594
|
active: '',
|
|
@@ -1360,94 +1629,100 @@ export const MESSAGE_TEMPLATE_MODES = Object.keys(_MESSAGE_TEMPLATE_MODES) as Me
|
|
|
1360
1629
|
export const messageTemplateModeValidator = exactMatchValidator<MessageTemplateMode>(MESSAGE_TEMPLATE_MODES)
|
|
1361
1630
|
|
|
1362
1631
|
const sharedReminderValidators = {
|
|
1363
|
-
msBeforeStartTime: nonNegNumberValidator
|
|
1364
|
-
didRemind:
|
|
1632
|
+
msBeforeStartTime: nonNegNumberValidator,
|
|
1633
|
+
didRemind: booleanValidatorOptional,
|
|
1365
1634
|
}
|
|
1366
1635
|
|
|
1367
1636
|
export const calendarEventReminderValidator = orValidator<{ [K in CalendarEventReminderType]: CalendarEventReminderInfoForType[K] } >({
|
|
1368
1637
|
webhook: objectValidator<CalendarEventReminderInfoForType['webhook']>({
|
|
1369
|
-
info: objectValidator<{}>({}, { emptyOk: true
|
|
1370
|
-
type: exactMatchValidator<'webhook'>(['webhook'])
|
|
1638
|
+
info: objectValidator<{}>({}, { emptyOk: true, isOptional: true }),
|
|
1639
|
+
type: exactMatchValidator<'webhook'>(['webhook']),
|
|
1371
1640
|
...sharedReminderValidators,
|
|
1372
|
-
})
|
|
1641
|
+
}),
|
|
1373
1642
|
'add-to-journey': objectValidator<CalendarEventReminderInfoForType['add-to-journey']>({
|
|
1374
1643
|
info: objectValidator<CalendarEventReminderInfoForType['add-to-journey']['info']>({
|
|
1375
|
-
journeyId:
|
|
1376
|
-
})
|
|
1377
|
-
type: exactMatchValidator<'add-to-journey'>(['add-to-journey'])
|
|
1644
|
+
journeyId: mongoIdStringRequired,
|
|
1645
|
+
}),
|
|
1646
|
+
type: exactMatchValidator<'add-to-journey'>(['add-to-journey']),
|
|
1378
1647
|
...sharedReminderValidators,
|
|
1379
|
-
})
|
|
1648
|
+
}),
|
|
1380
1649
|
"enduser-notification": objectValidator<CalendarEventReminderInfoForType['enduser-notification']>({
|
|
1381
1650
|
info: objectValidator<CalendarEventReminderNotificationInfo>({
|
|
1382
|
-
templateId:
|
|
1383
|
-
}, { emptyOk: true })
|
|
1384
|
-
type: exactMatchValidator<'enduser-notification'>(['enduser-notification'])
|
|
1651
|
+
templateId: mongoIdStringOptional,
|
|
1652
|
+
}, { emptyOk: true }),
|
|
1653
|
+
type: exactMatchValidator<'enduser-notification'>(['enduser-notification']),
|
|
1385
1654
|
...sharedReminderValidators,
|
|
1386
|
-
})
|
|
1655
|
+
}),
|
|
1387
1656
|
"user-notification": objectValidator<CalendarEventReminderInfoForType['user-notification']>({
|
|
1388
1657
|
info: objectValidator<CalendarEventReminderNotificationInfo>({
|
|
1389
|
-
templateId:
|
|
1390
|
-
}, { emptyOk: true })
|
|
1391
|
-
type: exactMatchValidator<'user-notification'>(['user-notification'])
|
|
1658
|
+
templateId: mongoIdStringOptional,
|
|
1659
|
+
}, { emptyOk: true }),
|
|
1660
|
+
type: exactMatchValidator<'user-notification'>(['user-notification']),
|
|
1392
1661
|
...sharedReminderValidators,
|
|
1393
|
-
})
|
|
1662
|
+
}),
|
|
1394
1663
|
})
|
|
1395
|
-
export const listOfCalendarEventRemindersValidator = listValidatorEmptyOk(calendarEventReminderValidator
|
|
1664
|
+
export const listOfCalendarEventRemindersValidator = listValidatorEmptyOk(calendarEventReminderValidator)
|
|
1396
1665
|
|
|
1397
1666
|
export const cancelConditionsValidator = listOfObjectsValidator<CancelCondition>({
|
|
1398
|
-
type: exactMatchValidator(['formResponse'])
|
|
1667
|
+
type: exactMatchValidator(['formResponse']),
|
|
1399
1668
|
info: objectValidator<FormSubmitCancellationConditionInfo>({
|
|
1400
1669
|
automationStepId: mongoIdStringRequired,
|
|
1401
|
-
}, { emptyOk: false })
|
|
1670
|
+
}, { emptyOk: false }),
|
|
1402
1671
|
})
|
|
1672
|
+
export const cancelConditionsValidatorOptional = listValidatorOptionalOrEmptyOk(objectValidator<CancelCondition>({
|
|
1673
|
+
type: exactMatchValidator(['formResponse']),
|
|
1674
|
+
info: objectValidator<FormSubmitCancellationConditionInfo>({
|
|
1675
|
+
automationStepId: mongoIdStringRequired,
|
|
1676
|
+
}, { emptyOk: false }),
|
|
1677
|
+
}))
|
|
1403
1678
|
|
|
1404
1679
|
const delayValidation = {
|
|
1405
1680
|
automationStepId: mongoIdStringRequired,
|
|
1406
|
-
delayInMS: nonNegNumberValidator
|
|
1407
|
-
delay: nonNegNumberValidator
|
|
1408
|
-
unit: UnitOfTimeValidator
|
|
1409
|
-
cancelConditions:
|
|
1681
|
+
delayInMS: nonNegNumberValidator, // use 0 when no delay
|
|
1682
|
+
delay: nonNegNumberValidator, // for UI only
|
|
1683
|
+
unit: UnitOfTimeValidator, // for UI only
|
|
1684
|
+
cancelConditions: cancelConditionsValidatorOptional,
|
|
1410
1685
|
}
|
|
1411
1686
|
|
|
1412
1687
|
export const automationEventValidator = orValidator<{ [K in AutomationEventType]: AutomationEvent & { type: K } } >({
|
|
1413
1688
|
formResponse: objectValidator<FormResponseAutomationEvent>({
|
|
1414
|
-
type: exactMatchValidator(['formResponse'])
|
|
1689
|
+
type: exactMatchValidator(['formResponse']),
|
|
1415
1690
|
info: objectValidator<WithAutomationStepId>({
|
|
1416
|
-
automationStepId:
|
|
1417
|
-
}, { emptyOk: false })
|
|
1418
|
-
})
|
|
1691
|
+
automationStepId: mongoIdStringRequired,
|
|
1692
|
+
}, { emptyOk: false }),
|
|
1693
|
+
}),
|
|
1419
1694
|
afterAction: objectValidator<AfterActionAutomationEvent>({
|
|
1420
|
-
type: exactMatchValidator(['afterAction'])
|
|
1421
|
-
info: objectValidator<AfterActionEventInfo>(delayValidation, { emptyOk: false })
|
|
1422
|
-
})
|
|
1695
|
+
type: exactMatchValidator(['afterAction']),
|
|
1696
|
+
info: objectValidator<AfterActionEventInfo>(delayValidation, { emptyOk: false }),
|
|
1697
|
+
}),
|
|
1423
1698
|
formUnsubmitted: objectValidator<FormUnsubmittedEvent>({
|
|
1424
|
-
type: exactMatchValidator(['formUnsubmitted'])
|
|
1699
|
+
type: exactMatchValidator(['formUnsubmitted']),
|
|
1425
1700
|
info: objectValidator<FormUnsubmittedEventInfo>({
|
|
1426
1701
|
...delayValidation,
|
|
1427
1702
|
automationStepId: mongoIdStringRequired,
|
|
1428
|
-
}, { emptyOk: false })
|
|
1429
|
-
})
|
|
1703
|
+
}, { emptyOk: false }),
|
|
1704
|
+
}),
|
|
1430
1705
|
onJourneyStart: objectValidator<OnJourneyStartAutomationEvent>({
|
|
1431
|
-
type: exactMatchValidator(['onJourneyStart'])
|
|
1432
|
-
info: objectValidator<{}>({ }, { emptyOk: true })
|
|
1433
|
-
})
|
|
1706
|
+
type: exactMatchValidator(['onJourneyStart']),
|
|
1707
|
+
info: objectValidator<{}>({ }, { emptyOk: true }),
|
|
1708
|
+
}),
|
|
1434
1709
|
ticketCompleted: objectValidator<TicketCompletedAutomationEvent>({
|
|
1435
|
-
type: exactMatchValidator(['ticketCompleted'])
|
|
1710
|
+
type: exactMatchValidator(['ticketCompleted']),
|
|
1436
1711
|
info: objectValidator<TicketCompletedEventInfo>({
|
|
1437
1712
|
automationStepId: mongoIdStringRequired,
|
|
1438
|
-
closedForReason:
|
|
1439
|
-
}, { emptyOk: false })
|
|
1440
|
-
})
|
|
1713
|
+
closedForReason: stringValidatorOptional,
|
|
1714
|
+
}, { emptyOk: false }),
|
|
1715
|
+
}),
|
|
1441
1716
|
})
|
|
1442
|
-
export const automationEventsValidator = listValidatorEmptyOk(automationEventValidator
|
|
1717
|
+
export const automationEventsValidator = listValidatorEmptyOk(automationEventValidator)
|
|
1443
1718
|
|
|
1444
1719
|
export const automationConditionValidator = orValidator<{ [K in AutomationConditionType]: AutomationCondition & { type: K } } >({
|
|
1445
1720
|
atJourneyState: objectValidator<AtJourneyStateAutomationCondition>({
|
|
1446
|
-
type: exactMatchValidator(['atJourneyState'])
|
|
1447
|
-
info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100
|
|
1448
|
-
})
|
|
1721
|
+
type: exactMatchValidator(['atJourneyState']),
|
|
1722
|
+
info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100, journeyId: mongoIdStringRequired }, { emptyOk: false }),
|
|
1723
|
+
}),
|
|
1449
1724
|
})
|
|
1450
|
-
export const listOfAutomationConditionsValidator = listValidatorEmptyOk(automationConditionValidator
|
|
1725
|
+
export const listOfAutomationConditionsValidator = listValidatorEmptyOk(automationConditionValidator)
|
|
1451
1726
|
|
|
1452
1727
|
const _SEND_FORM_CHANNELS: { [K in SendFormChannel]: any } = {
|
|
1453
1728
|
Email: '',
|
|
@@ -1455,63 +1730,64 @@ const _SEND_FORM_CHANNELS: { [K in SendFormChannel]: any } = {
|
|
|
1455
1730
|
}
|
|
1456
1731
|
export const SEND_FORM_CHANNELS = Object.keys(_SEND_FORM_CHANNELS) as SendFormChannel[]
|
|
1457
1732
|
export const sendFormChannelValidator = exactMatchValidator<SendFormChannel>(SEND_FORM_CHANNELS)
|
|
1733
|
+
export const sendFormChannelValidatorOptional = exactMatchValidatorOptional<SendFormChannel>(SEND_FORM_CHANNELS)
|
|
1458
1734
|
|
|
1459
1735
|
export const automationActionValidator = orValidator<{ [K in AutomationActionType]: AutomationAction & { type: K } } >({
|
|
1460
1736
|
setEnduserStatus: objectValidator<SetEnduserStatusAutomationAction>({
|
|
1461
|
-
type: exactMatchValidator(['setEnduserStatus'])
|
|
1462
|
-
info: objectValidator<SetEnduserStatusInfo>({ status: stringValidator250
|
|
1463
|
-
})
|
|
1737
|
+
type: exactMatchValidator(['setEnduserStatus']),
|
|
1738
|
+
info: objectValidator<SetEnduserStatusInfo>({ status: stringValidator250 }, { emptyOk: false }),
|
|
1739
|
+
}),
|
|
1464
1740
|
sendEmail: objectValidator<SendEmailAutomationAction>({
|
|
1465
|
-
type: exactMatchValidator(['sendEmail'])
|
|
1466
|
-
info: objectValidator<AutomationForMessage>({ senderId:
|
|
1467
|
-
})
|
|
1741
|
+
type: exactMatchValidator(['sendEmail']),
|
|
1742
|
+
info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringRequired, templateId: mongoIdStringRequired }, { emptyOk: false }),
|
|
1743
|
+
}),
|
|
1468
1744
|
sendSMS: objectValidator<SendSMSAutomationAction>({
|
|
1469
|
-
type: exactMatchValidator(['sendSMS'])
|
|
1470
|
-
info: objectValidator<AutomationForMessage>({ senderId:
|
|
1471
|
-
})
|
|
1745
|
+
type: exactMatchValidator(['sendSMS']),
|
|
1746
|
+
info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringRequired, templateId: mongoIdStringRequired }, { emptyOk: false }),
|
|
1747
|
+
}),
|
|
1472
1748
|
sendForm: objectValidator<SendFormAutomationAction>({
|
|
1473
|
-
type: exactMatchValidator(['sendForm'])
|
|
1749
|
+
type: exactMatchValidator(['sendForm']),
|
|
1474
1750
|
info: objectValidator<AutomationForFormRequest>({
|
|
1475
|
-
senderId:
|
|
1476
|
-
formId:
|
|
1477
|
-
channel:
|
|
1478
|
-
}, { emptyOk: false })
|
|
1479
|
-
})
|
|
1751
|
+
senderId: mongoIdStringRequired,
|
|
1752
|
+
formId: mongoIdStringRequired,
|
|
1753
|
+
channel: sendFormChannelValidatorOptional,
|
|
1754
|
+
}, { emptyOk: false }),
|
|
1755
|
+
}),
|
|
1480
1756
|
createTicket: objectValidator<CreateTicketAutomationAction>({
|
|
1481
|
-
type: exactMatchValidator(['createTicket'])
|
|
1757
|
+
type: exactMatchValidator(['createTicket']),
|
|
1482
1758
|
info: objectValidator<CreateTicketActionInfo>({
|
|
1483
|
-
title:
|
|
1759
|
+
title: stringValidatorOptional,
|
|
1484
1760
|
assignmentStrategy: orValidator<{ [K in CreateTicketAssignmentStrategyType ]: CreateTicketAssignmentStrategy & { type: K } }>({
|
|
1485
1761
|
'care-team-random': objectValidator<CreateTicketAssignmentStrategy>({
|
|
1486
|
-
type: exactMatchValidator<CreateTicketAssignmentStrategyType>(['care-team-random'])
|
|
1487
|
-
info: objectValidator<object>({}, { emptyOk: true })
|
|
1488
|
-
})
|
|
1489
|
-
})
|
|
1490
|
-
closeReasons:
|
|
1762
|
+
type: exactMatchValidator<CreateTicketAssignmentStrategyType>(['care-team-random']),
|
|
1763
|
+
info: objectValidator<object>({}, { emptyOk: true }),
|
|
1764
|
+
})
|
|
1765
|
+
}),
|
|
1766
|
+
closeReasons: listOfStringsValidatorOptionalOrEmptyOk,
|
|
1491
1767
|
defaultAssignee: mongoIdStringRequired,
|
|
1492
|
-
}, { emptyOk: false })
|
|
1493
|
-
})
|
|
1768
|
+
}, { emptyOk: false }),
|
|
1769
|
+
}),
|
|
1494
1770
|
sendWebhook: objectValidator<SendWebhookAutomationAction>({
|
|
1495
|
-
type: exactMatchValidator(['sendWebhook'])
|
|
1496
|
-
info: objectValidator<AutomationForWebhook>({ message: stringValidator5000
|
|
1497
|
-
})
|
|
1771
|
+
type: exactMatchValidator(['sendWebhook']),
|
|
1772
|
+
info: objectValidator<AutomationForWebhook>({ message: stringValidator5000 }, { emptyOk: false }),
|
|
1773
|
+
}),
|
|
1498
1774
|
})
|
|
1499
1775
|
|
|
1500
1776
|
export const relatedRecordValidator = objectValidator<RelatedRecord>({
|
|
1501
|
-
type: stringValidator100
|
|
1502
|
-
id:
|
|
1777
|
+
type: stringValidator100,
|
|
1778
|
+
id: mongoIdStringRequired,
|
|
1503
1779
|
creator: mongoIdStringOptional,
|
|
1504
1780
|
})
|
|
1505
|
-
export const listOfRelatedRecordsValidator = listValidatorEmptyOk(relatedRecordValidator
|
|
1781
|
+
export const listOfRelatedRecordsValidator = listValidatorEmptyOk(relatedRecordValidator)
|
|
1506
1782
|
|
|
1507
1783
|
export const searchOptionsValidator = objectValidator<SearchOptions>({
|
|
1508
|
-
query: stringValidator100
|
|
1784
|
+
query: stringValidator100,
|
|
1509
1785
|
})
|
|
1510
1786
|
|
|
1511
1787
|
export const notificationPreferenceValidator = objectValidator<NotificationPreference>({
|
|
1512
|
-
email:
|
|
1788
|
+
email: booleanValidatorOptional,
|
|
1513
1789
|
})
|
|
1514
|
-
export const notificationPreferencesValidator = objectAnyFieldsValidator(notificationPreferenceValidator
|
|
1790
|
+
export const notificationPreferencesValidator = objectAnyFieldsValidator(notificationPreferenceValidator)
|
|
1515
1791
|
|
|
1516
1792
|
export const FHIRObservationCategoryValidator = exactMatchValidator<ObservationCategory>(['vital-signs'])
|
|
1517
1793
|
|
|
@@ -1529,42 +1805,42 @@ export const FHIR_OBSERVATION_STATUS_CODES = Object.keys(_FHIR_OBSERVATION_STATU
|
|
|
1529
1805
|
export const FHIRObservationStatusCodeValidator = exactMatchValidator<ObservationStatusCode>(FHIR_OBSERVATION_STATUS_CODES)
|
|
1530
1806
|
|
|
1531
1807
|
export const FHIRObservationValueValidator = objectValidator<ObservationValue>({
|
|
1532
|
-
unit: stringValidator
|
|
1533
|
-
value: numberValidator
|
|
1808
|
+
unit: stringValidator,
|
|
1809
|
+
value: numberValidator,
|
|
1534
1810
|
})
|
|
1535
1811
|
|
|
1536
1812
|
export const previousFormFieldValidator = orValidator<{ [K in PreviousFormFieldType]: PreviousFormField & { type: K } } >({
|
|
1537
1813
|
root: objectValidator<PreviousFormFieldRoot>({
|
|
1538
|
-
type: exactMatchValidator(['root'])
|
|
1539
|
-
info: objectValidator<{}>({}, { emptyOk: true })
|
|
1540
|
-
})
|
|
1814
|
+
type: exactMatchValidator(['root']),
|
|
1815
|
+
info: objectValidator<{}>({}, { emptyOk: true }),
|
|
1816
|
+
}),
|
|
1541
1817
|
"after": objectValidator<PreviousFormFieldAfter>({
|
|
1542
|
-
type: exactMatchValidator(['after'])
|
|
1543
|
-
info: objectValidator<PreviousFormFieldAfterInfo>({ fieldId: mongoIdStringRequired }, { emptyOk: false })
|
|
1544
|
-
})
|
|
1818
|
+
type: exactMatchValidator(['after']),
|
|
1819
|
+
info: objectValidator<PreviousFormFieldAfterInfo>({ fieldId: mongoIdStringRequired }, { emptyOk: false }),
|
|
1820
|
+
}),
|
|
1545
1821
|
"previousEquals": objectValidator<PreviousFormFieldEquals>({
|
|
1546
|
-
type: exactMatchValidator(['previousEquals'])
|
|
1822
|
+
type: exactMatchValidator(['previousEquals']),
|
|
1547
1823
|
info: objectValidator<PreviousFormFieldEqualsInfo>({
|
|
1548
1824
|
fieldId: mongoIdStringRequired,
|
|
1549
|
-
equals: stringValidator250
|
|
1550
|
-
}, { emptyOk: false })
|
|
1551
|
-
})
|
|
1825
|
+
equals: stringValidator250,
|
|
1826
|
+
}, { emptyOk: false }),
|
|
1827
|
+
}),
|
|
1552
1828
|
})
|
|
1553
|
-
export const previousFormFieldsValidator = listValidatorEmptyOk(previousFormFieldValidator
|
|
1829
|
+
export const previousFormFieldsValidator = listValidatorEmptyOk(previousFormFieldValidator)
|
|
1554
1830
|
|
|
1555
1831
|
export const portalSettingsValidator = objectValidator<PortalSettings>({
|
|
1556
1832
|
|
|
1557
1833
|
})
|
|
1558
1834
|
|
|
1559
1835
|
export const organizationThemeValidator = objectValidator<OrganizationTheme>({
|
|
1560
|
-
logoURL:
|
|
1561
|
-
themeColor:
|
|
1562
|
-
name: stringValidator250
|
|
1563
|
-
subdomain: stringValidator250
|
|
1564
|
-
businessId:
|
|
1565
|
-
faviconURL: stringValidator250
|
|
1566
|
-
customPortalURL: stringValidator250
|
|
1567
|
-
portalSettings: portalSettingsValidator
|
|
1836
|
+
logoURL: stringValidatorOptional, // these don't really need to be optional
|
|
1837
|
+
themeColor: stringValidatorOptional, // these don't really need to be optional
|
|
1838
|
+
name: stringValidator250,
|
|
1839
|
+
subdomain: stringValidator250,
|
|
1840
|
+
businessId: mongoIdStringRequired,
|
|
1841
|
+
faviconURL: stringValidator250,
|
|
1842
|
+
customPortalURL: stringValidator250,
|
|
1843
|
+
portalSettings: portalSettingsValidator,
|
|
1568
1844
|
})
|
|
1569
1845
|
|
|
1570
1846
|
const _MANAGED_CONTENT_RECORD_TYPES: { [K in ManagedContentRecordType]: any } = {
|
|
@@ -1575,104 +1851,110 @@ const _MANAGED_CONTENT_RECORD_TYPES: { [K in ManagedContentRecordType]: any } =
|
|
|
1575
1851
|
export const MANAGED_CONTENT_RECORD_TYPES = Object.keys(_MANAGED_CONTENT_RECORD_TYPES) as ManagedContentRecordType[]
|
|
1576
1852
|
export const managedContentRecordTypeValidator = exactMatchValidator<ManagedContentRecordType>(MANAGED_CONTENT_RECORD_TYPES)
|
|
1577
1853
|
|
|
1578
|
-
export const passwordValidator:
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1854
|
+
export const passwordValidator: ValidatorDefinition<string> = {
|
|
1855
|
+
getExample: getExampleString,
|
|
1856
|
+
getType: getTypeString,
|
|
1857
|
+
validate: (
|
|
1858
|
+
(o) => build_validator((password) => {
|
|
1859
|
+
if (typeof password !== 'string') {
|
|
1860
|
+
throw new Error("Password must be a string")
|
|
1861
|
+
}
|
|
1862
|
+
if (password.length < 8) {
|
|
1863
|
+
throw new Error("Password must be at least 8 characters long")
|
|
1864
|
+
}
|
|
1585
1865
|
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1866
|
+
if (
|
|
1867
|
+
(password.match(/[a-z]/g)?.length ?? 0) < 1 // 1 lowercase
|
|
1868
|
+
|| (
|
|
1869
|
+
(password.match(/[A-Z]/g)?.length ?? 0) < 1 // 1 uppercase
|
|
1870
|
+
&& (password.match(/[0-9]/g)?.length ?? 0) < 1 // 1 number
|
|
1871
|
+
&& (password.match(/[^a-zA-Z0-9]/g)?.length ?? 0) < 1 // 1 special character
|
|
1872
|
+
)
|
|
1873
|
+
) {
|
|
1874
|
+
console.error('bad password regex')
|
|
1875
|
+
throw new Error('Password must included 1 uppercase letter, 1 number, or 1 symbol')
|
|
1876
|
+
}
|
|
1597
1877
|
|
|
1598
|
-
|
|
1599
|
-
}, { ...o, listOf: false, emptyStringOk: false, })
|
|
1878
|
+
return password
|
|
1879
|
+
}, { ...o, listOf: false, emptyStringOk: false, })
|
|
1880
|
+
),
|
|
1881
|
+
}
|
|
1600
1882
|
|
|
1601
1883
|
export const flowchartUIValidator = objectValidator<FlowchartUI>({
|
|
1602
|
-
x: numberValidator
|
|
1603
|
-
y: numberValidator
|
|
1884
|
+
x: numberValidator,
|
|
1885
|
+
y: numberValidator,
|
|
1604
1886
|
}, { emptyOk: true })
|
|
1605
1887
|
|
|
1606
1888
|
|
|
1607
1889
|
|
|
1608
1890
|
export const integrationAuthenticationsValidator = objectValidator<IntegrationAuthentication>({
|
|
1609
|
-
type: exactMatchValidator(['oauth2'])
|
|
1891
|
+
type: exactMatchValidator(['oauth2']),
|
|
1610
1892
|
info: objectValidator<OAuth2AuthenticationFields>({
|
|
1611
|
-
access_token: stringValidator250
|
|
1612
|
-
refresh_token: stringValidator250
|
|
1613
|
-
scope: stringValidator5000
|
|
1614
|
-
expiry_date: nonNegNumberValidator
|
|
1615
|
-
token_type: exactMatchValidator<'Bearer'>(['Bearer'])
|
|
1616
|
-
state:
|
|
1617
|
-
email:
|
|
1618
|
-
})
|
|
1893
|
+
access_token: stringValidator250,
|
|
1894
|
+
refresh_token: stringValidator250,
|
|
1895
|
+
scope: stringValidator5000,
|
|
1896
|
+
expiry_date: nonNegNumberValidator,
|
|
1897
|
+
token_type: exactMatchValidator<'Bearer'>(['Bearer']),
|
|
1898
|
+
state: stringValidatorOptional,
|
|
1899
|
+
email: emailValidatorOptional,
|
|
1900
|
+
}),
|
|
1619
1901
|
})
|
|
1620
1902
|
|
|
1621
1903
|
|
|
1622
1904
|
export const formFieldOptionsValidator = objectValidator<FormFieldOptions>({
|
|
1623
|
-
choices:
|
|
1624
|
-
from:
|
|
1625
|
-
to:
|
|
1626
|
-
other:
|
|
1627
|
-
radio:
|
|
1905
|
+
choices: listOfStringsValidatorOptionalOrEmptyOk,
|
|
1906
|
+
from: numberValidatorOptional,
|
|
1907
|
+
to: numberValidatorOptional,
|
|
1908
|
+
other: stringValidatorOptional,
|
|
1909
|
+
radio: booleanValidatorOptional,
|
|
1628
1910
|
})
|
|
1629
1911
|
|
|
1630
1912
|
export const blockValidator = orValidator<{ [K in BlockType]: Block & { type: K } } >({
|
|
1631
1913
|
h1: objectValidator<BlockContentH1>({
|
|
1632
|
-
type: exactMatchValidator(['h1'])
|
|
1914
|
+
type: exactMatchValidator(['h1']),
|
|
1633
1915
|
info: objectValidator<BlockContentH1['info']>({
|
|
1634
|
-
text:
|
|
1635
|
-
})
|
|
1636
|
-
})
|
|
1916
|
+
text: stringValidator5000EmptyOkay,
|
|
1917
|
+
}),
|
|
1918
|
+
}),
|
|
1637
1919
|
h2: objectValidator<BlockContentH2>({
|
|
1638
|
-
type: exactMatchValidator(['h2'])
|
|
1920
|
+
type: exactMatchValidator(['h2']),
|
|
1639
1921
|
info: objectValidator<BlockContentH1['info']>({
|
|
1640
|
-
text:
|
|
1641
|
-
})
|
|
1642
|
-
})
|
|
1922
|
+
text: stringValidator5000EmptyOkay,
|
|
1923
|
+
}),
|
|
1924
|
+
}),
|
|
1643
1925
|
html: objectValidator<BlockContentHTML>({
|
|
1644
|
-
type: exactMatchValidator(['html'])
|
|
1926
|
+
type: exactMatchValidator(['html']),
|
|
1645
1927
|
info: objectValidator<BlockContentHTML['info']>({
|
|
1646
|
-
html:
|
|
1647
|
-
})
|
|
1648
|
-
})
|
|
1928
|
+
html: stringValidator25000EmptyOkay,
|
|
1929
|
+
}),
|
|
1930
|
+
}),
|
|
1649
1931
|
image: objectValidator<BlockContentImage>({
|
|
1650
|
-
type: exactMatchValidator(['image'])
|
|
1932
|
+
type: exactMatchValidator(['image']),
|
|
1651
1933
|
info: objectValidator<BlockContentImage['info']>({
|
|
1652
|
-
link:
|
|
1653
|
-
name:
|
|
1654
|
-
height:
|
|
1655
|
-
width:
|
|
1656
|
-
})
|
|
1657
|
-
})
|
|
1934
|
+
link: stringValidator5000EmptyOkay,
|
|
1935
|
+
name: stringValidatorOptional,
|
|
1936
|
+
height: numberValidatorOptional,
|
|
1937
|
+
width: numberValidatorOptional,
|
|
1938
|
+
}),
|
|
1939
|
+
}),
|
|
1658
1940
|
pdf: objectValidator<BlockContentPDF>({
|
|
1659
|
-
type: exactMatchValidator(['pdf'])
|
|
1941
|
+
type: exactMatchValidator(['pdf']),
|
|
1660
1942
|
info: objectValidator<BlockContentPDF['info']>({
|
|
1661
|
-
link:
|
|
1662
|
-
name:
|
|
1663
|
-
height:
|
|
1664
|
-
width:
|
|
1665
|
-
})
|
|
1666
|
-
})
|
|
1943
|
+
link: stringValidator5000EmptyOkay,
|
|
1944
|
+
name: stringValidatorOptional,
|
|
1945
|
+
height: numberValidatorOptional,
|
|
1946
|
+
width: numberValidatorOptional,
|
|
1947
|
+
}),
|
|
1948
|
+
}),
|
|
1667
1949
|
youtube: objectValidator<BlockContentYoutube>({
|
|
1668
|
-
type: exactMatchValidator(['youtube'])
|
|
1950
|
+
type: exactMatchValidator(['youtube']),
|
|
1669
1951
|
info: objectValidator<BlockContentYoutube['info']>({
|
|
1670
|
-
link:
|
|
1671
|
-
name:
|
|
1672
|
-
height:
|
|
1673
|
-
width:
|
|
1674
|
-
})
|
|
1675
|
-
})
|
|
1952
|
+
link: stringValidator5000EmptyOkay,
|
|
1953
|
+
name: stringValidatorOptional,
|
|
1954
|
+
height: numberValidatorOptional,
|
|
1955
|
+
width: numberValidatorOptional,
|
|
1956
|
+
}),
|
|
1957
|
+
}),
|
|
1676
1958
|
})
|
|
1677
1959
|
|
|
1678
1960
|
const _BLOCK_TYPES: { [K in BlockType]: any } = {
|
|
@@ -1687,7 +1969,7 @@ export const BLOCK_TYPES = Object.keys(_BLOCK_TYPES) as BlockType[]
|
|
|
1687
1969
|
export const blockTypeValidator = exactMatchValidator<BlockType>(BLOCK_TYPES)
|
|
1688
1970
|
export const is_block_type = (type: any): type is BlockType => BLOCK_TYPES.includes(type)
|
|
1689
1971
|
|
|
1690
|
-
export const blocksValidator = listValidatorEmptyOk(blockValidator
|
|
1972
|
+
export const blocksValidator = listValidatorEmptyOk(blockValidator)
|
|
1691
1973
|
|
|
1692
1974
|
|
|
1693
1975
|
const _DATABASE_RECORD_FIELD_TYPES: { [K in DatabaseRecordFieldType]: any } = {
|
|
@@ -1717,33 +1999,33 @@ export const is_database_record_field_type = (type: any): type is DatabaseRecord
|
|
|
1717
1999
|
|
|
1718
2000
|
// structure as above instead if need unique label or additional config based on type
|
|
1719
2001
|
export const databaseFieldValidator = objectValidator<DatabaseRecordField>({
|
|
1720
|
-
type: databaseRecordFieldTypeValidator
|
|
1721
|
-
label: stringValidator250
|
|
2002
|
+
type: databaseRecordFieldTypeValidator,
|
|
2003
|
+
label: stringValidator250,
|
|
1722
2004
|
})
|
|
1723
|
-
export const databaseFieldsValidator = listValidator(databaseFieldValidator
|
|
2005
|
+
export const databaseFieldsValidator = listValidator(databaseFieldValidator)
|
|
1724
2006
|
|
|
1725
2007
|
|
|
1726
2008
|
export const databaseRecordValueValidator = orValidator<{ [K in DatabaseRecordFieldType]: DatabaseRecordValues[K] } >({
|
|
1727
2009
|
string: objectValidator<DatabaseRecordValues['string']>({
|
|
1728
|
-
type: exactMatchValidator(['string'])
|
|
1729
|
-
value: stringValidator1000
|
|
1730
|
-
})
|
|
2010
|
+
type: exactMatchValidator(['string']),
|
|
2011
|
+
value: stringValidator1000,
|
|
2012
|
+
}),
|
|
1731
2013
|
'string-long': objectValidator<DatabaseRecordValues['string-long']>({
|
|
1732
|
-
type: exactMatchValidator(['string-long'])
|
|
1733
|
-
value: stringValidator5000
|
|
1734
|
-
})
|
|
2014
|
+
type: exactMatchValidator(['string-long']),
|
|
2015
|
+
value: stringValidator5000,
|
|
2016
|
+
}),
|
|
1735
2017
|
'number': objectValidator<DatabaseRecordValues['number']>({
|
|
1736
|
-
type: exactMatchValidator(['number'])
|
|
1737
|
-
value: numberValidator
|
|
1738
|
-
})
|
|
2018
|
+
type: exactMatchValidator(['number']),
|
|
2019
|
+
value: numberValidator,
|
|
2020
|
+
}),
|
|
1739
2021
|
})
|
|
1740
|
-
export const databaseRecordValuesValidator = listValidator(databaseRecordValueValidator
|
|
2022
|
+
export const databaseRecordValuesValidator = listValidator(databaseRecordValueValidator)
|
|
1741
2023
|
|
|
1742
2024
|
export const organizationAccessValidator = objectValidator<OrganizationAccess>({
|
|
1743
|
-
create:
|
|
1744
|
-
update:
|
|
1745
|
-
read:
|
|
1746
|
-
delete:
|
|
2025
|
+
create: booleanValidatorOptional,
|
|
2026
|
+
update: booleanValidatorOptional,
|
|
2027
|
+
read: booleanValidatorOptional,
|
|
2028
|
+
delete: booleanValidatorOptional,
|
|
1747
2029
|
})
|
|
1748
2030
|
|
|
1749
2031
|
const _PORTAL_PAGES: { [K in PortalPage]: any } = {
|
|
@@ -1760,33 +2042,33 @@ export const portalPageValidator = exactMatchValidator<PortalPage>(PORTAL_PAGES)
|
|
|
1760
2042
|
|
|
1761
2043
|
export const portalBlockValidator = orValidator<{ [K in PortalBlockType]: PortalBlockForType[K] } >({
|
|
1762
2044
|
carePlan: objectValidator<PortalBlockForType['carePlan']>({
|
|
1763
|
-
type: exactMatchValidator(['carePlan'])
|
|
1764
|
-
info: objectValidator<PortalBlockForType['carePlan']['info']>({}, { emptyOk: true })
|
|
1765
|
-
})
|
|
2045
|
+
type: exactMatchValidator(['carePlan']),
|
|
2046
|
+
info: objectValidator<PortalBlockForType['carePlan']['info']>({}, { emptyOk: true })
|
|
2047
|
+
}),
|
|
1766
2048
|
education: objectValidator<PortalBlockForType['education']>({
|
|
1767
|
-
type: exactMatchValidator(['education'])
|
|
1768
|
-
info: objectValidator<PortalBlockForType['education']['info']>({}, { emptyOk: true })
|
|
1769
|
-
})
|
|
2049
|
+
type: exactMatchValidator(['education']),
|
|
2050
|
+
info: objectValidator<PortalBlockForType['education']['info']>({}, { emptyOk: true })
|
|
2051
|
+
}),
|
|
1770
2052
|
careTeam: objectValidator<PortalBlockForType['careTeam']>({
|
|
1771
|
-
type: exactMatchValidator(['careTeam'])
|
|
2053
|
+
type: exactMatchValidator(['careTeam']),
|
|
1772
2054
|
info: objectValidator<PortalBlockForType['careTeam']['info']>({
|
|
1773
|
-
title: stringValidator
|
|
2055
|
+
title: stringValidator,
|
|
1774
2056
|
// members: listValidatorEmptyOk(
|
|
1775
2057
|
// objectValidator<CareTeamMemberPortalCustomizationInfo>({
|
|
1776
2058
|
// title: stringValidator(),
|
|
1777
2059
|
// role: stringValidator({ isOptional: true }),
|
|
1778
2060
|
// })()
|
|
1779
2061
|
// )()
|
|
1780
|
-
})
|
|
1781
|
-
})
|
|
2062
|
+
})
|
|
2063
|
+
}),
|
|
1782
2064
|
text: objectValidator<PortalBlockForType['text']>({
|
|
1783
|
-
type: exactMatchValidator(['text'])
|
|
2065
|
+
type: exactMatchValidator(['text']),
|
|
1784
2066
|
info: objectValidator<PortalBlockForType['text']['info']>({
|
|
1785
|
-
text: stringValidator5000
|
|
1786
|
-
})
|
|
1787
|
-
})
|
|
2067
|
+
text: stringValidator5000,
|
|
2068
|
+
})
|
|
2069
|
+
}),
|
|
1788
2070
|
})
|
|
1789
|
-
export const portalBlocksValidator = listValidatorEmptyOk(portalBlockValidator
|
|
2071
|
+
export const portalBlocksValidator = listValidatorEmptyOk(portalBlockValidator)
|
|
1790
2072
|
|
|
1791
2073
|
const _PORTAL_BLOCK_TYPES: { [K in PortalBlockType]: any } = {
|
|
1792
2074
|
carePlan: '',
|
|
@@ -1802,14 +2084,14 @@ export const enduserTaskForEventValidator = objectValidator<EnduserTaskForEvent>
|
|
|
1802
2084
|
id: mongoIdStringRequired,
|
|
1803
2085
|
enduserId: mongoIdStringRequired,
|
|
1804
2086
|
})
|
|
1805
|
-
export const enduserTasksForEventValidator = listValidatorEmptyOk(enduserTaskForEventValidator
|
|
2087
|
+
export const enduserTasksForEventValidator = listValidatorEmptyOk(enduserTaskForEventValidator)
|
|
1806
2088
|
|
|
1807
2089
|
export const enduserFormResponseForEventValidator = objectValidator<EnduserFormResponseForEvent>({
|
|
1808
2090
|
enduserId: mongoIdStringRequired,
|
|
1809
2091
|
formId: mongoIdStringRequired,
|
|
1810
|
-
accessCode: stringValidator1000
|
|
2092
|
+
accessCode: stringValidator1000,
|
|
1811
2093
|
})
|
|
1812
|
-
export const enduserFormResponsesForEventValidator = listValidatorEmptyOk(enduserFormResponseForEventValidator
|
|
2094
|
+
export const enduserFormResponsesForEventValidator = listValidatorEmptyOk(enduserFormResponseForEventValidator)
|
|
1813
2095
|
|
|
1814
2096
|
export const VALID_STATES: string[] = [
|
|
1815
2097
|
"AK",
|
|
@@ -1873,23 +2155,23 @@ export const VALID_STATES: string[] = [
|
|
|
1873
2155
|
export const stateValidator = exactMatchValidator(VALID_STATES)
|
|
1874
2156
|
|
|
1875
2157
|
export const stateCredentialValidator = objectValidator<StateCredentialInfo>({
|
|
1876
|
-
expiresAt:
|
|
1877
|
-
state: stateValidator
|
|
2158
|
+
expiresAt: dateValidatorOptional,
|
|
2159
|
+
state: stateValidator,
|
|
1878
2160
|
})
|
|
1879
|
-
export const stateCredentialsValidator = listValidatorEmptyOk(stateCredentialValidator
|
|
2161
|
+
export const stateCredentialsValidator = listValidatorEmptyOk(stateCredentialValidator)
|
|
1880
2162
|
|
|
1881
2163
|
export const availabilityBlockValidator = objectValidator<AvailabilityBlock>({
|
|
1882
|
-
durationInMinutes: nonNegNumberValidator
|
|
1883
|
-
startTimeInMS: nonNegNumberValidator
|
|
2164
|
+
durationInMinutes: nonNegNumberValidator,
|
|
2165
|
+
startTimeInMS: nonNegNumberValidator,
|
|
1884
2166
|
userId: mongoIdStringRequired,
|
|
1885
2167
|
})
|
|
1886
|
-
export const availabilityBlocksValidator = listValidatorEmptyOk(availabilityBlockValidator
|
|
2168
|
+
export const availabilityBlocksValidator = listValidatorEmptyOk(availabilityBlockValidator)
|
|
1887
2169
|
|
|
1888
2170
|
export const weeklyAvailabilityValidator = objectValidator<WeeklyAvailability>({
|
|
1889
|
-
dayOfWeekStartingSundayIndexedByZero: nonNegNumberValidator
|
|
1890
|
-
endTimeInMinutes: nonNegNumberValidator
|
|
1891
|
-
startTimeInMinutes: nonNegNumberValidator
|
|
2171
|
+
dayOfWeekStartingSundayIndexedByZero: nonNegNumberValidator,
|
|
2172
|
+
endTimeInMinutes: nonNegNumberValidator,
|
|
2173
|
+
startTimeInMinutes: nonNegNumberValidator,
|
|
1892
2174
|
})
|
|
1893
|
-
export const weeklyAvailabilitiesValidator = listValidatorEmptyOk(weeklyAvailabilityValidator
|
|
2175
|
+
export const weeklyAvailabilitiesValidator = listValidatorEmptyOk(weeklyAvailabilityValidator)
|
|
1894
2176
|
|
|
1895
2177
|
export const timezoneValidator = exactMatchValidator<Timezone>(Object.keys(TIMEZONES) as Timezone[])
|