@juki-team/commons 0.1.43 → 0.1.46

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 (65) hide show
  1. package/dist/cjs/index.cjs +514 -546
  2. package/dist/esm/index.js +416 -491
  3. package/dist/types/constants/entity.d.ts +3 -3
  4. package/dist/types/constants/index.d.ts +1 -1
  5. package/dist/types/constants/organization.d.ts +9 -0
  6. package/dist/types/constants/websocket.d.ts +18 -22
  7. package/dist/types/dto/class.d.ts +34 -34
  8. package/dist/types/dto/code.d.ts +1 -1
  9. package/dist/types/dto/comments.d.ts +9 -9
  10. package/dist/types/dto/contest.d.ts +46 -42
  11. package/dist/types/dto/course.d.ts +13 -13
  12. package/dist/types/dto/entity.d.ts +30 -25
  13. package/dist/types/dto/excalidraw.d.ts +7 -7
  14. package/dist/types/dto/file.d.ts +10 -15
  15. package/dist/types/dto/image.d.ts +2 -2
  16. package/dist/types/dto/index.d.ts +1 -1
  17. package/dist/types/dto/judge.d.ts +5 -5
  18. package/dist/types/dto/markdown.d.ts +7 -7
  19. package/dist/types/dto/mermaid.d.ts +7 -7
  20. package/dist/types/dto/{company.d.ts → organization.d.ts} +16 -16
  21. package/dist/types/dto/problem.d.ts +22 -22
  22. package/dist/types/dto/scoreboard.d.ts +8 -18
  23. package/dist/types/dto/session.d.ts +9 -9
  24. package/dist/types/dto/socket.d.ts +76 -125
  25. package/dist/types/dto/statistics.d.ts +7 -7
  26. package/dist/types/dto/submission.d.ts +22 -22
  27. package/dist/types/dto/system.d.ts +7 -82
  28. package/dist/types/dto/url.d.ts +1 -1
  29. package/dist/types/dto/user.d.ts +22 -22
  30. package/dist/types/dto/virtual-user.d.ts +3 -25
  31. package/dist/types/dto/worksheet-submissions.d.ts +22 -22
  32. package/dist/types/dto/worksheet.d.ts +12 -12
  33. package/dist/types/helpers/class.d.ts +4 -4
  34. package/dist/types/helpers/comments.d.ts +1 -1
  35. package/dist/types/helpers/contest.d.ts +4 -4
  36. package/dist/types/helpers/date.d.ts +68 -0
  37. package/dist/types/helpers/document.d.ts +2 -2
  38. package/dist/types/helpers/index.d.ts +3 -0
  39. package/dist/types/helpers/number.d.ts +2 -0
  40. package/dist/types/helpers/responses.d.ts +1 -1
  41. package/dist/types/helpers/socket.d.ts +48 -50
  42. package/dist/types/helpers/time.d.ts +0 -11
  43. package/dist/types/helpers/user.d.ts +2 -2
  44. package/dist/types/index.d.ts +0 -1
  45. package/dist/types/types/class.d.ts +6 -6
  46. package/dist/types/types/comments.d.ts +2 -2
  47. package/dist/types/types/contest.d.ts +20 -23
  48. package/dist/types/types/entity.d.ts +13 -19
  49. package/dist/types/types/file.d.ts +6 -0
  50. package/dist/types/types/index.d.ts +3 -1
  51. package/dist/types/types/{company.d.ts → organization.d.ts} +2 -2
  52. package/dist/types/types/prisma.d.ts +2 -2
  53. package/dist/types/types/problems.d.ts +1 -1
  54. package/dist/types/types/scoreboard.d.ts +11 -0
  55. package/dist/types/types/sheet.d.ts +1 -1
  56. package/dist/types/types/socket.d.ts +32 -16
  57. package/dist/types/types/system.d.ts +76 -0
  58. package/dist/types/types/teams.d.ts +8 -8
  59. package/dist/types/types/virtual-user.d.ts +22 -0
  60. package/package.json +1 -1
  61. package/dist/types/constants/company.d.ts +0 -9
  62. package/dist/types/prototypes/Date.d.ts +0 -62
  63. package/dist/types/prototypes/Number.d.ts +0 -7
  64. package/dist/types/prototypes/index.d.ts +0 -3
  65. /package/dist/types/{prototypes/Error.d.ts → helpers/errors.d.ts} +0 -0
package/dist/esm/index.js CHANGED
@@ -89,20 +89,20 @@ var EntityAccess;
89
89
  EntityAccess["EXPOSED"] = "EXPOSED";
90
90
  })(EntityAccess || (EntityAccess = {}));
91
91
 
92
- var CompanyPlan;
93
- (function (CompanyPlan) {
94
- CompanyPlan["FREE"] = "FREE";
95
- CompanyPlan["STANDARD"] = "STANDARD";
96
- CompanyPlan["PREMIUM"] = "PREMIUM";
97
- CompanyPlan["CUSTOM"] = "CUSTOM";
98
- })(CompanyPlan || (CompanyPlan = {}));
99
- var CompanyLogoType;
100
- (function (CompanyLogoType) {
101
- CompanyLogoType["HORIZONTAL_WHITE"] = "horizontal-white";
102
- CompanyLogoType["HORIZONTAL_COLOR"] = "horizontal-color";
103
- CompanyLogoType["VERTICAL_WHITE"] = "vertical-white";
104
- CompanyLogoType["VERTICAL_COLOR"] = "vertical-color";
105
- })(CompanyLogoType || (CompanyLogoType = {}));
92
+ var OrganizationPlan;
93
+ (function (OrganizationPlan) {
94
+ OrganizationPlan["FREE"] = "FREE";
95
+ OrganizationPlan["STANDARD"] = "STANDARD";
96
+ OrganizationPlan["PREMIUM"] = "PREMIUM";
97
+ OrganizationPlan["CUSTOM"] = "CUSTOM";
98
+ })(OrganizationPlan || (OrganizationPlan = {}));
99
+ var OrganizationLogoType;
100
+ (function (OrganizationLogoType) {
101
+ OrganizationLogoType["HORIZONTAL_WHITE"] = "horizontal-white";
102
+ OrganizationLogoType["HORIZONTAL_COLOR"] = "horizontal-color";
103
+ OrganizationLogoType["VERTICAL_WHITE"] = "vertical-white";
104
+ OrganizationLogoType["VERTICAL_COLOR"] = "vertical-color";
105
+ })(OrganizationLogoType || (OrganizationLogoType = {}));
106
106
 
107
107
  var ContestStatus;
108
108
  (function (ContestStatus) {
@@ -145,7 +145,7 @@ var EntityState;
145
145
  })(EntityState || (EntityState = {}));
146
146
  var EntityCollection;
147
147
  (function (EntityCollection) {
148
- EntityCollection["COMPANY"] = "COMPANY";
148
+ EntityCollection["ORGANIZATION"] = "ORGANIZATION";
149
149
  EntityCollection["PROBLEM"] = "PROBLEM";
150
150
  EntityCollection["CONTEST"] = "CONTEST";
151
151
  EntityCollection["JUDGE"] = "JUDGE";
@@ -154,7 +154,7 @@ var EntityCollection;
154
154
  })(EntityCollection || (EntityCollection = {}));
155
155
  var CollectionKey;
156
156
  (function (CollectionKey) {
157
- CollectionKey["COMPANY"] = "C";
157
+ CollectionKey["ORGANIZATION"] = "C";
158
158
  CollectionKey["USER"] = "U";
159
159
  CollectionKey["PROBLEM"] = "P";
160
160
  CollectionKey["CLASS"] = "K";
@@ -526,7 +526,7 @@ var ErrorCode;
526
526
  ErrorCode["ERR0818"] = "ERR0818";
527
527
  ErrorCode["ERR0819"] = "ERR0819";
528
528
  ErrorCode["ERR0820"] = "ERR0820";
529
- // Company Errors ERR99XXX',
529
+ // Organization Errors ERR99XXX',
530
530
  ErrorCode["ERR9900"] = "ERR9900";
531
531
  ErrorCode["ERR9910"] = "ERR9910";
532
532
  ErrorCode["ERR9911"] = "ERR9911";
@@ -572,14 +572,6 @@ var QuizScoringMode;
572
572
  QuizScoringMode["PARTIAL"] = "PARTIAL";
573
573
  })(QuizScoringMode || (QuizScoringMode = {}));
574
574
 
