@tellescope/schema 0.0.6 → 0.0.10

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/schema.ts CHANGED
@@ -1,7 +1,29 @@
1
- import "@tellescope/types"
2
- // import "@tellescope/types-server"
1
+ import {
2
+ ServerModelForName,
3
+ DatabaseModel,
4
+ DatabaseRecord,
5
+ Enduser,
6
+ ObjectId,
7
+ ModelName,
8
+ } from "@tellescope/types-server"
9
+ import {
10
+ ErrorInfo,
11
+ Indexable,
12
+ Operation,
13
+ JSONType,
14
+ CRUD,
15
+ HTTPMethod,
16
+ } from "@tellescope/types-utilities"
17
+ import {
18
+ EnduserSession,
19
+ ConfiguredSession,
20
+ JourneyState,
21
+ UserSession,
22
+ } from "@tellescope/types-models"
3
23
 
4
24
  import {
25
+ EscapeBuilder,
26
+
5
27
  booleanValidator,
6
28
  dateValidator,
7
29
  emailValidator,
@@ -33,130 +55,136 @@ import {
33
55
  stringValidator250,
34
56
  stringValidator5000,
35
57
  listOfDisplayNameInfo,
58
+ fileTypeValidator,
59
+ fileSizeValidator,
36
60
  } from "@tellescope/validation"
37
61
 
38
62
  import {
39
63
  CREATOR_ONLY_ACCESS,
40
64
  DEFAULT_OPERATIONS,
41
65
  PLACEHOLDER_ID,
66
+ ENDUSER_SESSION_TYPE,
42
67
  } from "@tellescope/constants"
68
+ export type RelationshipConstraint<T> = {
69
+ explanation: string; // human readable, for documentation purposes
70
+ evaluate: (v: T, dependencies: Indexable<Partial<DatabaseModel>>, session: UserSession | EnduserSession) => string | void;
71
+ }
72
+
73
+ export type DependencyAccessConstraint <T> = { type: 'dependency', foreignModel: ModelName, foreignField: string, accessField: keyof T }
74
+
75
+ export type AccessConstraint <T> = { type: 'creatorOnly' }
76
+ | { type: 'filter', field: string }
77
+ | DependencyAccessConstraint<T>
78
+
79
+ export type UniqueArrayConstraint <T> = { array: keyof T, itemKey?: string }
80
+
81
+ export type Constraint <T> = {
82
+ unique: (keyof T & string | UniqueArrayConstraint<T>)[];
83
+ globalUnique?: (keyof T)[];
84
+ relationship: RelationshipConstraint<Partial<T>>[];
85
+ access?: AccessConstraint<T>[];
86
+ }
87
+
88
+ export type Initializer <T, R> = (a: T, s: UserSession | EnduserSession) => R
89
+
90
+ export type EndpointOptions = {
91
+ // parameters used for endpoint that aren't stored in the model
92
+ parameters?: { [index: string]: EscapeBuilder<any> },
93
+ }
94
+
95
+ export type DependencyDeletionAction = 'delete' | 'unset' | 'setNull' | 'nop'
96
+ export type DependecyRelationship = 'foreignKey' | 'value'
97
+
98
+ export type Dependency <T=DatabaseRecord> = {
99
+ dependsOn: ModelName[], // list of => OR, multiple dependency records => AND
100
+ dependencyField: string,
101
+ relationship: DependecyRelationship,
102
+ onDependencyDelete: DependencyDeletionAction,
103
+ getDependentValues?: (t: T) => JSONType[], // for accessing the values of a Dependency
104
+ filterByDependency?: (foreignValue: JSONType, foreignModel?: DatabaseModel) => { // for filtering against a Dependency
105
+ field: string,
106
+ value: JSONType | 'any',
107
+ },
108
+ }
109
+
110
+ export type ModelFieldInfo <T, R> = {
111
+ validator: EscapeBuilder<R>,
112
+ readonly?: boolean,
113
+ required?: boolean,
114
+ updatesDisabled?: boolean,
115
+ examples?: JSONType[],
116
+ initializer?: Initializer<Partial<T>, R>, // should include the required fields of T, not just partial
117
+ dependencies?: Dependency<Partial<T>>[],
118
+ }
119
+
120
+ export type ModelFields<T> = {
121
+ [K in keyof T]: ModelFieldInfo<T, T[K]>
122
+ }
123
+ export type extractFields<Type> = Type extends ModelFields<infer X> ? X : never
124
+
125
+ type ArgumentInfo = {
126
+ description?: string;
127
+ }
128
+
129
+ type ActionInfo = {
130
+ name?: string,
131
+ description?: string,
132
+ notes?: string[],
133
+ warnings?: string[],
134
+ }
135
+
136
+ type CustomAction <P=any, R=any> = {
137
+ op: Operation | 'custom',
138
+ access: CRUD,
139
+ // parameters: InputValidation<P>,
140
+ parameters: ModelFields<P>,
141
+ returns: R extends Array<any> ? ModelFieldInfo<any, R> : ModelFields<R>,
142
+ path?: string,
143
+ method?: HTTPMethod,
144
+ enduserOnly?: boolean,
145
+ } & ActionInfo
146
+
147
+ export type EnduserAction = {
148
+ field?: string,
149
+ } & ActionInfo
150
+
151
+ type CustomActionsForModel = {
152
+ [K in ModelName]: { [index: string]: CustomAction }
153
+ }
154
+
155
+ type ReadFilter <T> = { [K in keyof T]?: { required: boolean } }
156
+
157
+
158
+ // m is the original model (or undefined, if create)
159
+ // allows for easier event handling based on specific updates (by comparing args to pre-update model)
160
+ export type SideEffectHandler <T, O=any> = (args: Partial<T>[], m: (Partial<T> | undefined)[] | undefined, n: (Partial<T> & { _id: ObjectId })[], s: UserSession | EnduserSession, o: O) => Promise<ErrorInfo[]>;
161
+
162
+ type SideEffect = {
163
+ name: string;
164
+ description: string;
165
+ }
43
166
 
44
- // type RelationshipConstraint<T> = {
45
- // explanation: string; // human readable, for documentation purposes
46
- // evaluate: (v: T, dependencies: Indexable<Partial<DatabaseModel>>) => string | void;
47
- // }
48
-
49
- // type DependencyAccessConstraint <T> = { type: 'dependency', foreignModel: ModelName, foreignField: string, accessField: keyof T }
50
-
51
- // type AccessConstraint <T> = { type: 'creatorOnly' }
52
- // | { type: 'filter', field: string }
53
- // | DependencyAccessConstraint<T>
54
-
55
- // type UniqueArrayConstraint <T> = { array: keyof T, itemKey?: string }
56
-
57
- // type Constraint <T> = {
58
- // unique: (keyof T & string | UniqueArrayConstraint<T>)[];
59
- // globalUnique?: (keyof T)[];
60
- // relationship: RelationshipConstraint<Partial<T>>[];
61
- // access?: AccessConstraint<T>[];
62
- // }
63
-
64
- // type Initializer <T, R> = (a: T, s: ConfiguredSession) => R
65
-
66
- // type EndpointOptions = {
67
- // // parameters used for endpoint that aren't stored in the model
68
- // parameters?: { [index: string]: EscapeBuilder<any> },
69
- // }
70
-
71
- // type DependencyDeletionAction = 'delete' | 'unset' | 'setNull' | 'nop'
72
- // type DependecyRelationship = 'foreignKey' | 'value'
73
-
74
- // type Dependency <T=DatabaseRecord> = {
75
- // dependsOn: ModelName[], // list of => OR, multiple dependency records => AND
76
- // dependencyField: string,
77
- // relationship: DependecyRelationship,
78
- // onDependencyDelete: DependencyDeletionAction,
79
- // getDependentValues?: (t: T) => JSONType[], // for accessing the values of a Dependency
80
- // filterByDependency?: (foreignValue: JSONType, foreignModel?: DatabaseModel) => { // for filtering against a Dependency
81
- // field: string,
82
- // value: JSONType | 'any',
83
- // },
84
- // }
85
-
86
- // type ModelFieldInfo <T, R> = {
87
- // validator: EscapeBuilder<R>,
88
- // readonly?: boolean,
89
- // required?: boolean,
90
- // updatesDisabled?: boolean,
91
- // examples?: JSONType[],
92
- // initializer?: Initializer<Partial<T>, R>, // should include the required fields of T, not just partial
93
- // dependencies?: Dependency<Partial<T>>[],
94
- // }
95
-
96
- // export type ModelFields<T> = {
97
- // [K in keyof T]: ModelFieldInfo<T, T[K]>
98
- // }
99
- // type extractFields<Type> = Type extends ModelFields<infer X> ? X : never
100
-
101
- // type ArgumentInfo = {
102
- // description?: string;
103
- // }
104
-
105
- // type ActionInfo = {
106
- // name?: string,
107
- // description?: string,
108
- // notes?: string[],
109
- // warnings?: string[],
110
- // }
111
-
112
- // type CustomAction <P=any, R=any> = {
113
- // op: Operation | 'custom',
114
- // access: CRUD,
115
- // // parameters: InputValidation<P>,
116
- // parameters: ModelFields<P>,
117
- // returns: ModelFields<R>,
118
- // path?: string,
119
- // method?: HTTPMethod,
120
- // } & ActionInfo
121
-
122
- // type CustomActionsForModel = {
123
- // [K in ModelName]: { [index: string]: CustomAction }
124
- // }
125
-
126
- // type ReadFilter <T> = { [K in keyof T]?: { required: boolean } }
127
-
128
-
129
- // // m is the original model (or undefined, if create)
130
- // // allows for easier event handling based on specific updates (by comparing args to pre-update model)
131
- // type SideEffectHandler <T, O=any> = (args: Partial<T>[], m: (Partial<T> | undefined)[] | undefined, n: (Partial<T> & { _id: ObjectId })[], s: ConfiguredSession, o: O) => Promise<ErrorInfo[]>;
132
-
133
- // type SideEffect = {
134
- // name: string;
135
- // description: string;
136
- // }
137
-
138
- // export type Model<T, N extends ModelName> = {
139
- // info: {
140
- // name?: string,
141
- // description?: string,
142
- // sideEffects?: { [K in Operation]?: SideEffect[] }
143
- // },
144
- // fields: ModelFields<T>,
145
- // constraints: Constraint<T>,
146
- // defaultActions: { [K in Operation]?: ActionInfo },
147
- // customActions: CustomActionsForModel[N],
148
- // readFilter?: ReadFilter<T>,
149
- // options?: {
150
- // create?: EndpointOptions,
151
- // }
152
- // }
153
- // type extractModelType<Type> = Type extends Model<infer T, infer N> ? T : never
154
-
155
- // type DatabaseModelForName = ToServerModels<ModelForName>
156
-
157
- // type Schema = {
158
- // [N in keyof DatabaseModelForName]: Model<DatabaseModelForName[N], ModelName>
159
- // }
167
+ export type Model<T, N extends ModelName> = {
168
+ info: {
169
+ name?: string,
170
+ description?: string,
171
+ sideEffects?: { [K in Operation]?: SideEffect[] }
172
+ },
173
+ fields: ModelFields<T>,
174
+ constraints: Constraint<T>,
175
+ defaultActions: { [k in Operation]?: ActionInfo },
176
+ enduserActions?: { [index: string]: EnduserAction },
177
+ customActions: CustomActionsForModel[N],
178
+ readFilter?: ReadFilter<T>,
179
+ options?: {
180
+ create?: EndpointOptions,
181
+ }
182
+ }
183
+ export type extractModelType<Type> = Type extends Model<infer T, infer N> ? T : never
184
+
185
+ export type Schema = {
186
+ [N in keyof ServerModelForName]: Model<ServerModelForName[N], ModelName>
187
+ }
160
188
 
161
189
  const sideEffects = {
162
190
  trackJourneyEngagement: {
@@ -203,7 +231,11 @@ export type BuiltInFields_T = typeof BuiltInFields
203
231
  export type CustomActions = {
204
232
  api_keys: {
205
233
  create: CustomAction<{}, { id: string, key: string}>,
206
- }
234
+ },
235
+ files: {
236
+ prepare_file_upload: CustomAction<{ name: string, size: number, type: string }, { presignedUpload: object, file: File }>,
237
+ file_download_URL: CustomAction<{ secureName: string }, { downloadURL: string }>,
238
+ },
207
239
  journeys: {
208
240
  update_state: CustomAction<{ updates: JourneyState, id: string, name: string }, {}>,
209
241
  },
@@ -246,70 +278,26 @@ export const schema: SchemaV1 = {
246
278
  update: [sideEffects.trackJourneyEngagement],
247
279
  }
248
280
  },
249
- customActions: {
250
- set_password: {
251
- op: "custom", access: 'update', method: "post",
252
- name: 'Set enduser password',
253
- path: '/set-enduser-password',
254
- description: "Sets (or resets) an enduser's password. Minimum length 8 characters.",
255
- parameters: {
256
- id: { validator: mongoIdStringValidator, required: true },
257
- password: { validator: stringValidator100, required: true },
258
- },
259
- returns: { } //authToken: { validator: stringValidator5000 } },
260
- },
261
- is_authenticated: {
262
- op: "custom", access: 'read', method: "get",
263
- name: 'Check enduser authentication',
264
- path: '/enduser-is-authenticated',
265
- description: "Checks the validity of an enduser's authToken",
266
- parameters: {
267
- id: { validator: mongoIdStringValidator, required: true },
268
- authToken: { validator: stringValidator5000, required: true },
269
- },
270
- returns: {
271
- isAuthenticated: { validator: booleanValidator, required: true },
272
- enduser: { validator: 'enduser' },
273
- } as any // add enduser eventually, when validator defined
274
- },
275
- refresh_session: {
276
- op: "custom", access: 'update', method: "post",
277
- name: 'Refresh enduser authentication',
278
- path: '/refresh-enduser-session',
279
- description: "When called by an authenticated enduser, generates a new session",
280
- parameters: { },
281
- returns: {
282
- authToken: { validator: stringValidator, required: true },
283
- enduser: { validator: 'enduser' },
284
- } as any // add enduser eventually, when validator defined
285
- },
286
- logout: {
287
- op: "custom", access: 'update', method: "post",
288
- name: 'Logout enduser',
289
- path: '/logout-enduser',
290
- description: "Logs out an enduser",
291
- parameters: {},
292
- returns: {},
293
- },
281
+ constraints: {
282
+ unique: ['email', 'phone', 'externalId'],
283
+ relationship: [
284
+ {
285
+ explanation: 'One of email or phone is required',
286
+ evaluate: ({ email, phone }) => {
287
+ if (!(email || phone))
288
+ return 'One of email or phone is required'
289
+ }
290
+ }
291
+ ],
294
292
  },
293
+ defaultActions: DEFAULT_OPERATIONS,
295
294
  enduserActions: { logout: {}, refresh_session: {} },
296
- publicActions: {
297
- login: {
298
- op: "custom", access: 'read', method: "post",
299
- name: 'Login enduser',
300
- path: '/login-enduser',
301
- description: "Generates an authentication token for access to enduser-facing endpoints",
302
- parameters: {
303
- id: { validator: mongoIdStringValidator },
304
- password: { validator: stringValidator100, required: true }, // required until optional challenge token available
305
- phone: { validator: phoneValidator },
306
- email: { validator: emailValidator },
307
- },
308
- returns: { authToken: { validator: stringValidator5000 } },
309
- },
310
- },
311
295
  fields: {
312
296
  ...BuiltInFields,
297
+ externalId: {
298
+ validator: stringValidator250,
299
+ examples: ['addfed3e-ddea-415b-b52b-df820c944dbb'],
300
+ },
313
301
  email: {
314
302
  validator: emailValidator,
315
303
  examples: ['test@tellescope.com'],
@@ -372,23 +360,84 @@ export const schema: SchemaV1 = {
372
360
  lastCommunication: {
373
361
  validator: dateValidator,
374
362
  },
363
+ avatar: {
364
+ validator: stringValidator100,
365
+ dependencies: [
366
+ {
367
+ dependsOn: ['files'],
368
+ dependencyField: 'secureName',
369
+ relationship: 'foreignKey',
370
+ onDependencyDelete: 'unset',
371
+ },
372
+ ]
373
+ },
375
374
  // recentMessagePreview: {
376
375
  // validator: stringValidator,
377
376
  // },
378
377
  },
379
- constraints: {
380
- unique: ['email', 'phone'],
381
- relationship: [
382
- {
383
- explanation: 'One of email or phone is required',
384
- evaluate: ({ email, phone }) => {
385
- if (!(email || phone))
386
- return 'One of email or phone is required'
387
- }
388
- }
389
- ],
378
+ customActions: {
379
+ set_password: {
380
+ op: "custom", access: 'update', method: "post",
381
+ name: 'Set enduser password',
382
+ path: '/set-enduser-password',
383
+ description: "Sets (or resets) an enduser's password. Minimum length 8 characters.",
384
+ parameters: {
385
+ id: { validator: mongoIdStringValidator, required: true },
386
+ password: { validator: stringValidator100, required: true },
387
+ },
388
+ returns: { } //authToken: { validator: stringValidator5000 } },
389
+ },
390
+ is_authenticated: {
391
+ op: "custom", access: 'read', method: "get",
392
+ name: 'Check enduser authentication',
393
+ path: '/enduser-is-authenticated',
394
+ description: "Checks the validity of an enduser's authToken",
395
+ parameters: {
396
+ id: { validator: mongoIdStringValidator, required: true },
397
+ authToken: { validator: stringValidator5000, required: true },
398
+ },
399
+ returns: {
400
+ isAuthenticated: { validator: booleanValidator, required: true },
401
+ enduser: { validator: 'enduser' },
402
+ } as any // todo: add enduser eventually, when validator defined
403
+ },
404
+ refresh_session: {
405
+ op: "custom", access: 'update', method: "post",
406
+ name: 'Refresh enduser authentication',
407
+ path: '/refresh-enduser-session',
408
+ description: "When called by an authenticated enduser, generates a new session",
409
+ parameters: { },
410
+ enduserOnly: true,
411
+ returns: {
412
+ authToken: { validator: stringValidator, required: true },
413
+ enduser: { validator: 'enduser' },
414
+ } as any // todo: add enduser eventually, when validator defined
415
+ },
416
+ logout: {
417
+ op: "custom", access: 'update', method: "post",
418
+ name: 'Logout enduser',
419
+ path: '/logout-enduser',
420
+ description: "Logs out an enduser",
421
+ parameters: {},
422
+ returns: {},
423
+ },
424
+ },
425
+ publicActions: {
426
+ login: {
427
+ op: "custom", access: 'read', method: "post",
428
+ name: 'Login enduser',
429
+ path: '/login-enduser',
430
+ description: "Generates an authentication token for access to enduser-facing endpoints",
431
+ enduserOnly: true, // implemented as authenticate in enduser sdk only
432
+ parameters: {
433
+ id: { validator: mongoIdStringValidator },
434
+ password: { validator: stringValidator100, required: true }, // required until optional challenge token available
435
+ phone: { validator: phoneValidator },
436
+ email: { validator: emailValidator },
437
+ },
438
+ returns: { authToken: { validator: stringValidator5000 } },
439
+ },
390
440
  },
391
- defaultActions: DEFAULT_OPERATIONS,
392
441
  },
393
442
  api_keys: {
394
443
  info: {},
@@ -606,7 +655,7 @@ export const schema: SchemaV1 = {
606
655
  validator: mongoIdStringValidator,
607
656
  examples: [PLACEHOLDER_ID],
608
657
  readonly: true,
609
- initializer: (a, s) => (s as UserSession).userId,
658
+ initializer: (a, s) => (s as UserSession).id,
610
659
  },
611
660
  subject: {
612
661
  validator: stringValidator,
@@ -726,7 +775,7 @@ export const schema: SchemaV1 = {
726
775
  businessUserId: {
727
776
  validator: mongoIdStringValidator,
728
777
  readonly: true, // default to only self-sending, for now
729
- initializer: (a, s) => (s as UserSession).userId,
778
+ initializer: (a, s) => (s as UserSession).id,
730
779
  dependencies: [{
731
780
  dependsOn: ['users'],
732
781
  dependencyField: '_id',
@@ -762,7 +811,7 @@ export const schema: SchemaV1 = {
762
811
  chat_rooms: {
763
812
  info: {},
764
813
  constraints: {
765
- unique: [{ array: 'userIds' }],
814
+ unique: [{ array: 'userIds' }, { array: 'enduserIds' }],
766
815
  relationship: [],
767
816
  access: [
768
817
  { type: 'filter', field: 'userIds' },
@@ -843,7 +892,7 @@ export const schema: SchemaV1 = {
843
892
  senderId: {
844
893
  validator: mongoIdStringValidator,
845
894
  readonly: true, // create a separate endpoint for storing enduser chats
846
- initializer: (a, s) => (s as UserSession).userId ?? (s as EnduserSession).enduserId,
895
+ initializer: (a, s) => (s as UserSession).id ?? (s as EnduserSession).id,
847
896
  examples: [PLACEHOLDER_ID],
848
897
  dependencies: [{ // can be userId or enduserId
849
898
  dependsOn: ['users', 'endusers'],
@@ -937,6 +986,20 @@ export const schema: SchemaV1 = {
937
986
  roles: {
938
987
  validator: listOfStringsValidator,
939
988
  },
989
+ skills: {
990
+ validator: listOfStringsValidator,
991
+ },
992
+ avatar: {
993
+ validator: stringValidator100,
994
+ dependencies: [
995
+ {
996
+ dependsOn: ['files'],
997
+ dependencyField: 'secureName',
998
+ relationship: 'foreignKey',
999
+ onDependencyDelete: 'unset',
1000
+ },
1001
+ ]
1002
+ },
940
1003
  }
941
1004
  },
942
1005
  templates: {
@@ -969,5 +1032,120 @@ export const schema: SchemaV1 = {
969
1032
  initializer: () => 'enduser'
970
1033
  },
971
1034
  }
972
- }
1035
+ },
1036
+ files: {
1037
+ info: {},
1038
+ constraints: { unique: [], relationship: [] },
1039
+ defaultActions: { read: {}, readMany: {}, update: {} },
1040
+ fields: {
1041
+ ...BuiltInFields,
1042
+ name: {
1043
+ validator: stringValidator250,
1044
+ required: true,
1045
+ },
1046
+ size: {
1047
+ validator: fileSizeValidator,
1048
+ required: true,
1049
+ },
1050
+ type: {
1051
+ validator: fileTypeValidator,
1052
+ required: true
1053
+ },
1054
+ secureName: {
1055
+ validator: stringValidator250,
1056
+ readonly: true,
1057
+ },
1058
+ },
1059
+ enduserActions: { prepare_file_upload: {} },
1060
+ customActions: {
1061
+ prepare_file_upload: {
1062
+ op: "custom", access: 'create', method: "post",
1063
+ name: 'Prepare File Upload',
1064
+ path: '/prepare-file-upload',
1065
+ description: "Generates an upload link for a file, storing metadata as a File record.",
1066
+ parameters: {
1067
+ name: {
1068
+ validator: stringValidator250,
1069
+ required: true,
1070
+ },
1071
+ size: {
1072
+ validator: fileSizeValidator,
1073
+ required: true,
1074
+ },
1075
+ type: {
1076
+ validator: fileTypeValidator,
1077
+ required: true
1078
+ },
1079
+ },
1080
+ returns: {
1081
+ presignedUpload: {
1082
+ validator: objectAnyFieldsValidator,
1083
+ },
1084
+ file: {
1085
+ validator: 'file' as any, // todo: add file validator
1086
+ },
1087
+ },
1088
+ },
1089
+ file_download_URL: {
1090
+ op: "custom", access: 'read', method: "get",
1091
+ name: 'Generate File Download',
1092
+ path: '/file-download-link',
1093
+ description: "Generates a temporary download link for a file.",
1094
+ parameters: {
1095
+ secureName: { validator: stringValidator250 },
1096
+ },
1097
+ returns: {
1098
+ downloadURL: { validator: stringValidator250 },
1099
+ },
1100
+ },
1101
+ },
1102
+ },
1103
+ tickets: {
1104
+ info: {},
1105
+ constraints: {
1106
+ unique: [],
1107
+ relationship: [
1108
+ {
1109
+ explanation: 'When created by an enduser, enduserId must match their id',
1110
+ evaluate: ({ enduserId },_,session) => {
1111
+ if (session.type === ENDUSER_SESSION_TYPE && session.id !== enduserId)
1112
+ return "enduserId does not match creator id for enduser session"
1113
+ }
1114
+ },
1115
+ ],
1116
+ },
1117
+ defaultActions: DEFAULT_OPERATIONS,
1118
+ customActions: {},
1119
+ enduserActions: { create: {}, read: {}, readMany: {} },
1120
+ fields: {
1121
+ ...BuiltInFields,
1122
+ title: {
1123
+ validator: stringValidator100,
1124
+ required: true,
1125
+ examples: ["Ticket Name"],
1126
+ },
1127
+ enduserId: {
1128
+ validator: mongoIdStringValidator,
1129
+ required: true,
1130
+ examples: [PLACEHOLDER_ID],
1131
+ },
1132
+ closed: {
1133
+ validator: booleanValidator,
1134
+ initializer: () => false,
1135
+ },
1136
+ owner: {
1137
+ validator: mongoIdStringValidator,
1138
+ },
1139
+ message: {
1140
+ validator: stringValidator5000,
1141
+ examples: ["Message"],
1142
+ },
1143
+ type: {
1144
+ validator: stringValidator100,
1145
+ },
1146
+ skillsRequired: {
1147
+ validator: listOfStringsValidator,
1148
+ },
1149
+ }
1150
+ },
973
1151
  }
package/tsconfig.json CHANGED
@@ -9,6 +9,6 @@
9
9
  "references": [
10
10
  { "path": "../constants" },
11
11
  { "path": "../validation" },
12
- { "path": "../types" }
12
+ { "path": "../types-server" }
13
13
  ]
14
14
  }