epicenter-libs 3.33.0 → 3.34.1
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/CHANGELOG.md +17 -0
- package/dist/browser/epicenter.js +105 -2
- package/dist/browser/epicenter.js.map +1 -1
- package/dist/cjs/epicenter.js +105 -2
- package/dist/cjs/epicenter.js.map +1 -1
- package/dist/epicenter.js +105 -2
- package/dist/epicenter.js.map +1 -1
- package/dist/epicenter.min.js +1 -1
- package/dist/epicenter.min.js.map +1 -1
- package/dist/module/epicenter.js +105 -2
- package/dist/module/epicenter.js.map +1 -1
- package/dist/types/adapters/chat.d.ts +63 -0
- package/package.json +1 -1
- package/src/adapters/chat.ts +95 -0
- package/src/utils/identification.ts +4 -0
- package/dist/test/_virtual/runtime.js +0 -3
- package/dist/test/_virtual/runtime2.js +0 -3
- package/dist/test/adapters/account.js +0 -169
- package/dist/test/adapters/admin.js +0 -53
- package/dist/test/adapters/asset.js +0 -425
- package/dist/test/adapters/authentication.js +0 -349
- package/dist/test/adapters/channel.js +0 -201
- package/dist/test/adapters/chat.js +0 -199
- package/dist/test/adapters/cometd.js +0 -514
- package/dist/test/adapters/consensus.js +0 -484
- package/dist/test/adapters/daily.js +0 -244
- package/dist/test/adapters/email.js +0 -179
- package/dist/test/adapters/episode.js +0 -175
- package/dist/test/adapters/group.js +0 -655
- package/dist/test/adapters/leaderboard.js +0 -162
- package/dist/test/adapters/matchmaker.js +0 -159
- package/dist/test/adapters/presence.js +0 -85
- package/dist/test/adapters/project.js +0 -94
- package/dist/test/adapters/recaptcha.js +0 -24
- package/dist/test/adapters/run.js +0 -1008
- package/dist/test/adapters/somebody.js +0 -154
- package/dist/test/adapters/task.js +0 -192
- package/dist/test/adapters/time.js +0 -28
- package/dist/test/adapters/user.js +0 -105
- package/dist/test/adapters/vault.js +0 -403
- package/dist/test/adapters/video.js +0 -249
- package/dist/test/adapters/vonage.js +0 -130
- package/dist/test/adapters/wallet.js +0 -130
- package/dist/test/adapters/world.js +0 -507
- package/dist/test/apis/video.js +0 -294
- package/dist/test/apis/vonage.js +0 -121
- package/dist/test/epicenter.js +0 -121
- package/dist/test/node_modules/@babel/runtime/helpers/esm/defineProperty.js +0 -12
- package/dist/test/node_modules/@babel/runtime/helpers/esm/toPrimitive.js +0 -14
- package/dist/test/node_modules/@babel/runtime/helpers/esm/toPropertyKey.js +0 -9
- package/dist/test/node_modules/@babel/runtime/helpers/esm/typeof.js +0 -11
- package/dist/test/node_modules/cometd/AckExtension.js +0 -91
- package/dist/test/node_modules/cometd/CallbackPollingTransport.js +0 -148
- package/dist/test/node_modules/cometd/Client.js +0 -2160
- package/dist/test/node_modules/cometd/Extension.js +0 -47
- package/dist/test/node_modules/cometd/LongPollingTransport.js +0 -135
- package/dist/test/node_modules/cometd/ReloadExtension.js +0 -214
- package/dist/test/node_modules/cometd/RequestTransport.js +0 -252
- package/dist/test/node_modules/cometd/Transport.js +0 -167
- package/dist/test/node_modules/cometd/TransportRegistry.js +0 -107
- package/dist/test/node_modules/cometd/WebSocketTransport.js +0 -384
- package/dist/test/node_modules/cometd/cometd.js +0 -9
- package/dist/test/node_modules/regenerator-runtime/runtime.js +0 -773
- package/dist/test/utilities.js +0 -17
- package/dist/test/utils/config.js +0 -189
- package/dist/test/utils/constants.js +0 -293
- package/dist/test/utils/cookies.js +0 -75
- package/dist/test/utils/error-manager.js +0 -57
- package/dist/test/utils/error.js +0 -12
- package/dist/test/utils/fault.js +0 -34
- package/dist/test/utils/filter-parser.js +0 -68
- package/dist/test/utils/helpers.js +0 -9
- package/dist/test/utils/identification.js +0 -161
- package/dist/test/utils/result.js +0 -20
- package/dist/test/utils/router.js +0 -551
- package/dist/test/utils/store.js +0 -79
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import '../utils/helpers.js';
|
|
2
|
-
import '../utils/config.js';
|
|
3
|
-
import identification from '../utils/identification.js';
|
|
4
|
-
import '../utils/error-manager.js';
|
|
5
|
-
import Router from '../utils/router.js';
|
|
6
|
-
import cometdAdapter from './cometd.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Logs out of current Epicenter session. Also disconnects from CometD and removes user presence.
|
|
10
|
-
* Priorities:
|
|
11
|
-
* 1. Delete local session (even if 2 and 3 fail)
|
|
12
|
-
* 2. Delete remote session (even if 3 fails)
|
|
13
|
-
* 3. Other cleanup (disconnect CometD, delete presence)
|
|
14
|
-
* Cleanup operations require authentication, so await cleanup before delete.
|
|
15
|
-
* Base URL: DELETE `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/verification`
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
19
|
-
* await authAdapter.logout();
|
|
20
|
-
*
|
|
21
|
-
* @param [verificationOptionals] Optional arguments; pass network call options overrides here.
|
|
22
|
-
* @param [presenceOptionals] Optional arguments; pass network call options overrides here.
|
|
23
|
-
* @returns promise that resolves when logout is complete
|
|
24
|
-
*/
|
|
25
|
-
async function logout(verificationOptionals = {}, presenceOptionals = verificationOptionals) {
|
|
26
|
-
var _identification$sessi;
|
|
27
|
-
const cleanup = [cometdAdapter.disconnect()];
|
|
28
|
-
const groupKey = identification === null || identification === void 0 || (_identification$sessi = identification.session) === null || _identification$sessi === void 0 ? void 0 : _identification$sessi.groupKey;
|
|
29
|
-
if (groupKey) {
|
|
30
|
-
cleanup.push(new Router().delete(`/presence/group/${groupKey}`, presenceOptionals));
|
|
31
|
-
}
|
|
32
|
-
await Promise.allSettled(cleanup);
|
|
33
|
-
await new Router().delete('/verification', verificationOptionals).finally(() => identification.session = undefined);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Retrieves the current session from the server
|
|
38
|
-
* Base URL: GET `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/verification`
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
42
|
-
* const session = await authAdapter.getSession();
|
|
43
|
-
*
|
|
44
|
-
* @param [optionals] Optional arguments; pass network call options overrides here.
|
|
45
|
-
* @returns promise that resolves to the session object
|
|
46
|
-
*/
|
|
47
|
-
async function getSession(optionals = {}) {
|
|
48
|
-
const {
|
|
49
|
-
body
|
|
50
|
-
} = await new Router().get('/verification', optionals);
|
|
51
|
-
identification.session = body;
|
|
52
|
-
return body;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Retrieves the session stored in memory
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
60
|
-
* const session = authAdapter.getLocalSession();
|
|
61
|
-
*
|
|
62
|
-
* @returns the session object if it exists, undefined otherwise
|
|
63
|
-
*/
|
|
64
|
-
function getLocalSession() {
|
|
65
|
-
return identification.session;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Stores a session in memory
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
73
|
-
* authAdapter.setLocalSession(session);
|
|
74
|
-
*
|
|
75
|
-
* @param session The session object to store
|
|
76
|
-
* @returns the stored session object
|
|
77
|
-
*/
|
|
78
|
-
function setLocalSession(session) {
|
|
79
|
-
return identification.session = session;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Removes the session stored in memory and disconnects from CometD
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
87
|
-
* await authAdapter.removeLocalSession();
|
|
88
|
-
*
|
|
89
|
-
* @returns promise that resolves when the session is removed and CometD is disconnected
|
|
90
|
-
*/
|
|
91
|
-
async function removeLocalSession() {
|
|
92
|
-
identification.session = undefined;
|
|
93
|
-
await cometdAdapter.disconnect();
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Logs in a user or app and stores the session
|
|
98
|
-
* Base URL: POST `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/authentication`
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
102
|
-
* // User login
|
|
103
|
-
* const session = await authAdapter.login({
|
|
104
|
-
* handle: 'user@example.com',
|
|
105
|
-
* password: 'myPassword',
|
|
106
|
-
* groupKey: '00000165ad4e6a3cd22b993340b963820239',
|
|
107
|
-
* });
|
|
108
|
-
* // App login
|
|
109
|
-
* const session = await authAdapter.login({
|
|
110
|
-
* secretKey: 'my-secret-key',
|
|
111
|
-
* });
|
|
112
|
-
*
|
|
113
|
-
* @param credentials User or app credentials
|
|
114
|
-
* @param credentials.handle User handle (email or username)
|
|
115
|
-
* @param credentials.password User password
|
|
116
|
-
* @param [credentials.groupKey] Group key for user login
|
|
117
|
-
* @param credentials.secretKey Secret key for app login
|
|
118
|
-
* @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
|
|
119
|
-
* @param [optionals.objectType] Object type for authentication (defaults to 'user' or 'account' based on credentials)
|
|
120
|
-
* @param [optionals.forcePathInclusion] Controls cookie path behavior: `true` forces project-specific path (even on custom domains), `false` forces root path (even for users/admins on Epicenter domain), `undefined` uses defaults (project-specific for users/admins on Epicenter domain, root for custom domains)
|
|
121
|
-
* @returns promise that resolves to the session object
|
|
122
|
-
*/
|
|
123
|
-
async function login(credentials, optionals = {}) {
|
|
124
|
-
const {
|
|
125
|
-
objectType,
|
|
126
|
-
forcePathInclusion,
|
|
127
|
-
...routingOptions
|
|
128
|
-
} = optionals;
|
|
129
|
-
let payload;
|
|
130
|
-
if (Object.prototype.hasOwnProperty.call(credentials, 'handle')) {
|
|
131
|
-
const {
|
|
132
|
-
handle,
|
|
133
|
-
password,
|
|
134
|
-
groupKey
|
|
135
|
-
} = credentials;
|
|
136
|
-
payload = {
|
|
137
|
-
objectType: objectType !== null && objectType !== void 0 ? objectType : 'user',
|
|
138
|
-
handle,
|
|
139
|
-
password,
|
|
140
|
-
groupKey: groupKey || undefined
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
if (Object.prototype.hasOwnProperty.call(credentials, 'secretKey')) {
|
|
144
|
-
const {
|
|
145
|
-
secretKey
|
|
146
|
-
} = credentials;
|
|
147
|
-
payload = {
|
|
148
|
-
objectType: objectType !== null && objectType !== void 0 ? objectType : 'account',
|
|
149
|
-
secretKey
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
const session = await new Router().post('/authentication', {
|
|
153
|
-
inert: true,
|
|
154
|
-
includeAuthorization: false,
|
|
155
|
-
body: payload,
|
|
156
|
-
...routingOptions
|
|
157
|
-
}).then(({
|
|
158
|
-
body
|
|
159
|
-
}) => body);
|
|
160
|
-
await removeLocalSession();
|
|
161
|
-
identification.setSessionWithOptions(session, forcePathInclusion);
|
|
162
|
-
return session;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Regenerates your Epicenter session with the appropriate context.
|
|
167
|
-
* Base URL: PATCH `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/authentication`
|
|
168
|
-
*
|
|
169
|
-
* - For users: Updates session to the specified group context
|
|
170
|
-
* - For admins: Updates session to the specified account/project context (uses platform's focus API)
|
|
171
|
-
*
|
|
172
|
-
* This is automatically called when switching between projects/groups if the session cookie
|
|
173
|
-
* is scoped to a specific project path.
|
|
174
|
-
*
|
|
175
|
-
* Will fail if the user/admin does not already belong to the group/account.
|
|
176
|
-
*
|
|
177
|
-
* @example
|
|
178
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
179
|
-
* // Changes the current user session to have a group context associated with the provided key
|
|
180
|
-
* await authAdapter.regenerate('00000165ad4e6a3cd22b993340b963820239');
|
|
181
|
-
* // Changes the current admin session to use the account context for the 'acme' account
|
|
182
|
-
* await authAdapter.regenerate('acme', { objectType: 'admin' });
|
|
183
|
-
*
|
|
184
|
-
* @param groupOrAccount Group key or account name
|
|
185
|
-
* @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
|
|
186
|
-
* @param [optionals.objectType] The object type to regenerate for (defaults to 'user')
|
|
187
|
-
* @param [optionals.forcePathInclusion] Controls cookie path behavior: `true` forces project-specific path (even on custom domains), `false` forces root path (even for users/admins on Epicenter domain), `undefined` uses defaults (project-specific for users/admins on Epicenter domain, root for custom domains)
|
|
188
|
-
* @returns promise that resolves to the new session object
|
|
189
|
-
*/
|
|
190
|
-
async function regenerate(groupOrAccount, optionals = {}) {
|
|
191
|
-
const {
|
|
192
|
-
objectType = 'user',
|
|
193
|
-
accountShortName,
|
|
194
|
-
forcePathInclusion,
|
|
195
|
-
...routingOptions
|
|
196
|
-
} = optionals;
|
|
197
|
-
const session = await new Router().patch('/authentication', {
|
|
198
|
-
accountShortName: objectType === 'admin' ? groupOrAccount : accountShortName,
|
|
199
|
-
body: {
|
|
200
|
-
objectType,
|
|
201
|
-
groupKey: objectType === 'user' ? groupOrAccount : undefined
|
|
202
|
-
},
|
|
203
|
-
...routingOptions
|
|
204
|
-
}).then(({
|
|
205
|
-
body
|
|
206
|
-
}) => body);
|
|
207
|
-
await removeLocalSession();
|
|
208
|
-
identification.setSessionWithOptions(session, forcePathInclusion);
|
|
209
|
-
return session;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Authenticates using Single Sign-On (SSO)
|
|
214
|
-
* Base URL: GET `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/registration/sso/user`
|
|
215
|
-
*
|
|
216
|
-
* @example
|
|
217
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
218
|
-
* const session = await authAdapter.sso();
|
|
219
|
-
*
|
|
220
|
-
* @param [optionals] Optional arguments; pass network call options overrides here.
|
|
221
|
-
* @returns promise that resolves to the session object
|
|
222
|
-
*/
|
|
223
|
-
async function sso(optionals = {}) {
|
|
224
|
-
const session = await new Router().get('/registration/sso/user', optionals).then(({
|
|
225
|
-
body
|
|
226
|
-
}) => body);
|
|
227
|
-
identification.session = session;
|
|
228
|
-
return session;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Retrieves the SAML link from the SSO configuration
|
|
233
|
-
* Base URL: GET `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/registration/sso/user/saml`
|
|
234
|
-
*
|
|
235
|
-
* @example
|
|
236
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
237
|
-
* const samlLink = await authAdapter.getSAMLLink();
|
|
238
|
-
*
|
|
239
|
-
* @param [optionals] Optional arguments; pass network call options overrides here.
|
|
240
|
-
* @returns promise that resolves to the SAML link
|
|
241
|
-
*/
|
|
242
|
-
async function getSAMLLink(optionals = {}) {
|
|
243
|
-
return await new Router().get('/registration/sso/user/saml', optionals).then(({
|
|
244
|
-
body
|
|
245
|
-
}) => body);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Generates and returns an epicenter URL that will redirect to the SAML url
|
|
250
|
-
*
|
|
251
|
-
* @example
|
|
252
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
253
|
-
* const samlURL = authAdapter.generateSAMLLINK();
|
|
254
|
-
*
|
|
255
|
-
* @param [optionals] Optional arguments; pass network call options overrides here.
|
|
256
|
-
* @returns the generated SAML URL string
|
|
257
|
-
*/
|
|
258
|
-
function generateSAMLLINK(optionals = {}) {
|
|
259
|
-
return new Router().getURL('/registration/sso/user/saml', optionals).toString();
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Sends an outcome to an external link specified in project config. For example, sending a grade back to a third party platform.
|
|
264
|
-
* Base URL: POST `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/lti/{LTI_VERSION}/outcome`
|
|
265
|
-
*
|
|
266
|
-
* @example
|
|
267
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
268
|
-
* await authAdapter.ssoOutcome('1.3', {
|
|
269
|
-
* value: 95,
|
|
270
|
-
* sourcedId: 'student-assignment-123',
|
|
271
|
-
* outcomeServiceUrl: 'https://lms.example.com/outcome',
|
|
272
|
-
* });
|
|
273
|
-
*
|
|
274
|
-
* @param ltiVersion The version of LTI to use (valid versions: 1.1, 1.2, 1.3)
|
|
275
|
-
* @param outcomeInformation Outcome information to send
|
|
276
|
-
* @param outcomeInformation.value The value to pass back to the outcomeServiceUrl (e.g., the grade a student received)
|
|
277
|
-
* @param outcomeInformation.sourcedId The id of the current assignment/student as provided by the client using the SSO service
|
|
278
|
-
* @param outcomeInformation.outcomeServiceUrl The url called for passing back the outcome
|
|
279
|
-
* @param [optionals] Optional arguments; pass network call options overrides here.
|
|
280
|
-
* @returns promise that resolves to the response object
|
|
281
|
-
*/
|
|
282
|
-
async function ssoOutcome(ltiVersion, outcomeInformation, optionals = {}) {
|
|
283
|
-
const {
|
|
284
|
-
...routingOptions
|
|
285
|
-
} = optionals;
|
|
286
|
-
return await new Router().post(`/lti/${ltiVersion}/outcome`, {
|
|
287
|
-
body: outcomeInformation,
|
|
288
|
-
...routingOptions
|
|
289
|
-
}).then(({
|
|
290
|
-
body
|
|
291
|
-
}) => body);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Sends a link to reset a user's password to their email
|
|
296
|
-
* Base URL: POST `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/verification/password/user/{HANDLE}`
|
|
297
|
-
*
|
|
298
|
-
* @example
|
|
299
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
300
|
-
* const subject = 'Please reset your password for the Acme simulation';
|
|
301
|
-
* const redirectURL = 'https://forio.com/app/acme/simulations';
|
|
302
|
-
* const handle = 'testUser@test.com';
|
|
303
|
-
* await authAdapter.resetPassword(handle, { redirectURL, subject });
|
|
304
|
-
*
|
|
305
|
-
* @param handle Handle that user would use to login
|
|
306
|
-
* @param [optionals] Optional arguments; pass network call options overrides here. Special arguments specific to this method are listed below if they exist.
|
|
307
|
-
* @param [optionals.redirectURL] URL to redirect to after password reset is completed (must be in the forio domain)
|
|
308
|
-
* @param [optionals.subject] The subject of the email that will be sent
|
|
309
|
-
* @returns promise that resolves when the reset email is sent
|
|
310
|
-
*/
|
|
311
|
-
async function resetPassword(handle, optionals = {}) {
|
|
312
|
-
const {
|
|
313
|
-
redirectURL,
|
|
314
|
-
subject,
|
|
315
|
-
...routingOptions
|
|
316
|
-
} = optionals;
|
|
317
|
-
return await new Router().post(`/verification/password/user/${handle}`, {
|
|
318
|
-
...routingOptions,
|
|
319
|
-
body: {
|
|
320
|
-
redirectUrl: redirectURL,
|
|
321
|
-
subject
|
|
322
|
-
}
|
|
323
|
-
}).then(({
|
|
324
|
-
body
|
|
325
|
-
}) => body);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Verifies a token and retrieves the associated session
|
|
330
|
-
* Base URL: GET `https://forio.com/api/v3/{ACCOUNT}/{PROJECT}/verification`
|
|
331
|
-
*
|
|
332
|
-
* @example
|
|
333
|
-
* import { authAdapter } from 'epicenter-libs';
|
|
334
|
-
* const session = await authAdapter.verify('my-auth-token');
|
|
335
|
-
*
|
|
336
|
-
* @param token Authorization token to verify
|
|
337
|
-
* @param [optionals] Optional arguments; pass network call options overrides here.
|
|
338
|
-
* @returns promise that resolves to the session object
|
|
339
|
-
*/
|
|
340
|
-
async function verify(token, optionals = {}) {
|
|
341
|
-
return await new Router().get('/verification', {
|
|
342
|
-
authorization: `Bearer ${token}`,
|
|
343
|
-
...optionals
|
|
344
|
-
}).then(({
|
|
345
|
-
body
|
|
346
|
-
}) => body);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export { generateSAMLLINK, getLocalSession, getSAMLLink, getSession, login, logout, regenerate, removeLocalSession, resetPassword, setLocalSession, sso, ssoOutcome, verify };
|
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import _defineProperty from '../node_modules/@babel/runtime/helpers/esm/defineProperty.js';
|
|
2
|
-
import { SCOPE_BOUNDARY, PUSH_CATEGORY } from '../utils/constants.js';
|
|
3
|
-
import '../utils/helpers.js';
|
|
4
|
-
import EpicenterError from '../utils/error.js';
|
|
5
|
-
import '../utils/config.js';
|
|
6
|
-
import '../utils/identification.js';
|
|
7
|
-
import '../utils/error-manager.js';
|
|
8
|
-
import 'cross-fetch';
|
|
9
|
-
import cometdAdapter from './cometd.js';
|
|
10
|
-
|
|
11
|
-
// Generic type for push channel message custom data
|
|
12
|
-
|
|
13
|
-
// Base structure for channel push messages
|
|
14
|
-
|
|
15
|
-
const validateScope = scope => {
|
|
16
|
-
if (!scope) throw new EpicenterError('No scope found where one was required');
|
|
17
|
-
const {
|
|
18
|
-
scopeBoundary,
|
|
19
|
-
scopeKey,
|
|
20
|
-
pushCategory
|
|
21
|
-
} = scope;
|
|
22
|
-
if (!scopeBoundary) throw new EpicenterError('Missing scope component: scopeBoundary');
|
|
23
|
-
if (!scopeKey) throw new EpicenterError('Missing scope component: scopeKey');
|
|
24
|
-
if (!pushCategory) throw new EpicenterError('Missing scope component: pushCategory');
|
|
25
|
-
if (!Object.prototype.hasOwnProperty.call(SCOPE_BOUNDARY, scopeBoundary)) throw new EpicenterError(`Invalid scope boundary: ${scopeBoundary}`);
|
|
26
|
-
if (!Object.prototype.hasOwnProperty.call(PUSH_CATEGORY, pushCategory)) throw new EpicenterError(`Invalid push category: ${pushCategory}`);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Used to subscribe to CometD channels. Pass in a channel scope to instantiate, if a subscription to that scope already exists it will use it.
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* import { Channel, authAdapter, SCOPE_BOUNDARY, PUSH_CATEGORY } from 'epicenter-libs';
|
|
34
|
-
* const session = authAdapter.getLocalSession();
|
|
35
|
-
* const channel = new Channel({
|
|
36
|
-
* scopeBoundary: SCOPE_BOUNDARY.GROUP,
|
|
37
|
-
* scopeKey: session.groupKey,
|
|
38
|
-
* pushCategory: PUSH_CATEGORY.CHAT,
|
|
39
|
-
* });
|
|
40
|
-
* await channel.subscribe((data) => {
|
|
41
|
-
* console.log('Received message:', data);
|
|
42
|
-
* });
|
|
43
|
-
*/
|
|
44
|
-
class Channel {
|
|
45
|
-
/**
|
|
46
|
-
* Channel constructor
|
|
47
|
-
*
|
|
48
|
-
* @param scope Object with the scope boundary, scope key, and push category; defines the namespace for the channel
|
|
49
|
-
* @param scope.scopeBoundary Scope boundary, defines the type of scope; See [scope boundary](#SCOPE_BOUNDARY) for all types
|
|
50
|
-
* @param scope.scopeKey Scope key, a unique identifier tied to the scope. E.g., if your `scopeBoundary` is `GROUP`, your `scopeKey` will be your `groupKey`; for `EPISODE`, `episodeKey`, etc.
|
|
51
|
-
* @param scope.pushCategory Push category, defines the type of channel; See [push category](#PUSH_CATEGORY) for all types
|
|
52
|
-
*/
|
|
53
|
-
constructor(scope) {
|
|
54
|
-
_defineProperty(this, "path", void 0);
|
|
55
|
-
_defineProperty(this, "update", void 0);
|
|
56
|
-
_defineProperty(this, "subscription", null);
|
|
57
|
-
const {
|
|
58
|
-
scopeBoundary,
|
|
59
|
-
scopeKey,
|
|
60
|
-
pushCategory
|
|
61
|
-
} = scope;
|
|
62
|
-
validateScope(scope);
|
|
63
|
-
this.path = `/${scopeBoundary.toLowerCase()}/${scopeKey}/${pushCategory.toLowerCase()}`;
|
|
64
|
-
if (cometdAdapter.subscriptions.has(this.path)) {
|
|
65
|
-
this.subscription = cometdAdapter.subscriptions.get(this.path) || null;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Publishes content to the CometD channel
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* import { Channel, authAdapter, SCOPE_BOUNDARY, PUSH_CATEGORY } from 'epicenter-libs';
|
|
74
|
-
* const session = authAdapter.getLocalSession();
|
|
75
|
-
* const channel = new Channel({
|
|
76
|
-
* scopeBoundary: SCOPE_BOUNDARY.GROUP,
|
|
77
|
-
* scopeKey: session.groupKey,
|
|
78
|
-
* pushCategory: PUSH_CATEGORY.CHAT,
|
|
79
|
-
* });
|
|
80
|
-
* await channel.publish({ message: 'Hello!' });
|
|
81
|
-
*
|
|
82
|
-
* @param content Content to publish to the channel
|
|
83
|
-
* @returns promise that resolves to the CometD message response
|
|
84
|
-
*/
|
|
85
|
-
publish(content) {
|
|
86
|
-
return cometdAdapter.publish(this, content);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Subscribes to the CometD channel, attaching a handler for any channel updates. If a subscription already exists it will first unsubscribe, ensuring that only one subscription is ever attached to the channel.
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* import { Channel, authAdapter, SCOPE_BOUNDARY, PUSH_CATEGORY } from 'epicenter-libs';
|
|
94
|
-
* const session = authAdapter.getLocalSession();
|
|
95
|
-
* const channel = new Channel({
|
|
96
|
-
* scopeBoundary: SCOPE_BOUNDARY.GROUP,
|
|
97
|
-
* scopeKey: session.groupKey,
|
|
98
|
-
* pushCategory: PUSH_CATEGORY.CHAT,
|
|
99
|
-
* });
|
|
100
|
-
* await channel.subscribe((data) => {
|
|
101
|
-
* console.log(data.content);
|
|
102
|
-
* });
|
|
103
|
-
*
|
|
104
|
-
* @param update Function that is called whenever a channel update occurs
|
|
105
|
-
* @param [options] Optional arguments
|
|
106
|
-
* @param [options.inert] If true, creates an inert subscription that doesn't trigger reconnection
|
|
107
|
-
* @returns promise that resolves to the subscription object returned by CometD after a successful subscribe
|
|
108
|
-
*/
|
|
109
|
-
// eslint-disable-next-line complexity
|
|
110
|
-
async subscribe(update, options = {}) {
|
|
111
|
-
if (this.subscription) {
|
|
112
|
-
try {
|
|
113
|
-
await cometdAdapter.remove(this.subscription);
|
|
114
|
-
} catch (error) {
|
|
115
|
-
var _errorObj$information;
|
|
116
|
-
const errorObj = error;
|
|
117
|
-
const errorMessage = (errorObj === null || errorObj === void 0 ? void 0 : errorObj.message) || (errorObj === null || errorObj === void 0 || (_errorObj$information = errorObj.information) === null || _errorObj$information === void 0 ? void 0 : _errorObj$information.error) || '';
|
|
118
|
-
if (errorMessage.includes('session_unknown') || errorMessage.includes('402')) ; else {
|
|
119
|
-
// Re-throw other errors
|
|
120
|
-
throw error;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
this.update = update;
|
|
125
|
-
let retryCount = 0;
|
|
126
|
-
const maxRetries = 3;
|
|
127
|
-
while (retryCount < maxRetries) {
|
|
128
|
-
try {
|
|
129
|
-
this.subscription = await cometdAdapter.add(this, update, options);
|
|
130
|
-
return this.subscription;
|
|
131
|
-
} catch (error) {
|
|
132
|
-
var _errorObj$information2;
|
|
133
|
-
const errorObj = error;
|
|
134
|
-
const errorMessage = (errorObj === null || errorObj === void 0 ? void 0 : errorObj.message) || (errorObj === null || errorObj === void 0 || (_errorObj$information2 = errorObj.information) === null || _errorObj$information2 === void 0 ? void 0 : _errorObj$information2.error) || '';
|
|
135
|
-
if ((errorMessage.includes('session_unknown') || errorMessage.includes('402')) && retryCount < maxRetries - 1) {
|
|
136
|
-
retryCount++;
|
|
137
|
-
// Force fresh handshake
|
|
138
|
-
cometdAdapter.handshakeState = 'idle';
|
|
139
|
-
cometdAdapter.handshakePromise = undefined;
|
|
140
|
-
|
|
141
|
-
// Wait a moment before retrying
|
|
142
|
-
const retryDelay = 1000;
|
|
143
|
-
const currentRetry = retryCount;
|
|
144
|
-
await new Promise(resolve => setTimeout(resolve, retryDelay * currentRetry));
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Re-throw if not session_unknown or max retries exceeded
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
throw new Error(`Failed to subscribe to ${this.path} after ${maxRetries} attempts`);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Unsubscribes from the CometD channel
|
|
157
|
-
*
|
|
158
|
-
* @example
|
|
159
|
-
* import { Channel, authAdapter, SCOPE_BOUNDARY, PUSH_CATEGORY } from 'epicenter-libs';
|
|
160
|
-
* const session = authAdapter.getLocalSession();
|
|
161
|
-
* const channel = new Channel({
|
|
162
|
-
* scopeBoundary: SCOPE_BOUNDARY.GROUP,
|
|
163
|
-
* scopeKey: session.groupKey,
|
|
164
|
-
* pushCategory: PUSH_CATEGORY.CHAT,
|
|
165
|
-
* });
|
|
166
|
-
* await channel.subscribe((data) => console.log(data));
|
|
167
|
-
* // Later...
|
|
168
|
-
* await channel.unsubscribe();
|
|
169
|
-
*
|
|
170
|
-
* @returns promise that resolves when unsubscribed
|
|
171
|
-
*/
|
|
172
|
-
async unsubscribe() {
|
|
173
|
-
if (this.subscription) {
|
|
174
|
-
await cometdAdapter.remove(this.subscription);
|
|
175
|
-
this.subscription = null;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Unsubscribes from all CometD channels
|
|
181
|
-
*
|
|
182
|
-
* @example
|
|
183
|
-
* import { Channel, authAdapter, SCOPE_BOUNDARY, PUSH_CATEGORY } from 'epicenter-libs';
|
|
184
|
-
* const session = authAdapter.getLocalSession();
|
|
185
|
-
* const channel = new Channel({
|
|
186
|
-
* scopeBoundary: SCOPE_BOUNDARY.GROUP,
|
|
187
|
-
* scopeKey: session.groupKey,
|
|
188
|
-
* pushCategory: PUSH_CATEGORY.CHAT,
|
|
189
|
-
* });
|
|
190
|
-
* await channel.subscribe((data) => console.log(data));
|
|
191
|
-
* // Later, unsubscribe from all channels...
|
|
192
|
-
* await channel.unsubscribeAll();
|
|
193
|
-
*
|
|
194
|
-
* @returns promise that resolves when all channels are unsubscribed
|
|
195
|
-
*/
|
|
196
|
-
async unsubscribeAll() {
|
|
197
|
-
await cometdAdapter.empty();
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export { Channel as default };
|