@juki-team/commons 0.1.41 → 0.1.42
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/dist/cjs/index.cjs +142 -0
- package/dist/esm/index.js +127 -1
- package/dist/types/constants/websocket.d.ts +23 -1
- package/dist/types/dto/socket.d.ts +18 -2
- package/dist/types/helpers/socket.d.ts +20 -1
- package/dist/types/types/socket.d.ts +16 -1
- package/package.json +3 -3
package/dist/cjs/index.cjs
CHANGED
|
@@ -600,6 +600,9 @@ exports.WebSocketSubscriptionEvent = void 0;
|
|
|
600
600
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK"] = "UNSUBSCRIBE_CLIENT_TRACK";
|
|
601
601
|
WebSocketSubscriptionEvent["SUBSCRIBE_USER_NOTIFICATION"] = "SUBSCRIBE_USER_NOTIFICATION";
|
|
602
602
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_USER_NOTIFICATION"] = "UNSUBSCRIBE_USER_NOTIFICATION";
|
|
603
|
+
// an administrator watching the data (screenshots, location, device) sent by another client
|
|
604
|
+
WebSocketSubscriptionEvent["SUBSCRIBE_CLIENT_TRACK_DATA"] = "SUBSCRIBE_CLIENT_TRACK_DATA";
|
|
605
|
+
WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK_DATA"] = "UNSUBSCRIBE_CLIENT_TRACK_DATA";
|
|
603
606
|
})(exports.WebSocketSubscriptionEvent || (exports.WebSocketSubscriptionEvent = {}));
|
|
604
607
|
exports.WebSocketResponseEvent = void 0;
|
|
605
608
|
(function (WebSocketResponseEvent) {
|
|
@@ -623,6 +626,20 @@ exports.WebSocketResponseEvent = void 0;
|
|
|
623
626
|
WebSocketResponseEvent["USER_NOTIFICATION_SUBMISSION"] = "USER_NOTIFICATION_SUBMISSION";
|
|
624
627
|
WebSocketResponseEvent["USER_NOTIFICATION_CONTEST_CLARIFICATION"] = "USER_NOTIFICATION_CONTEST_CLARIFICATION";
|
|
625
628
|
})(exports.WebSocketResponseEvent || (exports.WebSocketResponseEvent = {}));
|
|
629
|
+
/**
|
|
630
|
+
* Roles of a contest, with the same names as the contest members in the DB.
|
|
631
|
+
* Each role has its own Ably channel: `contest:{contestKey}:{role}` (see `CHANNEL_CONTEST`).
|
|
632
|
+
* The inclusions follow `getContestAccessPermissions`:
|
|
633
|
+
* spectators ⊇ managers ⊇ administrators, spectators ⊇ participants, spectators ⊇ guests
|
|
634
|
+
*/
|
|
635
|
+
exports.ContestChannelRole = void 0;
|
|
636
|
+
(function (ContestChannelRole) {
|
|
637
|
+
ContestChannelRole["ADMINISTRATORS"] = "administrators";
|
|
638
|
+
ContestChannelRole["MANAGERS"] = "managers";
|
|
639
|
+
ContestChannelRole["PARTICIPANTS"] = "participants";
|
|
640
|
+
ContestChannelRole["GUESTS"] = "guests";
|
|
641
|
+
ContestChannelRole["SPECTATORS"] = "spectators";
|
|
642
|
+
})(exports.ContestChannelRole || (exports.ContestChannelRole = {}));
|
|
626
643
|
|
|
627
644
|
exports.DataViewMode = void 0;
|
|
628
645
|
(function (DataViewMode) {
|
|
@@ -2223,11 +2240,43 @@ const EMPTY_USER_PERMISSIONS = {
|
|
|
2223
2240
|
},
|
|
2224
2241
|
};
|
|
2225
2242
|
|
|
2243
|
+
// LEGACY channels (fan-out per client through the subscriptions registry in Redis)
|
|
2226
2244
|
const CHANNEL_PUBLISH_SUBSCRIPTIONS = 'pub:subscriptions';
|
|
2227
2245
|
const CHANNEL_SUBSCRIBE_NOTIFICATIONS = 'sub:notifications';
|
|
2228
2246
|
const CHANNEL_SUBSCRIBE_CLIENT = (clientId) => `sub:client:${clientId}`;
|
|
2229
2247
|
const CHANNEL_PUBLISH_MESSAGES = 'pub:messages';
|
|
2230
2248
|
const CHANNEL_PRESENCE_CLIENT = 'pre:client';
|
|
2249
|
+
// TOPIC channels
|
|
2250
|
+
// The backend publishes each event once on the channel of its topic and Ably does the fan-out.
|
|
2251
|
+
// Who can subscribe to each channel is decided by the API in the Ably token (capability), never by the client.
|
|
2252
|
+
// Dynamic segments are encoded so a key can never inject a `:` (the Ably segment separator used by the wildcards).
|
|
2253
|
+
const segment = (value) => encodeURIComponent(value);
|
|
2254
|
+
/** private: events of one session (code runs, requested data, client track commands) */
|
|
2255
|
+
const CHANNEL_SESSION = (sessionId) => `session:${segment(sessionId)}`;
|
|
2256
|
+
/** private: events of one user (own submissions while the contest is frozen, notifications) */
|
|
2257
|
+
const CHANNEL_USER = (userId) => `user:${segment(userId)}`;
|
|
2258
|
+
/** public: status of a submission when it is visible to everyone */
|
|
2259
|
+
const CHANNEL_SUBMISSION = (submitId) => `submission:${segment(submitId)}`;
|
|
2260
|
+
/** public: changes of a problem */
|
|
2261
|
+
const CHANNEL_PROBLEM = (problemKey) => `problem:${segment(problemKey)}`;
|
|
2262
|
+
/** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
|
|
2263
|
+
const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${role}`;
|
|
2264
|
+
/** system administrators only: data sent by a tracked client (screenshots, location, device) */
|
|
2265
|
+
const CHANNEL_CLIENT_TRACK = (trackedClientId) => `client-track:${segment(trackedClientId)}`;
|
|
2266
|
+
// capability resources (wildcards) of the public channels
|
|
2267
|
+
const CHANNEL_SUBMISSION_ALL = 'submission:*';
|
|
2268
|
+
const CHANNEL_PROBLEM_ALL = 'problem:*';
|
|
2269
|
+
const CHANNEL_CLIENT_TRACK_ALL = 'client-track:*';
|
|
2270
|
+
/**
|
|
2271
|
+
* Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
|
|
2272
|
+
*/
|
|
2273
|
+
const getContestChannelParams = (channel) => {
|
|
2274
|
+
const [namespace, contestKey, role, ...rest] = channel.split(':');
|
|
2275
|
+
if (namespace !== 'contest' || !contestKey || rest.length || !Object.values(exports.ContestChannelRole).includes(role)) {
|
|
2276
|
+
return null;
|
|
2277
|
+
}
|
|
2278
|
+
return { contestKey: decodeURIComponent(contestKey), role: role };
|
|
2279
|
+
};
|
|
2231
2280
|
|
|
2232
2281
|
const NEW_PAGE_SHEET = () => ({
|
|
2233
2282
|
id: uuid.v4(),
|
|
@@ -3010,6 +3059,16 @@ const isUnsubscribeUserNotificationWebSocketEventDTO = (event) => {
|
|
|
3010
3059
|
return isWebsocketSubscription(event)
|
|
3011
3060
|
&& event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
|
|
3012
3061
|
};
|
|
3062
|
+
const isSubscribeClientTrackDataWebSocketEventDTO = (event) => {
|
|
3063
|
+
return isWebsocketSubscription(event)
|
|
3064
|
+
&& event?.event === exports.WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK_DATA
|
|
3065
|
+
&& typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
|
|
3066
|
+
};
|
|
3067
|
+
const isUnsubscribeClientTrackDataWebSocketEventDTO = (event) => {
|
|
3068
|
+
return isWebsocketSubscription(event)
|
|
3069
|
+
&& event?.event === exports.WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK_DATA
|
|
3070
|
+
&& typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
|
|
3071
|
+
};
|
|
3013
3072
|
// is WebSocketResponseEventDTO, CHANNEL_SUBSCRIBE_CLIENT
|
|
3014
3073
|
const isWebSocketResponseEventDTO = (event) => {
|
|
3015
3074
|
return Object.values(exports.WebSocketResponseEvent).includes(event?.event)
|
|
@@ -3123,6 +3182,73 @@ const isUserNotificationContestClarificationWebSocketResponseEventDTO = (event)
|
|
|
3123
3182
|
const getWebSocketResponseEventKey = (event, clientId, id) => {
|
|
3124
3183
|
return `${event}-${clientId}-${id}`;
|
|
3125
3184
|
};
|
|
3185
|
+
const isWebSocketChannelsMessageDTO = (message) => {
|
|
3186
|
+
return Array.isArray(message?.channels)
|
|
3187
|
+
&& message.channels.every((channel) => typeof channel === 'string' && !!channel)
|
|
3188
|
+
&& Object.values(exports.WebSocketResponseEvent).includes(message?.event?.event);
|
|
3189
|
+
};
|
|
3190
|
+
/**
|
|
3191
|
+
* Key used by the client to dispatch a response received on a TOPIC channel to its subscribers.
|
|
3192
|
+
* It is the same key that `getKeyWebSocketEventDTO` (base-ui) computes for the subscription.
|
|
3193
|
+
* Returns null when the response is not addressed to this client.
|
|
3194
|
+
*/
|
|
3195
|
+
const getWebSocketResponseEventKeyOfResponse = (response, clientId) => {
|
|
3196
|
+
if (isCodeRunStatusMessageWebSocketResponseEventDTO(response)) {
|
|
3197
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.CODE_RUN_STATUS, clientId, response.runId);
|
|
3198
|
+
}
|
|
3199
|
+
if (isSubmissionRunStatusMessageWebSocketResponseEventDTO(response)) {
|
|
3200
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.SUBMISSION_RUN_STATUS, clientId, response.submitId);
|
|
3201
|
+
}
|
|
3202
|
+
if (isSendDataWebSocketResponseEventDTO(response)) {
|
|
3203
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.SEND_DATA_, clientId, response.dataId);
|
|
3204
|
+
}
|
|
3205
|
+
if (isContestChangesWebSocketResponseEventDTO(response)) {
|
|
3206
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.CONTEST_CHANGES, clientId, response.content.contestKey);
|
|
3207
|
+
}
|
|
3208
|
+
if (isProblemCrawledWebSocketResponseEventDTO(response)) {
|
|
3209
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.PROBLEM_CRAWLED, clientId, response.content.problemKey);
|
|
3210
|
+
}
|
|
3211
|
+
if (isSubmissionsCrawlWebSocketResponseEventDTO(response)) {
|
|
3212
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.SUBMISSIONS_CRAWL, clientId, join([response.content.contestKey, response.content.problemKeys]));
|
|
3213
|
+
}
|
|
3214
|
+
if (isClientTrackWebSocketResponseEventDTO(response)) {
|
|
3215
|
+
// the command is sent to the session channel, `key` holds the targeted client
|
|
3216
|
+
return response.key === clientId ? getWebSocketResponseEventKey(exports.WebSocketResponseEvent.CLIENT_TRACK, clientId, '*') : null;
|
|
3217
|
+
}
|
|
3218
|
+
if (isUserNotificationWebSocketResponseEventDTO(response)) {
|
|
3219
|
+
return getWebSocketResponseEventKey(exports.WebSocketResponseEvent.USER_NOTIFICATION_, clientId, '*');
|
|
3220
|
+
}
|
|
3221
|
+
return null;
|
|
3222
|
+
};
|
|
3223
|
+
/**
|
|
3224
|
+
* TOPIC channel that the client has to attach to receive the events of a subscription,
|
|
3225
|
+
* or null when the events arrive by the private channels (session / user) the client is always attached to.
|
|
3226
|
+
* Ably rejects the attach if the token has no capability for the channel.
|
|
3227
|
+
*/
|
|
3228
|
+
const getChannelOfWebSocketSubscribeEvent = (event) => {
|
|
3229
|
+
if (isSubscribeSubmissionRunStatusWebSocketEventDTO(event)) {
|
|
3230
|
+
return CHANNEL_SUBMISSION(event.submitId);
|
|
3231
|
+
}
|
|
3232
|
+
if (isSubscribeProblemCrawledWebSocketEventDTO(event)) {
|
|
3233
|
+
return CHANNEL_PROBLEM(event.problemKey);
|
|
3234
|
+
}
|
|
3235
|
+
if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
|
|
3236
|
+
return CHANNEL_CONTEST(event.contestKey, exports.ContestChannelRole.SPECTATORS);
|
|
3237
|
+
}
|
|
3238
|
+
if (isSubscribeClientTrackDataWebSocketEventDTO(event)) {
|
|
3239
|
+
return CHANNEL_CLIENT_TRACK(event.trackedClientId);
|
|
3240
|
+
}
|
|
3241
|
+
return null;
|
|
3242
|
+
};
|
|
3243
|
+
/**
|
|
3244
|
+
* Contest whose role channels the client needs (the API grants them when the token is requested with this contest).
|
|
3245
|
+
*/
|
|
3246
|
+
const getContestKeyOfWebSocketSubscribeEvent = (event) => {
|
|
3247
|
+
if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
|
|
3248
|
+
return event.contestKey;
|
|
3249
|
+
}
|
|
3250
|
+
return null;
|
|
3251
|
+
};
|
|
3126
3252
|
|
|
3127
3253
|
function splitTime(timeRemaining) {
|
|
3128
3254
|
const remaining = [];
|
|
@@ -3350,11 +3476,20 @@ exports.ACCEPTED_PROGRAMMING_LANGUAGES = ACCEPTED_PROGRAMMING_LANGUAGES;
|
|
|
3350
3476
|
exports.ASPECT_RATIO = ASPECT_RATIO;
|
|
3351
3477
|
exports.AssignmentState = AssignmentState;
|
|
3352
3478
|
exports.AssignmentType = AssignmentType;
|
|
3479
|
+
exports.CHANNEL_CLIENT_TRACK = CHANNEL_CLIENT_TRACK;
|
|
3480
|
+
exports.CHANNEL_CLIENT_TRACK_ALL = CHANNEL_CLIENT_TRACK_ALL;
|
|
3481
|
+
exports.CHANNEL_CONTEST = CHANNEL_CONTEST;
|
|
3353
3482
|
exports.CHANNEL_PRESENCE_CLIENT = CHANNEL_PRESENCE_CLIENT;
|
|
3483
|
+
exports.CHANNEL_PROBLEM = CHANNEL_PROBLEM;
|
|
3484
|
+
exports.CHANNEL_PROBLEM_ALL = CHANNEL_PROBLEM_ALL;
|
|
3354
3485
|
exports.CHANNEL_PUBLISH_MESSAGES = CHANNEL_PUBLISH_MESSAGES;
|
|
3355
3486
|
exports.CHANNEL_PUBLISH_SUBSCRIPTIONS = CHANNEL_PUBLISH_SUBSCRIPTIONS;
|
|
3487
|
+
exports.CHANNEL_SESSION = CHANNEL_SESSION;
|
|
3488
|
+
exports.CHANNEL_SUBMISSION = CHANNEL_SUBMISSION;
|
|
3489
|
+
exports.CHANNEL_SUBMISSION_ALL = CHANNEL_SUBMISSION_ALL;
|
|
3356
3490
|
exports.CHANNEL_SUBSCRIBE_CLIENT = CHANNEL_SUBSCRIBE_CLIENT;
|
|
3357
3491
|
exports.CHANNEL_SUBSCRIBE_NOTIFICATIONS = CHANNEL_SUBSCRIBE_NOTIFICATIONS;
|
|
3492
|
+
exports.CHANNEL_USER = CHANNEL_USER;
|
|
3358
3493
|
exports.CODE_LANGUAGE = CODE_LANGUAGE;
|
|
3359
3494
|
exports.COMPANY_PLAN = COMPANY_PLAN;
|
|
3360
3495
|
exports.CONTEST_ROLE = CONTEST_ROLE;
|
|
@@ -3459,8 +3594,11 @@ exports.contentsResponse = contentsResponse;
|
|
|
3459
3594
|
exports.errorsResponse = errorsResponse;
|
|
3460
3595
|
exports.getAssignmentCommentKey = getAssignmentCommentKey;
|
|
3461
3596
|
exports.getAssignmentUserCommentKey = getAssignmentUserCommentKey;
|
|
3597
|
+
exports.getChannelOfWebSocketSubscribeEvent = getChannelOfWebSocketSubscribeEvent;
|
|
3462
3598
|
exports.getClientId = getClientId;
|
|
3599
|
+
exports.getContestChannelParams = getContestChannelParams;
|
|
3463
3600
|
exports.getContestCommentKey = getContestCommentKey;
|
|
3601
|
+
exports.getContestKeyOfWebSocketSubscribeEvent = getContestKeyOfWebSocketSubscribeEvent;
|
|
3464
3602
|
exports.getDataLog = getDataLog;
|
|
3465
3603
|
exports.getDataOfTestCase = getDataOfTestCase;
|
|
3466
3604
|
exports.getDays = getDays;
|
|
@@ -3482,6 +3620,7 @@ exports.getTotalExercisesOfSummaryWorksheetsInPages = getTotalExercisesOfSummary
|
|
|
3482
3620
|
exports.getUserKey = getUserKey;
|
|
3483
3621
|
exports.getVerdictFromTestCase = getVerdictFromTestCase;
|
|
3484
3622
|
exports.getWebSocketResponseEventKey = getWebSocketResponseEventKey;
|
|
3623
|
+
exports.getWebSocketResponseEventKeyOfResponse = getWebSocketResponseEventKeyOfResponse;
|
|
3485
3624
|
exports.getWorksheetsInPages = getWorksheetsInPages;
|
|
3486
3625
|
exports.getYears = getYears;
|
|
3487
3626
|
exports.humanFileSize = humanFileSize;
|
|
@@ -3520,6 +3659,7 @@ exports.isSendDataWebSocketResponseEventDTO = isSendDataWebSocketResponseEventDT
|
|
|
3520
3659
|
exports.isStringJson = isStringJson;
|
|
3521
3660
|
exports.isSubmissionRunStatusMessageWebSocketResponseEventDTO = isSubmissionRunStatusMessageWebSocketResponseEventDTO;
|
|
3522
3661
|
exports.isSubmissionsCrawlWebSocketResponseEventDTO = isSubmissionsCrawlWebSocketResponseEventDTO;
|
|
3662
|
+
exports.isSubscribeClientTrackDataWebSocketEventDTO = isSubscribeClientTrackDataWebSocketEventDTO;
|
|
3523
3663
|
exports.isSubscribeClientTrackWebSocketEventDTO = isSubscribeClientTrackWebSocketEventDTO;
|
|
3524
3664
|
exports.isSubscribeCodeRunStatusWebSocketEventDTO = isSubscribeCodeRunStatusWebSocketEventDTO;
|
|
3525
3665
|
exports.isSubscribeContestChangesWebSocketEventDTO = isSubscribeContestChangesWebSocketEventDTO;
|
|
@@ -3529,6 +3669,7 @@ exports.isSubscribeSubmissionRunStatusWebSocketEventDTO = isSubscribeSubmissionR
|
|
|
3529
3669
|
exports.isSubscribeSubmissionsCrawlWebSocketEventDTO = isSubscribeSubmissionsCrawlWebSocketEventDTO;
|
|
3530
3670
|
exports.isSubscribeUserNotificationWebSocketEventDTO = isSubscribeUserNotificationWebSocketEventDTO;
|
|
3531
3671
|
exports.isTeamMember = isTeamMember;
|
|
3672
|
+
exports.isUnsubscribeClientTrackDataWebSocketEventDTO = isUnsubscribeClientTrackDataWebSocketEventDTO;
|
|
3532
3673
|
exports.isUnsubscribeClientTrackWebSocketEventDTO = isUnsubscribeClientTrackWebSocketEventDTO;
|
|
3533
3674
|
exports.isUnsubscribeCodeRunStatusWebSocketEventDTO = isUnsubscribeCodeRunStatusWebSocketEventDTO;
|
|
3534
3675
|
exports.isUnsubscribeContestChangesWebSocketEventDTO = isUnsubscribeContestChangesWebSocketEventDTO;
|
|
@@ -3542,6 +3683,7 @@ exports.isUserMessageWebSocketResponseEventDTO = isUserMessageWebSocketResponseE
|
|
|
3542
3683
|
exports.isUserNotificationContestClarificationWebSocketResponseEventDTO = isUserNotificationContestClarificationWebSocketResponseEventDTO;
|
|
3543
3684
|
exports.isUserNotificationSubmissionWebSocketResponseEventDTO = isUserNotificationSubmissionWebSocketResponseEventDTO;
|
|
3544
3685
|
exports.isUserNotificationWebSocketResponseEventDTO = isUserNotificationWebSocketResponseEventDTO;
|
|
3686
|
+
exports.isWebSocketChannelsMessageDTO = isWebSocketChannelsMessageDTO;
|
|
3545
3687
|
exports.isWebSocketResponseEventDTO = isWebSocketResponseEventDTO;
|
|
3546
3688
|
exports.isWebsocketSubscription = isWebsocketSubscription;
|
|
3547
3689
|
exports.isWorksheetAssignment = isWorksheetAssignment;
|
package/dist/esm/index.js
CHANGED
|
@@ -598,6 +598,9 @@ var WebSocketSubscriptionEvent;
|
|
|
598
598
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK"] = "UNSUBSCRIBE_CLIENT_TRACK";
|
|
599
599
|
WebSocketSubscriptionEvent["SUBSCRIBE_USER_NOTIFICATION"] = "SUBSCRIBE_USER_NOTIFICATION";
|
|
600
600
|
WebSocketSubscriptionEvent["UNSUBSCRIBE_USER_NOTIFICATION"] = "UNSUBSCRIBE_USER_NOTIFICATION";
|
|
601
|
+
// an administrator watching the data (screenshots, location, device) sent by another client
|
|
602
|
+
WebSocketSubscriptionEvent["SUBSCRIBE_CLIENT_TRACK_DATA"] = "SUBSCRIBE_CLIENT_TRACK_DATA";
|
|
603
|
+
WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK_DATA"] = "UNSUBSCRIBE_CLIENT_TRACK_DATA";
|
|
601
604
|
})(WebSocketSubscriptionEvent || (WebSocketSubscriptionEvent = {}));
|
|
602
605
|
var WebSocketResponseEvent;
|
|
603
606
|
(function (WebSocketResponseEvent) {
|
|
@@ -621,6 +624,20 @@ var WebSocketResponseEvent;
|
|
|
621
624
|
WebSocketResponseEvent["USER_NOTIFICATION_SUBMISSION"] = "USER_NOTIFICATION_SUBMISSION";
|
|
622
625
|
WebSocketResponseEvent["USER_NOTIFICATION_CONTEST_CLARIFICATION"] = "USER_NOTIFICATION_CONTEST_CLARIFICATION";
|
|
623
626
|
})(WebSocketResponseEvent || (WebSocketResponseEvent = {}));
|
|
627
|
+
/**
|
|
628
|
+
* Roles of a contest, with the same names as the contest members in the DB.
|
|
629
|
+
* Each role has its own Ably channel: `contest:{contestKey}:{role}` (see `CHANNEL_CONTEST`).
|
|
630
|
+
* The inclusions follow `getContestAccessPermissions`:
|
|
631
|
+
* spectators ⊇ managers ⊇ administrators, spectators ⊇ participants, spectators ⊇ guests
|
|
632
|
+
*/
|
|
633
|
+
var ContestChannelRole;
|
|
634
|
+
(function (ContestChannelRole) {
|
|
635
|
+
ContestChannelRole["ADMINISTRATORS"] = "administrators";
|
|
636
|
+
ContestChannelRole["MANAGERS"] = "managers";
|
|
637
|
+
ContestChannelRole["PARTICIPANTS"] = "participants";
|
|
638
|
+
ContestChannelRole["GUESTS"] = "guests";
|
|
639
|
+
ContestChannelRole["SPECTATORS"] = "spectators";
|
|
640
|
+
})(ContestChannelRole || (ContestChannelRole = {}));
|
|
624
641
|
|
|
625
642
|
var DataViewMode;
|
|
626
643
|
(function (DataViewMode) {
|
|
@@ -2221,11 +2238,43 @@ const EMPTY_USER_PERMISSIONS = {
|
|
|
2221
2238
|
},
|
|
2222
2239
|
};
|
|
2223
2240
|
|
|
2241
|
+
// LEGACY channels (fan-out per client through the subscriptions registry in Redis)
|
|
2224
2242
|
const CHANNEL_PUBLISH_SUBSCRIPTIONS = 'pub:subscriptions';
|
|
2225
2243
|
const CHANNEL_SUBSCRIBE_NOTIFICATIONS = 'sub:notifications';
|
|
2226
2244
|
const CHANNEL_SUBSCRIBE_CLIENT = (clientId) => `sub:client:${clientId}`;
|
|
2227
2245
|
const CHANNEL_PUBLISH_MESSAGES = 'pub:messages';
|
|
2228
2246
|
const CHANNEL_PRESENCE_CLIENT = 'pre:client';
|
|
2247
|
+
// TOPIC channels
|
|
2248
|
+
// The backend publishes each event once on the channel of its topic and Ably does the fan-out.
|
|
2249
|
+
// Who can subscribe to each channel is decided by the API in the Ably token (capability), never by the client.
|
|
2250
|
+
// Dynamic segments are encoded so a key can never inject a `:` (the Ably segment separator used by the wildcards).
|
|
2251
|
+
const segment = (value) => encodeURIComponent(value);
|
|
2252
|
+
/** private: events of one session (code runs, requested data, client track commands) */
|
|
2253
|
+
const CHANNEL_SESSION = (sessionId) => `session:${segment(sessionId)}`;
|
|
2254
|
+
/** private: events of one user (own submissions while the contest is frozen, notifications) */
|
|
2255
|
+
const CHANNEL_USER = (userId) => `user:${segment(userId)}`;
|
|
2256
|
+
/** public: status of a submission when it is visible to everyone */
|
|
2257
|
+
const CHANNEL_SUBMISSION = (submitId) => `submission:${segment(submitId)}`;
|
|
2258
|
+
/** public: changes of a problem */
|
|
2259
|
+
const CHANNEL_PROBLEM = (problemKey) => `problem:${segment(problemKey)}`;
|
|
2260
|
+
/** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
|
|
2261
|
+
const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${role}`;
|
|
2262
|
+
/** system administrators only: data sent by a tracked client (screenshots, location, device) */
|
|
2263
|
+
const CHANNEL_CLIENT_TRACK = (trackedClientId) => `client-track:${segment(trackedClientId)}`;
|
|
2264
|
+
// capability resources (wildcards) of the public channels
|
|
2265
|
+
const CHANNEL_SUBMISSION_ALL = 'submission:*';
|
|
2266
|
+
const CHANNEL_PROBLEM_ALL = 'problem:*';
|
|
2267
|
+
const CHANNEL_CLIENT_TRACK_ALL = 'client-track:*';
|
|
2268
|
+
/**
|
|
2269
|
+
* Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
|
|
2270
|
+
*/
|
|
2271
|
+
const getContestChannelParams = (channel) => {
|
|
2272
|
+
const [namespace, contestKey, role, ...rest] = channel.split(':');
|
|
2273
|
+
if (namespace !== 'contest' || !contestKey || rest.length || !Object.values(ContestChannelRole).includes(role)) {
|
|
2274
|
+
return null;
|
|
2275
|
+
}
|
|
2276
|
+
return { contestKey: decodeURIComponent(contestKey), role: role };
|
|
2277
|
+
};
|
|
2229
2278
|
|
|
2230
2279
|
const NEW_PAGE_SHEET = () => ({
|
|
2231
2280
|
id: v4(),
|
|
@@ -3008,6 +3057,16 @@ const isUnsubscribeUserNotificationWebSocketEventDTO = (event) => {
|
|
|
3008
3057
|
return isWebsocketSubscription(event)
|
|
3009
3058
|
&& event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
|
|
3010
3059
|
};
|
|
3060
|
+
const isSubscribeClientTrackDataWebSocketEventDTO = (event) => {
|
|
3061
|
+
return isWebsocketSubscription(event)
|
|
3062
|
+
&& event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK_DATA
|
|
3063
|
+
&& typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
|
|
3064
|
+
};
|
|
3065
|
+
const isUnsubscribeClientTrackDataWebSocketEventDTO = (event) => {
|
|
3066
|
+
return isWebsocketSubscription(event)
|
|
3067
|
+
&& event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK_DATA
|
|
3068
|
+
&& typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
|
|
3069
|
+
};
|
|
3011
3070
|
// is WebSocketResponseEventDTO, CHANNEL_SUBSCRIBE_CLIENT
|
|
3012
3071
|
const isWebSocketResponseEventDTO = (event) => {
|
|
3013
3072
|
return Object.values(WebSocketResponseEvent).includes(event?.event)
|
|
@@ -3121,6 +3180,73 @@ const isUserNotificationContestClarificationWebSocketResponseEventDTO = (event)
|
|
|
3121
3180
|
const getWebSocketResponseEventKey = (event, clientId, id) => {
|
|
3122
3181
|
return `${event}-${clientId}-${id}`;
|
|
3123
3182
|
};
|
|
3183
|
+
const isWebSocketChannelsMessageDTO = (message) => {
|
|
3184
|
+
return Array.isArray(message?.channels)
|
|
3185
|
+
&& message.channels.every((channel) => typeof channel === 'string' && !!channel)
|
|
3186
|
+
&& Object.values(WebSocketResponseEvent).includes(message?.event?.event);
|
|
3187
|
+
};
|
|
3188
|
+
/**
|
|
3189
|
+
* Key used by the client to dispatch a response received on a TOPIC channel to its subscribers.
|
|
3190
|
+
* It is the same key that `getKeyWebSocketEventDTO` (base-ui) computes for the subscription.
|
|
3191
|
+
* Returns null when the response is not addressed to this client.
|
|
3192
|
+
*/
|
|
3193
|
+
const getWebSocketResponseEventKeyOfResponse = (response, clientId) => {
|
|
3194
|
+
if (isCodeRunStatusMessageWebSocketResponseEventDTO(response)) {
|
|
3195
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.CODE_RUN_STATUS, clientId, response.runId);
|
|
3196
|
+
}
|
|
3197
|
+
if (isSubmissionRunStatusMessageWebSocketResponseEventDTO(response)) {
|
|
3198
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.SUBMISSION_RUN_STATUS, clientId, response.submitId);
|
|
3199
|
+
}
|
|
3200
|
+
if (isSendDataWebSocketResponseEventDTO(response)) {
|
|
3201
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.SEND_DATA_, clientId, response.dataId);
|
|
3202
|
+
}
|
|
3203
|
+
if (isContestChangesWebSocketResponseEventDTO(response)) {
|
|
3204
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.CONTEST_CHANGES, clientId, response.content.contestKey);
|
|
3205
|
+
}
|
|
3206
|
+
if (isProblemCrawledWebSocketResponseEventDTO(response)) {
|
|
3207
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.PROBLEM_CRAWLED, clientId, response.content.problemKey);
|
|
3208
|
+
}
|
|
3209
|
+
if (isSubmissionsCrawlWebSocketResponseEventDTO(response)) {
|
|
3210
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.SUBMISSIONS_CRAWL, clientId, join([response.content.contestKey, response.content.problemKeys]));
|
|
3211
|
+
}
|
|
3212
|
+
if (isClientTrackWebSocketResponseEventDTO(response)) {
|
|
3213
|
+
// the command is sent to the session channel, `key` holds the targeted client
|
|
3214
|
+
return response.key === clientId ? getWebSocketResponseEventKey(WebSocketResponseEvent.CLIENT_TRACK, clientId, '*') : null;
|
|
3215
|
+
}
|
|
3216
|
+
if (isUserNotificationWebSocketResponseEventDTO(response)) {
|
|
3217
|
+
return getWebSocketResponseEventKey(WebSocketResponseEvent.USER_NOTIFICATION_, clientId, '*');
|
|
3218
|
+
}
|
|
3219
|
+
return null;
|
|
3220
|
+
};
|
|
3221
|
+
/**
|
|
3222
|
+
* TOPIC channel that the client has to attach to receive the events of a subscription,
|
|
3223
|
+
* or null when the events arrive by the private channels (session / user) the client is always attached to.
|
|
3224
|
+
* Ably rejects the attach if the token has no capability for the channel.
|
|
3225
|
+
*/
|
|
3226
|
+
const getChannelOfWebSocketSubscribeEvent = (event) => {
|
|
3227
|
+
if (isSubscribeSubmissionRunStatusWebSocketEventDTO(event)) {
|
|
3228
|
+
return CHANNEL_SUBMISSION(event.submitId);
|
|
3229
|
+
}
|
|
3230
|
+
if (isSubscribeProblemCrawledWebSocketEventDTO(event)) {
|
|
3231
|
+
return CHANNEL_PROBLEM(event.problemKey);
|
|
3232
|
+
}
|
|
3233
|
+
if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
|
|
3234
|
+
return CHANNEL_CONTEST(event.contestKey, ContestChannelRole.SPECTATORS);
|
|
3235
|
+
}
|
|
3236
|
+
if (isSubscribeClientTrackDataWebSocketEventDTO(event)) {
|
|
3237
|
+
return CHANNEL_CLIENT_TRACK(event.trackedClientId);
|
|
3238
|
+
}
|
|
3239
|
+
return null;
|
|
3240
|
+
};
|
|
3241
|
+
/**
|
|
3242
|
+
* Contest whose role channels the client needs (the API grants them when the token is requested with this contest).
|
|
3243
|
+
*/
|
|
3244
|
+
const getContestKeyOfWebSocketSubscribeEvent = (event) => {
|
|
3245
|
+
if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
|
|
3246
|
+
return event.contestKey;
|
|
3247
|
+
}
|
|
3248
|
+
return null;
|
|
3249
|
+
};
|
|
3124
3250
|
|
|
3125
3251
|
function splitTime(timeRemaining) {
|
|
3126
3252
|
const remaining = [];
|
|
@@ -3344,4 +3470,4 @@ const isQuizTextSheet = (value) => {
|
|
|
3344
3470
|
&& ['text', 'number', 'textarea'].includes(value?.inputType);
|
|
3345
3471
|
};
|
|
3346
3472
|
|
|
3347
|
-
export { ACCEPTED_PROGRAMMING_LANGUAGES, ASPECT_RATIO, AspectRatio, AssignmentClass, AssignmentState, AssignmentType, CHANNEL_PRESENCE_CLIENT, CHANNEL_PUBLISH_MESSAGES, CHANNEL_PUBLISH_SUBSCRIPTIONS, CHANNEL_SUBSCRIBE_CLIENT, CHANNEL_SUBSCRIBE_NOTIFICATIONS, CODE_LANGUAGE, COMPANY_PLAN, CONTEST_ROLE, CONTEST_STATUS, COOKIE_JUKI_SESSION_ID, COURSE_ROLE, CodeLanguage, CollectionKey, CompanyLogoType, CompanyPlan, ContestEventAction, ContestProblemBlockedByType, ContestProblemPrerequisiteType, ContestStatus, ContestTimeStatus, CourseRole, CourseStatus, CourseType, DAY_NAMES, DEFAULT_JUKI_PROFILE_IMAGE, DataViewMode, EMPTY_DOCUMENT_MEMBERS, EMPTY_ENTITY_MEMBERS, EMPTY_USER_PERMISSIONS, ENTITY_ACCESS, ENTITY_STATE, ERROR, EmailSubscription, EmailValidationState, EntityAccess, EntityCollection, EntityMembersRank, EntityState, EntityStatus, ErrorCode, FILE_ROLE, FILE_TYPE, FileMemberRole, FileType, FilesJukiPub, GroupType, HEADER_JUKI_FORWARDED_HOST, HEADER_JUKI_INTERNAL_API_KEY, HEADER_JUKI_METADATA, HEADER_JUKI_SECRET_TOKEN, HEADER_JUKI_VISITOR_SESSION_ID, HOURS, HTTPMethod, JUDGE, JUKI_APP_COMPANY_KEY, JUKI_APP_EMAIL_TEMPLATE, JkError, Judge, LANGUAGE, LOWERCASE_LETTERS, Language, LogLevel, LogOperation, MAX_DATE, MEMBER_ROLE, MILLISECONDS, MINUTES, MIN_DATE, MONTH_NAMES, MemberRole, MemberType, MenuViewMode, NEW_PAGE_SHEET, NUMBERS, NotificationType, ONE_DAY, ONE_HOUR, ONE_MINUTE, ONE_SECOND, ONE_WEEK, PAGE, PAGE_SIZE, PAGE_SIZES, PALLETE, PROBLEM_INPUT, PROBLEM_MODE, PROBLEM_MODES, PROBLEM_OUTPUT, PROBLEM_ROLE, PROBLEM_TYPE, PROBLEM_TYPES, PROBLEM_VERDICT, PROBLEM_VERDICTS, ProblemInput, ProblemOutput, ProblemScoringMode, ProblemType, ProblemVerdict, ProfileSetting, QuizScoringMode, RUNNER_ACCEPTED_PROBLEM_MODES, RUNNER_ACCEPTED_PROBLEM_TYPES, RUNNER_ACCEPTED_PROGRAMMING_LANGUAGES, RUNNER_TYPE, Role, RunnerType, SECONDS, SEC_120, SEC_30, SEC_60, SEC_90, SEPARATOR_TOKEN, SUBMISSION_RUN_STATUS, SUPPORT_EMAIL, SYSTEM_ROLE, ScopeData, Status, SubmissionRunStatus, SystemRole, TEAM_ROLE, THEME, TeamRole, TeamStatus, Theme, TypeTestCase, UPPERCASE_LETTERS, USER_ROLE, USER_STATUS, UserRole, UserStatus, UserTeamStatus, WebSocketMessageEvent, WebSocketResponseEvent, WebSocketSubscriptionEvent, WorkingIn, WorksheetType, YEARS, _KEY, _SUB_SUB_TAB, _SUB_TAB, _TAB, _TYPE, areArraysDifferent, chunkString, cleanRequest, clearAsyncInterval, consoleError, consoleInfo, consoleWarn, contentResponse, contentsResponse, errorsResponse, getAssignmentCommentKey, getAssignmentUserCommentKey, getClientId, getContestCommentKey, getDataLog, getDataOfTestCase, getDays, getDefaultMeta, getDocumentAccess, getHours, getMilliseconds, getMinutes, getMonths, getParamsOfClientId, getParamsOfUserKey, getPlainText, getProblemCommentKey, getProblemJudgeKey, getRandomString, getSeconds, getSummaryWorksheetsInPages, getTotalExercisesOfSummaryWorksheetsInPages, getUserKey, getVerdictFromTestCase, getWebSocketResponseEventKey, getWorksheetsInPages, getYears, humanFileSize, indexToLetters, isBasicWorksheet, isChatCompletionsWebSocketEventDTO, isClientTrackDeviceWebSocketEventDTO, isClientTrackLocationWebSocketEventDTO, isClientTrackScreenshotWebSocketEventDTO, isClientTrackWebSocketResponseEventDTO, isCodeEditorSheet, isCodeRunStatusMessageWebSocketResponseEventDTO, isContestAssignment, isContestChangesWebSocketResponseEventDTO, isCourseAssignment, isEndlessContest, isFutureContest, isGlobalContest, isJkmdSheet, isObjectJson, isPastContest, isPingWebSocketEventDTO, isPongWebSocketResponseEventDTO, isProblemCrawledWebSocketResponseEventDTO, isQuizOptionsSheet, isQuizProblemSheet, isQuizTextSheet, isSenDataChatCompletionsWebSocketResponseEventDTO, isSendDataClientTrackWebSocketResponseEventDTO, isSendDataEc2InstancesListWebSocketResponseEventDTO, isSendDataEcsTaskDefinitionListWebSocketResponseEventDTO, isSendDataEcsTasksListWebSocketResponseEventDTO, isSendDataRunCommandWebSocketResponseEventDTO, isSendDataSsmSessionsListWebSocketResponseEventDTO, isSendDataWebSocketResponseEventDTO, isStringJson, isSubmissionRunStatusMessageWebSocketResponseEventDTO, isSubmissionsCrawlWebSocketResponseEventDTO, isSubscribeClientTrackWebSocketEventDTO, isSubscribeCodeRunStatusWebSocketEventDTO, isSubscribeContestChangesWebSocketEventDTO, isSubscribeGetDataWebSocketEventDTO, isSubscribeProblemCrawledWebSocketEventDTO, isSubscribeSubmissionRunStatusWebSocketEventDTO, isSubscribeSubmissionsCrawlWebSocketEventDTO, isSubscribeUserNotificationWebSocketEventDTO, isTeamMember, isUnsubscribeClientTrackWebSocketEventDTO, isUnsubscribeCodeRunStatusWebSocketEventDTO, isUnsubscribeContestChangesWebSocketEventDTO, isUnsubscribeGetDataWebSocketEventDTO, isUnsubscribeProblemCrawledWebSocketEventDTO, isUnsubscribeSubmissionRunStatusWebSocketEventDTO, isUnsubscribeSubmissionsCrawlWebSocketEventDTO, isUnsubscribeUserNotificationWebSocketEventDTO, isUserMember, isUserMessageWebSocketResponseEventDTO, isUserNotificationContestClarificationWebSocketResponseEventDTO, isUserNotificationSubmissionWebSocketResponseEventDTO, isUserNotificationWebSocketResponseEventDTO, isWebSocketResponseEventDTO, isWebsocketSubscription, isWorksheetAssignment, join, lettersToIndex, memorySizeOf, mergeVerdicts, mex, normalizeToLocalStartOfDay, normalizeToLocalStartOfHour, normalizeToLocalStartOfMinutes, normalizeToLocalStartOfSeconds, objectUpdate, objectsUpdate, range, removeExtension, safeJsonParse, setAsyncInterval, split, splitTime, stringToArrayBuffer, toEntityMembersDTO, toJkError };
|
|
3473
|
+
export { ACCEPTED_PROGRAMMING_LANGUAGES, ASPECT_RATIO, AspectRatio, AssignmentClass, AssignmentState, AssignmentType, CHANNEL_CLIENT_TRACK, CHANNEL_CLIENT_TRACK_ALL, CHANNEL_CONTEST, CHANNEL_PRESENCE_CLIENT, CHANNEL_PROBLEM, CHANNEL_PROBLEM_ALL, CHANNEL_PUBLISH_MESSAGES, CHANNEL_PUBLISH_SUBSCRIPTIONS, CHANNEL_SESSION, CHANNEL_SUBMISSION, CHANNEL_SUBMISSION_ALL, CHANNEL_SUBSCRIBE_CLIENT, CHANNEL_SUBSCRIBE_NOTIFICATIONS, CHANNEL_USER, CODE_LANGUAGE, COMPANY_PLAN, CONTEST_ROLE, CONTEST_STATUS, COOKIE_JUKI_SESSION_ID, COURSE_ROLE, CodeLanguage, CollectionKey, CompanyLogoType, CompanyPlan, ContestChannelRole, ContestEventAction, ContestProblemBlockedByType, ContestProblemPrerequisiteType, ContestStatus, ContestTimeStatus, CourseRole, CourseStatus, CourseType, DAY_NAMES, DEFAULT_JUKI_PROFILE_IMAGE, DataViewMode, EMPTY_DOCUMENT_MEMBERS, EMPTY_ENTITY_MEMBERS, EMPTY_USER_PERMISSIONS, ENTITY_ACCESS, ENTITY_STATE, ERROR, EmailSubscription, EmailValidationState, EntityAccess, EntityCollection, EntityMembersRank, EntityState, EntityStatus, ErrorCode, FILE_ROLE, FILE_TYPE, FileMemberRole, FileType, FilesJukiPub, GroupType, HEADER_JUKI_FORWARDED_HOST, HEADER_JUKI_INTERNAL_API_KEY, HEADER_JUKI_METADATA, HEADER_JUKI_SECRET_TOKEN, HEADER_JUKI_VISITOR_SESSION_ID, HOURS, HTTPMethod, JUDGE, JUKI_APP_COMPANY_KEY, JUKI_APP_EMAIL_TEMPLATE, JkError, Judge, LANGUAGE, LOWERCASE_LETTERS, Language, LogLevel, LogOperation, MAX_DATE, MEMBER_ROLE, MILLISECONDS, MINUTES, MIN_DATE, MONTH_NAMES, MemberRole, MemberType, MenuViewMode, NEW_PAGE_SHEET, NUMBERS, NotificationType, ONE_DAY, ONE_HOUR, ONE_MINUTE, ONE_SECOND, ONE_WEEK, PAGE, PAGE_SIZE, PAGE_SIZES, PALLETE, PROBLEM_INPUT, PROBLEM_MODE, PROBLEM_MODES, PROBLEM_OUTPUT, PROBLEM_ROLE, PROBLEM_TYPE, PROBLEM_TYPES, PROBLEM_VERDICT, PROBLEM_VERDICTS, ProblemInput, ProblemOutput, ProblemScoringMode, ProblemType, ProblemVerdict, ProfileSetting, QuizScoringMode, RUNNER_ACCEPTED_PROBLEM_MODES, RUNNER_ACCEPTED_PROBLEM_TYPES, RUNNER_ACCEPTED_PROGRAMMING_LANGUAGES, RUNNER_TYPE, Role, RunnerType, SECONDS, SEC_120, SEC_30, SEC_60, SEC_90, SEPARATOR_TOKEN, SUBMISSION_RUN_STATUS, SUPPORT_EMAIL, SYSTEM_ROLE, ScopeData, Status, SubmissionRunStatus, SystemRole, TEAM_ROLE, THEME, TeamRole, TeamStatus, Theme, TypeTestCase, UPPERCASE_LETTERS, USER_ROLE, USER_STATUS, UserRole, UserStatus, UserTeamStatus, WebSocketMessageEvent, WebSocketResponseEvent, WebSocketSubscriptionEvent, WorkingIn, WorksheetType, YEARS, _KEY, _SUB_SUB_TAB, _SUB_TAB, _TAB, _TYPE, areArraysDifferent, chunkString, cleanRequest, clearAsyncInterval, consoleError, consoleInfo, consoleWarn, contentResponse, contentsResponse, errorsResponse, getAssignmentCommentKey, getAssignmentUserCommentKey, getChannelOfWebSocketSubscribeEvent, getClientId, getContestChannelParams, getContestCommentKey, getContestKeyOfWebSocketSubscribeEvent, getDataLog, getDataOfTestCase, getDays, getDefaultMeta, getDocumentAccess, getHours, getMilliseconds, getMinutes, getMonths, getParamsOfClientId, getParamsOfUserKey, getPlainText, getProblemCommentKey, getProblemJudgeKey, getRandomString, getSeconds, getSummaryWorksheetsInPages, getTotalExercisesOfSummaryWorksheetsInPages, getUserKey, getVerdictFromTestCase, getWebSocketResponseEventKey, getWebSocketResponseEventKeyOfResponse, getWorksheetsInPages, getYears, humanFileSize, indexToLetters, isBasicWorksheet, isChatCompletionsWebSocketEventDTO, isClientTrackDeviceWebSocketEventDTO, isClientTrackLocationWebSocketEventDTO, isClientTrackScreenshotWebSocketEventDTO, isClientTrackWebSocketResponseEventDTO, isCodeEditorSheet, isCodeRunStatusMessageWebSocketResponseEventDTO, isContestAssignment, isContestChangesWebSocketResponseEventDTO, isCourseAssignment, isEndlessContest, isFutureContest, isGlobalContest, isJkmdSheet, isObjectJson, isPastContest, isPingWebSocketEventDTO, isPongWebSocketResponseEventDTO, isProblemCrawledWebSocketResponseEventDTO, isQuizOptionsSheet, isQuizProblemSheet, isQuizTextSheet, isSenDataChatCompletionsWebSocketResponseEventDTO, isSendDataClientTrackWebSocketResponseEventDTO, isSendDataEc2InstancesListWebSocketResponseEventDTO, isSendDataEcsTaskDefinitionListWebSocketResponseEventDTO, isSendDataEcsTasksListWebSocketResponseEventDTO, isSendDataRunCommandWebSocketResponseEventDTO, isSendDataSsmSessionsListWebSocketResponseEventDTO, isSendDataWebSocketResponseEventDTO, isStringJson, isSubmissionRunStatusMessageWebSocketResponseEventDTO, isSubmissionsCrawlWebSocketResponseEventDTO, isSubscribeClientTrackDataWebSocketEventDTO, isSubscribeClientTrackWebSocketEventDTO, isSubscribeCodeRunStatusWebSocketEventDTO, isSubscribeContestChangesWebSocketEventDTO, isSubscribeGetDataWebSocketEventDTO, isSubscribeProblemCrawledWebSocketEventDTO, isSubscribeSubmissionRunStatusWebSocketEventDTO, isSubscribeSubmissionsCrawlWebSocketEventDTO, isSubscribeUserNotificationWebSocketEventDTO, isTeamMember, isUnsubscribeClientTrackDataWebSocketEventDTO, isUnsubscribeClientTrackWebSocketEventDTO, isUnsubscribeCodeRunStatusWebSocketEventDTO, isUnsubscribeContestChangesWebSocketEventDTO, isUnsubscribeGetDataWebSocketEventDTO, isUnsubscribeProblemCrawledWebSocketEventDTO, isUnsubscribeSubmissionRunStatusWebSocketEventDTO, isUnsubscribeSubmissionsCrawlWebSocketEventDTO, isUnsubscribeUserNotificationWebSocketEventDTO, isUserMember, isUserMessageWebSocketResponseEventDTO, isUserNotificationContestClarificationWebSocketResponseEventDTO, isUserNotificationSubmissionWebSocketResponseEventDTO, isUserNotificationWebSocketResponseEventDTO, isWebSocketChannelsMessageDTO, isWebSocketResponseEventDTO, isWebsocketSubscription, isWorksheetAssignment, join, lettersToIndex, memorySizeOf, mergeVerdicts, mex, normalizeToLocalStartOfDay, normalizeToLocalStartOfHour, normalizeToLocalStartOfMinutes, normalizeToLocalStartOfSeconds, objectUpdate, objectsUpdate, range, removeExtension, safeJsonParse, setAsyncInterval, split, splitTime, stringToArrayBuffer, toEntityMembersDTO, toJkError };
|
|
@@ -1,6 +1,28 @@
|
|
|
1
|
-
import { ClientId } from '../types';
|
|
1
|
+
import { ClientId, ContestChannelRole } from '../types';
|
|
2
2
|
export declare const CHANNEL_PUBLISH_SUBSCRIPTIONS = "pub:subscriptions";
|
|
3
3
|
export declare const CHANNEL_SUBSCRIBE_NOTIFICATIONS = "sub:notifications";
|
|
4
4
|
export declare const CHANNEL_SUBSCRIBE_CLIENT: (clientId: ClientId) => string;
|
|
5
5
|
export declare const CHANNEL_PUBLISH_MESSAGES = "pub:messages";
|
|
6
6
|
export declare const CHANNEL_PRESENCE_CLIENT = "pre:client";
|
|
7
|
+
/** private: events of one session (code runs, requested data, client track commands) */
|
|
8
|
+
export declare const CHANNEL_SESSION: (sessionId: string) => string;
|
|
9
|
+
/** private: events of one user (own submissions while the contest is frozen, notifications) */
|
|
10
|
+
export declare const CHANNEL_USER: (userId: string) => string;
|
|
11
|
+
/** public: status of a submission when it is visible to everyone */
|
|
12
|
+
export declare const CHANNEL_SUBMISSION: (submitId: string) => string;
|
|
13
|
+
/** public: changes of a problem */
|
|
14
|
+
export declare const CHANNEL_PROBLEM: (problemKey: string) => string;
|
|
15
|
+
/** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
|
|
16
|
+
export declare const CHANNEL_CONTEST: (contestKey: string, role: ContestChannelRole) => string;
|
|
17
|
+
/** system administrators only: data sent by a tracked client (screenshots, location, device) */
|
|
18
|
+
export declare const CHANNEL_CLIENT_TRACK: (trackedClientId: ClientId) => string;
|
|
19
|
+
export declare const CHANNEL_SUBMISSION_ALL = "submission:*";
|
|
20
|
+
export declare const CHANNEL_PROBLEM_ALL = "problem:*";
|
|
21
|
+
export declare const CHANNEL_CLIENT_TRACK_ALL = "client-track:*";
|
|
22
|
+
/**
|
|
23
|
+
* Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
|
|
24
|
+
*/
|
|
25
|
+
export declare const getContestChannelParams: (channel: string) => {
|
|
26
|
+
contestKey: string;
|
|
27
|
+
role: ContestChannelRole;
|
|
28
|
+
} | null;
|
|
@@ -94,8 +94,16 @@ export interface UnsubscribeUserNotificationWebSocketEventDTO extends WebsocketS
|
|
|
94
94
|
event: WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
|
|
95
95
|
userKey: string;
|
|
96
96
|
}
|
|
97
|
-
export
|
|
98
|
-
|
|
97
|
+
export interface SubscribeClientTrackDataWebSocketEventDTO extends WebsocketSubscription {
|
|
98
|
+
event: WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK_DATA;
|
|
99
|
+
trackedClientId: ClientId;
|
|
100
|
+
}
|
|
101
|
+
export interface UnsubscribeClientTrackDataWebSocketEventDTO extends WebsocketSubscription {
|
|
102
|
+
event: WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK_DATA;
|
|
103
|
+
trackedClientId: ClientId;
|
|
104
|
+
}
|
|
105
|
+
export type WebSocketSubscribeEventDTO = SubscribeCodeRunStatusWebSocketEventDTO | SubscribeSubmissionRunStatusWebSocketEventDTO | SubscribeGetDataWebSocketEventDTO | SubscribeProblemCrawledWebSocketEventDTO | SubscribeSubmissionsCrawlWebSocketEventDTO | SubscribeContestChangesWebSocketEventDTO | SubscribeClientTrackWebSocketEventDTO | SubscribeUserNotificationWebsocketEventDTO | SubscribeClientTrackDataWebSocketEventDTO;
|
|
106
|
+
export type WebSocketUnsubscribeEventDTO = UnsubscribeCodeRunStatusWebSocketEventDTO | UnsubscribeSubmissionRunStatusWebSocketEventDTO | UnsubscribeGetDataWebSocketEventDTO | UnsubscribeProblemCrawledWebSocketEventDTO | UnsubscribeSubmissionsCrawlWebSocketEventDTO | UnsubscribeContestChangesWebSocketEventDTO | UnsubscribeClientTrackWebSocketEventDTO | UnsubscribeUserNotificationWebSocketEventDTO | UnsubscribeClientTrackDataWebSocketEventDTO;
|
|
99
107
|
export interface WebSocketResponse {
|
|
100
108
|
event: WebSocketResponseEvent;
|
|
101
109
|
key: WebSocketResponseEventKey;
|
|
@@ -253,4 +261,12 @@ export interface UserNotificationContestClarificationWebSocketResponseEventDTO e
|
|
|
253
261
|
};
|
|
254
262
|
}
|
|
255
263
|
export type WebSocketResponseEventDTO = PongWebSocketResponseEventDTO | CodeRunStatusWebSocketResponseEventDTO | SubmissionRunStatusWebSocketResponseEventDTO | UserMessageWebSocketResponseEventDTO | SendDataEcsTaskDefinitionListWebSocketResponseEventDTO | SendDataEcsTasksListWebSocketResponseEventDTO | SendDataEc2InstancesListWebSocketResponseEventDTO | SendDataSsmSessionsListWebSocketResponseEventDTO | ProblemCrawledWebSocketResponseEventDTO | SendDataChatCompletionsWebSocketResponseEventDTO | SubmissionsCrawlWebSocketResponseEventDTO | ContestChangesWebSocketResponseEventDTO | SendDataRunCommandWebSocketResponseEventDTO | SendDataClientTrackWebSocketResponseEventDTO | ClientTrackWebSocketResponseEventDTO | UserNotificationSubmissionWebSocketResponseEventDTO | UserNotificationContestClarificationWebSocketResponseEventDTO;
|
|
264
|
+
/**
|
|
265
|
+
* Message sent by the backend producers to the websocket SQS queue:
|
|
266
|
+
* the producer (trusted, with access to the DB) decides the Ably channels where the event is published.
|
|
267
|
+
*/
|
|
268
|
+
export interface WebSocketChannelsMessageDTO {
|
|
269
|
+
channels: string[];
|
|
270
|
+
event: WebSocketResponseEventDTO;
|
|
271
|
+
}
|
|
256
272
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChatCompletionsWebSocketEventDTO, ClientTrackDeviceWebSocketEventDTO, ClientTrackLocationWebSocketEventDTO, ClientTrackScreenshotWebSocketEventDTO, ClientTrackWebSocketResponseEventDTO, CodeRunStatusWebSocketResponseEventDTO, ContestChangesWebSocketResponseEventDTO, PingWebSocketEventDTO, PongWebSocketResponseEventDTO, ProblemCrawledWebSocketResponseEventDTO, SendDataChatCompletionsWebSocketResponseEventDTO, SendDataClientTrackWebSocketResponseEventDTO, SendDataEc2InstancesListWebSocketResponseEventDTO, SendDataEcsTaskDefinitionListWebSocketResponseEventDTO, SendDataEcsTasksListWebSocketResponseEventDTO, SendDataRunCommandWebSocketResponseEventDTO, SendDataSsmSessionsListWebSocketResponseEventDTO, SendDataWebSocketResponseEventDTO, SubmissionRunStatusWebSocketResponseEventDTO, SubmissionsCrawlWebSocketResponseEventDTO, SubscribeClientTrackWebSocketEventDTO, SubscribeCodeRunStatusWebSocketEventDTO, SubscribeContestChangesWebSocketEventDTO, SubscribeGetDataWebSocketEventDTO, SubscribeProblemCrawledWebSocketEventDTO, SubscribeSubmissionRunStatusWebSocketEventDTO, SubscribeSubmissionsCrawlWebSocketEventDTO, SubscribeUserNotificationWebsocketEventDTO, UnsubscribeClientTrackWebSocketEventDTO, UnsubscribeCodeRunStatusWebSocketEventDTO, UnsubscribeContestChangesWebSocketEventDTO, UnsubscribeGetDataWebSocketEventDTO, UnsubscribeProblemCrawledWebSocketEventDTO, UnsubscribeSubmissionRunStatusWebSocketEventDTO, UnsubscribeSubmissionsCrawlWebSocketEventDTO, UnsubscribeUserNotificationWebSocketEventDTO, UserMessageWebSocketResponseEventDTO, UserNotificationContestClarificationWebSocketResponseEventDTO, UserNotificationSubmissionWebSocketResponseEventDTO, UserNotificationWebSocketResponseEventDTO, WebSocketMessageEventDTO, WebSocketResponseEventDTO, WebSocketSubscribeEventDTO, WebSocketUnsubscribeEventDTO } from '../dto';
|
|
1
|
+
import { ChatCompletionsWebSocketEventDTO, ClientTrackDeviceWebSocketEventDTO, ClientTrackLocationWebSocketEventDTO, ClientTrackScreenshotWebSocketEventDTO, ClientTrackWebSocketResponseEventDTO, CodeRunStatusWebSocketResponseEventDTO, ContestChangesWebSocketResponseEventDTO, PingWebSocketEventDTO, PongWebSocketResponseEventDTO, ProblemCrawledWebSocketResponseEventDTO, SendDataChatCompletionsWebSocketResponseEventDTO, SendDataClientTrackWebSocketResponseEventDTO, SendDataEc2InstancesListWebSocketResponseEventDTO, SendDataEcsTaskDefinitionListWebSocketResponseEventDTO, SendDataEcsTasksListWebSocketResponseEventDTO, SendDataRunCommandWebSocketResponseEventDTO, SendDataSsmSessionsListWebSocketResponseEventDTO, SendDataWebSocketResponseEventDTO, SubmissionRunStatusWebSocketResponseEventDTO, SubmissionsCrawlWebSocketResponseEventDTO, SubscribeClientTrackDataWebSocketEventDTO, SubscribeClientTrackWebSocketEventDTO, SubscribeCodeRunStatusWebSocketEventDTO, SubscribeContestChangesWebSocketEventDTO, SubscribeGetDataWebSocketEventDTO, SubscribeProblemCrawledWebSocketEventDTO, SubscribeSubmissionRunStatusWebSocketEventDTO, SubscribeSubmissionsCrawlWebSocketEventDTO, SubscribeUserNotificationWebsocketEventDTO, UnsubscribeClientTrackDataWebSocketEventDTO, UnsubscribeClientTrackWebSocketEventDTO, UnsubscribeCodeRunStatusWebSocketEventDTO, UnsubscribeContestChangesWebSocketEventDTO, UnsubscribeGetDataWebSocketEventDTO, UnsubscribeProblemCrawledWebSocketEventDTO, UnsubscribeSubmissionRunStatusWebSocketEventDTO, UnsubscribeSubmissionsCrawlWebSocketEventDTO, UnsubscribeUserNotificationWebSocketEventDTO, UserMessageWebSocketResponseEventDTO, UserNotificationContestClarificationWebSocketResponseEventDTO, UserNotificationSubmissionWebSocketResponseEventDTO, UserNotificationWebSocketResponseEventDTO, WebSocketChannelsMessageDTO, WebSocketMessageEventDTO, WebSocketResponseEventDTO, WebSocketSubscribeEventDTO, WebSocketUnsubscribeEventDTO } from '../dto';
|
|
2
2
|
import { ClientId, WebSocketResponseEvent, WebSocketResponseEventKey } from '../types';
|
|
3
3
|
export declare const isWebsocketSubscription: (event: any) => event is WebSocketSubscribeEventDTO | WebSocketUnsubscribeEventDTO | WebSocketMessageEventDTO;
|
|
4
4
|
export declare const isPingWebSocketEventDTO: (event: any) => event is PingWebSocketEventDTO;
|
|
@@ -22,6 +22,8 @@ export declare const isSubscribeClientTrackWebSocketEventDTO: (event: any) => ev
|
|
|
22
22
|
export declare const isUnsubscribeClientTrackWebSocketEventDTO: (event: any) => event is UnsubscribeClientTrackWebSocketEventDTO;
|
|
23
23
|
export declare const isSubscribeUserNotificationWebSocketEventDTO: (event: any) => event is SubscribeUserNotificationWebsocketEventDTO;
|
|
24
24
|
export declare const isUnsubscribeUserNotificationWebSocketEventDTO: (event: any) => event is UnsubscribeUserNotificationWebSocketEventDTO;
|
|
25
|
+
export declare const isSubscribeClientTrackDataWebSocketEventDTO: (event: any) => event is SubscribeClientTrackDataWebSocketEventDTO;
|
|
26
|
+
export declare const isUnsubscribeClientTrackDataWebSocketEventDTO: (event: any) => event is UnsubscribeClientTrackDataWebSocketEventDTO;
|
|
25
27
|
export declare const isWebSocketResponseEventDTO: (event: any) => event is WebSocketResponseEventDTO;
|
|
26
28
|
export declare const isPongWebSocketResponseEventDTO: (event: any) => event is PongWebSocketResponseEventDTO;
|
|
27
29
|
export declare const isCodeRunStatusMessageWebSocketResponseEventDTO: (event: any) => event is CodeRunStatusWebSocketResponseEventDTO;
|
|
@@ -43,3 +45,20 @@ export declare const isUserNotificationWebSocketResponseEventDTO: (event: any) =
|
|
|
43
45
|
export declare const isUserNotificationSubmissionWebSocketResponseEventDTO: (event: any) => event is UserNotificationSubmissionWebSocketResponseEventDTO;
|
|
44
46
|
export declare const isUserNotificationContestClarificationWebSocketResponseEventDTO: (event: any) => event is UserNotificationContestClarificationWebSocketResponseEventDTO;
|
|
45
47
|
export declare const getWebSocketResponseEventKey: (event: WebSocketResponseEvent, clientId: ClientId, id: string) => WebSocketResponseEventKey;
|
|
48
|
+
export declare const isWebSocketChannelsMessageDTO: (message: any) => message is WebSocketChannelsMessageDTO;
|
|
49
|
+
/**
|
|
50
|
+
* Key used by the client to dispatch a response received on a TOPIC channel to its subscribers.
|
|
51
|
+
* It is the same key that `getKeyWebSocketEventDTO` (base-ui) computes for the subscription.
|
|
52
|
+
* Returns null when the response is not addressed to this client.
|
|
53
|
+
*/
|
|
54
|
+
export declare const getWebSocketResponseEventKeyOfResponse: (response: WebSocketResponseEventDTO, clientId: ClientId) => WebSocketResponseEventKey | null;
|
|
55
|
+
/**
|
|
56
|
+
* TOPIC channel that the client has to attach to receive the events of a subscription,
|
|
57
|
+
* or null when the events arrive by the private channels (session / user) the client is always attached to.
|
|
58
|
+
* Ably rejects the attach if the token has no capability for the channel.
|
|
59
|
+
*/
|
|
60
|
+
export declare const getChannelOfWebSocketSubscribeEvent: (event: WebSocketSubscribeEventDTO) => string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Contest whose role channels the client needs (the API grants them when the token is requested with this contest).
|
|
63
|
+
*/
|
|
64
|
+
export declare const getContestKeyOfWebSocketSubscribeEvent: (event: WebSocketSubscribeEventDTO) => string | null;
|
|
@@ -22,7 +22,9 @@ export declare enum WebSocketSubscriptionEvent {
|
|
|
22
22
|
SUBSCRIBE_CLIENT_TRACK = "SUBSCRIBE_CLIENT_TRACK",
|
|
23
23
|
UNSUBSCRIBE_CLIENT_TRACK = "UNSUBSCRIBE_CLIENT_TRACK",
|
|
24
24
|
SUBSCRIBE_USER_NOTIFICATION = "SUBSCRIBE_USER_NOTIFICATION",
|
|
25
|
-
UNSUBSCRIBE_USER_NOTIFICATION = "UNSUBSCRIBE_USER_NOTIFICATION"
|
|
25
|
+
UNSUBSCRIBE_USER_NOTIFICATION = "UNSUBSCRIBE_USER_NOTIFICATION",
|
|
26
|
+
SUBSCRIBE_CLIENT_TRACK_DATA = "SUBSCRIBE_CLIENT_TRACK_DATA",
|
|
27
|
+
UNSUBSCRIBE_CLIENT_TRACK_DATA = "UNSUBSCRIBE_CLIENT_TRACK_DATA"
|
|
26
28
|
}
|
|
27
29
|
export declare enum WebSocketResponseEvent {
|
|
28
30
|
PONG = "PONG",
|
|
@@ -47,3 +49,16 @@ export declare enum WebSocketResponseEvent {
|
|
|
47
49
|
}
|
|
48
50
|
export type ClientId = `${RecordId}|${string}`;
|
|
49
51
|
export type WebSocketResponseEventKey = `${WebSocketResponseEvent}-${ClientId}-${string}`;
|
|
52
|
+
/**
|
|
53
|
+
* Roles of a contest, with the same names as the contest members in the DB.
|
|
54
|
+
* Each role has its own Ably channel: `contest:{contestKey}:{role}` (see `CHANNEL_CONTEST`).
|
|
55
|
+
* The inclusions follow `getContestAccessPermissions`:
|
|
56
|
+
* spectators ⊇ managers ⊇ administrators, spectators ⊇ participants, spectators ⊇ guests
|
|
57
|
+
*/
|
|
58
|
+
export declare enum ContestChannelRole {
|
|
59
|
+
ADMINISTRATORS = "administrators",
|
|
60
|
+
MANAGERS = "managers",
|
|
61
|
+
PARTICIPANTS = "participants",
|
|
62
|
+
GUESTS = "guests",
|
|
63
|
+
SPECTATORS = "spectators"
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juki-team/commons",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"author": "juki-team",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"rollup": "^4.57.1",
|
|
31
31
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
32
32
|
"typedoc": "^0.28.16",
|
|
33
|
-
"typescript": "^
|
|
33
|
+
"typescript": "^6.0.3"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"uuid": "^13.0.0 || ^14.0.0"
|
|
@@ -40,6 +40,6 @@
|
|
|
40
40
|
"watch": "rollup -cw",
|
|
41
41
|
"build": "rm -rf docs && rm -rf dist && rollup -c && pnpm run docs",
|
|
42
42
|
"push-commit": "f() { git add -A && git commit -m \"${1:-chore}\" && pnpm push; }; f",
|
|
43
|
-
"push": "f() {
|
|
43
|
+
"push": "f() { pnpm version patch --no-git-tag-version --no-git-checks && pnpm build && pnpm publish --tag release-0.1 --no-git-checks && version=\"v$(node -p \"require('./package.json').version\")\" && git add -A && git commit -m $version && git tag -a $version -m $version && git push origin v0.1.x --follow-tags; }; f"
|
|
44
44
|
}
|
|
45
45
|
}
|