epicenter-libs 3.11.0

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.
Files changed (107) hide show
  1. package/CHANGELOG.md +345 -0
  2. package/LICENSE.md +37 -0
  3. package/README.md +134 -0
  4. package/dist/browser/AckExtension-e67c6a28.js +129 -0
  5. package/dist/browser/AckExtension-e67c6a28.js.map +1 -0
  6. package/dist/browser/ReloadExtension-b1e50033.js +253 -0
  7. package/dist/browser/ReloadExtension-b1e50033.js.map +1 -0
  8. package/dist/browser/cometd-eeabdcd4.js +3438 -0
  9. package/dist/browser/cometd-eeabdcd4.js.map +1 -0
  10. package/dist/browser/epicenter-2cce2971.js +6086 -0
  11. package/dist/browser/epicenter-2cce2971.js.map +1 -0
  12. package/dist/browser/epicenter.js +2 -0
  13. package/dist/browser/epicenter.js.map +1 -0
  14. package/dist/cjs/AckExtension-f5178e19.js +131 -0
  15. package/dist/cjs/AckExtension-f5178e19.js.map +1 -0
  16. package/dist/cjs/ReloadExtension-65b036ba.js +255 -0
  17. package/dist/cjs/ReloadExtension-65b036ba.js.map +1 -0
  18. package/dist/cjs/cometd-473408f4.js +3441 -0
  19. package/dist/cjs/cometd-473408f4.js.map +1 -0
  20. package/dist/cjs/epicenter-12ceb814.js +7248 -0
  21. package/dist/cjs/epicenter-12ceb814.js.map +1 -0
  22. package/dist/cjs/epicenter.js +54 -0
  23. package/dist/cjs/epicenter.js.map +1 -0
  24. package/dist/epicenter.js +9895 -0
  25. package/dist/epicenter.js.map +1 -0
  26. package/dist/epicenter.min.js +2 -0
  27. package/dist/epicenter.min.js.map +1 -0
  28. package/dist/module/AckExtension-6181d8b5.js +129 -0
  29. package/dist/module/AckExtension-6181d8b5.js.map +1 -0
  30. package/dist/module/ReloadExtension-eaa8c42c.js +253 -0
  31. package/dist/module/ReloadExtension-eaa8c42c.js.map +1 -0
  32. package/dist/module/cometd-af78008d.js +3438 -0
  33. package/dist/module/cometd-af78008d.js.map +1 -0
  34. package/dist/module/epicenter-9b8c92a9.js +7213 -0
  35. package/dist/module/epicenter-9b8c92a9.js.map +1 -0
  36. package/dist/module/epicenter.js +7 -0
  37. package/dist/module/epicenter.js.map +1 -0
  38. package/dist/types/adapters/account.d.ts +44 -0
  39. package/dist/types/adapters/admin.d.ts +33 -0
  40. package/dist/types/adapters/asset.d.ts +46 -0
  41. package/dist/types/adapters/authentication.d.ts +62 -0
  42. package/dist/types/adapters/channel.d.ts +39 -0
  43. package/dist/types/adapters/chat.d.ts +105 -0
  44. package/dist/types/adapters/cometd.d.ts +25 -0
  45. package/dist/types/adapters/email.d.ts +86 -0
  46. package/dist/types/adapters/episode.d.ts +91 -0
  47. package/dist/types/adapters/group.d.ts +273 -0
  48. package/dist/types/adapters/index.d.ts +21 -0
  49. package/dist/types/adapters/leaderboard.d.ts +68 -0
  50. package/dist/types/adapters/presence.d.ts +35 -0
  51. package/dist/types/adapters/project.d.ts +99 -0
  52. package/dist/types/adapters/recaptcha.d.ts +1 -0
  53. package/dist/types/adapters/run.d.ts +253 -0
  54. package/dist/types/adapters/task.d.ts +154 -0
  55. package/dist/types/adapters/time.d.ts +2 -0
  56. package/dist/types/adapters/user.d.ts +38 -0
  57. package/dist/types/adapters/vault.d.ts +94 -0
  58. package/dist/types/adapters/world.d.ts +230 -0
  59. package/dist/types/epicenter.d.ts +10 -0
  60. package/dist/types/utils/config.d.ts +90 -0
  61. package/dist/types/utils/constants.d.ts +290 -0
  62. package/dist/types/utils/cookies.d.ts +16 -0
  63. package/dist/types/utils/error-manager.d.ts +21 -0
  64. package/dist/types/utils/error.d.ts +4 -0
  65. package/dist/types/utils/fault.d.ts +17 -0
  66. package/dist/types/utils/helpers.d.ts +4 -0
  67. package/dist/types/utils/identification.d.ts +47 -0
  68. package/dist/types/utils/index.d.ts +11 -0
  69. package/dist/types/utils/result.d.ts +6 -0
  70. package/dist/types/utils/router.d.ts +157 -0
  71. package/dist/types/utils/store.d.ts +31 -0
  72. package/package.json +103 -0
  73. package/src/adapters/account.ts +104 -0
  74. package/src/adapters/admin.ts +53 -0
  75. package/src/adapters/asset.ts +195 -0
  76. package/src/adapters/authentication.ts +173 -0
  77. package/src/adapters/channel.ts +83 -0
  78. package/src/adapters/chat.ts +186 -0
  79. package/src/adapters/cometd.ts +297 -0
  80. package/src/adapters/email.ts +146 -0
  81. package/src/adapters/episode.ts +163 -0
  82. package/src/adapters/group.ts +511 -0
  83. package/src/adapters/index.ts +43 -0
  84. package/src/adapters/leaderboard.ts +122 -0
  85. package/src/adapters/presence.ts +63 -0
  86. package/src/adapters/project.ts +123 -0
  87. package/src/adapters/recaptcha.ts +11 -0
  88. package/src/adapters/run.ts +726 -0
  89. package/src/adapters/task.ts +213 -0
  90. package/src/adapters/time.ts +36 -0
  91. package/src/adapters/user.ts +75 -0
  92. package/src/adapters/vault.ts +232 -0
  93. package/src/adapters/world.ts +412 -0
  94. package/src/epicenter.ts +96 -0
  95. package/src/globals.d.ts +16 -0
  96. package/src/utils/config.ts +168 -0
  97. package/src/utils/constants.ts +324 -0
  98. package/src/utils/cookies.ts +71 -0
  99. package/src/utils/error-manager.ts +66 -0
  100. package/src/utils/error.ts +9 -0
  101. package/src/utils/fault.ts +39 -0
  102. package/src/utils/helpers.ts +7 -0
  103. package/src/utils/identification.ts +128 -0
  104. package/src/utils/index.ts +11 -0
  105. package/src/utils/result.ts +15 -0
  106. package/src/utils/router.ts +547 -0
  107. package/src/utils/store.ts +82 -0
