@tellescope/schema 0.0.4 → 0.0.8
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 +158 -1
- package/lib/cjs/schema.d.ts.map +1 -1
- package/lib/cjs/schema.js +214 -164
- package/lib/cjs/schema.js.map +1 -1
- package/lib/esm/schema.d.ts +158 -1
- package/lib/esm/schema.d.ts.map +1 -1
- package/lib/esm/schema.js +215 -165
- package/lib/esm/schema.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -6
- package/src/schema.ts +381 -183
- 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,
|
|
@@ -32,6 +54,9 @@ import {
|
|
|
32
54
|
messageTemplateTypeValidator,
|
|
33
55
|
stringValidator250,
|
|
34
56
|
stringValidator5000,
|
|
57
|
+
listOfDisplayNameInfo,
|
|
58
|
+
fileTypeValidator,
|
|
59
|
+
fileSizeValidator,
|
|
35
60
|
} from "@tellescope/validation"
|
|
36
61
|
|
|
37
62
|
import {
|
|
@@ -39,123 +64,126 @@ import {
|
|
|
39
64
|
DEFAULT_OPERATIONS,
|
|
40
65
|
PLACEHOLDER_ID,
|
|
41
66
|
} from "@tellescope/constants"
|
|
67
|
+
export type RelationshipConstraint<T> = {
|
|
68
|
+
explanation: string; // human readable, for documentation purposes
|
|
69
|
+
evaluate: (v: T, dependencies: Indexable<Partial<DatabaseModel>>) => string | void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type DependencyAccessConstraint <T> = { type: 'dependency', foreignModel: ModelName, foreignField: string, accessField: keyof T }
|
|
73
|
+
|
|
74
|
+
export type AccessConstraint <T> = { type: 'creatorOnly' }
|
|
75
|
+
| { type: 'filter', field: string }
|
|
76
|
+
| DependencyAccessConstraint<T>
|
|
77
|
+
|
|
78
|
+
export type UniqueArrayConstraint <T> = { array: keyof T, itemKey?: string }
|
|
79
|
+
|
|
80
|
+
export type Constraint <T> = {
|
|
81
|
+
unique: (keyof T & string | UniqueArrayConstraint<T>)[];
|
|
82
|
+
globalUnique?: (keyof T)[];
|
|
83
|
+
relationship: RelationshipConstraint<Partial<T>>[];
|
|
84
|
+
access?: AccessConstraint<T>[];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type Initializer <T, R> = (a: T, s: ConfiguredSession | EnduserSession) => R
|
|
88
|
+
|
|
89
|
+
export type EndpointOptions = {
|
|
90
|
+
// parameters used for endpoint that aren't stored in the model
|
|
91
|
+
parameters?: { [index: string]: EscapeBuilder<any> },
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type DependencyDeletionAction = 'delete' | 'unset' | 'setNull' | 'nop'
|
|
95
|
+
export type DependecyRelationship = 'foreignKey' | 'value'
|
|
96
|
+
|
|
97
|
+
export type Dependency <T=DatabaseRecord> = {
|
|
98
|
+
dependsOn: ModelName[], // list of => OR, multiple dependency records => AND
|
|
99
|
+
dependencyField: string,
|
|
100
|
+
relationship: DependecyRelationship,
|
|
101
|
+
onDependencyDelete: DependencyDeletionAction,
|
|
102
|
+
getDependentValues?: (t: T) => JSONType[], // for accessing the values of a Dependency
|
|
103
|
+
filterByDependency?: (foreignValue: JSONType, foreignModel?: DatabaseModel) => { // for filtering against a Dependency
|
|
104
|
+
field: string,
|
|
105
|
+
value: JSONType | 'any',
|
|
106
|
+
},
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type ModelFieldInfo <T, R> = {
|
|
110
|
+
validator: EscapeBuilder<R>,
|
|
111
|
+
readonly?: boolean,
|
|
112
|
+
required?: boolean,
|
|
113
|
+
updatesDisabled?: boolean,
|
|
114
|
+
examples?: JSONType[],
|
|
115
|
+
initializer?: Initializer<Partial<T>, R>, // should include the required fields of T, not just partial
|
|
116
|
+
dependencies?: Dependency<Partial<T>>[],
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export type ModelFields<T> = {
|
|
120
|
+
[K in keyof T]: ModelFieldInfo<T, T[K]>
|
|
121
|
+
}
|
|
122
|
+
export type extractFields<Type> = Type extends ModelFields<infer X> ? X : never
|
|
123
|
+
|
|
124
|
+
type ArgumentInfo = {
|
|
125
|
+
description?: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
type ActionInfo = {
|
|
129
|
+
name?: string,
|
|
130
|
+
description?: string,
|
|
131
|
+
notes?: string[],
|
|
132
|
+
warnings?: string[],
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
type CustomAction <P=any, R=any> = {
|
|
136
|
+
op: Operation | 'custom',
|
|
137
|
+
access: CRUD,
|
|
138
|
+
// parameters: InputValidation<P>,
|
|
139
|
+
parameters: ModelFields<P>,
|
|
140
|
+
returns: R extends Array<any> ? ModelFieldInfo<any, R> : ModelFields<R>,
|
|
141
|
+
path?: string,
|
|
142
|
+
method?: HTTPMethod,
|
|
143
|
+
enduserOnly?: boolean,
|
|
144
|
+
} & ActionInfo
|
|
145
|
+
|
|
146
|
+
export type EnduserAction = {
|
|
147
|
+
field?: string,
|
|
148
|
+
} & ActionInfo
|
|
149
|
+
|
|
150
|
+
type CustomActionsForModel = {
|
|
151
|
+
[K in ModelName]: { [index: string]: CustomAction }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
type ReadFilter <T> = { [K in keyof T]?: { required: boolean } }
|
|
155
|
+
|
|
42
156
|
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// type Dependency <T=DatabaseRecord> = {
|
|
74
|
-
// dependsOn: ModelName[], // list of => OR, multiple dependency records => AND
|
|
75
|
-
// dependencyField: string,
|
|
76
|
-
// relationship: DependecyRelationship,
|
|
77
|
-
// onDependencyDelete: DependencyDeletionAction,
|
|
78
|
-
// getDependentValues?: (t: T) => JSONType[], // for accessing the values of a Dependency
|
|
79
|
-
// filterByDependency?: (foreignValue: JSONType, foreignModel?: DatabaseModel) => { // for filtering against a Dependency
|
|
80
|
-
// field: string,
|
|
81
|
-
// value: JSONType | 'any',
|
|
82
|
-
// },
|
|
83
|
-
// }
|
|
84
|
-
|
|
85
|
-
// type ModelFieldInfo <T, R> = {
|
|
86
|
-
// validator: EscapeBuilder<R>,
|
|
87
|
-
// readonly?: boolean,
|
|
88
|
-
// required?: boolean,
|
|
89
|
-
// updatesDisabled?: boolean,
|
|
90
|
-
// examples?: JSONType[],
|
|
91
|
-
// initializer?: Initializer<Partial<T>, R>, // should include the required fields of T, not just partial
|
|
92
|
-
// dependencies?: Dependency<Partial<T>>[],
|
|
93
|
-
// }
|
|
94
|
-
|
|
95
|
-
// export type ModelFields<T> = {
|
|
96
|
-
// [K in keyof T]: ModelFieldInfo<T, T[K]>
|
|
97
|
-
// }
|
|
98
|
-
// type extractFields<Type> = Type extends ModelFields<infer X> ? X : never
|
|
99
|
-
|
|
100
|
-
// type ArgumentInfo = {
|
|
101
|
-
// description?: string;
|
|
102
|
-
// }
|
|
103
|
-
|
|
104
|
-
// type ActionInfo = {
|
|
105
|
-
// name?: string,
|
|
106
|
-
// description?: string,
|
|
107
|
-
// notes?: string[],
|
|
108
|
-
// warnings?: string[],
|
|
109
|
-
// }
|
|
110
|
-
|
|
111
|
-
// type CustomAction <P=any, R=any> = {
|
|
112
|
-
// op: Operation | 'custom',
|
|
113
|
-
// access: CRUD,
|
|
114
|
-
// // parameters: InputValidation<P>,
|
|
115
|
-
// parameters: ModelFields<P>,
|
|
116
|
-
// returns: ModelFields<R>,
|
|
117
|
-
// path?: string,
|
|
118
|
-
// method?: HTTPMethod,
|
|
119
|
-
// } & ActionInfo
|
|
120
|
-
|
|
121
|
-
// type CustomActionsForModel = {
|
|
122
|
-
// [K in ModelName]: { [index: string]: CustomAction }
|
|
123
|
-
// }
|
|
124
|
-
|
|
125
|
-
// type ReadFilter <T> = { [K in keyof T]?: { required: boolean } }
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
// // m is the original model (or undefined, if create)
|
|
129
|
-
// // allows for easier event handling based on specific updates (by comparing args to pre-update model)
|
|
130
|
-
// type SideEffectHandler <T, O=any> = (args: Partial<T>[], m: (Partial<T> | undefined)[] | undefined, n: (Partial<T> & { _id: ObjectId })[], s: ConfiguredSession, o: O) => Promise<ErrorInfo[]>;
|
|
131
|
-
|
|
132
|
-
// type SideEffect = {
|
|
133
|
-
// name: string;
|
|
134
|
-
// description: string;
|
|
135
|
-
// }
|
|
136
|
-
|
|
137
|
-
// export type Model<T, N extends ModelName> = {
|
|
138
|
-
// info: {
|
|
139
|
-
// name?: string,
|
|
140
|
-
// description?: string,
|
|
141
|
-
// sideEffects?: { [K in Operation]?: SideEffect[] }
|
|
142
|
-
// },
|
|
143
|
-
// fields: ModelFields<T>,
|
|
144
|
-
// constraints: Constraint<T>,
|
|
145
|
-
// defaultActions: { [K in Operation]?: ActionInfo },
|
|
146
|
-
// customActions: CustomActionsForModel[N],
|
|
147
|
-
// readFilter?: ReadFilter<T>,
|
|
148
|
-
// options?: {
|
|
149
|
-
// create?: EndpointOptions,
|
|
150
|
-
// }
|
|
151
|
-
// }
|
|
152
|
-
// type extractModelType<Type> = Type extends Model<infer T, infer N> ? T : never
|
|
153
|
-
|
|
154
|
-
// type DatabaseModelForName = ToServerModels<ModelForName>
|
|
155
|
-
|
|
156
|
-
// type Schema = {
|
|
157
|
-
// [N in keyof DatabaseModelForName]: Model<DatabaseModelForName[N], ModelName>
|
|
158
|
-
// }
|
|
157
|
+
// m is the original model (or undefined, if create)
|
|
158
|
+
// allows for easier event handling based on specific updates (by comparing args to pre-update model)
|
|
159
|
+
export type SideEffectHandler <T, O=any> = (args: Partial<T>[], m: (Partial<T> | undefined)[] | undefined, n: (Partial<T> & { _id: ObjectId })[], s: ConfiguredSession | EnduserSession, o: O) => Promise<ErrorInfo[]>;
|
|
160
|
+
|
|
161
|
+
type SideEffect = {
|
|
162
|
+
name: string;
|
|
163
|
+
description: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export type Model<T, N extends ModelName> = {
|
|
167
|
+
info: {
|
|
168
|
+
name?: string,
|
|
169
|
+
description?: string,
|
|
170
|
+
sideEffects?: { [K in Operation]?: SideEffect[] }
|
|
171
|
+
},
|
|
172
|
+
fields: ModelFields<T>,
|
|
173
|
+
constraints: Constraint<T>,
|
|
174
|
+
defaultActions: { [k in Operation]?: ActionInfo },
|
|
175
|
+
enduserActions?: { [index: string]: EnduserAction },
|
|
176
|
+
customActions: CustomActionsForModel[N],
|
|
177
|
+
readFilter?: ReadFilter<T>,
|
|
178
|
+
options?: {
|
|
179
|
+
create?: EndpointOptions,
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
export type extractModelType<Type> = Type extends Model<infer T, infer N> ? T : never
|
|
183
|
+
|
|
184
|
+
export type Schema = {
|
|
185
|
+
[N in keyof ServerModelForName]: Model<ServerModelForName[N], ModelName>
|
|
186
|
+
}
|
|
159
187
|
|
|
160
188
|
const sideEffects = {
|
|
161
189
|
trackJourneyEngagement: {
|
|
@@ -169,6 +197,10 @@ const sideEffects = {
|
|
|
169
197
|
sendSMSMessages: {
|
|
170
198
|
name: "sendSMSMessages",
|
|
171
199
|
description: "Sends emails if logOnly is not true"
|
|
200
|
+
},
|
|
201
|
+
updateChatroomCache: {
|
|
202
|
+
name: "updateChatroomCache",
|
|
203
|
+
description: "Updates the chatroom with a preview of the recent message and sender"
|
|
172
204
|
}
|
|
173
205
|
}
|
|
174
206
|
export type SideEffectNames = keyof typeof sideEffects
|
|
@@ -198,7 +230,11 @@ export type BuiltInFields_T = typeof BuiltInFields
|
|
|
198
230
|
export type CustomActions = {
|
|
199
231
|
api_keys: {
|
|
200
232
|
create: CustomAction<{}, { id: string, key: string}>,
|
|
201
|
-
}
|
|
233
|
+
},
|
|
234
|
+
files: {
|
|
235
|
+
prepare_file_upload: CustomAction<{ name: string, size: number, type: string }, { presignedUpload: object, file: File }>,
|
|
236
|
+
file_download_URL: CustomAction<{ secureName: string }, { downloadURL: string }>,
|
|
237
|
+
},
|
|
202
238
|
journeys: {
|
|
203
239
|
update_state: CustomAction<{ updates: JourneyState, id: string, name: string }, {}>,
|
|
204
240
|
},
|
|
@@ -208,6 +244,12 @@ export type CustomActions = {
|
|
|
208
244
|
{ id: string, authToken: string },
|
|
209
245
|
{ isAuthenticated: true, enduser: Enduser } | { isAuthenticated: false, enduser: null }
|
|
210
246
|
>,
|
|
247
|
+
refresh_session: CustomAction<{}, { enduser: Enduser, authToken: string }>,
|
|
248
|
+
logout: CustomAction<{ }, { }>,
|
|
249
|
+
},
|
|
250
|
+
users: {
|
|
251
|
+
display_names: CustomAction<{ }, { fname: string, lname: string, id: string }[]>,
|
|
252
|
+
refresh_session: CustomAction<{}, { user: UserSession, authToken: string }>,
|
|
211
253
|
}
|
|
212
254
|
}
|
|
213
255
|
|
|
@@ -235,50 +277,26 @@ export const schema: SchemaV1 = {
|
|
|
235
277
|
update: [sideEffects.trackJourneyEngagement],
|
|
236
278
|
}
|
|
237
279
|
},
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
},
|
|
250
|
-
is_authenticated: {
|
|
251
|
-
op: "custom", access: 'read', method: "get",
|
|
252
|
-
name: 'Check enduser authentication',
|
|
253
|
-
path: '/enduser-is-authenticated',
|
|
254
|
-
description: "Checks the validity of an enduser's authToken",
|
|
255
|
-
parameters: {
|
|
256
|
-
id: { validator: mongoIdStringValidator, required: true },
|
|
257
|
-
authToken: { validator: stringValidator5000, required: true },
|
|
258
|
-
},
|
|
259
|
-
returns: {
|
|
260
|
-
isAuthenticated: { validator: booleanValidator, required: true },
|
|
261
|
-
enduser: { validator: 'enduser' },
|
|
262
|
-
} as any // add enduser eventually, when validator defined
|
|
263
|
-
},
|
|
264
|
-
},
|
|
265
|
-
publicActions: {
|
|
266
|
-
login: {
|
|
267
|
-
op: "custom", access: 'read', method: "post",
|
|
268
|
-
name: 'Login enduser',
|
|
269
|
-
path: '/login-enduser',
|
|
270
|
-
description: "Generates an authentication token for access to enduser-facing endpoints",
|
|
271
|
-
parameters: {
|
|
272
|
-
id: { validator: mongoIdStringValidator },
|
|
273
|
-
password: { validator: stringValidator100, required: true }, // required until optional challenge token available
|
|
274
|
-
phone: { validator: phoneValidator },
|
|
275
|
-
email: { validator: emailValidator },
|
|
276
|
-
},
|
|
277
|
-
returns: { authToken: { validator: stringValidator5000 } },
|
|
278
|
-
},
|
|
280
|
+
constraints: {
|
|
281
|
+
unique: ['email', 'phone', 'externalId'],
|
|
282
|
+
relationship: [
|
|
283
|
+
{
|
|
284
|
+
explanation: 'One of email or phone is required',
|
|
285
|
+
evaluate: ({ email, phone }) => {
|
|
286
|
+
if (!(email || phone))
|
|
287
|
+
return 'One of email or phone is required'
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
],
|
|
279
291
|
},
|
|
292
|
+
defaultActions: DEFAULT_OPERATIONS,
|
|
293
|
+
enduserActions: { logout: {}, refresh_session: {} },
|
|
280
294
|
fields: {
|
|
281
295
|
...BuiltInFields,
|
|
296
|
+
externalId: {
|
|
297
|
+
validator: stringValidator250,
|
|
298
|
+
examples: ['addfed3e-ddea-415b-b52b-df820c944dbb'],
|
|
299
|
+
},
|
|
282
300
|
email: {
|
|
283
301
|
validator: emailValidator,
|
|
284
302
|
examples: ['test@tellescope.com'],
|
|
@@ -341,23 +359,84 @@ export const schema: SchemaV1 = {
|
|
|
341
359
|
lastCommunication: {
|
|
342
360
|
validator: dateValidator,
|
|
343
361
|
},
|
|
362
|
+
avatar: {
|
|
363
|
+
validator: stringValidator100,
|
|
364
|
+
dependencies: [
|
|
365
|
+
{
|
|
366
|
+
dependsOn: ['files'],
|
|
367
|
+
dependencyField: 'secureName',
|
|
368
|
+
relationship: 'foreignKey',
|
|
369
|
+
onDependencyDelete: 'unset',
|
|
370
|
+
},
|
|
371
|
+
]
|
|
372
|
+
},
|
|
344
373
|
// recentMessagePreview: {
|
|
345
374
|
// validator: stringValidator,
|
|
346
375
|
// },
|
|
347
376
|
},
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
377
|
+
customActions: {
|
|
378
|
+
set_password: {
|
|
379
|
+
op: "custom", access: 'update', method: "post",
|
|
380
|
+
name: 'Set enduser password',
|
|
381
|
+
path: '/set-enduser-password',
|
|
382
|
+
description: "Sets (or resets) an enduser's password. Minimum length 8 characters.",
|
|
383
|
+
parameters: {
|
|
384
|
+
id: { validator: mongoIdStringValidator, required: true },
|
|
385
|
+
password: { validator: stringValidator100, required: true },
|
|
386
|
+
},
|
|
387
|
+
returns: { } //authToken: { validator: stringValidator5000 } },
|
|
388
|
+
},
|
|
389
|
+
is_authenticated: {
|
|
390
|
+
op: "custom", access: 'read', method: "get",
|
|
391
|
+
name: 'Check enduser authentication',
|
|
392
|
+
path: '/enduser-is-authenticated',
|
|
393
|
+
description: "Checks the validity of an enduser's authToken",
|
|
394
|
+
parameters: {
|
|
395
|
+
id: { validator: mongoIdStringValidator, required: true },
|
|
396
|
+
authToken: { validator: stringValidator5000, required: true },
|
|
397
|
+
},
|
|
398
|
+
returns: {
|
|
399
|
+
isAuthenticated: { validator: booleanValidator, required: true },
|
|
400
|
+
enduser: { validator: 'enduser' },
|
|
401
|
+
} as any // todo: add enduser eventually, when validator defined
|
|
402
|
+
},
|
|
403
|
+
refresh_session: {
|
|
404
|
+
op: "custom", access: 'update', method: "post",
|
|
405
|
+
name: 'Refresh enduser authentication',
|
|
406
|
+
path: '/refresh-enduser-session',
|
|
407
|
+
description: "When called by an authenticated enduser, generates a new session",
|
|
408
|
+
parameters: { },
|
|
409
|
+
enduserOnly: true,
|
|
410
|
+
returns: {
|
|
411
|
+
authToken: { validator: stringValidator, required: true },
|
|
412
|
+
enduser: { validator: 'enduser' },
|
|
413
|
+
} as any // todo: add enduser eventually, when validator defined
|
|
414
|
+
},
|
|
415
|
+
logout: {
|
|
416
|
+
op: "custom", access: 'update', method: "post",
|
|
417
|
+
name: 'Logout enduser',
|
|
418
|
+
path: '/logout-enduser',
|
|
419
|
+
description: "Logs out an enduser",
|
|
420
|
+
parameters: {},
|
|
421
|
+
returns: {},
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
publicActions: {
|
|
425
|
+
login: {
|
|
426
|
+
op: "custom", access: 'read', method: "post",
|
|
427
|
+
name: 'Login enduser',
|
|
428
|
+
path: '/login-enduser',
|
|
429
|
+
description: "Generates an authentication token for access to enduser-facing endpoints",
|
|
430
|
+
enduserOnly: true, // implemented as authenticate in enduser sdk only
|
|
431
|
+
parameters: {
|
|
432
|
+
id: { validator: mongoIdStringValidator },
|
|
433
|
+
password: { validator: stringValidator100, required: true }, // required until optional challenge token available
|
|
434
|
+
phone: { validator: phoneValidator },
|
|
435
|
+
email: { validator: emailValidator },
|
|
436
|
+
},
|
|
437
|
+
returns: { authToken: { validator: stringValidator5000 } },
|
|
438
|
+
},
|
|
359
439
|
},
|
|
360
|
-
defaultActions: DEFAULT_OPERATIONS,
|
|
361
440
|
},
|
|
362
441
|
api_keys: {
|
|
363
442
|
info: {},
|
|
@@ -575,7 +654,7 @@ export const schema: SchemaV1 = {
|
|
|
575
654
|
validator: mongoIdStringValidator,
|
|
576
655
|
examples: [PLACEHOLDER_ID],
|
|
577
656
|
readonly: true,
|
|
578
|
-
initializer: (a, s) => (s as UserSession).
|
|
657
|
+
initializer: (a, s) => (s as UserSession).id,
|
|
579
658
|
},
|
|
580
659
|
subject: {
|
|
581
660
|
validator: stringValidator,
|
|
@@ -695,7 +774,7 @@ export const schema: SchemaV1 = {
|
|
|
695
774
|
businessUserId: {
|
|
696
775
|
validator: mongoIdStringValidator,
|
|
697
776
|
readonly: true, // default to only self-sending, for now
|
|
698
|
-
initializer: (a, s) => (s as UserSession).
|
|
777
|
+
initializer: (a, s) => (s as UserSession).id,
|
|
699
778
|
dependencies: [{
|
|
700
779
|
dependsOn: ['users'],
|
|
701
780
|
dependencyField: '_id',
|
|
@@ -740,6 +819,9 @@ export const schema: SchemaV1 = {
|
|
|
740
819
|
},
|
|
741
820
|
fields: {
|
|
742
821
|
...BuiltInFields,
|
|
822
|
+
title: {
|
|
823
|
+
validator: stringValidator100,
|
|
824
|
+
},
|
|
743
825
|
type: {
|
|
744
826
|
validator: chatRoomTypeValidator,
|
|
745
827
|
initializer: () => 'internal'
|
|
@@ -759,6 +841,16 @@ export const schema: SchemaV1 = {
|
|
|
759
841
|
enduserIds: {
|
|
760
842
|
validator: listOfMongoIdStringValidator,
|
|
761
843
|
// add pull dependency for enduser deletion?
|
|
844
|
+
},
|
|
845
|
+
recentMessage: {
|
|
846
|
+
validator: stringValidator,
|
|
847
|
+
initializer: () => '',
|
|
848
|
+
readonly: true,
|
|
849
|
+
},
|
|
850
|
+
recentSender: {
|
|
851
|
+
validator: mongoIdStringValidator,
|
|
852
|
+
initializer: () => '',
|
|
853
|
+
readonly: true,
|
|
762
854
|
}
|
|
763
855
|
},
|
|
764
856
|
defaultActions: DEFAULT_OPERATIONS,
|
|
@@ -766,12 +858,22 @@ export const schema: SchemaV1 = {
|
|
|
766
858
|
customActions: {},
|
|
767
859
|
},
|
|
768
860
|
chats: {
|
|
769
|
-
info: {
|
|
861
|
+
info: {
|
|
862
|
+
sideEffects: {
|
|
863
|
+
create: [sideEffects.updateChatroomCache]
|
|
864
|
+
}
|
|
865
|
+
},
|
|
770
866
|
constraints: {
|
|
771
867
|
unique: [],
|
|
772
868
|
relationship: [],
|
|
773
869
|
access: [{ type: 'dependency', foreignModel: 'chat_rooms', foreignField: '_id', accessField: 'roomId' }]
|
|
774
870
|
},
|
|
871
|
+
defaultActions: { create: {}, read: {}, readMany: {}, delete: {} }, // avoid createMany for now
|
|
872
|
+
readFilter: {
|
|
873
|
+
roomId: { required: true },
|
|
874
|
+
},
|
|
875
|
+
enduserActions: { create: {}, read: {}, readMany: {} },
|
|
876
|
+
customActions: {},
|
|
775
877
|
fields: {
|
|
776
878
|
...BuiltInFields,
|
|
777
879
|
roomId: {
|
|
@@ -789,7 +891,7 @@ export const schema: SchemaV1 = {
|
|
|
789
891
|
senderId: {
|
|
790
892
|
validator: mongoIdStringValidator,
|
|
791
893
|
readonly: true, // create a separate endpoint for storing enduser chats
|
|
792
|
-
initializer: (a, s) => (s as UserSession).
|
|
894
|
+
initializer: (a, s) => (s as UserSession).id ?? (s as EnduserSession).id,
|
|
793
895
|
examples: [PLACEHOLDER_ID],
|
|
794
896
|
dependencies: [{ // can be userId or enduserId
|
|
795
897
|
dependsOn: ['users', 'endusers'],
|
|
@@ -817,12 +919,6 @@ export const schema: SchemaV1 = {
|
|
|
817
919
|
validator: idStringToDateValidator,
|
|
818
920
|
},
|
|
819
921
|
},
|
|
820
|
-
defaultActions: DEFAULT_OPERATIONS,
|
|
821
|
-
readFilter: {
|
|
822
|
-
roomId: { required: true },
|
|
823
|
-
},
|
|
824
|
-
enduserActions: { create: {}, read: {}, readMany: {} },
|
|
825
|
-
customActions: {},
|
|
826
922
|
},
|
|
827
923
|
users: {
|
|
828
924
|
info: {},
|
|
@@ -832,7 +928,31 @@ export const schema: SchemaV1 = {
|
|
|
832
928
|
relationship: [],
|
|
833
929
|
},
|
|
834
930
|
defaultActions: { read: {}, readMany: {} },
|
|
835
|
-
customActions: {
|
|
931
|
+
customActions: {
|
|
932
|
+
display_names: {
|
|
933
|
+
op: "custom", access: 'read', method: "get",
|
|
934
|
+
name: 'User Display Names',
|
|
935
|
+
path: '/user-display-names',
|
|
936
|
+
description: "Gets display names for users, accessible by endusers",
|
|
937
|
+
parameters: {},
|
|
938
|
+
returns: {
|
|
939
|
+
validator: listOfDisplayNameInfo
|
|
940
|
+
},
|
|
941
|
+
},
|
|
942
|
+
refresh_session: {
|
|
943
|
+
op: "custom", access: 'update', method: "post",
|
|
944
|
+
name: 'Refresh enduser authentication',
|
|
945
|
+
path: '/refresh-session',
|
|
946
|
+
description: "When called by an authenticated user, generates a new session",
|
|
947
|
+
parameters: { },
|
|
948
|
+
returns: {
|
|
949
|
+
authToken: { validator: stringValidator, required: true },
|
|
950
|
+
enduser: { validator: 'user' },
|
|
951
|
+
} as any // add enduser eventually, when validator defined
|
|
952
|
+
},
|
|
953
|
+
|
|
954
|
+
},
|
|
955
|
+
enduserActions: { display_names: {} },
|
|
836
956
|
fields: {
|
|
837
957
|
...BuiltInFields,
|
|
838
958
|
email: {
|
|
@@ -865,6 +985,17 @@ export const schema: SchemaV1 = {
|
|
|
865
985
|
roles: {
|
|
866
986
|
validator: listOfStringsValidator,
|
|
867
987
|
},
|
|
988
|
+
avatar: {
|
|
989
|
+
validator: stringValidator100,
|
|
990
|
+
dependencies: [
|
|
991
|
+
{
|
|
992
|
+
dependsOn: ['files'],
|
|
993
|
+
dependencyField: 'secureName',
|
|
994
|
+
relationship: 'foreignKey',
|
|
995
|
+
onDependencyDelete: 'unset',
|
|
996
|
+
},
|
|
997
|
+
]
|
|
998
|
+
},
|
|
868
999
|
}
|
|
869
1000
|
},
|
|
870
1001
|
templates: {
|
|
@@ -897,5 +1028,72 @@ export const schema: SchemaV1 = {
|
|
|
897
1028
|
initializer: () => 'enduser'
|
|
898
1029
|
},
|
|
899
1030
|
}
|
|
1031
|
+
},
|
|
1032
|
+
files: {
|
|
1033
|
+
info: {},
|
|
1034
|
+
constraints: { unique: [], relationship: [] },
|
|
1035
|
+
defaultActions: { read: {}, readMany: {}, update: {} },
|
|
1036
|
+
fields: {
|
|
1037
|
+
...BuiltInFields,
|
|
1038
|
+
name: {
|
|
1039
|
+
validator: stringValidator250,
|
|
1040
|
+
required: true,
|
|
1041
|
+
},
|
|
1042
|
+
size: {
|
|
1043
|
+
validator: fileSizeValidator,
|
|
1044
|
+
required: true,
|
|
1045
|
+
},
|
|
1046
|
+
type: {
|
|
1047
|
+
validator: fileTypeValidator,
|
|
1048
|
+
required: true
|
|
1049
|
+
},
|
|
1050
|
+
secureName: {
|
|
1051
|
+
validator: stringValidator250,
|
|
1052
|
+
readonly: true,
|
|
1053
|
+
},
|
|
1054
|
+
},
|
|
1055
|
+
enduserActions: { prepare_file_upload: {} },
|
|
1056
|
+
customActions: {
|
|
1057
|
+
prepare_file_upload: {
|
|
1058
|
+
op: "custom", access: 'create', method: "post",
|
|
1059
|
+
name: 'Prepare File Upload',
|
|
1060
|
+
path: '/prepare-file-upload',
|
|
1061
|
+
description: "Generates an upload link for a file, storing metadata as a File record.",
|
|
1062
|
+
parameters: {
|
|
1063
|
+
name: {
|
|
1064
|
+
validator: stringValidator250,
|
|
1065
|
+
required: true,
|
|
1066
|
+
},
|
|
1067
|
+
size: {
|
|
1068
|
+
validator: fileSizeValidator,
|
|
1069
|
+
required: true,
|
|
1070
|
+
},
|
|
1071
|
+
type: {
|
|
1072
|
+
validator: fileTypeValidator,
|
|
1073
|
+
required: true
|
|
1074
|
+
},
|
|
1075
|
+
},
|
|
1076
|
+
returns: {
|
|
1077
|
+
presignedUpload: {
|
|
1078
|
+
validator: objectAnyFieldsValidator,
|
|
1079
|
+
},
|
|
1080
|
+
file: {
|
|
1081
|
+
validator: 'file' as any, // todo: add file validator
|
|
1082
|
+
},
|
|
1083
|
+
},
|
|
1084
|
+
},
|
|
1085
|
+
file_download_URL: {
|
|
1086
|
+
op: "custom", access: 'read', method: "get",
|
|
1087
|
+
name: 'Generate File Download',
|
|
1088
|
+
path: '/file-download-link',
|
|
1089
|
+
description: "Generates a temporary download link for a file.",
|
|
1090
|
+
parameters: {
|
|
1091
|
+
secureName: { validator: stringValidator250 },
|
|
1092
|
+
},
|
|
1093
|
+
returns: {
|
|
1094
|
+
downloadURL: { validator: stringValidator250 },
|
|
1095
|
+
},
|
|
1096
|
+
},
|
|
1097
|
+
},
|
|
900
1098
|
}
|
|
901
1099
|
}
|