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