@tellescope/validation 0.0.92 → 0.0.95

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/src/validation.ts CHANGED
@@ -50,9 +50,8 @@ import {
50
50
  UpdateStateForJourneyAutomationAction,
51
51
  RemoveFromSequenceAutomationAction,
52
52
  AddToSequenceAutomationAction,
53
- AutomationEnduserStatus,
53
+ AutomatedActionStatus,
54
54
  AutomationForTemplate,
55
- CreateTaskAutomationAction,
56
55
  ChatAttachment,
57
56
  FormFieldType,
58
57
  FormResponseValue,
@@ -66,6 +65,18 @@ import {
66
65
  ChatRoomUserInfo,
67
66
  RelatedRecord,
68
67
  SearchOptions,
68
+ WithAutomationStepId,
69
+ AfterActionEventInfo,
70
+ AfterActionAutomationEvent,
71
+ OnJourneyStartAutomationEvent,
72
+ UnitOfTime,
73
+ CreateTicketAutomationAction,
74
+ FormUnsubmittedEvent,
75
+ FormUnsubmittedEventInfo,
76
+ CancelCondition,
77
+ FormSubmitCancellationConditionInfo,
78
+ SetEnduserStatusAutomationAction,
79
+ SetEnduserStatusInfo,
69
80
  } from "@tellescope/types-models"
70
81
  import {
71
82
  UserDisplayInfo,
@@ -263,7 +274,7 @@ export const orValidator = <T>(escapeFunctions: { [K in keyof T]: EscapeFunction
263
274
  return escape(value)
264
275
  } catch(err) { continue }
265
276
  }
266
- throw 'Value does not match any of the expected options'
277
+ throw `Value does not match any of the expected options`
267
278
  },
268
279
  { ...o, listOf: false }
269
280
  )
@@ -278,7 +289,11 @@ export const filterCommandsValidator: EscapeBuilder<FilterType> = (o={}) => buil
278
289
  }, { ...o, isObject: true, listOf: false }
279
290
  )
280
291
 
