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