@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/lib/cjs/schema.d.ts +138 -1
- package/lib/cjs/schema.d.ts.map +1 -1
- package/lib/cjs/schema.js +199 -168
- package/lib/cjs/schema.js.map +1 -1
- package/lib/esm/schema.d.ts +138 -1
- package/lib/esm/schema.d.ts.map +1 -1
- package/lib/esm/schema.js +201 -170
- package/lib/esm/schema.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/src/schema.ts +374 -196
- package/tsconfig.json +1 -1
package/src/schema.ts
CHANGED
|
@@ -1,7 +1,29 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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).
|
|
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).
|
|
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).
|
|
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
|
}
|