281
- export const objectValidator = <T extends object>(i: InputValidation<Required<T>>, objectOptions={ emptyOk: true }): EscapeBuilder<T> => (o={}) => build_validator(
292
+ interface ObjectOptions {
293
+ emptyOk?: boolean,
294
+ throwOnUnrecognizedField?: boolean,
295
+ }
296
+ export const objectValidator = <T extends object>(i: InputValidation<Required<T>>, objectOptions={ emptyOk: true } as ObjectOptions): EscapeBuilder<T> => (o={}) => build_validator(
282
297
  (object: any) => {
283
298
  const emptyOk = objectOptions.emptyOk ?? true
284
299
  const validated = {} as T
@@ -290,14 +305,17 @@ export const objectValidator = <T extends object>(i: InputValidation<Required<T>
290
305
  throw new Error(`Expected a non-empty object`)
291
306
  }
292
307
 
293
- const unrecognizedFields = []
294
- for (const field in object) {
295
- if (!(i as Indexable)[field]) {
296
- unrecognizedFields.push(field)
297
- }
298
- }
299
- if (unrecognizedFields.length > 0) {
300
- throw new Error(`Got unexpected field(s) [${unrecognizedFields.join(', ')}]`)
308
+ // don't throw on unrecognized fields, just ignore/don't validate them
309
+ if (objectOptions.throwOnUnrecognizedField) {
310
+ const unrecognizedFields = []
311
+ for (const field in object) {
312
+ if (!(i as Indexable)[field]) {
313
+ unrecognizedFields.push(field)
314
+ }
315
+ }
316
+ if (unrecognizedFields.length > 0) {
317
+ throw new Error(`Got unexpected field(s) [${unrecognizedFields.join(', ')}]`)
318
+ }
301
319
  }
302
320
 
303
321
  for (const field in i) {
@@ -311,6 +329,41 @@ export const objectValidator = <T extends object>(i: InputValidation<Required<T>
311
329
  return validated
312
330
  }, { ...o, isObject: true, listOf: false }
313
331
  )
332
+ export const listOfObjectsValidator = <T extends object>(i: InputValidation<Required<T>>, objectOptions={ emptyOk: true }): EscapeBuilder<T[]> => (o={}) => build_validator(
333
+ (object: any) => {
334
+ const emptyOk = !!objectOptions.emptyOk
335
+ const validated = {} as T
336
+
337
+ if (!is_object(object)) {
338
+ throw new Error(`Expected a non-null object by got ${object}`)
339
+ }
340
+ if (!emptyOk && object_is_empty(object)) {
341
+ throw new Error(`Expected a non-empty object`)
342
+ }
343
+
344
+ // don't throw on unrecognized fields, just ignore/don't validate them
345
+ // const unrecognizedFields = []
346
+ // for (const field in object) {
347
+ // if (!(i as Indexable)[field]) {
348
+ // unrecognizedFields.push(field)
349
+ // }
350
+ // }
351
+ // if (unrecognizedFields.length > 0) {
352
+ // throw new Error(`Got unexpected field(s) [${unrecognizedFields.join(', ')}]`)
353
+ // }
354
+
355
+ for (const field in i) {
356
+ const value = (object as Indexable)[field]
357
+
358
+ const escaped = i[field](value) // may be required
359
+ if (escaped === undefined) continue
360
+
361
+ validated[field] = escaped
362
+ }
363
+
364
+ return validated
365
+ }, { ...o, isObject: true, listOf: true }
366
+ )
314
367
 
315
368
  export const objectAnyFieldsValidator = <T=string | number>(valueValidator?: EscapeFunction<T>): EscapeBuilder<Indexable<T>> => (o={}) => build_validator(
316
369
  (object: any) => {
@@ -498,7 +551,7 @@ export const journeysValidator: EscapeBuilder<Indexable> = (options={}) => build
498
551
  }
499
552
 
500
553
  const mIdValidator = mongoIdValidator()
501
- const stateValidator = stringValidator({ maxLength: 75, errorMessage: "Journey state names may not exceed 75 characters" })
554
+ const stateValidator = stringValidator({ isOptional: true, maxLength: 75, errorMessage: "Journey state names may not exceed 75 characters" })
502
555
  for (const j in journeys) {
503
556
  mIdValidator(j);
504
557
  (journeys as Indexable)[j] = stateValidator(journeys[j as keyof typeof journeys]);
@@ -955,12 +1008,23 @@ export const CUDValidator = objectValidator<CUDSubscription>({
955
1008
  delete: booleanValidator({ isOptional: true }),
956
1009
  })
957
1010
 
1011
+ const _UNIT_OF_TIME: { [K in UnitOfTime]: any } = {
1012
+ Days: '',
1013
+ Hours: '',
1014
+ Minutes: '',
1015
+ Seconds: '',
1016
+ }
1017
+ export const UNITS_OF_TIME = Object.keys(_UNIT_OF_TIME) as UnitOfTime[]
1018
+
1019
+ export const UnitOfTimeValidator = exactMatchValidator<UnitOfTime>(UNITS_OF_TIME)
1020
+
958
1021
  const WebhookSubscriptionValidatorObject = {} as { [K in WebhookSupportedModel]: EscapeFunction<CUDSubscription> }
959
1022
  for (const model in WEBHOOK_MODELS) {
960
1023
  WebhookSubscriptionValidatorObject[model as WebhookSupportedModel] = CUDValidator({ listOf: false, isOptional: true })
961
1024
  }
962
1025
  export const WebhookSubscriptionValidator = objectValidator<{ [K in WebhookSupportedModel]: CUDSubscription}>(
963
- WebhookSubscriptionValidatorObject
1026
+ WebhookSubscriptionValidatorObject,
1027
+ { throwOnUnrecognizedField: true }
964
1028
  )
965
1029
 
966
1030
  export const sessionTypeValidator = exactMatchValidator<SessionType>(['user', 'enduser'])
@@ -1032,18 +1096,22 @@ export const chatRoomUserInfoValidator = objectAnyFieldsValidator(objectValidato
1032
1096
  unreadCount: nonNegNumberValidator(),
1033
1097
  })())
1034
1098
 
1035
- const _AUTOMATION_ENDUSER_STATUS: { [K in AutomationEnduserStatus]: any } = {
1099
+ const _AUTOMATION_ENDUSER_STATUS: { [K in AutomatedActionStatus]: any } = {
1036
1100
  active: '',
1037
- paused: '',
1038
1101
  finished: '',
1102
+ cancelled: '',
1103
+ error: '',
1039
1104
  }
1040
- export const AUTOMATION_ENDUSER_STATUS = Object.keys(_AUTOMATION_ENDUSER_STATUS) as AutomationEnduserStatus[]
1041
- export const automationEnduserStatusValidator = exactMatchValidator<AutomationEnduserStatus>(AUTOMATION_ENDUSER_STATUS)
1105
+ export const AUTOMATION_ENDUSER_STATUS = Object.keys(_AUTOMATION_ENDUSER_STATUS) as AutomatedActionStatus[]
1106
+ export const automatedActionStatusValidator = exactMatchValidator<AutomatedActionStatus>(AUTOMATION_ENDUSER_STATUS)
1042
1107
 
1043
1108
  const _AUTOMATION_EVENTS: { [K in AutomationEventType]: any } = {
1044
1109
  enterState: '',
1045
1110
  formResponse: '',
1046
1111
  leaveState: '',
1112
+ afterAction: '',
1113
+ onJourneyStart: '',
1114
+ formUnsubmitted: '',
1047
1115
  }
1048
1116
  export const AUTOMATION_EVENTS = Object.keys(_AUTOMATION_EVENTS) as AutomationEventType[]
1049
1117
  export const automationEventTypeValidator = exactMatchValidator<AutomationEventType>(AUTOMATION_EVENTS)
@@ -1051,13 +1119,14 @@ export const automationEventTypeValidator = exactMatchValidator<AutomationEventT
1051
1119
  const _AUTOMATION_ACTIONS: { [K in AutomationActionType]: any } = {
1052
1120
  addToSequence: '',
1053
1121
  removeFromSequence: '',
1054
- createTask: '',
1122
+ createTicket: '',
1055
1123
  sendEmail: '',
1056
1124
  sendSMS: '',
1057
1125
  sendForm: '',
1058
1126
  sendNotification: '',
1059
1127
  updateStateForJourney: '',
1060
1128
  sendWebhook: '',
1129
+ setEnduserStatus: '',
1061
1130
  }
1062
1131
  export const AUTOMATION_ACTIONS = Object.keys(_AUTOMATION_ACTIONS) as AutomationActionType[]
1063
1132
  export const automationActionTypeValidator = exactMatchValidator<AutomationActionType>(AUTOMATION_ACTIONS)
@@ -1070,6 +1139,22 @@ const _MESSAGE_TEMPLATE_MODES: { [K in MessageTemplateMode]: any } = {
1070
1139
  export const MESSAGE_TEMPLATE_MODES = Object.keys(_MESSAGE_TEMPLATE_MODES) as MessageTemplateMode[]
1071
1140
  export const messageTemplateModeValidator = exactMatchValidator<MessageTemplateMode>(MESSAGE_TEMPLATE_MODES)
1072
1141
 
1142
+ export const cancelConditionsValidator = listOfObjectsValidator<CancelCondition>({
1143
+ type: exactMatchValidator(['formResponse'])(),
1144
+ info: objectValidator<FormSubmitCancellationConditionInfo>({
1145
+ automationStepId: mongoIdStringRequired,
1146
+ formId: mongoIdStringRequired,
1147
+ }, { emptyOk: false })(),
1148
+ })
1149
+
1150
+ const delayValidation = {
1151
+ automationStepId: mongoIdStringRequired,
1152
+ delayInMS: nonNegNumberValidator(), // use 0 when no delay
1153
+ delay: nonNegNumberValidator(), // for UI only
1154
+ unit: UnitOfTimeValidator(), // for UI only
1155
+ cancelConditions: cancelConditionsValidator({ isOptional: true, emptyListOk: true })
1156
+ }
1157
+
1073
1158
  export const calendarEventReminderValidator = objectValidator<CalendarEventReminder>({
1074
1159
  type: exactMatchValidator<CalendarEventReminderType>(['webhook'])(),
1075
1160
  remindAt: nonNegNumberValidator(),
@@ -1080,62 +1165,85 @@ export const listOfCalendarEventRemindersValidator = listValidator(calendarEvent
1080
1165
  export const automationEventValidator = orValidator<{ [K in AutomationEventType]: AutomationEvent & { type: K } } >({
1081
1166
  enterState: objectValidator<EnterStateAutomationEvent>({
1082
1167
  type: exactMatchValidator(['enterState'])(),
1083
- info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired })(),
1168
+ info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired }, { emptyOk: false })(),
1084
1169
  })(),
1085
1170
  leaveState: objectValidator<LeaveStateAutomationEvent>({
1086
1171
  type: exactMatchValidator(['leaveState'])(),
1087
- info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired })(),
1172
+ info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired }, { emptyOk: false })(),
1088
1173
  })(),
1089
1174
  formResponse: objectValidator<FormResponseAutomationEvent>({
1090
1175
  type: exactMatchValidator(['formResponse'])(),
1091
- info: objectValidator<AutomationForForm>({ formId: mongoIdStringValidator() })(),
1176
+ info: objectValidator<AutomationForForm & WithAutomationStepId>({
1177
+ formId: mongoIdStringValidator(),
1178
+ automationStepId: mongoIdStringValidator(),
1179
+ }, { emptyOk: false })(),
1180
+ })(),
1181
+ afterAction: objectValidator<AfterActionAutomationEvent>({
1182
+ type: exactMatchValidator(['afterAction'])(),
1183
+ info: objectValidator<AfterActionEventInfo>(delayValidation, { emptyOk: false })(),
1184
+ })(),
1185
+ formUnsubmitted: objectValidator<FormUnsubmittedEvent>({
1186
+ type: exactMatchValidator(['formUnsubmitted'])(),
1187
+ info: objectValidator<FormUnsubmittedEventInfo>({
1188
+ ...delayValidation,
1189
+ automationStepId: mongoIdStringRequired,
1190
+ formId: mongoIdStringRequired,
1191
+ }, { emptyOk: false })(),
1192
+ })(),
1193
+ onJourneyStart: objectValidator<OnJourneyStartAutomationEvent>({
1194
+ type: exactMatchValidator(['onJourneyStart'])(),
1195
+ info: objectValidator<{}>({ }, { emptyOk: true })(),
1092
1196
  })(),
1093
1197
  })
1094
1198
 
1095
1199
  export const automationConditionValidator = orValidator<{ [K in AutomationConditionType]: AutomationCondition & { type: K } } >({
1096
1200
  atJourneyState: objectValidator<AtJourneyStateAutomationCondition>({
1097
1201
  type: exactMatchValidator(['atJourneyState'])(),
1098
- info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired })(),
1202
+ info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired }, { emptyOk: false })(),
1099
1203
  })(),
