@tellescope/validation 0.0.93 → 0.0.96

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,8 +1139,24 @@ 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
+ }, { emptyOk: false })(),
1147
+ })
1148
+
1149
+ const delayValidation = {
1150
+ automationStepId: mongoIdStringRequired,
1151
+ delayInMS: nonNegNumberValidator(), // use 0 when no delay
1152
+ delay: nonNegNumberValidator(), // for UI only
1153
+ unit: UnitOfTimeValidator(), // for UI only
1154
+ cancelConditions: cancelConditionsValidator({ isOptional: true, emptyListOk: true })
1155
+ }
1156
+
1073
1157
  export const calendarEventReminderValidator = objectValidator<CalendarEventReminder>({
1074
- type: exactMatchValidator<CalendarEventReminderType>(['webhook'])(),
1158
+ type: exactMatchValidator<CalendarEventReminderType>(['webhook'])(), // built-in calendar-specific reminder
1159
+ // action: use this field for general pupose automation event actions
1075
1160
  remindAt: nonNegNumberValidator(),
1076
1161
  didRemind: booleanValidator({ isOptional: true }),
1077
1162
  })()
@@ -1080,62 +1165,83 @@ 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<WithAutomationStepId>({
1177
+ automationStepId: mongoIdStringValidator(),
1178
+ }, { emptyOk: false })(),
1179
+ })(),
1180
+ afterAction: objectValidator<AfterActionAutomationEvent>({
1181
+ type: exactMatchValidator(['afterAction'])(),
1182
+ info: objectValidator<AfterActionEventInfo>(delayValidation, { emptyOk: false })(),
1183
+ })(),
1184
+ formUnsubmitted: objectValidator<FormUnsubmittedEvent>({
1185
+ type: exactMatchValidator(['formUnsubmitted'])(),
1186
+ info: objectValidator<FormUnsubmittedEventInfo>({
1187
+ ...delayValidation,
1188
+ automationStepId: mongoIdStringRequired,
1189
+ }, { emptyOk: false })(),
1190
+ })(),
1191
+ onJourneyStart: objectValidator<OnJourneyStartAutomationEvent>({
1192
+ type: exactMatchValidator(['onJourneyStart'])(),
1193
+ info: objectValidator<{}>({ }, { emptyOk: true })(),
1092
1194
  })(),
1093
1195
  })
1094
1196
 
1095
1197
  export const automationConditionValidator = orValidator<{ [K in AutomationConditionType]: AutomationCondition & { type: K } } >({
1096
1198
  atJourneyState: objectValidator<AtJourneyStateAutomationCondition>({
1097
1199
  type: exactMatchValidator(['atJourneyState'])(),
1098
- info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired })(),
1200
+ info: objectValidator<AutomationForJourneyAndState>({ state: stringValidator100(), journeyId: mongoIdStringRequired }, { emptyOk: false })(),
1099
1201
  })(),
1100
1202
  })
1101
1203
  export const listOfAutomationConditionsValidator = listValidatorEmptyOk(automationConditionValidator())
1102
1204
 
1103
1205
  export const automationActionValidator = orValidator<{ [K in AutomationActionType]: AutomationAction & { type: K } } >({
1206
+ setEnduserStatus: objectValidator<SetEnduserStatusAutomationAction>({
1207
+ type: exactMatchValidator(['setEnduserStatus'])(),
1208
+ info: objectValidator<SetEnduserStatusInfo>({ status: stringValidator250() }, { emptyOk: false })(),
1209
+ })(),
1104
1210
  sendEmail: objectValidator<SendEmailAutomationAction>({
1105
1211
  type: exactMatchValidator(['sendEmail'])(),
1106
- info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() })(),
1212
+ info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() }, { emptyOk: false })(),
1107
1213
  })(),
1108
1214
  sendSMS: objectValidator<SendSMSAutomationAction>({
1109
1215
  type: exactMatchValidator(['sendSMS'])(),
1110
- info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() })(),
1216
+ info: objectValidator<AutomationForMessage>({ senderId: mongoIdStringValidator(), templateId: mongoIdStringValidator() }, { emptyOk: false })(),
1111
1217
  })(),
1112
1218
  sendForm: objectValidator<SendFormAutomationAction>({
1113
1219
  type: exactMatchValidator(['sendForm'])(),
1114
- info: objectValidator<AutomationForFormRequest>({ senderId: mongoIdStringValidator(), formId: mongoIdStringValidator() })(),
1220
+ info: objectValidator<AutomationForFormRequest>({ senderId: mongoIdStringValidator(), formId: mongoIdStringValidator() }, { emptyOk: false })(),
1115
1221
  })(),
1116
- createTask: objectValidator<CreateTaskAutomationAction>({
1117
- type: exactMatchValidator(['createTask'])(),
1118
- info: objectValidator<AutomationForTemplate>({ templateId: mongoIdStringValidator() })(),
1222
+ createTicket: objectValidator<CreateTicketAutomationAction>({
1223
+ type: exactMatchValidator(['createTicket'])(),
1224
+ info: objectValidator<AutomationForTemplate>({ templateId: mongoIdStringValidator() }, { emptyOk: false })(),
1119
1225
  })(),
1120
1226
  sendNotification: objectValidator<SendNotificationAutomationAction>({
1121
1227
  type: exactMatchValidator(['sendNotification'])(),
1122
- info: objectValidator<AutomationForNotification>({ templateId: mongoIdStringRequired, destination: stringValidator5000() })(),
1228
+ info: objectValidator<AutomationForNotification>({ templateId: mongoIdStringRequired, destination: stringValidator5000() }, { emptyOk: false })(),
1123
1229
  })(),
1124
1230
  sendWebhook: objectValidator<SendWebhookAutomationAction>({
1125
1231
  type: exactMatchValidator(['sendWebhook'])(),
1126
- info: objectValidator<AutomationForWebhook>({ message: stringValidator5000() })(),
1232
+ info: objectValidator<AutomationForWebhook>({ message: stringValidator5000() }, { emptyOk: false })(),
1127
1233
  })(),
1128
1234
  updateStateForJourney: objectValidator<UpdateStateForJourneyAutomationAction>({
1129
1235
  type: exactMatchValidator(['updateStateForJourney'])(),
1130
- info: objectValidator<AutomationForJourneyAndState>({ journeyId: mongoIdStringRequired, state: stringValidator100() })(),
1236
+ info: objectValidator<AutomationForJourneyAndState>({ journeyId: mongoIdStringRequired, state: stringValidator100() }, { emptyOk: false })(),
1131
1237
  })(),
1132
1238
  addToSequence: objectValidator<AddToSequenceAutomationAction>({
1133
1239
  type: exactMatchValidator(['addToSequence'])(),
1134
- info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() })(),
1240
+ info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() }, { emptyOk: false })(),
1135
1241
  })(),
1136
1242
  removeFromSequence: objectValidator<RemoveFromSequenceAutomationAction>({
1137
1243
  type: exactMatchValidator(['removeFromSequence'])(),
1138
- info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() })(),
1244
+ info: objectValidator<AutomationForAutomation>({ automationId: mongoIdStringValidator() }, { emptyOk: false })(),
1139
1245
  })(),
1140
1246
  })
1141
1247