@@ -0,0 +1,511 @@
1
+ import type { UserSession } from '../utils/identification';
2
+ import type { RoutingOptions, Page, GenericSearchOptions } from '../utils/router';
3
+ import type { User } from './user';
4
+
5
+ import { Router, EpicenterError, identification, ROLE } from '../utils';
6
+
7
+ enum AUGMENT {
8
+ MEMBERS = 'MEMBERS',
9
+ QUANTIZED = 'QUANTIZED',
10
+ }
11
+
12
+ interface Pricing {
13
+ amount: number
14
+ }
15
+
16
+ interface FlightRecorder {
17
+ start: number,
18
+ stop: number,
19
+ enabled: boolean,
20
+ }
21
+
22
+ interface GroupUpdate {
23
+ runLimit?: number,
24
+ organization?: string,
25
+ allowSelfRegistration?: boolean,
26
+ flightRecorder?: FlightRecorder,
27
+ event?: string,
28
+ allowMembershipChanges?: boolean,
29
+ pricing?: Pricing,
30
+ startDate?: Date,
31
+ expirationDate?: Date,
32
+ capacity?: number,
33
+ }
34
+
35
+ interface GroupPermission {
36
+ available: boolean,
37
+ objectType: 'group',
38
+ role: keyof typeof ROLE,
39
+ }
40
+
41
+ export interface Member extends GroupPermission {
42
+ user: User,
43
+ }
44
+
45
+ export interface Group extends GroupUpdate {
46
+ name: string,
47
+ groupKey: string,
48
+ members?: Member[],
49
+ }
50
+
51
+
52
+ /**
53
+ * Provides information on a particular Epicenter group.
54
+ * @example
55
+ * import { authAdapter, groupAdapter } from 'epicenter';
56
+ * const session = authAdapter.getLocalSession();
57
+ * // include members of the group in the response
58
+ * const group = await groupAdapter.get(session.groupKey, { augment: 'MEMBERS' });
59
+ * // include metrics relating to the group in the response
60
+ * const group = await groupAdapter.get(session.groupKey, { augment: 'QUANTIZED' });
61
+ * @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
62
+ * @param [optionals.augment] Specifies which additional information you'd like returned with the group
63
+ * @param [optionals.groupKey] Group key, if omitted will attempt to use the group associated with the current session
64
+ * @returns promise that resolves to a group
65
+ */
66
+ export async function get(
67
+ optionals: {
68
+ augment?: keyof typeof AUGMENT,
69
+ groupKey?: string,
70
+ } & RoutingOptions = {}
71
+ ): Promise<Group> {
72
+ const {
73
+ groupKey, augment,
74
+ ...routingOptions
75
+ } = optionals;
76
+ let uriComponent = '';
77
+ if (augment === AUGMENT.MEMBERS) uriComponent = '/member';
78
+ if (augment === AUGMENT.QUANTIZED) uriComponent = '/quantized';
79
+ const session = identification.session as UserSession;
80
+ return await new Router()
81
+ .get(`/group${uriComponent}/${groupKey ?? session?.groupKey}`, routingOptions)
82
+ .then(({ body }) => body);
83
+ }
84
+
85
+
86
+ /**
87
+ * Deletes the group; available only to Epicenter admins
88
+ * @example
89
+ * epicenter.groupAdapter.destroy('0000017dd3bf540e5ada5b1e058f08f20461');
90
+ * @param groupKey Key associated with group
91
+ * @param [optionals] Optional arguments; pass network call options overrides here.
92
+ * @returns promise that resolves to undefined if successful
93
+ */
94
+ export async function destroy(
95
+ groupKey: string,
96
+ optionals: RoutingOptions = {},
97
+ ): Promise<void> {
98
+
99
+ return await new Router()
100
+ .delete(`/group/${groupKey}`, optionals)
101
+ .then(({ body }) => body);
102
+ }
103
+
104
+
105
+ /**
106
+ * Provides information on for all groups in the project
107
+ * @example
108
+ * const groups = await epicenter.groupAdapter.gather();
109
+ * @param [optionals] Optional arguments; pass network call options overrides here.
110
+ * @param [optionals.includeExpired] Indicates whether to include expired groups in the query
111
+ * @returns promise that resolves to a list of groups
112
+ */
113
+ export async function gather(
114
+ optionals: { includeExpired?: boolean } & RoutingOptions = {}
115
+ ): Promise<Group[]> {
116
+ const {
117
+ includeExpired,
118
+ ...routingOptions
119
+ } = optionals;
120
+
121
+ return await new Router()
122
+ .withSearchParams({ includeExpired })
123
+ .get('/group', routingOptions)
124
+ .then(({ body }) => body);
125
+ }
126
+
127
+
128
+ /**
129
+ * Updates fields for a particular group; available only to Epicenter admins.
130
+ * @example
131
+ * epicenter.groupAdapter.update('0000017dd3bf540e5ada5b1e058f08f20461', { event: 'Orientation Day' });
132
+ * @param groupKey Key associated with group
133
+ * @param update Attributes you wish to update
134
+ * @param [update.runLimit] Defines the upper limit of runs allowed in the group
135
+ * @param [update.organization] Name of the organization owning the group
136
+ * @param [update.allowSelfRegistration] TODO -- this does something, it's just that the frontend devs don't know what yet
137
+ * @param [update.flightRecorder] Diagnostic tool for logging http requests for the server
138
+ * @param [update.flightRecorder].start Start time (epoch time)
139
+ * @param [update.flightRecorder].stop End time (epoch time)
140
+ * @param [update.flightRecorder].enabled Enabled flag for the flight recorder
141
+ * @param [update.event] Name of the event the group is playing for
142
+ * @param [update.allowMembershipChanges] TODO -- this does something, it's just that the frontend devs don't know what yet
143
+ * @param [update.pricing] TODO -- this does something, it's just that the frontend devs don't know what yet
144
+ * @param [update.pricing].number TODO -- this does something, it's just that the frontend devs don't know what yet
145
+ * @param [update.startDate] TODO -- this does something, it's just that the frontend devs don't know what yet
146
+ * @param [update.expirationDate] Date the group expires
147
+ * @param [update.capacity] Defines the upper limit on the number of users allowed in the group
148
+ * @param [optionals] Optional arguments; pass network call options overrides here.
149
+ * @returns promise that resolves to the updated group
150
+ */
151
+ export async function update(
152
+ groupKey: string,
153
+ update: GroupUpdate,
154
+ optionals: RoutingOptions = {}
155
+ ): Promise<Group> {
156
+ const {
157
+ runLimit, organization, allowSelfRegistration, flightRecorder,
158
+ event, allowMembershipChanges, pricing,
159
+ startDate, expirationDate, capacity,
160
+ } = update;
161
+
162
+ return await new Router()
163
+ .patch(`/group/${groupKey}`, {
164
+ body: {
165
+ runLimit, organization, allowSelfRegistration, flightRecorder,
166
+ event, allowMembershipChanges, pricing,
167
+ startDate, expirationDate, capacity,
168
+ },
169
+ ...optionals,
170
+ })
171
+ .then(({ body }) => body);
172
+ }
173
+
174
+
175
+ /**
176
+ * Creates a new group; available only to Epicenter admins
177
+ * @example
178
+ * epicenter.groupAdapter.create({
179
+ * runLimit: 10,
180
+ * name: 'my-group-name',
181
+ * });
182
+ * @param group Group object
183
+ * @param group.name Group name (required)
184
+ * @param [group.runLimit] Defines the upper limit on the number of runs allowed in the group
185
+ * @param [group.organization] Name of the organization owning the group
186
+ * @param [group.allowSelfRegistration] TODO -- this does something, it's just that the frontend devs don't know what yet
187
+ * @param [group.flightRecorder] Diagnostic tool for loggin http requests for the server
188
+ * @param [group.flightRecorder.start] Start time (epoch time)
189
+ * @param [group.flightRecorder.stop] End time (epoch time)
190
+ * @param [group.flightRecorder.enabled] Enabled flag for the flight recorder
191
+ * @param [group.event] Name of the event the group is playing for
192
+ * @param [group.allowMembershipChanges] TODO -- this does something, it's just that the frontend devs don't know what yet
193
+ * @param [group.pricing] TODO -- this does something, it's just that the frontend devs don't know what yet
194
+ * @param [group.startDate] TODO -- this does something, it's just that the frontend devs don't know what yet
195
+ * @param [group.expirationDate] Date the group expires
196
+ * @param [group.capacity] Defines the upper limit on the number of users allowed in the group
197
+ * @param [optionals] Optional arguments; pass network call options overrides here.
198
+ * @returns promise that resolves to the newly created group
199
+ */
200
+ export async function create(
201
+ group: Group,
202
+ optionals: RoutingOptions = {}
203
+ ): Promise<Group> {
204
+ const {
205
+ name, runLimit, organization, allowSelfRegistration,
206
+ flightRecorder, event, allowMembershipChanges, pricing,
207
+ startDate, expirationDate, capacity,
208
+ } = group;
209
+ if (!name) throw new EpicenterError('Cannot create a group with no name');
210
+ return await new Router()
211
+ .post('/group', {
212
+ body: {
213
+ name, runLimit, organization, allowSelfRegistration,
214
+ flightRecorder, event, allowMembershipChanges, pricing,
215
+ startDate, expirationDate, capacity,
216
+ },
217
+ ...optionals,
218
+ })
219
+ .then(({ body }) => body);
220
+ }
221
+
222
+
223
+ /**
224
+ * Queries for groups
225
+ * @example
226
+ * import { groupAdapter } from 'epicenter';
227
+ * const filter = [
228
+ * 'name|=group1|group2', // look for groups whose name is 'group1' or 'group2'
229
+ * 'groupKey=0000017dd3bf540e5ada5b1e058f08f20461', // look for groups with the specific group key
230
+ * 'approximateMemberCount>30', // look for groups larger than 30
231
+ * 'startDate<2022-01-03T20:30:53.054Z', // look for groups with start date before Jan 3rd 2022
232
+ * 'expirationDate<2022-01-03T20:30:53.054Z', // look for groups with expiration date before Jan 3rd 2022
233
+ * // 'account.shortName=acme', // specifies account, intended for admin use
234
+ * // 'project.shortName=simulations', // specifies project, intended for admin use
235
+ * ];
236
+ * groupAdapter.query({
237
+ * filter,
238
+ * sort: ['+group.name'] // sort all findings by group name ascending (lexigraphically)
239
+ * first: 3, // page should start with the 4th item found (will default to 0)
240
+ * max: 10, // page should only include the first 10 items
241
+ * });
242
+ * @param searchOptions Search options for the query
243
+ * @param [searchOptions.filter] Filters for searching
244
+ * @param [searchOptions.sort] Sorting criteria
245
+ * @param [searchOptions.first] The starting index of the page returned
246
+ * @param [searchOptions.max] The number of entries per page
247
+ * @param [optionals] Optional arguments; pass network call options overrides here.
248
+ * @returns promise that resolves to a page of groups
249
+ */
250
+ export async function query(
251
+ searchOptions: { quantized?: boolean } & GenericSearchOptions,
252
+ optionals: RoutingOptions = {}
253
+ ): Promise<Page<Group>> {
254
+ const { filter = [], sort = [], first, max, quantized } = searchOptions;
255
+
256
+ const searchParams = {
257
+ filter: filter.join(';') || undefined,
258
+ sort: sort.join(';') || undefined,
259
+ first, max,
260
+ };
261
+
262
+ return await new Router()
263
+ .withSearchParams(searchParams)
264
+ .get(`/group${quantized ? '/quantized' : ''}/search`, {
265
+ paginated: true,
266
+ ...optionals,
267
+ })
268
+ .then(({ body }) => body);
269
+ }
270
+ /** DEPRECATED -- use groupAdapter.query instead */
271
+ export async function search(
272
+ optionals: { quantized?: boolean } & GenericSearchOptions & RoutingOptions = {}
273
+ ): Promise<Page<Group>> {
274
+ console.warn('DEPRECATION WARNING: groupAdapter.search is deprecated and will be removed with the next release. Use groupAdapter.query instead.');
275
+ const { filter = [], sort = [], first, max, quantized, ...routingOptions } = optionals;
276
+ const searchOptions = { filter, sort, first, max, quantized };
277
+ return await query(searchOptions, routingOptions);
278
+ }
279
+
280
+
281
+ /**
282
+ * Retrieves a group with given group name
283
+ * @example
284
+ * epicenter.groupAdapter.withGroupName('my-group-name');
285
+ * @param name Name associated with the group
286
+ * @param [optionals] Optional arguments; pass network call options overrides here.
287
+ * @returns promise that resolves to a group
288
+ */
289
+ export async function withGroupName(
290
+ name: string,
291
+ optionals: RoutingOptions = {}
292
+ ): Promise<Group> {
293
+
294
+ return await new Router()
295
+ .get(`/group/with/${name}`, optionals)
296
+ .then(({ body }) => body);
297
+ }
298
+
299
+
300
+ /**
301
+ * Retrieves the list of groups a particular user is in; intended for admin use
302
+ * @example
303
+ * epicenter.groupAdapter.forUser(
304
+ * '000001796733eef0842f4d6d960997018a3b', // get groups where this user is a member of
305
+ * { role: ['FACILITATOR'] } // where this user is a facilitator in the group
306
+ * );
307
+ * @param userKey Name associated with the group
308
+ * @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
309
+ * @param [optionals.includeExpired] Indicates whether to include expired groups in the query
310
+ * @param [optionals.includeAllMembers] Indicates whether to include the other members in the group (by default, only the requested user appears)
311
+ * @param [optionals.role] Role or list of possible roles the user holds in the group
312
+ * @returns promise that resolves to a list of groups
313
+ */
314
+ export async function forUser(
315
+ userKey: string,
316
+ optionals: {
317
+ includeAllMembers?: boolean,
318
+ includeExpired?: boolean,
319
+ role?: string | string[],
320
+ } & RoutingOptions = {},
321
+ ): Promise<Group[]> {
322
+ const {
323
+ includeExpired, includeAllMembers, role,
324
+ ...routingOptions
325
+ } = optionals;
326
+ const isMultiple = Array.isArray(role) && role.length > 0;
327
+ const roleList = isMultiple ? role : [role];
328
+ const searchParams = {
329
+ includeExpired,
330
+ includeAllMembers,
331
+ role: role ? roleList : undefined,
332
+ };
333
+
334
+ return await new Router()
335
+ .withSearchParams(searchParams)
336
+ .get(`/group/member/for/${userKey}`, routingOptions)
337
+ .then(({ body }) => body);
338
+ }
339
+
340
+
341
+ /**
342
+ * Retrieves the list of groups particular to the current session
343
+ * @example
344
+ * const groups = await epicenter.groupAdapter.getSessionGroups();
345
+ * @param [optionals] Optional arguments; pass network call options overrides here.
346
+ * @param [optionals.includeExpired] Indicates whether to include expired groups in the query
347
+ * @param [optionals.includeAllMembers] Indicates whether to include the other members in the group (by default, only the requested user appears)
348
+ * @param [optionals.role] Role or list of possible roles the user holds in the group
349
+ * @returns promise that resolves to a list of groups
350
+ */
351
+ export async function getSessionGroups(
352
+ optionals: {
353
+ includeAllMembers?: boolean,
354
+ includeExpired?: boolean,
355
+ role?: string | string[],
356
+ } & RoutingOptions = {},
357
+ ): Promise<Group[]> {
358
+ const {
359
+ includeExpired, role,
360
+ ...routingOptions
361
+ } = optionals;
362
+ const isMultiple = Array.isArray(role) && role.length > 0;
363
+ const roleList = isMultiple ? role : [role];
364
+ const searchParams = {
365
+ includeExpired,
366
+ role: role ? roleList : undefined,
367
+ };
368
+
369
+ return await new Router()
370
+ .withSearchParams(searchParams)
371
+ .get('/group/member', routingOptions)
372
+ .then(({ body }) => body);
373
+ }
374
+
375
+
376
+ /**
377
+ * Self-application for membership in a group; will only work if the group has the self-registration setting turned on.
378
+ * @example
379
+ * epicenter.groupAdapter.register('0000017dd3bf540e5ada5b1e058f08f20461');
380
+ * @param groupKey Key associated with group
381
+ * @param [optionals] Optional arguments; pass network call options overrides here.
382
+ * @returns promise that resolves in a group
383
+ */
384
+ export async function register(
385
+ groupKey: string,
386
+ optionals: RoutingOptions = {}
387
+ ): Promise<Group> {
388
+
389
+ return await new Router()
390
+ .post(`/group/selfRegistration/${groupKey}`, optionals)
391
+ .then(({ body }) => body);
392
+ }
393
+
394
+
395
+ type UserInput = string | { userKey: string, role?: keyof typeof ROLE, available?: boolean };
396
+ /**
397
+ * Adds user(s) to the group
398
+ * @example
399
+ * epicenter.groupAdapter.addUser('000001796733eef0842f4d6d960997018a3b');
400
+ * epicenter.groupAdapter.addUser([{
401
+ * userKey: '000001796733eef0842f4d6d960997018a3b',
402
+ * role: 'REVIEWER',
403
+ * available: false,
404
+ * }]);
405
+ * @param usersInput List of user keys or user input objects (properties defined below)
406
+ * @param usersInput[].userKey User key
407
+ * @param [usersInput[].role] User's role -- defaults to PARTICIPANT if unset; See [ROLE](#ROLE) for all types
408
+ * @param [usersInput[].available] Indicates whether or not the user is 'active' (for semantic labeling) -- defaults to true if unset
409
+ * @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
410
+ * @param [optionals.groupKey] Group key to do indicate the group; will default to the group key associated with the current session
411
+ * @returns promise that resolves to the group the user was added to
412
+ */
413
+ export async function addUser(
414
+ usersInput: UserInput | UserInput[],
415
+ optionals: { groupKey?: string } & RoutingOptions = {}
416
+ ):Promise<Group> {
417
+ const { groupKey, ...routingOptions } = optionals;
418
+
419
+ const users = Array.isArray(usersInput) ? usersInput : [usersInput];
420
+ const session = identification.session as UserSession;
421
+ return await new Router()
422
+ .post(`/group/member/${groupKey ?? session?.groupKey}`, {
423
+ body: users.map((u) => {
424
+ const userKey = typeof u === 'string' ? u : u.userKey;
425
+ const role = typeof u === 'string' ? ROLE.PARTICIPANT : u.role;
426
+ const available = typeof u === 'string' ? true : u.available;
427
+
428
+ return {
429
+ role,
430
+ userKey,
431
+ objectType: 'group',
432
+ available: available ?? true,
433
+ };
434
+ }),
435
+ ...routingOptions,
436
+ })
437
+ .then(({ body }) => body);
438
+ }
439
+
440
+
441
+ /**
442
+ * Updates a user's group membership information
443
+ * @example
444
+ * epicenter.groupAdapter.updateUser('000001796733eef0842f4d6d960997018a3b', { role: 'LEADER' });
445
+ * @param userKey User key
446
+ * @param update Object containing the updates to a user's group membership information
447
+ * @param [update.role] User's role; See [ROLE](#ROLE) for all types
448
+ * @param [update.available] Indicates whether or not the user is 'active' (for semantic labeling)
449
+ * @param [optionals] Optional arguments; pass network call options overrides here.
450
+ * @returns promise that resolves to the membership information that was updated
451
+ */
452
+ export async function updateUser(
453
+ userKey: string,
454
+ update: { role?: keyof typeof ROLE, available?: boolean },
455
+ optionals: { groupKey?: string } & RoutingOptions = {}
456
+ ):Promise<GroupPermission> {
457
+ const { role, available } = update;
458
+ const { groupKey, ...routingOptions } = optionals;
459
+ const session = identification.session as UserSession;
460
+ return await new Router()
461
+ .patch(`/group/member/${groupKey ?? session?.groupKey}/${userKey}`, {
462
+ body: {
463
+ objectType: 'group',
464
+ role,
465
+ available,
466
+ },
467
+ ...routingOptions,
468
+ })
469
+ .then(({ body }) => body);
470
+ }
471
+
472
+
473
+ /**
474
+ * Removes user(s) from the group
475
+ * @example
476
+ * const userKeys = members.map(({ userKey }) => userKey);
477
+ * epicenter.groupAdapter.removeUsers(userKeys)
478
+ * @param userKey Key associated with the user or an array of user keys to remove from group
479
+ * @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
480
+ * @param [optionals.groupKey] Group key for the group you want to remove from; defaults to the group in the current session
481
+ * @returns promise that resolves to undefined when successful
482
+ */
483
+ export async function removeUser(
484
+ userKey: string | string[],
485
+ optionals: { groupKey?: string } & RoutingOptions = {}
486
+ ): Promise<void> {
487
+ const { groupKey, ...routingOptions } = optionals;
488
+ const hasMultiple = Array.isArray(userKey) && userKey.length > 1;
489
+ const uriComponent = hasMultiple ? '' : `/${userKey.length === 1 ? userKey[0] : userKey}`;
490
+ const searchParams = hasMultiple ? { userKey } : undefined;
491
+ const session = identification.session as UserSession;
492
+ return await new Router()
493
+ .withSearchParams(searchParams)
494
+ .delete(`/group/member/${groupKey ?? session?.groupKey}${uriComponent}`, routingOptions)
495
+ .then(({ body }) => body);
496
+ }
497
+
498
+
499
+ export async function statusUpdate(
500
+ code: string,
501
+ message: string,
502
+ optionals: { groupKey?: string } & RoutingOptions = {}
503
+ ): Promise<Group> {
504
+ const { groupKey, ...routingOptions } = optionals;
505
+ const session = identification.session as UserSession;
506
+ return await new Router()
507
+ .patch(`/group/status/${groupKey ?? session?.groupKey}`, {
508
+ body: { code, message },
509
+ ...routingOptions,
510
+ }).then(({ body }) => body);
511
+ }
@@ -0,0 +1,43 @@
1
+ import * as accountAdapter from './account';
2
+ import * as adminAdapter from './admin';
3
+ import * as authAdapter from './authentication';
4
+ import * as assetAdapter from './asset';
5
+ import * as emailAdapter from './email';
6
+ import * as episodeAdapter from './episode';
7
+ import * as groupAdapter from './group';
8
+ import * as leaderboardAdapter from './leaderboard';
9
+ import * as presenceAdapter from './presence';
10
+ import * as projectAdapter from './project';
11
+ import * as recaptchaAdapter from './recaptcha';
12
+ import * as runAdapter from './run';
13
+ import * as userAdapter from './user';
14
+ import * as vaultAdapter from './vault';
15
+ import * as worldAdapter from './world';
16
+ import * as timeAdapter from './time';
17
+ import * as taskAdapter from './task';
18
+ import * as chatAdapter from './chat';
19
+ import { default as cometdAdapter } from './cometd';
20
+ import { default as Channel } from './channel';
21
+
22
+ export {
23
+ accountAdapter,
24
+ adminAdapter,
25
+ authAdapter,
26
+ assetAdapter,
27
+ chatAdapter,
28
+ cometdAdapter,
29
+ emailAdapter,
30
+ episodeAdapter,
31
+ groupAdapter,
32
+ leaderboardAdapter,
33
+ presenceAdapter,
34
+ projectAdapter,
35
+ recaptchaAdapter,
36
+ runAdapter,
37
+ timeAdapter,
38
+ userAdapter,
39
+ vaultAdapter,
40
+ worldAdapter,
41
+ taskAdapter,
42
+ Channel,
43
+ };
@@ -0,0 +1,122 @@
1
+ import type { UserSession } from 'utils/identification';
2
+ import type { RoutingOptions, GenericSearchOptions } from 'utils/router';
3
+ import type { GenericScope } from 'utils/constants';
4
+
5
+ import { identification, Router } from 'utils';
6
+
7
+
8
+ interface Score {
9
+ name: string,
10
+ quantity: number,
11
+ }
12
+
13
+ interface Tag {
14
+ label: string,
15
+ content: string,
16
+ }
17
+
18
+ interface Leaderboard {
19
+ lastUpdated: Date,
20
+ }
21
+
22
+
23
+ /**
24
+ * Creates a leaderboard entry.
25
+ * @example
26
+ * import { leaderboardAdapter } from 'epicenter';
27
+ * const leaderboard = await leaderboardAdapter.post(
28
+ * 'class-23-leaderboard',
29
+ * [{ name: 'total', quantity: 20 }, { name: 'extraCredit', quantity: 2 }],
30
+ * { scopeBoundary: SCOPE_BOUNDARY.GROUP, scopeKey: '0000017dd3bf540e5ada5b1e058f08f20461' },
31
+ * { tags: [{ label: 'role', content: 'doctor' }] }
32
+ * );
33
+ * @param collection Name of the leaderboard
34
+ * @param scope Scope attached to the leaderboard entry; allows for scoping
35
+ * @param scope.scopeBoundary Can be a couple things, commonly group, project, episode, or world
36
+ * @param scope.scopeKey Key of the resource defined by the scope boundary
37
+ * @param scope.userKey User key for the user creating the entry, if omitted will use the one in current session
38
+ * @param scores List of score objects
39
+ * @param scores[].name Name of the score
40
+ * @param scores[].quantity Value of the score
41
+ * @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
42
+ * @params [optionals.tags] Tags for the leaderboard entry, helps to provide another layer of scope if needed
43
+ * @returns promise that resolves to the leaderboard entry created
44
+ */
45
+ export async function update(
46
+ collection: string,
47
+ scope: { userKey?: string } & GenericScope,
48
+ scores: Score[],
49
+ optionals: { tags?: Tag[] } & RoutingOptions = {}
50
+ ): Promise<Leaderboard> {
51
+ const { tags, ...routingOptions } = optionals;
52
+ const { scopeBoundary, scopeKey, userKey } = scope;
53
+ const session = identification.session as UserSession;
54
+ return await new Router()
55
+ .post('/leaderboard', {
56
+ body: {
57
+ scope: {
58
+ scopeBoundary,
59
+ scopeKey,
60
+ userKey: userKey ?? session?.userKey,
61
+ },
62
+ collection,
63
+ scores, tags,
64
+ },
65
+ ...routingOptions,
66
+ }).then(({ body }) => body);
67
+ }
68
+
69
+ /**
70
+ * Gathers leaderboard information; not paginable (hence named 'list' and not 'query'). Technically there is no leader
71
+ * @example
72
+ * import { leaderboardAdapter } from 'epicenter';
73
+ * const leaderboard = await leaderboardAdapter.list('myLeaderboard', scope, {
74
+ * filter: [
75
+ * 'tag.role=doctor', // look for leaderboard entries tagged with role=doctor
76
+ * 'score.total>0' // where the users scored a total higher than 0
77
+ * ],
78
+ * sort: ['+score.total'], // sort results by 'total' in ascending order,
79
+ * first: 0,
80
+ * max: 20 // retrieve only the first 20 entries
81
+ * });
82
+ * @param collection Name of the leaderboard
83
+ * @param scope Scope attached to the leaderboard entry; allows for scoping
84
+ * @param scope.scopeBoundary Can be a couple things, commonly group, project, episode, or world
85
+ * @param scope.scopeKey Key of the resource defined by the scope boundary
86
+ * @param searchOptions Search options for the query
87
+ * @param [searchOptions.filter] Filters for searching
88
+ * @param [searchOptions.sort] Sorting criteria
89
+ * @param [searchOptions.first] The starting index of the list returned
90
+ * @param [searchOptions.max] The maximum number of entries in the list
91
+ * @param [optionals] Optional arguments; pass network call options overrides here.
92
+ * @returns promise that resolves to to a list of leaderboard entries
93
+ */
94
+ export async function list(
95
+ collection: string,
96
+ scope: GenericScope,
97
+ searchOptions: GenericSearchOptions,
98
+ optionals: RoutingOptions = {}
99
+ ): Promise<Leaderboard[]> {
100
+ const { scopeBoundary, scopeKey } = scope;
101
+ const { filter = [], sort = [], first, max } = searchOptions;
102
+ const searchParams = {
103
+ filter: filter.join(';') || undefined,
104
+ sort: sort.join(';') || undefined,
105
+ first, max,
106
+ };
107
+
108
+ return await new Router()
109
+ .withSearchParams(searchParams)
110
+ .get(`/leaderboard/${scopeBoundary}/${scopeKey}/${collection}`, optionals)
111
+ .then(({ body }) => body);
112
+ }
113
+
114
+ export async function get(
115
+ collection: string,
116
+ scope: GenericScope,
117
+ searchOptions: GenericSearchOptions,
118
+ optionals: RoutingOptions = {}
119
+ ): Promise<Leaderboard[]> {
120
+ console.warn('DEPRECATION WARNING: leaderboardAdapter.get is deprecated and will be removed with the next release. Use leaderboardAdapter.list instead.');
121
+ return await list(collection, scope, searchOptions, optionals);
122
+ }