1100
1204
  })
1101
1205
  export const listOfAutomationConditionsValidator = listValidatorEmptyOk(automationConditionValidator())
1102
1206
 
1103
1207
  export const automationActionValidator = orValidator<{ [K in AutomationActionType]: AutomationAction & { type: K } } >({
1208
+ setEnduserStatus: objectValidator<SetEnduserStatusAutomationAction>({
1209
+ type: exactMatchValidator(['setEnduserStatus'])(),
1210
+ info: objectValidator<SetEnduserStatusInfo>({ status: stringValidator250() }, { emptyOk: false })(),
1211
+ })(),
1104
1212
  sendEmail: objectValidator<SendEmailAutomationAction>({
1105
1213
  type: exactMatchValidator(['sendEmail'])(),
1106
- info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() })(),
1214
+ info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() }, { emptyOk: false })(),
1107
1215
  })(),
1108
1216
  sendSMS: objectValidator<SendSMSAutomationAction>({
1109
1217
  type: exactMatchValidator(['sendSMS'])(),
1110
- info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() })(),
1218
+ info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() }, { emptyOk: false })(),
1111
1219
  })(),
1112
1220
  sendForm: objectValidator<SendFormAutomationAction>({
1113
1221
  type: exactMatchValidator(['sendForm'])(),
1114
- info: objectValidator<AutomationForFormRequest>({ senderId: mongoIdStringValidator(), formId: mongoIdStringValidator() })(),
1222
+ info: objectValidator<AutomationForFormRequest>({ senderId: mongoIdStringValidator(), formId: mongoIdStringValidator() }, { emptyOk: false })(),
1115
1223
  })(),