575
- var WebSocketMessageEvent;
576
- (function (WebSocketMessageEvent) {
577
- WebSocketMessageEvent["PING"] = "PING";
578
- WebSocketMessageEvent["CLIENT_TRACK_LOCATION"] = "CLIENT_TRACK_LOCATION";
579
- WebSocketMessageEvent["CLIENT_TRACK_SCREENSHOT"] = "CLIENT_TRACK_SCREENSHOT";
580
- WebSocketMessageEvent["CLIENT_TRACK_DEVICE"] = "CLIENT_TRACK_DEVICE";
581
- WebSocketMessageEvent["CHAT_COMPLETIONS"] = "CHAT_COMPLETIONS";
582
- })(WebSocketMessageEvent || (WebSocketMessageEvent = {}));
583
575
  /**
584
576
  * Subscriptions of the client. With the TOPIC channels they are not sent to the server anymore:
585
577
  * they only say which channel the client attaches (`getChannelOfWebSocketSubscribeEvent`) and the dispatch key.
@@ -598,17 +590,13 @@ var WebSocketSubscriptionEvent;
598
590
  WebSocketSubscriptionEvent["UNSUBSCRIBE_SUBMISSIONS_CRAWL"] = "UNSUBSCRIBE_SUBMISSIONS_CRAWL";
599
591
  WebSocketSubscriptionEvent["SUBSCRIBE_CONTEST_CHANGES"] = "SUBSCRIBE_CONTEST_CHANGES";
600
592
  WebSocketSubscriptionEvent["UNSUBSCRIBE_CONTEST_CHANGES"] = "UNSUBSCRIBE_CONTEST_CHANGES";
601
- WebSocketSubscriptionEvent["SUBSCRIBE_CLIENT_TRACK"] = "SUBSCRIBE_CLIENT_TRACK";
602
- WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK"] = "UNSUBSCRIBE_CLIENT_TRACK";
603
593
  WebSocketSubscriptionEvent["SUBSCRIBE_USER_NOTIFICATION"] = "SUBSCRIBE_USER_NOTIFICATION";
604
594
  WebSocketSubscriptionEvent["UNSUBSCRIBE_USER_NOTIFICATION"] = "UNSUBSCRIBE_USER_NOTIFICATION";
605
- // an administrator watching the data (screenshots, location, device) sent by another client
606
- WebSocketSubscriptionEvent["SUBSCRIBE_CLIENT_TRACK_DATA"] = "SUBSCRIBE_CLIENT_TRACK_DATA";
607
- WebSocketSubscriptionEvent["UNSUBSCRIBE_CLIENT_TRACK_DATA"] = "UNSUBSCRIBE_CLIENT_TRACK_DATA";
595
+ WebSocketSubscriptionEvent["SUBSCRIBE_SUBMISSIONS_JUDGING"] = "SUBSCRIBE_SUBMISSIONS_JUDGING";
596
+ WebSocketSubscriptionEvent["UNSUBSCRIBE_SUBMISSIONS_JUDGING"] = "UNSUBSCRIBE_SUBMISSIONS_JUDGING";
608
597
  })(WebSocketSubscriptionEvent || (WebSocketSubscriptionEvent = {}));
609
598
  var WebSocketResponseEvent;
610
599
  (function (WebSocketResponseEvent) {
611
- WebSocketResponseEvent["PONG"] = "PONG";
612
600
  WebSocketResponseEvent["CODE_RUN_STATUS"] = "CODE_RUN_STATUS";
613
601
  WebSocketResponseEvent["SUBMISSION_RUN_STATUS"] = "SUBMISSION_RUN_STATUS";
614
602
  WebSocketResponseEvent["USER_MESSAGE"] = "USER_MESSAGE";
@@ -618,15 +606,13 @@ var WebSocketResponseEvent;
618
606
  WebSocketResponseEvent["SEND_DATA_EC2_INSTANCES_LIST"] = "SEND_DATA_EC2_INSTANCES_LIST";
619
607
  WebSocketResponseEvent["SEND_DATA_SSM_SESSIONS_LIST"] = "SEND_DATA_SSM_SESSIONS_LIST";
620
608
  WebSocketResponseEvent["SEND_DATA_RUN_COMMAND"] = "SEND_DATA_RUN_COMMAND";
621
- WebSocketResponseEvent["SEND_DATA_CLIENT_TRACK"] = "SEND_DATA_CLIENT_TRACK";
622
- WebSocketResponseEvent["SEND_DATA_CHAT_COMPLETIONS"] = "SEND_DATA_CHAT_COMPLETIONS";
623
609
  WebSocketResponseEvent["PROBLEM_CRAWLED"] = "PROBLEM_CRAWLED";
624
610
  WebSocketResponseEvent["SUBMISSIONS_CRAWL"] = "SUBMISSIONS_CRAWL";
625
611
  WebSocketResponseEvent["CONTEST_CHANGES"] = "CONTEST_CHANGES";
626
- WebSocketResponseEvent["CLIENT_TRACK"] = "CLIENT_TRACK";
627
612
  WebSocketResponseEvent["USER_NOTIFICATION_"] = "USER_NOTIFICATION_";
628
613
  WebSocketResponseEvent["USER_NOTIFICATION_SUBMISSION"] = "USER_NOTIFICATION_SUBMISSION";
629
614
  WebSocketResponseEvent["USER_NOTIFICATION_CONTEST_CLARIFICATION"] = "USER_NOTIFICATION_CONTEST_CLARIFICATION";
615
+ WebSocketResponseEvent["SUBMISSION_JUDGING"] = "SUBMISSION_JUDGING";
630
616
  })(WebSocketResponseEvent || (WebSocketResponseEvent = {}));
631
617
  /**
632
618
  * Roles of a contest, with the same names as the contest members in the DB.
@@ -642,6 +628,25 @@ var ContestChannelRole;
642
628
  ContestChannelRole["GUESTS"] = "guests";
643
629
  ContestChannelRole["SPECTATORS"] = "spectators";
644
630
  })(ContestChannelRole || (ContestChannelRole = {}));
631
+ /**
632
+ * Roles of a problem, the ones computed by `getProblemAccessPermissions` (backend).
633
+ * Each role has its own Ably channel: `problem:{problemKey}:{role}` (see `CHANNEL_PROBLEM`).
634
+ */
635
+ var ProblemChannelRole;
636
+ (function (ProblemChannelRole) {
637
+ ProblemChannelRole["ADMINISTRATORS"] = "administrators";
638
+ ProblemChannelRole["MANAGERS"] = "managers";
639
+ ProblemChannelRole["SPECTATORS"] = "spectators";
640
+ })(ProblemChannelRole || (ProblemChannelRole = {}));
641
+ /**
642
+ * Roles of the public channels of a user: `user:{userId}:{role}` (see `CHANNEL_USER_ROLE`).
643
+ * There are no per-user permissions: `spectators` is everyone who can list the submissions of the user.
644
+ * The private channel of the user is `user:{userId}` (see `CHANNEL_USER`).
645
+ */
646
+ var UserChannelRole;
647
+ (function (UserChannelRole) {
648
+ UserChannelRole["SPECTATORS"] = "spectators";
649
+ })(UserChannelRole || (UserChannelRole = {}));
645
650
 
646
651
  var DataViewMode;