1116
- createTask: objectValidator<CreateTaskAutomationAction>({
1117
- type: exactMatchValidator(['createTask'])(),
1118
- info: objectValidator<AutomationForTemplate>({ templateId: mongoIdStringValidator() })(),
1224
+ createTicket: objectValidator<CreateTicketAutomationAction>({
1225
+ type: exactMatchValidator(['createTicket'])(),
1226
+ info: objectValidator<AutomationForTemplate>({ templateId: mongoIdStringValidator() }, { emptyOk: false })(),
1119
1227
  })(),
1120
1228
  sendNotification: objectValidator<SendNotificationAutomationAction>({
1121
1229
  type: exactMatchValidator(['sendNotification'])(),
1122
- info: objectValidator<AutomationForNotification>({ templateId: mongoIdStringRequired, destination: stringValidator5000() })(),
1230
+ info: objectValidator<AutomationForNotification>({ templateId: mongoIdStringRequired, destination: stringValidator5000() }, { emptyOk: false })(),
1123
1231
  })(),
1124
1232
  sendWebhook: objectValidator<SendWebhookAutomationAction>({
1125
1233
  type: exactMatchValidator(['sendWebhook'])(),
1126
- info: objectValidator<AutomationForWebhook>({ message: stringValidator5000() })(),
1234
+ info: objectValidator<AutomationForWebhook>({ message: stringValidator5000() }, { emptyOk: false })(),
1127
1235
  })(),
1128
1236
  updateStateForJourney: objectValidator<UpdateStateForJourneyAutomationAction>({
1129
1237
  type: exactMatchValidator(['updateStateForJourney'])(),
1130
- info: objectValidator<AutomationForJourneyAndState>({ journeyId: mongoIdStringRequired, state: stringValidator100() })(),
1238
+ info: objectValidator<AutomationForJourneyAndState>({ journeyId: mongoIdStringRequired, state: stringValidator100() }, { emptyOk: false })(),
1131
1239
  })(),
1132
1240
  addToSequence: objectValidator<AddToSequenceAutomationAction>({
1133
1241
  type: exactMatchValidator(['addToSequence'])(),
1134
- info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() })(),
1242
+ info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() }, { emptyOk: false })(),
1135
1243
  })(),
1136
1244
  removeFromSequence: objectValidator<RemoveFromSequenceAutomationAction>({
1137
1245
  type: exactMatchValidator(['removeFromSequence'])(),
1138
- info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() })(),
1246
+ info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() }, { emptyOk: false })(),
1139
1247
  })(),
1140
1248
  })
1141
1249