647
652
  (function (DataViewMode) {
@@ -1335,25 +1340,25 @@ const HEADER_JUKI_SECRET_TOKEN = 'x-juki-secret-token';
1335
1340
  const HEADER_JUKI_INTERNAL_API_KEY = 'x-juki-internal-api-key';
1336
1341
  const COOKIE_JUKI_SESSION_ID = 'juki-session-id';
1337
1342
 
1338
- const JUKI_APP_COMPANY_KEY = 'juki-app';
1339
- const COMPANY_PLAN = {
1340
- [CompanyPlan.FREE]: {
1341
- value: CompanyPlan.FREE,
1343
+ const JUKI_APP_ORGANIZATION_KEY = 'juki-app';
1344
+ const ORGANIZATION_PLAN = {
1345
+ [OrganizationPlan.FREE]: {
1346
+ value: OrganizationPlan.FREE,
1342
1347
  label: 'free',
1343
1348
  description: 'the resources, runners and compilers, are shared with the juki.app giving priority to juki.app',
1344
1349
  },
1345
- [CompanyPlan.STANDARD]: {
1346
- value: CompanyPlan.STANDARD,
1350
+ [OrganizationPlan.STANDARD]: {
1351
+ value: OrganizationPlan.STANDARD,
1347
1352
  label: 'standard',
1348
1353
  description: 'the resources are dedicated, 1 runner and 1 compiler',
1349
1354
  },
1350
- [CompanyPlan.PREMIUM]: {
1351
- value: CompanyPlan.PREMIUM,
1355
+ [OrganizationPlan.PREMIUM]: {
1356
+ value: OrganizationPlan.PREMIUM,
1352
1357
  label: 'premium',
1353
1358
  description: 'the resources are dedicated and on demand use with at least 1 runner and 1 compiler',
1354
1359
  },
1355
- [CompanyPlan.CUSTOM]: {
1356
- value: CompanyPlan.CUSTOM,
1360
+ [OrganizationPlan.CUSTOM]: {
1361
+ value: OrganizationPlan.CUSTOM,
1357
1362
  label: 'custom',
1358
1363
  description: 'the resources are dedicated and on demand use with at least 1 (settable) runner and 1 (settable) compiler',
1359
1364
  },
@@ -1976,18 +1981,18 @@ const ERROR = {
1976
1981
  [ErrorCode.ERR9997]: { value: ErrorCode.ERR9997, message: 'aborted request', status: 400 },
1977
1982
  [ErrorCode.ERR9998]: { value: ErrorCode.ERR9998, message: 'error on response', status: 400 },
1978
1983
  [ErrorCode.ERR9999]: { value: ErrorCode.ERR9999, message: 'service no found', status: 400 },
1979
- // COMPANY ERRORS ERR99XX
1980
- [ErrorCode.ERR9900]: { value: ErrorCode.ERR9900, message: 'internal server error on company service', status: 500 },
1981
- // Company server errors
1982
- [ErrorCode.ERR9910]: { value: ErrorCode.ERR9910, message: 'company not created', status: 500 },
1983
- [ErrorCode.ERR9911]: { value: ErrorCode.ERR9911, message: 'company not found', status: 500 },
1984
- [ErrorCode.ERR9912]: { value: ErrorCode.ERR9912, message: 'company not updated', status: 500 },
1985
- [ErrorCode.ERR9913]: { value: ErrorCode.ERR9913, message: 'company not deleted', status: 500 },
1986
- // Company user permission error
1987
- [ErrorCode.ERR9914]: { value: ErrorCode.ERR9914, message: 'not allowed to create the company', status: 400 },
1988
- [ErrorCode.ERR9915]: { value: ErrorCode.ERR9915, message: 'not allowed to view the company', status: 400 },
1989
- [ErrorCode.ERR9916]: { value: ErrorCode.ERR9916, message: 'not allowed to updated the company', status: 400 },
1990
- [ErrorCode.ERR9917]: { value: ErrorCode.ERR9917, message: 'not allowed to deleted the company', status: 400 },
1984
+ // ORGANIZATION ERRORS ERR99XX
1985
+ [ErrorCode.ERR9900]: { value: ErrorCode.ERR9900, message: 'internal server error on organization service', status: 500 },
1986
+ // Organization server errors
1987
+ [ErrorCode.ERR9910]: { value: ErrorCode.ERR9910, message: 'organization not created', status: 500 },
1988
+ [ErrorCode.ERR9911]: { value: ErrorCode.ERR9911, message: 'organization not found', status: 500 },
1989
+ [ErrorCode.ERR9912]: { value: ErrorCode.ERR9912, message: 'organization not updated', status: 500 },
1990
+ [ErrorCode.ERR9913]: { value: ErrorCode.ERR9913, message: 'organization not deleted', status: 500 },
1991
+ // Organization user permission error
1992
+ [ErrorCode.ERR9914]: { value: ErrorCode.ERR9914, message: 'not allowed to create the organization', status: 400 },
1993
+ [ErrorCode.ERR9915]: { value: ErrorCode.ERR9915, message: 'not allowed to view the organization', status: 400 },
1994
+ [ErrorCode.ERR9916]: { value: ErrorCode.ERR9916, message: 'not allowed to updated the organization', status: 400 },
1995
+ [ErrorCode.ERR9917]: { value: ErrorCode.ERR9917, message: 'not allowed to deleted the organization', status: 400 },
1991
1996
  // USER ERRORS ERR00XX
1992
1997
  [ErrorCode.ERR0000]: { value: ErrorCode.ERR0000, message: 'internal server error on users service', status: 500 },
1993
1998
  // User server errors
@@ -2233,7 +2238,7 @@ const EMPTY_USER_PERMISSIONS = {
2233
2238
  create: false,
2234
2239
  manage: false,
2235
2240
  },
2236
- company: {
2241
+ organization: {
2237
2242
  manage: false,
2238
2243
  administrate: false,
2239
2244
  },
@@ -2242,46 +2247,37 @@ const EMPTY_USER_PERMISSIONS = {
2242
2247
  },
2243
2248
  };
2244
2249
 
2245
- // LEGACY channels (fan-out per client through the subscriptions registry in Redis)
2246
- /** @deprecated the subscriptions registry was replaced by the TOPIC channels granted in the Ably token */
2247
- const CHANNEL_PUBLISH_SUBSCRIPTIONS = 'pub:subscriptions';
2248
- /** @deprecated not used, the events arrive by the TOPIC channels */
2249
- const CHANNEL_SUBSCRIBE_NOTIFICATIONS = 'sub:notifications';
2250
- /** @deprecated the events arrive by the TOPIC channels */
2251
- const CHANNEL_SUBSCRIBE_CLIENT = (clientId) => `sub:client:${clientId}`;
2252
- /** messages from the clients to the backend (chat completions, client track screenshots) */
2253
- const CHANNEL_PUBLISH_MESSAGES = 'pub:messages';
2254
- /** @deprecated global presence channel (limited to 200 members by Ably), replaced by CHANNEL_COMPANY_PRESENCE */
2255
- const CHANNEL_PRESENCE_CLIENT = 'pre:client';
2256
2250
  // TOPIC channels
2257
2251
  // The backend publishes each event once on the channel of its topic and Ably does the fan-out.
2258
2252
  // Who can subscribe to each channel is decided by the API in the Ably token (capability), never by the client.
2259
2253
  // Dynamic segments are encoded so a key can never inject a `:` (the Ably segment separator used by the wildcards).
2260
2254
  const segment = (value) => encodeURIComponent(value);
2261
- /** private: events of one session (code runs, requested data, client track commands) */
2255
+ /** private: events of one session (code runs, requested data) */
2262
2256
  const CHANNEL_SESSION = (sessionId) => `session:${segment(sessionId)}`;
2263
- /** private: events of one user (own submissions while the contest is frozen, notifications) */
2257
+ /** private: events of one user (own submissions while the contest is frozen, notifications, own problem crawls) */
2264
2258
  const CHANNEL_USER = (userId) => `user:${segment(userId)}`;
2259
+ /** per role: public events of one user (judging of its submissions visible to everyone, see `UserChannelRole`) */
2260
+ const CHANNEL_USER_ROLE = (userId, role) => `user:${segment(userId)}:${role}`;
2265
2261
  /** public: status of a submission when it is visible to everyone */
2266
2262
  const CHANNEL_SUBMISSION = (submitId) => `submission:${segment(submitId)}`;
2267
- /** public: changes of a problem */
2268
- const CHANNEL_PROBLEM = (problemKey) => `problem:${segment(problemKey)}`;
2263
+ /** per role: events of a problem for one role (judging of its submissions, see `ProblemChannelRole`) */
2264
+ const CHANNEL_PROBLEM = (problemKey, role) => `problem:${segment(problemKey)}:${role}`;
2269
2265
  /** per role: events of a contest for one role (and the roles above it, see `ContestChannelRole`) */
2270
2266
  const CHANNEL_CONTEST = (contestKey, role) => `contest:${segment(contestKey)}:${role}`;
2271
- /** system administrators only: data sent by a tracked client (screenshots, location, device) */
2272
- const CHANNEL_CLIENT_TRACK = (trackedClientId) => `client-track:${segment(trackedClientId)}`;
2273
2267
  /**
2274
- * presence of the clients (tabs) of the logged users of a company (by its key), data: `UserPresenceData`.
2275
- * The clients only enter (capability `presence`), only the administrators of the company receive it
2268
+ * presence of the clients (tabs) of the logged users of a organization (by its key), data: `UserPresenceData`.
2269
+ * The clients only enter (capability `presence`), only the administrators of the organization receive it
2276
2270
  * (capability `presence-subscribe`). Ably limits the presence members per channel (200 by default,
2277
2271
  * more with server-side batching enabled on the `presence` namespace).
2278
2272
  * The identity of a member is its `clientId` (`sessionId|uiId`, verified by Ably), never its data.
2279
2273
  */
2280
- const CHANNEL_COMPANY_PRESENCE = (companyKey) => `presence:company:${segment(companyKey)}`;
2281
- // capability resources (wildcards) of the public channels
2274
+ const CHANNEL_ORGANIZATION_PRESENCE = (organizationKey) => `presence:organization:${segment(organizationKey)}`;
2275
+ // capability resources (wildcards) of the public channels.
2276
+ // Ably: a trailing `*` replaces one or more segments, any other `*` exactly one segment. So `user:*:spectators`
2277
+ // matches every `user:{userId}:spectators` but never the private `user:{userId}`.
2278
+ // There is no public `problem:*`: it would also match the role channels `problem:{problemKey}:{role}`.
2282
2279
  const CHANNEL_SUBMISSION_ALL = 'submission:*';
2283
- const CHANNEL_PROBLEM_ALL = 'problem:*';
2284
- const CHANNEL_CLIENT_TRACK_ALL = 'client-track:*';
2280
+ const CHANNEL_USER_SPECTATORS_ALL = `user:*:${UserChannelRole.SPECTATORS}`;
2285
2281
  /**
2286
2282
  * Returns the contest and role of a `CHANNEL_CONTEST` channel name, or null if it is not one.
2287
2283
  */
@@ -2292,6 +2288,16 @@ const getContestChannelParams = (channel) => {
2292
2288
  }
2293
2289
  return { contestKey: decodeURIComponent(contestKey), role: role };
2294
2290
  };
2291
+ /**
2292
+ * Returns the problem and role of a `CHANNEL_PROBLEM` channel name, or null if it is not one.
2293
+ */
2294
+ const getProblemChannelParams = (channel) => {
2295
+ const [namespace, problemKey, role, ...rest] = channel.split(':');
2296
+ if (namespace !== 'problem' || !problemKey || rest.length || !Object.values(ProblemChannelRole).includes(role)) {
2297
+ return null;
2298
+ }
2299
+ return { problemKey: decodeURIComponent(problemKey), role: role };
2300
+ };
2295
2301
 
2296
2302
  const NEW_PAGE_SHEET = () => ({
2297
2303
  id: v4(),
@@ -2383,31 +2389,212 @@ const isContestAssignment = (assignment) => {
2383
2389
  };
2384
2390
 
2385
2391
  const getAssignmentCommentKey = (classKey, cycleKey, sessionKey, assignmentKey) => `class:${classKey}|cycle:${cycleKey}|session:${sessionKey}|assignment:${assignmentKey}`;
2386
- const getAssignmentUserCommentKey = (classKey, cycleKey, sessionKey, assignmentKey, userNickname, userCompany) => `class:${classKey}|cycle:${cycleKey}|session:${sessionKey}|assignment:${assignmentKey}|user_nickname:${userNickname}|user_company:${userCompany}`;
2392
+ const getAssignmentUserCommentKey = (classKey, cycleKey, sessionKey, assignmentKey, userNickname, userOrganization) => `class:${classKey}|cycle:${cycleKey}|session:${sessionKey}|assignment:${assignmentKey}|user_nickname:${userNickname}|user_organization:${userOrganization}`;
2387
2393
  const getProblemCommentKey = (problemKey) => `problem:${problemKey}`;
2388
2394
  const getContestCommentKey = (contestKey) => `contest:${contestKey}`;
2389
2395
 
2390
2396
  const isEndlessContest = (settings) => {
2391
- return settings?.startTimestamp === MIN_DATE.getTime()
2392
- && settings?.frozenTimestamp === MAX_DATE.getTime()
2393
- && settings?.quietTimestamp === MAX_DATE.getTime()
2394
- && settings?.endTimestamp === MAX_DATE.getTime()
2397
+ return settings?.startsAt === MIN_DATE.getTime()
2398
+ && settings?.frozenAt === MAX_DATE.getTime()
2399
+ && settings?.silencedAt === MAX_DATE.getTime()
2400
+ && settings?.endsAt === MAX_DATE.getTime()
2395
2401
  && settings?.penalty === 0;
2396
2402
  };
2397
2403
  const isGlobalContest = (settings) => {
2398
- return settings?.startTimestamp === 0
2399
- && settings?.frozenTimestamp === 0
2400
- && settings?.quietTimestamp === 0
2401
- && settings?.endTimestamp === 0
2404
+ return settings?.startsAt === 0
2405
+ && settings?.frozenAt === 0
2406
+ && settings?.silencedAt === 0
2407
+ && settings?.endsAt === 0
2402
2408
  && settings?.penalty === 0;
2403
2409
  };
2404
2410
  const isPastContest = (settings) => {
2405
- return Date.now() > (settings?.endTimestamp ?? 0);
2411
+ return Date.now() > (settings?.endsAt ?? 0);
2406
2412
  };
2407
2413
  const isFutureContest = (settings) => {
2408
- return (settings?.startTimestamp ?? 0) > Date.now();
2414
+ return (settings?.startsAt ?? 0) > Date.now();
2409
2415
  };
2410
2416
 
2417
+ const changeYear = (date, year) => {
2418
+ const newDate = new Date(date);
2419
+ newDate.setFullYear(year);
2420
+ return newDate;
2421
+ };
2422
+ const changeMonth = (date, monthIndex) => {
2423
+ const newDate = new Date(date);
2424
+ newDate.setMonth(monthIndex);
2425
+ return newDate;
2426
+ };
2427
+ const changeDay = (date, day) => {
2428
+ const newDate = new Date(date);
2429
+ newDate.setDate(day);
2430
+ return newDate;
2431
+ };
2432
+ const changeHours = (date, hours) => {
2433
+ const newDate = new Date(date);
2434
+ newDate.setHours(hours);
2435
+ return newDate;
2436
+ };
2437
+ const changeMinutes = (date, minutes) => {
2438
+ const newDate = new Date(date);
2439
+ newDate.setMinutes(minutes);
2440
+ return newDate;
2441
+ };
2442
+ const changeSeconds = (date, seconds) => {
2443
+ const newDate = new Date(date);
2444
+ newDate.setSeconds(seconds);
2445
+ return newDate;
2446
+ };
2447
+ const changeMilliseconds = (date, milliseconds) => {
2448
+ const newDate = new Date(date);
2449
+ newDate.setMilliseconds(milliseconds);
2450
+ return newDate;
2451
+ };
2452
+ const decreaseYear = (date, count = 1) => changeYear(date, date.getFullYear() - count);
2453
+ const increaseYear = (date, count = 1) => changeYear(date, date.getFullYear() + count);
2454
+ const decreaseMonth = (date) => {
2455
+ const newDate = new Date(date);
2456
+ newDate.setMonth(newDate.getMonth() - 1);
2457
+ return newDate;
2458
+ };
2459
+ const increaseMonth = (date) => {
2460
+ const newDate = new Date(date);
2461
+ newDate.setMonth(newDate.getMonth() + 1);
2462
+ return newDate;
2463
+ };
2464
+ const decreaseDay = (date) => {
2465
+ const newDate = new Date(date);
2466
+ newDate.setDate(newDate.getDate() - 1);
2467
+ return newDate;
2468
+ };
2469
+ const increaseDay = (date) => {
2470
+ const newDate = new Date(date);
2471
+ newDate.setDate(newDate.getDate() + 1);
2472
+ return newDate;
2473
+ };
2474
+ const startOfDay = (date) => {
2475
+ const newDate = new Date(date);
2476
+ newDate.setHours(0, 0, 0, 0);
2477
+ return newDate;
2478
+ };
2479
+ const endOfDay = (date) => {
2480
+ const newDate = new Date(date);
2481
+ newDate.setHours(23, 59, 59, 999);
2482
+ return newDate;
2483
+ };
2484
+ const startOfMonth = (date) => {
2485
+ const newDate = new Date(date);
2486
+ newDate.setDate(1);
2487
+ return startOfDay(newDate);
2488
+ };
2489
+ const endOfMonth = (date) => {
2490
+ const nextMonth = startOfMonth(increaseMonth(date));
2491
+ return new Date(nextMonth.getTime() - 1);
2492
+ };
2493
+ const startOfYear = (date) => {
2494
+ const newDate = new Date(date);
2495
+ newDate.setMonth(0);
2496
+ return startOfMonth(newDate);
2497
+ };
2498
+ const endOfYear = (date) => {
2499
+ const nextYear = startOfYear(increaseYear(date));
2500
+ return new Date(nextYear.getTime() - 1);
2501
+ };
2502
+ const startOfWeek = (date) => {
2503
+ const newDate = new Date(date);
2504
+ while (newDate.getDay()) {
2505
+ newDate.setDate(newDate.getDate() - 1);
2506
+ }
2507
+ return startOfDay(newDate);
2508
+ };
2509
+ const endOfWeek = (date) => {
2510
+ const newDate = new Date(date);
2511
+ while (newDate.getDay() < 6) {
2512
+ newDate.setDate(newDate.getDate() + 1);
2513
+ }
2514
+ return endOfDay(newDate);
2515
+ };
2516
+ const startOfHour = (date) => {
2517
+ const newDate = new Date(date);
2518
+ newDate.setMinutes(0, 0, 0);
2519
+ return newDate;
2520
+ };
2521
+ const endOfHour = (date) => {
2522
+ const newDate = new Date(date);
2523
+ newDate.setMinutes(59, 59, 999);
2524
+ return newDate;
2525
+ };
2526
+ const startOfMinute = (date) => {
2527
+ const newDate = new Date(date);
2528
+ newDate.setSeconds(0, 0);
2529
+ return newDate;
2530
+ };
2531
+ const endOfMinute = (date) => {
2532
+ const newDate = new Date(date);
2533
+ newDate.setSeconds(59, 999);
2534
+ return newDate;
2535
+ };
2536
+ const startOfSecond = (date) => {
2537
+ const newDate = new Date(date);
2538
+ newDate.setMilliseconds(0);
2539
+ return newDate;
2540
+ };
2541
+ const endOfSecond = (date) => {
2542
+ const newDate = new Date(date);
2543
+ newDate.setMilliseconds(999);
2544
+ return newDate;
2545
+ };
2546
+ const isEqual = (a, b) => a.getTime() === b.getTime();
2547
+ const isSameYear = (a, b) => a.getFullYear() === b.getFullYear();
2548
+ const isSameMonth = (a, b) => isSameYear(a, b) && a.getMonth() === b.getMonth();
2549
+ const isSameDay = (a, b) => isSameMonth(a, b) && a.getDate() === b.getDate();
2550
+ const isSameHour = (a, b) => isSameDay(a, b) && a.getHours() === b.getHours();
2551
+ const isSameMinute = (a, b) => isSameHour(a, b) && a.getMinutes() === b.getMinutes();
2552
+ const isSameSecond = (a, b) => isSameMinute(a, b) && a.getSeconds() === b.getSeconds();
2553
+ const isSameMillisecond = (a, b) => isEqual(a, b);
2554
+ const isToday = (date) => isSameDay(date, new Date());
2555
+ const isValidDate = (date) => date instanceof Date && !Number.isNaN(date.getTime());
2556
+ const isAfter = (a, b) => a.getTime() > b.getTime();
2557
+ const isBefore = (a, b) => a.getTime() < b.getTime();
2558
+ const isYearAfter = (a, b) => a.getFullYear() > b.getFullYear();
2559
+ const isMonthAfter = (a, b) => isYearAfter(a, b) || (isSameYear(a, b) && a.getMonth() > b.getMonth());
2560
+ const isDayAfter = (a, b) => isMonthAfter(a, b) || (isSameMonth(a, b) && a.getDate() > b.getDate());
2561
+ const isHoursAfter = (a, b) => isDayAfter(a, b) || (isSameDay(a, b) && a.getHours() > b.getHours());
2562
+ const isMinutesAfter = (a, b) => isHoursAfter(a, b) || (isSameHour(a, b) && a.getMinutes() > b.getMinutes());
2563
+ const isSecondsAfter = (a, b) => isMinutesAfter(a, b) || (isSameMinute(a, b) && a.getSeconds() > b.getSeconds());
2564
+ const isMillisecondsAfter = (a, b) => isSecondsAfter(a, b) || (isSameSecond(a, b) && a.getMilliseconds() > b.getMilliseconds());
2565
+ const isYearBefore = (a, b) => a.getFullYear() < b.getFullYear();
2566
+ const isMonthBefore = (a, b) => isYearBefore(a, b) || (isSameYear(a, b) && a.getMonth() < b.getMonth());
2567
+ const isDayBefore = (a, b) => isMonthBefore(a, b) || (isSameMonth(a, b) && a.getDate() < b.getDate());
2568
+ const isHoursBefore = (a, b) => isDayBefore(a, b) || (isSameDay(a, b) && a.getHours() < b.getHours());
2569
+ const isMinutesBefore = (a, b) => isHoursBefore(a, b) || (isSameHour(a, b) && a.getMinutes() < b.getMinutes());
2570
+ const isSecondsBefore = (a, b) => isMinutesBefore(a, b) || (isSameMinute(a, b) && a.getSeconds() < b.getSeconds());
2571
+ const isMillisecondsBefore = (a, b) => isSecondsBefore(a, b) || (isSameSecond(a, b) && a.getMilliseconds() < b.getMilliseconds());
2572
+ const isWithinInterval = (date, { start, end }, cmp = '[]') => (cmp.charAt(0) === '[' ? isEqual(date, start) || isAfter(date, start) : isAfter(date, start)) &&
2573
+ (cmp.charAt(1) === ']' ? isEqual(date, end) || isBefore(date, end) : isBefore(date, end));
2574
+ const normalizeToLocalStartOfDay = (timestamp) => {
2575
+ const d = new Date(timestamp);
2576
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate());
2577
+ };
2578
+ const normalizeToLocalStartOfHour = (timestamp) => {
2579
+ const d = new Date(timestamp);
2580
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours());
2581
+ };
2582
+ const normalizeToLocalStartOfMinutes = (timestamp) => {
2583
+ const d = new Date(timestamp);
2584
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes());
2585
+ };
2586
+ const normalizeToLocalStartOfSeconds = (timestamp) => {
2587
+ const d = new Date(timestamp);
2588
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds());
2589
+ };
2590
+ const getYears = (d) => d.getFullYear();
2591
+ const getMonths = (d) => d.getFullYear() * 12 + d.getMonth();
2592
+ const getDays = (d) => Math.floor(normalizeToLocalStartOfDay(d).getTime() / ONE_DAY);
2593
+ const getHours = (d) => Math.floor(normalizeToLocalStartOfHour(d).getTime() / ONE_HOUR);
2594
+ const getMinutes = (d) => Math.floor(normalizeToLocalStartOfMinutes(d).getTime() / ONE_MINUTE);
2595
+ const getSeconds = (d) => Math.floor(normalizeToLocalStartOfSeconds(d).getTime() / 1000);
2596
+ const getMilliseconds = (d) => d.getTime();
2597
+
2411
2598
  const getDocumentAccess = (document) => {
2412
2599
  switch (true) {
2413
2600
  case (document?.members?.rankAdministrators === EntityMembersRank.NONE || document?.members?.rankAdministrators === EntityMembersRank.CLOSE)
@@ -2444,7 +2631,7 @@ const isUserMember = (member) => {
2444
2631
  const isTeamMember = (member) => {
2445
2632
  return typeof member.teamId === 'string';
2446
2633
  };
2447
- const toEntityMembersDTO = (members) => {
2634
+ const toEntityMembersDto = (members) => {
2448
2635
  return {
2449
2636
  rankAdministrators: members.rankAdministrators,
2450
2637
  administrators: Object.keys(members.administrators),
@@ -2459,6 +2646,21 @@ const toEntityMembersDTO = (members) => {
2459
2646
  };
2460
2647
  };
2461
2648
 
2649
+ class JkError extends Error {
2650
+ constructor(code, custom) {
2651
+ const message = custom?.message || ERROR[code].message;
2652
+ super(message);
2653
+ this.message = message;
2654
+ this.code = code;
2655
+ if (custom?.stack) {
2656
+ this.stack = custom.stack;
2657
+ }
2658
+ if (custom?.data) {
2659
+ this.data = custom.data;
2660
+ }
2661
+ }
2662
+ }
2663
+
2462
2664
  function removeExtension(fileName) {
2463
2665
  const i = fileName.lastIndexOf('.');
2464
2666
  return i !== -1 ? fileName.substring(0, i) : fileName;
@@ -2613,6 +2815,9 @@ const getDataLog = (log) => {
2613
2815
  };
2614
2816
  };
2615
2817
 
2818
+ const padStart = (n, maxLength, fillString = '0') => `${n}`.padStart(maxLength, fillString);
2819
+ const padEnd = (n, maxLength, fillString = '0') => `${n}`.padEnd(maxLength, fillString);
2820
+
2616
2821
  function memorySizeOf(obj) {
2617
2822
  let bytes = 0;
2618
2823
  function sizeOf(obj) {
@@ -2647,247 +2852,6 @@ function memorySizeOf(obj) {
2647
2852
  return sizeOf(obj);
2648
2853
  }
2649
2854
 
2650
- /* eslint-disable no-extend-native */
2651
- Date.prototype.changeYear = function (year) {
2652
- const newDate = new Date(this);
2653
- newDate.setFullYear(year);
2654
- return newDate;
2655
- };
2656
- Date.prototype.changeMonth = function (monthIndex) {
2657
- const newDate = new Date(this);
2658
- newDate.setMonth(monthIndex);
2659
- return newDate;
2660
- };
2661
- Date.prototype.changeDay = function (date) {
2662
- const newDate = new Date(this);
2663
- newDate.setDate(date);
2664
- return newDate;
2665
- };
2666
- Date.prototype.changeHours = function (hours) {
2667
- const newDate = new Date(this);
2668
- newDate.setHours(hours);
2669
- return newDate;
2670
- };
2671
- Date.prototype.changeMinutes = function (minutes) {
2672
- const newDate = new Date(this);
2673
- newDate.setMinutes(minutes);
2674
- return newDate;
2675
- };
2676
- Date.prototype.changeSeconds = function (seconds) {
2677
- const newDate = new Date(this);
2678
- newDate.setSeconds(seconds);
2679
- return newDate;
2680
- };
2681
- Date.prototype.changeMilliseconds = function (milliseconds) {
2682
- const newDate = new Date(this);
2683
- newDate.setMilliseconds(milliseconds);
2684
- return newDate;
2685
- };
2686
- Date.prototype.decreaseYear = function (count = 1) {
2687
- return this.changeYear(this.getFullYear() - count);
2688
- };
2689
- Date.prototype.increaseYear = function (count = 1) {
2690
- return this.changeYear(this.getFullYear() + count);
2691
- };
2692
- Date.prototype.decreaseMonth = function () {
2693
- const newDate = new Date(this);
2694
- newDate.setMonth(newDate.getMonth() - 1);
2695
- return newDate;
2696
- };
2697
- Date.prototype.increaseMonth = function () {
2698
- const newDate = new Date(this);
2699
- newDate.setMonth(newDate.getMonth() + 1);
2700
- return newDate;
2701
- };
2702
- Date.prototype.increaseDay = function () {
2703
- const newDate = new Date(this);
2704
- newDate.setDate(newDate.getDate() + 1);
2705
- return newDate;
2706
- };
2707
- Date.prototype.decreaseDay = function () {
2708
- const newDate = new Date(this);
2709
- newDate.setDate(newDate.getDate() - 1);
2710
- return newDate;
2711
- };
2712
- Date.prototype.startOfYear = function () {
2713
- const newDate = new Date(this);
2714
- newDate.setMonth(0);
2715
- return newDate.startOfMonth();
2716
- };
2717
- Date.prototype.endOfYear = function () {
2718
- const nextMonth = this.increaseYear().startOfYear();
2719
- return new Date(nextMonth.getTime() - 1);
2720
- };
2721
- Date.prototype.startOfMonth = function () {
2722
- const newDate = new Date(this);
2723
- newDate.setDate(1);
2724
- return newDate.startOfDay();
2725
- };
2726
- Date.prototype.endOfMonth = function () {
2727
- const nextMonth = this.increaseMonth().startOfMonth();
2728
- return new Date(nextMonth.getTime() - 1);
2729
- };
2730
- Date.prototype.startOfWeek = function () {
2731
- const newDate = new Date(this);
2732
- while (newDate.getDay()) {
2733
- newDate.setDate(newDate.getDate() - 1);
2734
- }
2735
- return newDate.startOfDay();
2736
- };
2737
- Date.prototype.endOfWeek = function () {
2738
- const newDate = new Date(this);
2739
- while (newDate.getDay() < 6) {
2740
- newDate.setDate(newDate.getDate() - 1);
2741
- }
2742
- return newDate.endOfDay();
2743
- };
2744
- Date.prototype.startOfDay = function () {
2745
- const newDate = new Date(this);
2746
- newDate.setHours(0, 0, 0, 0);
2747
- return newDate;
2748
- };
2749
- Date.prototype.endOfDay = function () {
2750
- const newDate = new Date(this);
2751
- newDate.setHours(23, 59, 59, 999);
2752
- return newDate;
2753
- };
2754
- Date.prototype.startOfHour = function () {
2755
- const newDate = new Date(this);
2756
- newDate.setMinutes(0, 0, 0);
2757
- return newDate;
2758
- };
2759
- Date.prototype.endOfHour = function () {
2760
- const newDate = new Date(this);
2761
- newDate.setMinutes(59, 59, 999);
2762
- return newDate;
2763
- };
2764
- Date.prototype.startOfMinute = function () {
2765
- const newDate = new Date(this);
2766
- newDate.setSeconds(0, 0);
2767
- return newDate;
2768
- };
2769
- Date.prototype.endOfMinute = function () {
2770
- const newDate = new Date(this);
2771
- newDate.setSeconds(59, 999);
2772
- return newDate;
2773
- };
2774
- Date.prototype.startOfSecond = function () {
2775
- const newDate = new Date(this);
2776
- newDate.setMilliseconds(0);
2777
- return newDate;
2778
- };
2779
- Date.prototype.endOfSecond = function () {
2780
- const newDate = new Date(this);
2781
- newDate.setMilliseconds(999);
2782
- return newDate;
2783
- };
2784
- Date.prototype.isToday = function () {
2785
- const today = new Date();
2786
- return this.isSameDay(today);
2787
- };
2788
- Date.prototype.isEqual = function (date) {
2789
- return this.getTime() === date.getTime();
2790
- };
2791
- Date.prototype.isSameYear = function (date) {
2792
- return this.getFullYear() === date.getFullYear();
2793
- };
2794
- Date.prototype.isSameMonth = function (date) {
2795
- return this.isSameYear(date) && this.getMonth() === date.getMonth();
2796
- };
2797
- Date.prototype.isSameDay = function (date) {
2798
- return this.isSameMonth(date) && this.getDate() === date.getDate();
2799
- };
2800
- Date.prototype.isSameHour = function (date) {
2801
- return this.isSameDay(date) && this.getHours() === date.getHours();
2802
- };
2803
- Date.prototype.isSameMinute = function (date) {
2804
- return this.isSameHour(date) && this.getMinutes() === date.getMinutes();
2805
- };
2806
- Date.prototype.isSameSecond = function (date) {
2807
- return this.isSameMinute(date) && this.getSeconds() === date.getSeconds();
2808
- };
2809
- Date.prototype.isSameMillisecond = function (date) {
2810
- return this.isEqual(date);
2811
- };
2812
- Date.prototype.isValidDate = function () {
2813
- return this instanceof Date && !isNaN(this.getTime());
2814
- };
2815
- Date.prototype.isYearAfter = function (date) {
2816
- return this.getFullYear() > date.getFullYear();
2817
- };
2818
- Date.prototype.isMonthAfter = function (date) {
2819
- return this.isYearAfter(date) || (this.isSameYear(date) && this.getMonth() > date.getMonth());
2820
- };
2821
- Date.prototype.isDayAfter = function (date) {
2822
- return this.isMonthAfter(date) || (this.isSameMonth(date) && this.getDate() > date.getDate());
2823
- };
2824
- Date.prototype.isHoursAfter = function (date) {
2825
- return this.isDayAfter(date) || (this.isSameDay(date) && this.getHours() > date.getHours());
2826
- };
2827
- Date.prototype.isMinutesAfter = function (date) {
2828
- return this.isHoursAfter(date) || (this.isSameHour(date) && this.getMinutes() > date.getMinutes());
2829
- };
2830
- Date.prototype.isSecondsAfter = function (date) {
2831
- return this.isMinutesAfter(date) || (this.isSameMinute(date) && this.getSeconds() > date.getSeconds());
2832
- };
2833
- Date.prototype.isMillisecondsAfter = function (date) {
2834
- return this.isSecondsAfter(date) || (this.isSameSecond(date) && this.getMilliseconds() > date.getMilliseconds());
2835
- };
2836
- Date.prototype.isAfter = function (date) {
2837
- return this.getTime() > date.getTime();
2838
- };
2839
- Date.prototype.isYearBefore = function (date) {
2840
- return this.getFullYear() < date.getFullYear();
2841
- };
2842
- Date.prototype.isMonthBefore = function (date) {
2843
- return this.isYearBefore(date) || (this.isSameYear(date) && this.getMonth() < date.getMonth());
2844
- };
2845
- Date.prototype.isDayBefore = function (date) {
2846
- return this.isMonthBefore(date) || (this.isSameMonth(date) && this.getDate() < date.getDate());
2847
- };
2848
- Date.prototype.isHoursBefore = function (date) {
2849
- return this.isDayBefore(date) || (this.isSameDay(date) && this.getHours() < date.getHours());
2850
- };
2851
- Date.prototype.isMinutesBefore = function (date) {
2852
- return this.isHoursBefore(date) || (this.isSameHour(date) && this.getMinutes() < date.getMinutes());
2853
- };
2854
- Date.prototype.isSecondsBefore = function (date) {
2855
- return this.isMinutesBefore(date) || (this.isSameMinute(date) && this.getSeconds() < date.getSeconds());
2856
- };
2857
- Date.prototype.isMillisecondsBefore = function (date) {
2858
- return this.isSecondsBefore(date) || (this.isSameSecond(date) && this.getMilliseconds() < date.getMilliseconds());
2859
- };
2860
- Date.prototype.isBefore = function (date) {
2861
- return this.getTime() < date.getTime();
2862
- };
2863
- Date.prototype.isWithinInterval = function ({ start, end }, cmp = '[]') {
2864
- return (cmp.charAt(0) === '[' ? this.isEqual(start) || this.isAfter(start) : this.isAfter(start)) &&
2865
- (cmp.charAt(1) === '[' ? this.isEqual(end) || this.isBefore(end) : this.isBefore(end));
2866
- };
2867
-
2868
- class JkError extends Error {
2869
- constructor(code, custom) {
2870
- const message = custom?.message || ERROR[code].message;
2871
- super(message);
2872
- this.message = message;
2873
- this.code = code;
2874
- if (custom?.stack) {
2875
- this.stack = custom.stack;
2876
- }
2877
- if (custom?.data) {
2878
- this.data = custom.data;
2879
- }
2880
- }
2881
- }
2882
-
2883
- /* eslint-disable no-extend-native */
2884
- Number.prototype.padStart = function (maxLength, fillString = '0') {
2885
- return (this + '').padStart(maxLength, fillString);
2886
- };
2887
- Number.prototype.padEnd = function (maxLength, fillString = '0') {
2888
- return (this + '').padEnd(maxLength, fillString);
2889
- };
2890
-
2891
2855
  function toJkError(err) {
2892
2856
  const error = new Error();
2893
2857
  let code = err?.code;
@@ -2981,258 +2945,230 @@ const getDefaultMeta = (contents, sort) => {
2981
2945
  };
2982
2946
 
2983
2947
  const isWebsocketSubscription = (event) => {
2984
- return (Object.values(WebSocketSubscriptionEvent).includes(event?.event) || Object.values(WebSocketMessageEvent).includes(event?.event))
2948
+ return Object.values(WebSocketSubscriptionEvent).includes(event?.event)
2985
2949
  && typeof event?.clientId === 'string' && !!event.clientId;
2986
2950
  };
2987
- // Custom CHANNEL_PUBLISH_MESSAGES
2988
- const isPingWebSocketEventDTO = (event) => {
2989
- return isWebsocketSubscription(event)
2990
- && event?.event === WebSocketMessageEvent.PING;
2991
- };
2992
- const isClientTrackLocationWebSocketEventDTO = (event) => {
2993
- return isWebsocketSubscription(event)
2994
- && event?.event === WebSocketMessageEvent.CLIENT_TRACK_LOCATION;
2995
- };
2996
- const isClientTrackScreenshotWebSocketEventDTO = (event) => {
2997
- return isWebsocketSubscription(event)
2998
- && event?.event === WebSocketMessageEvent.CLIENT_TRACK_SCREENSHOT;
2999
- };
3000
- const isClientTrackDeviceWebSocketEventDTO = (event) => {
3001
- return isWebsocketSubscription(event)
3002
- && event?.event === WebSocketMessageEvent.CLIENT_TRACK_DEVICE;
3003
- };
3004
- const isChatCompletionsWebSocketEventDTO = (event) => {
3005
- return isWebsocketSubscription(event)
3006
- && event?.event === WebSocketMessageEvent.CHAT_COMPLETIONS;
3007
- };
3008
2951
  // CHANNEL_PUBLISH_SUBSCRIPTIONS
3009
- const isSubscribeCodeRunStatusWebSocketEventDTO = (event) => {
2952
+ const isSubscribeCodeRunStatusWebSocketEventDto = (event) => {
3010
2953
  return isWebsocketSubscription(event)
3011
2954
  && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_CODE_RUN_STATUS
3012
2955
  && typeof event?.runId === 'string' && !!event.runId;
3013
2956
  };
3014
- const isUnsubscribeCodeRunStatusWebSocketEventDTO = (event) => {
2957
+ const isUnsubscribeCodeRunStatusWebSocketEventDto = (event) => {
3015
2958
  return isWebsocketSubscription(event)
3016
2959
  && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_CODE_RUN_STATUS
3017
2960
  && typeof event?.runId === 'string' && !!event.runId;
3018
2961
  };
3019
- const isSubscribeSubmissionRunStatusWebSocketEventDTO = (event) => {
2962
+ const isSubscribeSubmissionRunStatusWebSocketEventDto = (event) => {
3020
2963
  return isWebsocketSubscription(event)
3021
2964
  && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSION_RUN_STATUS
3022
2965
  && typeof event?.submitId === 'string' && !!event.submitId;
3023
2966
  };
3024
- const isUnsubscribeSubmissionRunStatusWebSocketEventDTO = (event) => {
2967
+ const isUnsubscribeSubmissionRunStatusWebSocketEventDto = (event) => {
3025
2968
  return isWebsocketSubscription(event)
3026
2969
  && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSION_RUN_STATUS
3027
2970
  && typeof event?.submitId === 'string' && !!event.submitId;
3028
2971
  };
3029
- const isSubscribeGetDataWebSocketEventDTO = (event) => {
2972
+ const isSubscribeGetDataWebSocketEventDto = (event) => {
3030
2973
  return isWebsocketSubscription(event)
3031
2974
  && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_GET_DATA;
3032
2975
  };
3033
- const isUnsubscribeGetDataWebSocketEventDTO = (event) => {
2976
+ const isUnsubscribeGetDataWebSocketEventDto = (event) => {
3034
2977
  return isWebsocketSubscription(event)
3035
2978
  && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_GET_DATA;
3036
2979
  };
3037
- const isSubscribeProblemCrawledWebSocketEventDTO = (event) => {
2980
+ const isSubscribeProblemCrawledWebSocketEventDto = (event) => {
3038
2981
  return isWebsocketSubscription(event)
3039
2982
  && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_PROBLEM_CRAWLED;
3040
2983
  };
3041
- const isUnsubscribeProblemCrawledWebSocketEventDTO = (event) => {
2984
+ const isUnsubscribeProblemCrawledWebSocketEventDto = (event) => {
3042
2985
  return isWebsocketSubscription(event)
3043
2986
  && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_PROBLEM_CRAWLED;
3044
2987
  };
3045
- const isSubscribeSubmissionsCrawlWebSocketEventDTO = (event) => {
2988
+ const isSubscribeSubmissionsCrawlWebSocketEventDto = (event) => {
3046
2989
  return isWebsocketSubscription(event)
3047
2990
  && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSIONS_CRAWL;
3048
2991
  };
3049
- const isUnsubscribeSubmissionsCrawlWebSocketEventDTO = (event) => {
2992
+ const isUnsubscribeSubmissionsCrawlWebSocketEventDto = (event) => {
3050
2993
  return isWebsocketSubscription(event)
3051
2994
  && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSIONS_CRAWL;
3052
2995
  };
3053
- const isSubscribeContestChangesWebSocketEventDTO = (event) => {
2996
+ const isSubscribeContestChangesWebSocketEventDto = (event) => {
3054
2997
  return isWebsocketSubscription(event)
3055
2998
  && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_CONTEST_CHANGES;
3056
2999
  };
3057
- const isUnsubscribeContestChangesWebSocketEventDTO = (event) => {
3000
+ const isUnsubscribeContestChangesWebSocketEventDto = (event) => {
3058
3001
  return isWebsocketSubscription(event)
3059
3002
  && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_CONTEST_CHANGES;
3060
3003
  };
3061
- const isSubscribeClientTrackWebSocketEventDTO = (event) => {
3062
- return isWebsocketSubscription(event)
3063
- && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK;
3064
- };
3065
- const isUnsubscribeClientTrackWebSocketEventDTO = (event) => {
3066
- return isWebsocketSubscription(event)
3067
- && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK;
3068
- };
3069
- const isSubscribeUserNotificationWebSocketEventDTO = (event) => {
3004
+ const isSubscribeUserNotificationWebSocketEventDto = (event) => {
3070
3005
  return isWebsocketSubscription(event)
3071
3006
  && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_USER_NOTIFICATION;
3072
3007
  };
3073
- const isUnsubscribeUserNotificationWebSocketEventDTO = (event) => {
3008
+ const isUnsubscribeUserNotificationWebSocketEventDto = (event) => {
3074
3009
  return isWebsocketSubscription(event)
3075
3010
  && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_USER_NOTIFICATION;
3076
3011
  };
3077
- const isSubscribeClientTrackDataWebSocketEventDTO = (event) => {
3012
+ const isNonEmptyString = (value) => typeof value === 'string' && !!value;
3013
+ /**
3014
+ * Exactly one of `problemKey` / `contestKey` / `userId` is set.
3015
+ */
3016
+ const isSubmissionsJudgingScope = (scope) => {
3017
+ return [scope?.problemKey, scope?.contestKey, scope?.userId].filter(isNonEmptyString).length === 1;
3018
+ };
3019
+ const isSubscribeSubmissionsJudgingWebSocketEventDto = (event) => {
3078
3020
  return isWebsocketSubscription(event)
3079
- && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_CLIENT_TRACK_DATA
3080
- && typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
3021
+ && event?.event === WebSocketSubscriptionEvent.SUBSCRIBE_SUBMISSIONS_JUDGING
3022
+ && isSubmissionsJudgingScope(event);
3081
3023
  };
3082
- const isUnsubscribeClientTrackDataWebSocketEventDTO = (event) => {
3024
+ const isUnsubscribeSubmissionsJudgingWebSocketEventDto = (event) => {
3083
3025
  return isWebsocketSubscription(event)
3084
- && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_CLIENT_TRACK_DATA
3085
- && typeof event?.trackedClientId === 'string' && !!event.trackedClientId;
3026
+ && event?.event === WebSocketSubscriptionEvent.UNSUBSCRIBE_SUBMISSIONS_JUDGING
3027
+ && isSubmissionsJudgingScope(event);
3086
3028
  };
3087
- // is WebSocketResponseEventDTO, CHANNEL_SUBSCRIBE_CLIENT
3088
- const isWebSocketResponseEventDTO = (event) => {
3029
+ // is WebSocketResponseEventDto, CHANNEL_SUBSCRIBE_CLIENT
3030
+ const isWebSocketResponseEventDto = (event) => {
3089
3031
  return Object.values(WebSocketResponseEvent).includes(event?.event)
3090
3032
  && typeof event?.key === 'string'
3091
3033
  && typeof event?.connectionId === 'string'
3092
- && typeof event?.messageTimestamp === 'number' && !!event.messageTimestamp;
3093
- };
3094
- const isPongWebSocketResponseEventDTO = (event) => {
3095
- return isWebSocketResponseEventDTO(event)
3096
- && event?.event === WebSocketResponseEvent.PONG
3097
- && !!event?.data;
3034
+ && typeof event?.createdAt === 'number' && !!event.createdAt;
3098
3035
  };
3099
- const isCodeRunStatusMessageWebSocketResponseEventDTO = (event) => {
3100
- return isWebSocketResponseEventDTO(event)
3036
+ const isCodeRunStatusMessageWebSocketResponseEventDto = (event) => {
3037
+ return isWebSocketResponseEventDto(event)
3101
3038
  && event?.event === WebSocketResponseEvent.CODE_RUN_STATUS
3102
3039
  && typeof event?.runId === 'string' && !!event.runId
3103
3040
  && event?.status in SubmissionRunStatus;
3104
3041
  };
3105
- const isSubmissionRunStatusMessageWebSocketResponseEventDTO = (event) => {
3106
- return isWebSocketResponseEventDTO(event)
3042
+ const isSubmissionRunStatusMessageWebSocketResponseEventDto = (event) => {
3043
+ return isWebSocketResponseEventDto(event)
3107
3044
  && event?.event === WebSocketResponseEvent.SUBMISSION_RUN_STATUS
3108
3045
  && typeof event?.submitId === 'string' && !!event.submitId
3109
3046
  && event?.status in SubmissionRunStatus
3110
3047
  && event?.verdict in ProblemVerdict
3111
3048
  && typeof event?.points === 'number';
3112
3049
  };
3113
- const isUserMessageWebSocketResponseEventDTO = (event) => {
3114
- return isWebSocketResponseEventDTO(event)
3050
+ const isSubmissionJudgingWebSocketResponseEventDto = (event) => {
3051
+ return isWebSocketResponseEventDto(event)
3052
+ && event?.event === WebSocketResponseEvent.SUBMISSION_JUDGING
3053
+ && isNonEmptyString(event?.submitId)
3054
+ && isNonEmptyString(event?.problemKey)
3055
+ && (event?.contestKey === null || isNonEmptyString(event?.contestKey))
3056
+ && isNonEmptyString(event?.userId)
3057
+ && typeof event?.judging === 'boolean'
3058
+ && event?.status in SubmissionRunStatus
3059
+ && event?.verdict in ProblemVerdict
3060
+ && typeof event?.points === 'number';
3061
+ };
3062
+ const isUserMessageWebSocketResponseEventDto = (event) => {
3063
+ return isWebSocketResponseEventDto(event)
3115
3064
  && event?.event === WebSocketResponseEvent.USER_MESSAGE
3116
3065
  && typeof event?.user?.nickname === 'string' && !!event.user?.nickname
3117
3066
  && typeof event?.user?.imageUrl === 'string' && !!event.user?.imageUrl
3118
- && typeof event?.user?.company?.key === 'string' && !!event.user?.company?.key
3067
+ && typeof event?.user?.organization?.key === 'string' && !!event.user?.organization?.key
3119
3068
  && !!event?.content;
3120
3069
  };
3121
- const isSendDataWebSocketResponseEventDTO = (event) => {
3070
+ const isSendDataWebSocketResponseEventDto = (event) => {
3122
3071
  return [
3123
3072
  WebSocketResponseEvent.SEND_DATA_ECS_TASK_DEFINITIONS_LIST,
3124
3073
  WebSocketResponseEvent.SEND_DATA_EC2_INSTANCES_LIST,
3125
3074
  WebSocketResponseEvent.SEND_DATA_ECS_TASKS_LIST,
3126
3075
  WebSocketResponseEvent.SEND_DATA_SSM_SESSIONS_LIST,
3127
3076
  WebSocketResponseEvent.SEND_DATA_RUN_COMMAND,
3128
- WebSocketResponseEvent.SEND_DATA_CLIENT_TRACK,
3129
- WebSocketResponseEvent.SEND_DATA_CHAT_COMPLETIONS,
3130
3077
  ].includes(event?.event)
3131
3078
  && typeof event?.dataId === 'string' && !!event.dataId
3132
3079
  && !!event?.content;
3133
3080
  };
3134
- const isSendDataEcsTaskDefinitionListWebSocketResponseEventDTO = (event) => {
3135
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3081
+ const isSendDataEcsTaskDefinitionListWebSocketResponseEventDto = (event) => {
3082
+ return isWebSocketResponseEventDto(event) && isSendDataWebSocketResponseEventDto(event)
3136
3083
  && event?.event === WebSocketResponseEvent.SEND_DATA_ECS_TASK_DEFINITIONS_LIST;
3137
3084
  };
3138
- const isSendDataEc2InstancesListWebSocketResponseEventDTO = (event) => {
3139
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3085
+ const isSendDataEc2InstancesListWebSocketResponseEventDto = (event) => {
3086
+ return isWebSocketResponseEventDto(event) && isSendDataWebSocketResponseEventDto(event)
3140
3087
  && event?.event === WebSocketResponseEvent.SEND_DATA_EC2_INSTANCES_LIST;
3141
3088
  };
3142
- const isSendDataEcsTasksListWebSocketResponseEventDTO = (event) => {
3143
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3089
+ const isSendDataEcsTasksListWebSocketResponseEventDto = (event) => {
3090
+ return isWebSocketResponseEventDto(event) && isSendDataWebSocketResponseEventDto(event)
3144
3091
  && event?.event === WebSocketResponseEvent.SEND_DATA_ECS_TASKS_LIST;
3145
3092
  };
3146
- const isSendDataSsmSessionsListWebSocketResponseEventDTO = (event) => {
3147
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3093
+ const isSendDataSsmSessionsListWebSocketResponseEventDto = (event) => {
3094
+ return isWebSocketResponseEventDto(event) && isSendDataWebSocketResponseEventDto(event)
3148
3095
  && event?.event === WebSocketResponseEvent.SEND_DATA_SSM_SESSIONS_LIST;
3149
3096
  };
3150
- const isSendDataRunCommandWebSocketResponseEventDTO = (event) => {
3151
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3097
+ const isSendDataRunCommandWebSocketResponseEventDto = (event) => {
3098
+ return isWebSocketResponseEventDto(event) && isSendDataWebSocketResponseEventDto(event)
3152
3099
  && event?.event === WebSocketResponseEvent.SEND_DATA_RUN_COMMAND;
3153
3100
  };
3154
- const isSendDataClientTrackWebSocketResponseEventDTO = (event) => {
3155
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3156
- && event?.event === WebSocketResponseEvent.SEND_DATA_CLIENT_TRACK;
3157
- };
3158
- const isSenDataChatCompletionsWebSocketResponseEventDTO = (event) => {
3159
- return isWebSocketResponseEventDTO(event) && isSendDataWebSocketResponseEventDTO(event)
3160
- && event?.event === WebSocketResponseEvent.SEND_DATA_CHAT_COMPLETIONS;
3161
- };
3162
- const isProblemCrawledWebSocketResponseEventDTO = (event) => {
3163
- return isWebSocketResponseEventDTO(event)
3101
+ const isProblemCrawledWebSocketResponseEventDto = (event) => {
3102
+ return isWebSocketResponseEventDto(event)
3164
3103
  && event?.event === WebSocketResponseEvent.PROBLEM_CRAWLED
3165
3104
  && !!event?.content;
3166
3105
  };
3167
- const isSubmissionsCrawlWebSocketResponseEventDTO = (event) => {
3168
- return isWebSocketResponseEventDTO(event)
3106
+ const isSubmissionsCrawlWebSocketResponseEventDto = (event) => {
3107
+ return isWebSocketResponseEventDto(event)
3169
3108
  && event?.event === WebSocketResponseEvent.SUBMISSIONS_CRAWL
3170
3109
  && !!event?.content;
3171
3110
  };
3172
- const isContestChangesWebSocketResponseEventDTO = (event) => {
3173
- return isWebSocketResponseEventDTO(event)
3111
+ const isContestChangesWebSocketResponseEventDto = (event) => {
3112
+ return isWebSocketResponseEventDto(event)
3174
3113
  && event?.event === WebSocketResponseEvent.CONTEST_CHANGES
3175
3114
  && !!event?.content;
3176
3115
  };
3177
- const isClientTrackWebSocketResponseEventDTO = (event) => {
3178
- return isWebSocketResponseEventDTO(event)
3179
- && event?.event === WebSocketResponseEvent.CLIENT_TRACK;
3180
- };
3181
- const isUserNotificationWebSocketResponseEventDTO = (event) => {
3116
+ const isUserNotificationWebSocketResponseEventDto = (event) => {
3182
3117
  return [
3183
3118
  WebSocketResponseEvent.USER_NOTIFICATION_SUBMISSION,
3184
3119
  WebSocketResponseEvent.USER_NOTIFICATION_CONTEST_CLARIFICATION,
3185
3120
  ].includes(event?.event)
3186
3121
  && !!event?.content;
3187
3122
  };
3188
- const isUserNotificationSubmissionWebSocketResponseEventDTO = (event) => {
3189
- return isWebSocketResponseEventDTO(event) && isUserNotificationWebSocketResponseEventDTO(event)
3123
+ const isUserNotificationSubmissionWebSocketResponseEventDto = (event) => {
3124
+ return isWebSocketResponseEventDto(event) && isUserNotificationWebSocketResponseEventDto(event)
3190
3125
  && event?.event === WebSocketResponseEvent.USER_NOTIFICATION_SUBMISSION;
3191
3126
  };
3192
- const isUserNotificationContestClarificationWebSocketResponseEventDTO = (event) => {
3193
- return isWebSocketResponseEventDTO(event) && isUserNotificationWebSocketResponseEventDTO(event)
3127
+ const isUserNotificationContestClarificationWebSocketResponseEventDto = (event) => {
3128
+ return isWebSocketResponseEventDto(event) && isUserNotificationWebSocketResponseEventDto(event)
3194
3129
  && event?.event === WebSocketResponseEvent.USER_NOTIFICATION_CONTEST_CLARIFICATION;
3195
3130
  };
3196
3131
  // generic
3197
3132
  const getWebSocketResponseEventKey = (event, clientId, id) => {
3198
3133
  return `${event}-${clientId}-${id}`;
3199
3134
  };
3200
- const isWebSocketChannelsMessageDTO = (message) => {
3135
+ const isWebSocketChannelsMessageDto = (message) => {
3201
3136
  return Array.isArray(message?.channels)
3202
3137
  && message.channels.every((channel) => typeof channel === 'string' && !!channel)
3203
3138
  && Object.values(WebSocketResponseEvent).includes(message?.event?.event);
3204
3139
  };
3205
3140
  /**
3206
3141
  * Key used by the client to dispatch a response received on a TOPIC channel to its subscribers.
3207
- * It is the same key that `getKeyWebSocketEventDTO` (base-ui) computes for the subscription.
3142
+ * It is the same key that `getKeyWebSocketEventDto` (base-ui) computes for the subscription.
3208
3143
  * Returns null when the response is not addressed to this client.
3209
3144
  */
3210
3145
  const getWebSocketResponseEventKeyOfResponse = (response, clientId) => {
3211
- if (isCodeRunStatusMessageWebSocketResponseEventDTO(response)) {
3146
+ if (isCodeRunStatusMessageWebSocketResponseEventDto(response)) {
3212
3147
  return getWebSocketResponseEventKey(WebSocketResponseEvent.CODE_RUN_STATUS, clientId, response.runId);
3213
3148
  }
3214
- if (isSubmissionRunStatusMessageWebSocketResponseEventDTO(response)) {
3149
+ if (isSubmissionRunStatusMessageWebSocketResponseEventDto(response)) {
3215
3150
  return getWebSocketResponseEventKey(WebSocketResponseEvent.SUBMISSION_RUN_STATUS, clientId, response.submitId);
3216
3151
  }
3217
- if (isSendDataWebSocketResponseEventDTO(response)) {
3152
+ if (isSendDataWebSocketResponseEventDto(response)) {
3218
3153
  return getWebSocketResponseEventKey(WebSocketResponseEvent.SEND_DATA_, clientId, response.dataId);
3219
3154
  }
3220
- if (isContestChangesWebSocketResponseEventDTO(response)) {
3155
+ if (isContestChangesWebSocketResponseEventDto(response)) {
3221
3156
  return getWebSocketResponseEventKey(WebSocketResponseEvent.CONTEST_CHANGES, clientId, response.content.contestKey);
3222
3157
  }
3223
- if (isProblemCrawledWebSocketResponseEventDTO(response)) {
3158
+ if (isProblemCrawledWebSocketResponseEventDto(response)) {
3224
3159
  return getWebSocketResponseEventKey(WebSocketResponseEvent.PROBLEM_CRAWLED, clientId, response.content.problemKey);
3225
3160
  }
3226
- if (isSubmissionsCrawlWebSocketResponseEventDTO(response)) {
3161
+ if (isSubmissionsCrawlWebSocketResponseEventDto(response)) {
3227
3162
  return getWebSocketResponseEventKey(WebSocketResponseEvent.SUBMISSIONS_CRAWL, clientId, join([response.content.contestKey, response.content.problemKeys]));
3228
3163
  }
3229
- if (isClientTrackWebSocketResponseEventDTO(response)) {
3230
- // the command is sent to the session channel, `key` holds the targeted client
3231
- return response.key === clientId ? getWebSocketResponseEventKey(WebSocketResponseEvent.CLIENT_TRACK, clientId, '*') : null;
3232
- }
3233
- if (isUserNotificationWebSocketResponseEventDTO(response)) {
3164
+ if (isUserNotificationWebSocketResponseEventDto(response)) {
3234
3165
  return getWebSocketResponseEventKey(WebSocketResponseEvent.USER_NOTIFICATION_, clientId, '*');
3235
3166
  }
3167
+ if (isSubmissionJudgingWebSocketResponseEventDto(response)) {
3168
+ // one key for every table: the same event is published on several channels (problem / contest / user) and the
3169
+ // client deduplicates it, so it is dispatched once; each table filters by the submissions it lists
3170
+ return getWebSocketResponseEventKey(WebSocketResponseEvent.SUBMISSION_JUDGING, clientId, '*');
3171
+ }
3236
3172
  return null;
3237
3173
  };
3238
3174
  /**
@@ -3241,17 +3177,25 @@ const getWebSocketResponseEventKeyOfResponse = (response, clientId) => {
3241
3177
  * Ably rejects the attach if the token has no capability for the channel.
3242
3178
  */
3243
3179
  const getChannelOfWebSocketSubscribeEvent = (event) => {
3244
- if (isSubscribeSubmissionRunStatusWebSocketEventDTO(event)) {
3180
+ if (isSubscribeSubmissionRunStatusWebSocketEventDto(event)) {
3245
3181
  return CHANNEL_SUBMISSION(event.submitId);
3246
3182
  }
3247
- if (isSubscribeProblemCrawledWebSocketEventDTO(event)) {
3248
- return CHANNEL_PROBLEM(event.problemKey);
3249
- }
3250
- if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
3183
+ // SUBSCRIBE_PROBLEM_CRAWLED: the event arrives by the private user channel of who requested the crawl
3184
+ if (isSubscribeContestChangesWebSocketEventDto(event) || isSubscribeSubmissionsCrawlWebSocketEventDto(event)) {
3251
3185
  return CHANNEL_CONTEST(event.contestKey, ContestChannelRole.SPECTATORS);
3252
3186
  }
3253
- if (isSubscribeClientTrackDataWebSocketEventDTO(event)) {
3254
- return CHANNEL_CLIENT_TRACK(event.trackedClientId);
3187
+ if (isSubscribeSubmissionsJudgingWebSocketEventDto(event)) {
3188
+ // the judging start/end is published on the spectators channel when it is visible to everyone; the hidden ones
3189
+ // (frozen / quiet contests) arrive by the role channels of the contest (managers) and the private user channel
3190
+ if ('problemKey' in event && event.problemKey) {
3191
+ return CHANNEL_PROBLEM(event.problemKey, ProblemChannelRole.SPECTATORS);
3192
+ }
3193
+ if ('contestKey' in event && event.contestKey) {
3194
+ return CHANNEL_CONTEST(event.contestKey, ContestChannelRole.SPECTATORS);
3195
+ }
3196
+ if ('userId' in event && event.userId) {
3197
+ return CHANNEL_USER_ROLE(event.userId, UserChannelRole.SPECTATORS);
3198
+ }
3255
3199
  }
3256
3200
  return null;
3257
3201
  };
@@ -3259,11 +3203,23 @@ const getChannelOfWebSocketSubscribeEvent = (event) => {
3259
3203
  * Contest whose role channels the client needs (the API grants them when the token is requested with this contest).
3260
3204
  */
3261
3205
  const getContestKeyOfWebSocketSubscribeEvent = (event) => {
3262
- if (isSubscribeContestChangesWebSocketEventDTO(event) || isSubscribeSubmissionsCrawlWebSocketEventDTO(event)) {
3206
+ if (isSubscribeContestChangesWebSocketEventDto(event) || isSubscribeSubmissionsCrawlWebSocketEventDto(event)) {
3207
+ return event.contestKey;
3208
+ }
3209
+ if (isSubscribeSubmissionsJudgingWebSocketEventDto(event) && 'contestKey' in event && event.contestKey) {
3263
3210
  return event.contestKey;
3264
3211
  }
3265
3212
  return null;
3266
3213
  };
3214
+ /**
3215
+ * Problem whose role channels the client needs (the API grants them when the token is requested with this problem).
3216
+ */
3217
+ const getProblemKeyOfWebSocketSubscribeEvent = (event) => {
3218
+ if (isSubscribeSubmissionsJudgingWebSocketEventDto(event) && 'problemKey' in event && event.problemKey) {
3219
+ return event.problemKey;
3220
+ }
3221
+ return null;
3222
+ };
3267
3223
 
3268
3224
  function splitTime(timeRemaining) {
3269
3225
  const remaining = [];
@@ -3334,44 +3290,13 @@ function splitTime(timeRemaining) {
3334
3290
  // }
3335
3291
  return remaining;
3336
3292
  }
3337
- function normalizeToLocalStartOfDay(timestamp) {
3338
- const date = new Date(timestamp);
3339
- return new Date(date.getFullYear(), date.getMonth(), date.getDate());
3340
- }
3341
- function normalizeToLocalStartOfHour(timestamp) {
3342
- const date = new Date(timestamp);
3343
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours());
3344
- }
3345
- function normalizeToLocalStartOfMinutes(timestamp) {
3346
- const date = new Date(timestamp);
3347
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
3348
- }
3349
- function normalizeToLocalStartOfSeconds(timestamp) {
3350
- const date = new Date(timestamp);
3351
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes());
3352
- }
3353
- const getYears = (d) => d.getFullYear();
3354
- const getMonths = (d) => d.getFullYear() * 12 + d.getMonth();
3355
- const getDays = (d) => {
3356
- return Math.floor(normalizeToLocalStartOfDay(d).getTime() / ONE_DAY);
3357
- };
3358
- const getHours = (d) => {
3359
- return Math.floor(normalizeToLocalStartOfHour(d).getTime() / ONE_HOUR);
3360
- };
3361
- const getMinutes = (d) => {
3362
- return Math.floor(normalizeToLocalStartOfMinutes(d).getTime() / ONE_MINUTE);
3363
- };
3364
- const getSeconds = (d) => {
3365
- return Math.floor(normalizeToLocalStartOfSeconds(d).getTime() / 1000);
3366
- };
3367
- const getMilliseconds = (d) => d.getTime();
3368
3293
 
3369
- const getUserKey = (userNickname, userCompanyKey) => {
3370
- return userNickname + '|' + userCompanyKey;
3294
+ const getUserKey = (userNickname, userOrganizationKey) => {
3295
+ return userNickname + '|' + userOrganizationKey;
3371
3296
  };
3372
3297
  const getParamsOfUserKey = (userKey) => {
3373
- const [userNickname, userCompanyKey] = userKey.split('|');
3374
- return { userNickname, userCompanyKey };
3298
+ const [userNickname, userOrganizationKey] = userKey.split('|');
3299
+ return { userNickname, userOrganizationKey };
3375
3300
  };
3376
3301
  const getClientId = (sessionId, uiId) => {
3377
3302
  return `${sessionId}|${uiId}`;
@@ -3487,4 +3412,4 @@ const isQuizTextSheet = (value) => {
3487
3412
  && ['text', 'number', 'textarea'].includes(value?.inputType);
3488
3413
  };
3489
3414
 
3490
- export { ACCEPTED_PROGRAMMING_LANGUAGES, ASPECT_RATIO, AspectRatio, AssignmentClass, AssignmentState, AssignmentType, CHANNEL_CLIENT_TRACK, CHANNEL_CLIENT_TRACK_ALL, CHANNEL_COMPANY_PRESENCE, 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 };
3415
+ export { ACCEPTED_PROGRAMMING_LANGUAGES, ASPECT_RATIO, AspectRatio, AssignmentClass, AssignmentState, AssignmentType, CHANNEL_CONTEST, CHANNEL_ORGANIZATION_PRESENCE, CHANNEL_PROBLEM, CHANNEL_SESSION, CHANNEL_SUBMISSION, CHANNEL_SUBMISSION_ALL, CHANNEL_USER, CHANNEL_USER_ROLE, CHANNEL_USER_SPECTATORS_ALL, CODE_LANGUAGE, CONTEST_ROLE, CONTEST_STATUS, COOKIE_JUKI_SESSION_ID, COURSE_ROLE, CodeLanguage, CollectionKey, 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_EMAIL_TEMPLATE, JUKI_APP_ORGANIZATION_KEY, 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, ORGANIZATION_PLAN, OrganizationLogoType, OrganizationPlan, PAGE, PAGE_SIZE, PAGE_SIZES, PALLETE, PROBLEM_INPUT, PROBLEM_MODE, PROBLEM_MODES, PROBLEM_OUTPUT, PROBLEM_ROLE, PROBLEM_TYPE, PROBLEM_TYPES, PROBLEM_VERDICT, PROBLEM_VERDICTS, ProblemChannelRole, 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, UserChannelRole, UserRole, UserStatus, UserTeamStatus, WebSocketResponseEvent, WebSocketSubscriptionEvent, WorkingIn, WorksheetType, YEARS, _KEY, _SUB_SUB_TAB, _SUB_TAB, _TAB, _TYPE, areArraysDifferent, changeDay, changeHours, changeMilliseconds, changeMinutes, changeMonth, changeSeconds, changeYear, chunkString, cleanRequest, clearAsyncInterval, consoleError, consoleInfo, consoleWarn, contentResponse, contentsResponse, decreaseDay, decreaseMonth, decreaseYear, endOfDay, endOfHour, endOfMinute, endOfMonth, endOfSecond, endOfWeek, endOfYear, errorsResponse, getAssignmentCommentKey, getAssignmentUserCommentKey, getChannelOfWebSocketSubscribeEvent, getClientId, getContestChannelParams, getContestCommentKey, getContestKeyOfWebSocketSubscribeEvent, getDataLog, getDataOfTestCase, getDays, getDefaultMeta, getDocumentAccess, getHours, getMilliseconds, getMinutes, getMonths, getParamsOfClientId, getParamsOfUserKey, getPlainText, getProblemChannelParams, getProblemCommentKey, getProblemJudgeKey, getProblemKeyOfWebSocketSubscribeEvent, getRandomString, getSeconds, getSummaryWorksheetsInPages, getTotalExercisesOfSummaryWorksheetsInPages, getUserKey, getVerdictFromTestCase, getWebSocketResponseEventKey, getWebSocketResponseEventKeyOfResponse, getWorksheetsInPages, getYears, humanFileSize, increaseDay, increaseMonth, increaseYear, indexToLetters, isAfter, isBasicWorksheet, isBefore, isCodeEditorSheet, isCodeRunStatusMessageWebSocketResponseEventDto, isContestAssignment, isContestChangesWebSocketResponseEventDto, isCourseAssignment, isDayAfter, isDayBefore, isEndlessContest, isEqual, isFutureContest, isGlobalContest, isHoursAfter, isHoursBefore, isJkmdSheet, isMillisecondsAfter, isMillisecondsBefore, isMinutesAfter, isMinutesBefore, isMonthAfter, isMonthBefore, isObjectJson, isPastContest, isProblemCrawledWebSocketResponseEventDto, isQuizOptionsSheet, isQuizProblemSheet, isQuizTextSheet, isSameDay, isSameHour, isSameMillisecond, isSameMinute, isSameMonth, isSameSecond, isSameYear, isSecondsAfter, isSecondsBefore, isSendDataEc2InstancesListWebSocketResponseEventDto, isSendDataEcsTaskDefinitionListWebSocketResponseEventDto, isSendDataEcsTasksListWebSocketResponseEventDto, isSendDataRunCommandWebSocketResponseEventDto, isSendDataSsmSessionsListWebSocketResponseEventDto, isSendDataWebSocketResponseEventDto, isStringJson, isSubmissionJudgingWebSocketResponseEventDto, isSubmissionRunStatusMessageWebSocketResponseEventDto, isSubmissionsCrawlWebSocketResponseEventDto, isSubmissionsJudgingScope, isSubscribeCodeRunStatusWebSocketEventDto, isSubscribeContestChangesWebSocketEventDto, isSubscribeGetDataWebSocketEventDto, isSubscribeProblemCrawledWebSocketEventDto, isSubscribeSubmissionRunStatusWebSocketEventDto, isSubscribeSubmissionsCrawlWebSocketEventDto, isSubscribeSubmissionsJudgingWebSocketEventDto, isSubscribeUserNotificationWebSocketEventDto, isTeamMember, isToday, isUnsubscribeCodeRunStatusWebSocketEventDto, isUnsubscribeContestChangesWebSocketEventDto, isUnsubscribeGetDataWebSocketEventDto, isUnsubscribeProblemCrawledWebSocketEventDto, isUnsubscribeSubmissionRunStatusWebSocketEventDto, isUnsubscribeSubmissionsCrawlWebSocketEventDto, isUnsubscribeSubmissionsJudgingWebSocketEventDto, isUnsubscribeUserNotificationWebSocketEventDto, isUserMember, isUserMessageWebSocketResponseEventDto, isUserNotificationContestClarificationWebSocketResponseEventDto, isUserNotificationSubmissionWebSocketResponseEventDto, isUserNotificationWebSocketResponseEventDto, isValidDate, isWebSocketChannelsMessageDto, isWebSocketResponseEventDto, isWebsocketSubscription, isWithinInterval, isWorksheetAssignment, isYearAfter, isYearBefore, join, lettersToIndex, memorySizeOf, mergeVerdicts, mex, normalizeToLocalStartOfDay, normalizeToLocalStartOfHour, normalizeToLocalStartOfMinutes, normalizeToLocalStartOfSeconds, objectUpdate, objectsUpdate, padEnd, padStart, range, removeExtension, safeJsonParse, setAsyncInterval, split, splitTime, startOfDay, startOfHour, startOfMinute, startOfMonth, startOfSecond, startOfWeek, startOfYear, stringToArrayBuffer, toEntityMembersDto, toJkError };