@orjok/commons 1.0.2

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/index.cjs ADDED
@@ -0,0 +1,1723 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/services/user.service.ts
2
+ var UserService = class {
3
+ constructor(network) {
4
+ this.network = network;
5
+ }
6
+ async get(id) {
7
+ const result = await this.network.query(
8
+ `query GetUser($id: String!) {
9
+ getUser(id: $id) {
10
+ id fullName avatarUrl avatarConfig tier subscriptionExpiresAt
11
+ aiEvaluationRemaining questionCount packCount contestCount
12
+ EngineeringRating MedicalRating VarsityRating BCSRating
13
+ sscOverallRating sscPhysicsRating sscChemistryRating sscMathRating sscBiologyRating
14
+ hscOverallRating hscPhysicsRating hscChemistryRating hscMathRating hscBiologyRating
15
+ bcsOverallRating
16
+ }
17
+ }`,
18
+ { id }
19
+ );
20
+ return result.data.getUser;
21
+ }
22
+ async updateAvatar(input) {
23
+ const result = await this.network.mutate(
24
+ `mutation UpdateUser($input: UpdateUserInput!) {
25
+ updateUser(input: $input) {
26
+ id fullName avatarUrl avatarConfig
27
+ }
28
+ }`,
29
+ { input: { id: input.userId, avatarUrl: input.avatarUrl, avatarConfig: input.avatarConfig } }
30
+ );
31
+ return result.data.updateUser;
32
+ }
33
+ async getQuestions(userId, nextToken) {
34
+ const result = await this.network.query(
35
+ `query ListUserQuestions($owner: ID!, $nextToken: String, $sortDirection: ModelSortDirection) {
36
+ listQuestionObjectByOwnerAndCreatedAt(owner: $owner, sortDirection: $sortDirection, nextToken: $nextToken) {
37
+ items {
38
+ id question imageUrl language level difficulty type voteCount
39
+ verificationStatus owner packId createdAt
40
+ options { items { id content } }
41
+ tags { items { id tagId } }
42
+ }
43
+ nextToken
44
+ }
45
+ }`,
46
+ { owner: userId, nextToken, sortDirection: "DESC" }
47
+ );
48
+ return result.data.listQuestionObjectByOwnerAndCreatedAt;
49
+ }
50
+ async getPacks(userId, nextToken) {
51
+ const result = await this.network.query(
52
+ `query ListUserPacks($owner: ID!, $nextToken: String, $sortDirection: ModelSortDirection) {
53
+ listPackByOwnerAndCreatedAt(owner: $owner, sortDirection: $sortDirection, nextToken: $nextToken) {
54
+ items {
55
+ id name language level difficulty questionCount automaticNumbering
56
+ owner subjectId chapterId topicId verificationStatus createdAt
57
+ tags { items { id tagId } }
58
+ }
59
+ nextToken
60
+ }
61
+ }`,
62
+ { owner: userId, nextToken, sortDirection: "DESC" }
63
+ );
64
+ return result.data.listPackByOwnerAndCreatedAt;
65
+ }
66
+ async getCourses(userId) {
67
+ const result = await this.network.query(
68
+ `query ListUserCourses($owner: ID!, $sortDirection: ModelSortDirection) {
69
+ listCourseByOwnerAndCreatedAt(owner: $owner, sortDirection: $sortDirection) {
70
+ items {
71
+ id name description imageUrl videoCount fileCount price totalEnrolled owner createdAt
72
+ }
73
+ }
74
+ }`,
75
+ { owner: userId, sortDirection: "DESC" }
76
+ );
77
+ return result.data.listCourseByOwnerAndCreatedAt.items;
78
+ }
79
+ async getEnrolledCourses(userId) {
80
+ const result = await this.network.query(
81
+ `query ListEnrolledCourses($userId: ID!, $sortDirection: ModelSortDirection) {
82
+ listCourseEnrolledByUserIdAndCreatedAt(userId: $userId, sortDirection: $sortDirection) {
83
+ items {
84
+ id courseId userId score rank createdAt
85
+ course { id name description imageUrl price totalEnrolled }
86
+ }
87
+ }
88
+ }`,
89
+ { userId, sortDirection: "DESC" }
90
+ );
91
+ return result.data.listCourseEnrolledByUserIdAndCreatedAt.items;
92
+ }
93
+ };
94
+
95
+ // src/services/question.service.ts
96
+ var QuestionService = class {
97
+ constructor(network) {
98
+ this.network = network;
99
+ }
100
+ async create(input) {
101
+ const result = await this.network.mutate(
102
+ `mutation CreateQuestion($question: String!, $answer: String!, $options: String!, $language: String!, $level: String!, $difficulty: String!, $type: String, $explanation: String, $tags: String, $imagePayload: String, $optionsImagesPayload: String, $packId: ID, $order: Int, $contestId: ID, $subjectId: ID, $chapterId: ID, $topicId: ID, $extra: String, $markingInstructions: String) {
103
+ createQuestion(question: $question, answer: $answer, options: $options, language: $language, level: $level, difficulty: $difficulty, type: $type, explanation: $explanation, tags: $tags, imagePayload: $imagePayload, optionsImagesPayload: $optionsImagesPayload, packId: $packId, order: $order, contestId: $contestId, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId, extra: $extra, markingInstructions: $markingInstructions) {
104
+ status questionId
105
+ }
106
+ }`,
107
+ input
108
+ );
109
+ return result.data.createQuestion;
110
+ }
111
+ async get(id) {
112
+ const result = await this.network.query(
113
+ `query GetQuestion($id: String!) {
114
+ getQuestionObject(id: $id) {
115
+ id question imageUrl language level difficulty type voteCount
116
+ verificationStatus owner packId subjectId chapterId topicId order createdAt
117
+ options { items { id content } }
118
+ tags { items { id tagId } }
119
+ }
120
+ }`,
121
+ { id }
122
+ );
123
+ return result.data.getQuestionObject;
124
+ }
125
+ async getFull(id) {
126
+ const result = await this.network.query(
127
+ `query GetFullQuestion($id: String!) {
128
+ getQuestionObject(id: $id) {
129
+ id question answer explanation extra imageUrl language level difficulty type
130
+ markingInstructions voteCount verificationStatus owner packId
131
+ subjectId chapterId topicId order createdAt
132
+ options { items { id content } }
133
+ tags { items { id tagId } }
134
+ user { id fullName avatarUrl }
135
+ }
136
+ }`,
137
+ { id }
138
+ );
139
+ return result.data.getQuestionObject;
140
+ }
141
+ async getAnswer(id) {
142
+ const result = await this.network.query(
143
+ `query GetAnswer($id: String!) {
144
+ getQuestionObject(id: $id) { answer }
145
+ }`,
146
+ { id }
147
+ );
148
+ if (!result.data.getQuestionObject) return null;
149
+ return { id, content: result.data.getQuestionObject.answer };
150
+ }
151
+ async getQuestionId(packId, order) {
152
+ const result = await this.network.query(
153
+ `query GetQuestionId($packId: ID!, $order: ModelIntKeyConditionInput) {
154
+ listQuestionObjectByPackIdAndOrder(packId: $packId, order: $order, limit: 1) {
155
+ items { id }
156
+ }
157
+ }`,
158
+ { packId, order: { eq: order } }
159
+ );
160
+ return _nullishCoalesce(_optionalChain([result, 'access', _2 => _2.data, 'access', _3 => _3.listQuestionObjectByPackIdAndOrder, 'access', _4 => _4.items, 'access', _5 => _5[0], 'optionalAccess', _6 => _6.id]), () => ( null));
161
+ }
162
+ async update(id, fields) {
163
+ const result = await this.network.mutate(
164
+ `mutation UpdateQuestion($input: UpdateQuestionObjectInput!) {
165
+ updateQuestionObject(input: $input) {
166
+ id question answer explanation extra imageUrl language level difficulty type
167
+ markingInstructions voteCount owner packId subjectId chapterId topicId order createdAt
168
+ options { items { id content } }
169
+ }
170
+ }`,
171
+ { input: { id, ...fields } }
172
+ );
173
+ return result.data.updateQuestionObject;
174
+ }
175
+ async delete(id) {
176
+ const result = await this.network.mutate(
177
+ `mutation DeleteQuestion($input: DeleteQuestionObjectInput!) {
178
+ deleteQuestionObject(input: $input) { id }
179
+ }`,
180
+ { input: { id } }
181
+ );
182
+ return result.data.deleteQuestionObject;
183
+ }
184
+ async vote(input) {
185
+ const result = await this.network.mutate(
186
+ `mutation Vote($questionId: ID!, $type: String!, $modelType: String!) {
187
+ vote(questionId: $questionId, type: $type, modelType: $modelType) {
188
+ status id
189
+ }
190
+ }`,
191
+ input
192
+ );
193
+ return result.data.vote;
194
+ }
195
+ async upVote(questionId) {
196
+ return this.vote({ questionId, type: "upvote", modelType: "question" });
197
+ }
198
+ async downVote(questionId) {
199
+ return this.vote({ questionId, type: "downvote", modelType: "question" });
200
+ }
201
+ async verify(id, userId) {
202
+ const result = await this.network.mutate(
203
+ `mutation VerifyQuestion($input: CreateVerificationInput!) {
204
+ createVerification(input: $input) { id verifiedObjectId type userId }
205
+ }`,
206
+ { input: { verifiedObjectId: id, type: "question", userId } }
207
+ );
208
+ return result.data.createVerification;
209
+ }
210
+ async report(id, reason) {
211
+ const result = await this.network.mutate(
212
+ `mutation ReportQuestion($input: CreateQuestionReportInput!) {
213
+ createQuestionReport(input: $input) { id }
214
+ }`,
215
+ { input: { questionId: id, reason } }
216
+ );
217
+ return result.data.createQuestionReport;
218
+ }
219
+ async addTags(input) {
220
+ const result = await this.network.mutate(
221
+ `mutation AddQuestionTag($tags: String!, $packId: ID, $questionId: ID) {
222
+ addQuestionTag(tags: $tags, packId: $packId, questionId: $questionId) {
223
+ status
224
+ }
225
+ }`,
226
+ input
227
+ );
228
+ return result.data.addQuestionTag;
229
+ }
230
+ async listBySubject(input) {
231
+ const variables = {
232
+ subjectId: input.id,
233
+ sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
234
+ limit: _nullishCoalesce(input.limit, () => ( 20)),
235
+ nextToken: input.nextToken
236
+ };
237
+ const result = await this.network.query(
238
+ `query ListQuestionsBySubject($subjectId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
239
+ listQuestionObjectBySubjectIdAndCreatedAt(subjectId: $subjectId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
240
+ items {
241
+ id question imageUrl language level difficulty type voteCount
242
+ verificationStatus owner packId createdAt
243
+ options { items { id content } }
244
+ }
245
+ nextToken
246
+ }
247
+ }`,
248
+ variables
249
+ );
250
+ return result.data.listQuestionObjectBySubjectIdAndCreatedAt;
251
+ }
252
+ async listByChapter(input) {
253
+ const variables = {
254
+ chapterId: input.id,
255
+ sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
256
+ limit: _nullishCoalesce(input.limit, () => ( 20)),
257
+ nextToken: input.nextToken
258
+ };
259
+ const result = await this.network.query(
260
+ `query ListQuestionsByChapter($chapterId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
261
+ listQuestionObjectByChapterIdAndCreatedAt(chapterId: $chapterId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
262
+ items {
263
+ id question imageUrl language level difficulty type voteCount
264
+ verificationStatus owner packId createdAt
265
+ options { items { id content } }
266
+ }
267
+ nextToken
268
+ }
269
+ }`,
270
+ variables
271
+ );
272
+ return result.data.listQuestionObjectByChapterIdAndCreatedAt;
273
+ }
274
+ async listByTopic(input) {
275
+ const variables = {
276
+ topicId: input.id,
277
+ sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
278
+ limit: _nullishCoalesce(input.limit, () => ( 20)),
279
+ nextToken: input.nextToken
280
+ };
281
+ const result = await this.network.query(
282
+ `query ListQuestionsByTopic($topicId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
283
+ listQuestionObjectByTopicIdAndCreatedAt(topicId: $topicId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
284
+ items {
285
+ id question imageUrl language level difficulty type voteCount
286
+ verificationStatus owner packId createdAt
287
+ options { items { id content } }
288
+ }
289
+ nextToken
290
+ }
291
+ }`,
292
+ variables
293
+ );
294
+ return result.data.listQuestionObjectByTopicIdAndCreatedAt;
295
+ }
296
+ async listByRandomHash(input) {
297
+ const compositeKey = [input.language, input.difficulty].filter(Boolean).join("_");
298
+ const variables = {
299
+ subjectId: input.id,
300
+ sortDirection: _nullishCoalesce(input.sortDirection, () => ( "ASC")),
301
+ limit: _nullishCoalesce(input.limit, () => ( 1)),
302
+ language_difficulty_randomHash: input.randomHashFilter ? { beginsWith: compositeKey, ...input.randomHashFilter } : { beginsWith: compositeKey }
303
+ };
304
+ const result = await this.network.query(
305
+ `query ListByRandomHash($subjectId: String!, $language_difficulty_randomHash: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int) {
306
+ listQuestionObjectBySubjectIdAndLanguage_difficulty_randomHash(subjectId: $subjectId, language_difficulty_randomHash: $language_difficulty_randomHash, sortDirection: $sortDirection, limit: $limit) {
307
+ items {
308
+ id question imageUrl language level difficulty type voteCount
309
+ verificationStatus owner packId subjectId chapterId topicId createdAt
310
+ options { items { id content } }
311
+ }
312
+ nextToken
313
+ }
314
+ }`,
315
+ variables
316
+ );
317
+ return result.data.listQuestionObjectBySubjectIdAndLanguage_difficulty_randomHash;
318
+ }
319
+ };
320
+
321
+ // src/services/pack.service.ts
322
+ var PackService = class {
323
+ constructor(network) {
324
+ this.network = network;
325
+ }
326
+ async create(input) {
327
+ const result = await this.network.mutate(
328
+ `mutation CreatePack($name: String!, $level: String!, $language: String!, $difficulty: String!, $automaticNumbering: Boolean, $subjectId: ID, $chapterId: ID, $topicId: ID) {
329
+ createPackObject(name: $name, level: $level, language: $language, difficulty: $difficulty, automaticNumbering: $automaticNumbering, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId) {
330
+ status id
331
+ }
332
+ }`,
333
+ input
334
+ );
335
+ return result.data.createPackObject;
336
+ }
337
+ async get(id) {
338
+ const result = await this.network.query(
339
+ `query GetPack($id: ID!) {
340
+ getPack(id: $id) {
341
+ id name language level difficulty questionCount automaticNumbering
342
+ owner subjectId chapterId topicId packGroupId verificationStatus createdAt
343
+ tags { items { id tagId } }
344
+ user { id fullName avatarUrl }
345
+ }
346
+ }`,
347
+ { id }
348
+ );
349
+ return result.data.getPack;
350
+ }
351
+ async getFull(id) {
352
+ const result = await this.network.query(
353
+ `query GetFullPack($id: ID!) {
354
+ getPack(id: $id) {
355
+ id name language level difficulty questionCount automaticNumbering
356
+ owner subjectId chapterId topicId packGroupId verificationStatus createdAt
357
+ tags { items { id tagId } }
358
+ user { id fullName avatarUrl }
359
+ questions(sortDirection: ASC, limit: 200) {
360
+ items {
361
+ id question answer explanation extra imageUrl language level difficulty type
362
+ markingInstructions voteCount owner order createdAt
363
+ options { items { id content } }
364
+ tags { items { id tagId } }
365
+ }
366
+ }
367
+ }
368
+ }`,
369
+ { id }
370
+ );
371
+ return result.data.getPack;
372
+ }
373
+ async update(id, fields) {
374
+ const result = await this.network.mutate(
375
+ `mutation UpdatePack($input: UpdatePackInput!) {
376
+ updatePack(input: $input) {
377
+ id name language level difficulty questionCount automaticNumbering
378
+ owner subjectId chapterId topicId verificationStatus createdAt
379
+ }
380
+ }`,
381
+ { input: { id, ...fields } }
382
+ );
383
+ return result.data.updatePack;
384
+ }
385
+ async delete(id) {
386
+ const result = await this.network.mutate(
387
+ `mutation DeletePack($input: DeletePackInput!) {
388
+ deletePack(input: $input) { id }
389
+ }`,
390
+ { input: { id } }
391
+ );
392
+ return result.data.deletePack;
393
+ }
394
+ async verify(id, userId) {
395
+ const result = await this.network.mutate(
396
+ `mutation VerifyPack($input: CreateVerificationInput!) {
397
+ createVerification(input: $input) { id verifiedObjectId type userId }
398
+ }`,
399
+ { input: { verifiedObjectId: id, type: "pack", userId } }
400
+ );
401
+ return result.data.createVerification;
402
+ }
403
+ async report(id, reason) {
404
+ const result = await this.network.mutate(
405
+ `mutation ReportPack($input: CreatePackReportInput!) {
406
+ createPackReport(input: $input) { id }
407
+ }`,
408
+ { input: { packId: id, reason } }
409
+ );
410
+ return result.data.createPackReport;
411
+ }
412
+ async submitExam(packId, selectedOptions) {
413
+ const result = await this.network.mutate(
414
+ `mutation SubmitPackExam($packId: ID!, $selectedOptions: String!) {
415
+ submitPackExam(packId: $packId, selectedOptions: $selectedOptions) {
416
+ status id
417
+ }
418
+ }`,
419
+ { packId, selectedOptions: JSON.stringify(selectedOptions) }
420
+ );
421
+ return result.data.submitPackExam;
422
+ }
423
+ async getExams(userId, nextToken) {
424
+ const result = await this.network.query(
425
+ `query ListPackExams($owner: ID!, $sortDirection: ModelSortDirection, $nextToken: String) {
426
+ listPackExamResultsByOwnerAndCreatedAt(owner: $owner, sortDirection: $sortDirection, nextToken: $nextToken) {
427
+ items {
428
+ id packId selectedOptions aiEvaluations owner createdAt
429
+ pack { id name language level difficulty questionCount }
430
+ }
431
+ nextToken
432
+ }
433
+ }`,
434
+ { owner: userId, sortDirection: "DESC", nextToken }
435
+ );
436
+ return result.data.listPackExamResultsByOwnerAndCreatedAt;
437
+ }
438
+ async getExamResult(resultId) {
439
+ const result = await this.network.query(
440
+ `query GetPackExamResult($id: ID!) {
441
+ getPackExamResults(id: $id) {
442
+ id packId selectedOptions aiEvaluations owner createdAt
443
+ pack { id name language level difficulty questionCount }
444
+ }
445
+ }`,
446
+ { id: resultId }
447
+ );
448
+ return result.data.getPackExamResults;
449
+ }
450
+ async listBySubject(input) {
451
+ const result = await this.network.query(
452
+ `query ListPacksBySubject($subjectId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
453
+ listPackBySubjectIdAndCreatedAt(subjectId: $subjectId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
454
+ items {
455
+ id name language level difficulty questionCount owner createdAt verificationStatus
456
+ tags { items { id tagId } }
457
+ }
458
+ nextToken
459
+ }
460
+ }`,
461
+ { subjectId: input.id, sortDirection: "DESC", limit: _nullishCoalesce(input.limit, () => ( 20)), nextToken: input.nextToken }
462
+ );
463
+ return result.data.listPackBySubjectIdAndCreatedAt;
464
+ }
465
+ async listByChapter(input) {
466
+ const result = await this.network.query(
467
+ `query ListPacksByChapter($chapterId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
468
+ listPackByChapterIdAndCreatedAt(chapterId: $chapterId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
469
+ items {
470
+ id name language level difficulty questionCount owner createdAt verificationStatus
471
+ tags { items { id tagId } }
472
+ }
473
+ nextToken
474
+ }
475
+ }`,
476
+ { chapterId: input.id, sortDirection: "DESC", limit: _nullishCoalesce(input.limit, () => ( 20)), nextToken: input.nextToken }
477
+ );
478
+ return result.data.listPackByChapterIdAndCreatedAt;
479
+ }
480
+ async listByTopic(input) {
481
+ const result = await this.network.query(
482
+ `query ListPacksByTopic($topicId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
483
+ listPackByTopicIdAndCreatedAt(topicId: $topicId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
484
+ items {
485
+ id name language level difficulty questionCount owner createdAt verificationStatus
486
+ tags { items { id tagId } }
487
+ }
488
+ nextToken
489
+ }
490
+ }`,
491
+ { topicId: input.id, sortDirection: "DESC", limit: _nullishCoalesce(input.limit, () => ( 20)), nextToken: input.nextToken }
492
+ );
493
+ return result.data.listPackByTopicIdAndCreatedAt;
494
+ }
495
+ async listGroups(type, level) {
496
+ const queryField = level ? "listPackGroupByTypeLevelAndOrder" : "listPackGroupByTypeAndOrder";
497
+ const variables = level ? { typeLevel: `${type}_${level}`, sortDirection: "ASC" } : { type, sortDirection: "ASC" };
498
+ const result = await this.network.query(
499
+ level ? `query ListPackGroups($typeLevel: String!, $sortDirection: ModelSortDirection) {
500
+ listPackGroupByTypeLevelAndOrder(typeLevel: $typeLevel, sortDirection: $sortDirection) {
501
+ items { id name description imageUrl type level typeLevel packCount order }
502
+ }
503
+ }` : `query ListPackGroups($type: String!, $sortDirection: ModelSortDirection) {
504
+ listPackGroupByTypeAndOrder(type: $type, sortDirection: $sortDirection) {
505
+ items { id name description imageUrl type level typeLevel packCount order }
506
+ }
507
+ }`,
508
+ variables
509
+ );
510
+ return result.data[queryField].items;
511
+ }
512
+ async getGroup(id) {
513
+ const result = await this.network.query(
514
+ `query GetPackGroup($id: ID!) {
515
+ getPackGroup(id: $id) {
516
+ id name description imageUrl type level typeLevel packCount order
517
+ packs { items { id name language level difficulty questionCount owner createdAt verificationStatus } }
518
+ }
519
+ }`,
520
+ { id }
521
+ );
522
+ return result.data.getPackGroup;
523
+ }
524
+ };
525
+
526
+ // src/services/contest.service.ts
527
+ var ContestService = class {
528
+ constructor(network) {
529
+ this.network = network;
530
+ }
531
+ async create(input) {
532
+ const result = await this.network.mutate(
533
+ `mutation MakeContest($name: String!, $description: String!, $level: String!, $language: String!, $startTime: AWSDateTime!, $endTime: AWSDateTime!, $subject: String!, $isRated: Boolean!, $questions: String!, $maximumParticipants: Int!, $solutionVideoUrl: String, $imageUrl: String) {
534
+ makeContest(name: $name, description: $description, level: $level, language: $language, startTime: $startTime, endTime: $endTime, subject: $subject, isRated: $isRated, questions: $questions, maximumParticipants: $maximumParticipants, solutionVideoUrl: $solutionVideoUrl, imageUrl: $imageUrl) {
535
+ status id
536
+ }
537
+ }`,
538
+ input
539
+ );
540
+ return result.data.makeContest;
541
+ }
542
+ async get(id) {
543
+ const result = await this.network.query(
544
+ `query GetContest($id: ID!) {
545
+ getContest(id: $id) {
546
+ id name description startTime endTime level language owner isRated subject
547
+ totalQuestions resultsPublished totalParticipants maximumParticipants
548
+ rankings globalPk solutionVideoUrl imageUrl
549
+ }
550
+ }`,
551
+ { id }
552
+ );
553
+ return result.data.getContest;
554
+ }
555
+ async getName(id) {
556
+ const result = await this.network.query(
557
+ `query GetContestName($id: ID!) { getContest(id: $id) { name } }`,
558
+ { id }
559
+ );
560
+ return _nullishCoalesce(_optionalChain([result, 'access', _7 => _7.data, 'access', _8 => _8.getContest, 'optionalAccess', _9 => _9.name]), () => ( null));
561
+ }
562
+ async list(nextToken, level) {
563
+ const variables = level ? { level, sortDirection: "DESC", nextToken } : { globalPk: "ALL", sortDirection: "DESC", nextToken };
564
+ const result = await this.network.query(
565
+ level ? `query ListContests($level: String!, $sortDirection: ModelSortDirection, $nextToken: String) {
566
+ listContestByLevelAndStartTime(level: $level, sortDirection: $sortDirection, nextToken: $nextToken) {
567
+ items { id name description startTime endTime level language owner isRated subject totalQuestions resultsPublished totalParticipants maximumParticipants solutionVideoUrl imageUrl }
568
+ nextToken
569
+ }
570
+ }` : `query ListContests($globalPk: String!, $sortDirection: ModelSortDirection, $nextToken: String) {
571
+ listContestByGlobalPkAndStartTime(globalPk: $globalPk, sortDirection: $sortDirection, nextToken: $nextToken) {
572
+ items { id name description startTime endTime level language owner isRated subject totalQuestions resultsPublished totalParticipants maximumParticipants solutionVideoUrl imageUrl }
573
+ nextToken
574
+ }
575
+ }`,
576
+ variables
577
+ );
578
+ const key = level ? "listContestByLevelAndStartTime" : "listContestByGlobalPkAndStartTime";
579
+ return result.data[key];
580
+ }
581
+ async participate(contestId) {
582
+ const result = await this.network.mutate(
583
+ `mutation ParticipateContest($contestId: ID!) {
584
+ participateContest(contestId: $contestId) { status id }
585
+ }`,
586
+ { contestId }
587
+ );
588
+ return result.data.participateContest;
589
+ }
590
+ async checkParticipation(contestId) {
591
+ const result = await this.network.query(
592
+ `query CheckParticipation($contestId: ID!) {
593
+ checkUserParticipation(contestId: $contestId) {
594
+ status participated selectedOptions score rank beforeRating afterRating
595
+ }
596
+ }`,
597
+ { contestId }
598
+ );
599
+ return result.data.checkUserParticipation;
600
+ }
601
+ async selectOption(contestId, optionId, order) {
602
+ const result = await this.network.mutate(
603
+ `mutation SelectContestOption($contestId: ID!, $optionId: String!, $order: Int!) {
604
+ selectContestOption(contestId: $contestId, optionId: $optionId, order: $order) { status }
605
+ }`,
606
+ { contestId, optionId, order }
607
+ );
608
+ return result.data.selectContestOption;
609
+ }
610
+ async getQuestions(contestId) {
611
+ const result = await this.network.query(
612
+ `query GetContestQuestions($contestId: ID!) {
613
+ getContestQuestions(contestId: $contestId) { status questions }
614
+ }`,
615
+ { contestId }
616
+ );
617
+ return result.data.getContestQuestions;
618
+ }
619
+ async getAnswers(contestId) {
620
+ const result = await this.network.query(
621
+ `query GetContestAnswers($contestId: ID!) {
622
+ getContestAnswers(contestId: $contestId) { status answers }
623
+ }`,
624
+ { contestId }
625
+ );
626
+ return result.data.getContestAnswers;
627
+ }
628
+ async publish(contestId) {
629
+ const result = await this.network.mutate(
630
+ `mutation PublishResults($contestId: ID!) {
631
+ publishContestResults(contestId: $contestId) { status }
632
+ }`,
633
+ { contestId }
634
+ );
635
+ return result.data.publishContestResults;
636
+ }
637
+ async getLeaderboard(contestId, nextToken) {
638
+ const result = await this.network.query(
639
+ `query GetLeaderboard($contestId: ID!, $sortDirection: ModelSortDirection, $nextToken: String) {
640
+ listContestParticipantByContestIdAndRank(contestId: $contestId, sortDirection: $sortDirection, nextToken: $nextToken) {
641
+ items { id contestId userId rank score afterRating beforeRating createdAt user { id fullName avatarUrl } }
642
+ nextToken
643
+ }
644
+ }`,
645
+ { contestId, sortDirection: "ASC", nextToken }
646
+ );
647
+ const data = result.data.listContestParticipantByContestIdAndRank;
648
+ return {
649
+ status: "success",
650
+ leaderboard: JSON.stringify(data.items),
651
+ nextToken: data.nextToken
652
+ };
653
+ }
654
+ async getUserResults(userId, nextToken) {
655
+ const result = await this.network.query(
656
+ `query GetUserResults($userId: ID!, $sortDirection: ModelSortDirection, $nextToken: String) {
657
+ listContestParticipantByUserIdAndCreatedAt(userId: $userId, sortDirection: $sortDirection, nextToken: $nextToken) {
658
+ items { id contestId userId rank score afterRating beforeRating selectedOptions createdAt contest { id name subject level startTime } }
659
+ nextToken
660
+ }
661
+ }`,
662
+ { userId, sortDirection: "DESC", nextToken }
663
+ );
664
+ return result.data.listContestParticipantByUserIdAndCreatedAt;
665
+ }
666
+ async updateSolutionVideo(contestId, url) {
667
+ const result = await this.network.mutate(
668
+ `mutation UpdateSolutionVideo($input: UpdateContestInput!) {
669
+ updateContest(input: $input) { id solutionVideoUrl }
670
+ }`,
671
+ { input: { id: contestId, solutionVideoUrl: url } }
672
+ );
673
+ return { status: result.data.updateContest ? "success" : "error" };
674
+ }
675
+ };
676
+
677
+ // src/services/course.service.ts
678
+ var CourseService = class {
679
+ constructor(network) {
680
+ this.network = network;
681
+ }
682
+ async create(input) {
683
+ const result = await this.network.mutate(
684
+ `mutation MakeCourse($name: String!, $description: String!, $price: Int!, $imageUrl: String) {
685
+ makeCourse(name: $name, description: $description, price: $price, imageUrl: $imageUrl) { status courseId }
686
+ }`,
687
+ input
688
+ );
689
+ return result.data.makeCourse;
690
+ }
691
+ async get(id) {
692
+ const result = await this.network.query(
693
+ `query GetCourse($id: ID!) {
694
+ getCourse(id: $id) { id name description imageUrl videoCount fileCount price totalEnrolled owner createdAt }
695
+ }`,
696
+ { id }
697
+ );
698
+ return result.data.getCourse;
699
+ }
700
+ async getItems(courseId) {
701
+ const result = await this.network.query(
702
+ `query ListCourseItems($courseId: ID!, $sortDirection: ModelSortDirection) {
703
+ listCourseItemsByCourseIdAndOrder(courseId: $courseId, sortDirection: $sortDirection) {
704
+ items { id type name courseId parentId order owner }
705
+ }
706
+ }`,
707
+ { courseId, sortDirection: "ASC" }
708
+ );
709
+ return result.data.listCourseItemsByCourseIdAndOrder.items;
710
+ }
711
+ async createItem(input) {
712
+ const result = await this.network.mutate(
713
+ `mutation CreateCourseItem($courseId: ID!, $name: String!, $order: Int!, $type: CourseItemsType, $parentId: ID, $id: ID) {
714
+ createCourseItem(courseId: $courseId, name: $name, order: $order, type: $type, parentId: $parentId, id: $id) { status id }
715
+ }`,
716
+ input
717
+ );
718
+ return result.data.createCourseItem;
719
+ }
720
+ async updateItem(id, name, order) {
721
+ const result = await this.network.mutate(
722
+ `mutation UpdateCourseItem($input: UpdateCourseItemsInput!) {
723
+ updateCourseItems(input: $input) { id type name courseId parentId order owner }
724
+ }`,
725
+ { input: { id, name, order } }
726
+ );
727
+ return result.data.updateCourseItems;
728
+ }
729
+ async deleteItem(input) {
730
+ const result = await this.network.mutate(
731
+ `mutation DeleteCourseItem($id: ID!, $fileType: String!, $courseId: ID!, $parentId: ID) {
732
+ deleteCourseItem(id: $id, fileType: $fileType, courseId: $courseId, parentId: $parentId) { status }
733
+ }`,
734
+ input
735
+ );
736
+ return result.data.deleteCourseItem;
737
+ }
738
+ async enroll(input) {
739
+ const result = await this.network.mutate(
740
+ `mutation EnrollStudent($courseId: ID!, $userId: ID!) {
741
+ enrollStudent(courseId: $courseId, userId: $userId) { status id }
742
+ }`,
743
+ input
744
+ );
745
+ return result.data.enrollStudent;
746
+ }
747
+ async getEnrolledStudent(courseId, userId) {
748
+ const result = await this.network.query(
749
+ `query GetEnrolledStudent($courseId: ID!, $filter: ModelCourseEnrolledFilterInput) {
750
+ listCourseEnrolledByCourseIdAndCreatedAt(courseId: $courseId, filter: $filter) {
751
+ items { id courseId userId owner score rank createdAt }
752
+ }
753
+ }`,
754
+ { courseId, filter: { userId: { eq: userId } } }
755
+ );
756
+ return _nullishCoalesce(result.data.listCourseEnrolledByCourseIdAndCreatedAt.items[0], () => ( null));
757
+ }
758
+ async getEnrolledStudents(courseId, nextToken) {
759
+ const result = await this.network.query(
760
+ `query ListEnrolledStudents($courseId: ID!, $sortDirection: ModelSortDirection, $nextToken: String) {
761
+ listCourseEnrolledByCourseIdAndCreatedAt(courseId: $courseId, sortDirection: $sortDirection, nextToken: $nextToken) {
762
+ items { id courseId userId owner score rank createdAt user { id fullName avatarUrl } }
763
+ nextToken
764
+ }
765
+ }`,
766
+ { courseId, sortDirection: "DESC", nextToken }
767
+ );
768
+ return result.data.listCourseEnrolledByCourseIdAndCreatedAt;
769
+ }
770
+ async sendEnrollmentRequest(input) {
771
+ const result = await this.network.mutate(
772
+ `mutation SendEnrollmentRequest($input: CreateCourseEnrollmentRequestInput!) {
773
+ createCourseEnrollmentRequest(input: $input) { id }
774
+ }`,
775
+ { input: { courseId: input.courseId, name: input.name, phone: input.phone, transactionID: input.transactionId, coupon: input.couponId } }
776
+ );
777
+ return result.data.createCourseEnrollmentRequest;
778
+ }
779
+ async getSignedURL(input) {
780
+ const result = await this.network.query(
781
+ `query GetR2SignedURL($courseId: ID!, $fileName: String!, $fileType: String!, $parentId: ID) {
782
+ getR2SignedURL(courseId: $courseId, fileName: $fileName, fileType: $fileType, parentId: $parentId) { status signedURL }
783
+ }`,
784
+ input
785
+ );
786
+ return result.data.getR2SignedURL;
787
+ }
788
+ async getSignedFileURL(input) {
789
+ const result = await this.network.query(
790
+ `query GetR2SignedFileURL($courseId: ID!, $itemId: ID!, $key: ID!) {
791
+ getR2SignedFileURL(courseId: $courseId, itemId: $itemId, key: $key) { status signedURL }
792
+ }`,
793
+ input
794
+ );
795
+ return result.data.getR2SignedFileURL;
796
+ }
797
+ async createVideo(input) {
798
+ const result = await this.network.query(
799
+ `query CreateCourseVideo($courseId: ID!, $fileName: String!, $fileType: String!) {
800
+ createCourseVideo(courseId: $courseId, fileName: $fileName, fileType: $fileType) { status videoId }
801
+ }`,
802
+ input
803
+ );
804
+ return result.data.createCourseVideo;
805
+ }
806
+ async uploadVideoToBunny(input) {
807
+ const result = await this.network.mutate(
808
+ `mutation UploadR2VideoToBunny($key: String!, $videoId: String!, $fileType: String!) {
809
+ uploadR2VideoToBunny(key: $key, videoId: $videoId, fileType: $fileType) { status }
810
+ }`,
811
+ input
812
+ );
813
+ return result.data.uploadR2VideoToBunny;
814
+ }
815
+ async getLiveExams(courseId, nextToken) {
816
+ const result = await this.network.query(
817
+ `query ListLiveExams($courseId: ID!, $sortDirection: ModelSortDirection, $nextToken: String) {
818
+ listCourseLiveExamByCourseIdAndStartTime(courseId: $courseId, sortDirection: $sortDirection, nextToken: $nextToken) {
819
+ items { id courseId name startTime endTime owner totalParticipants resultsPublished }
820
+ nextToken
821
+ }
822
+ }`,
823
+ { courseId, sortDirection: "DESC", nextToken }
824
+ );
825
+ return result.data.listCourseLiveExamByCourseIdAndStartTime;
826
+ }
827
+ async createLiveExam(input) {
828
+ const result = await this.network.mutate(
829
+ `mutation MakeCourseLiveExam($courseId: ID!, $name: String!, $questions: String!, $startTime: AWSDateTime!, $endTime: AWSDateTime!) {
830
+ makeCourseLiveExam(courseId: $courseId, name: $name, questions: $questions, startTime: $startTime, endTime: $endTime) { status id }
831
+ }`,
832
+ input
833
+ );
834
+ return result.data.makeCourseLiveExam;
835
+ }
836
+ async getLiveExamQuestions(examId) {
837
+ const result = await this.network.query(
838
+ `query GetLiveExamQuestions($examId: ID!) {
839
+ getCourseLiveExamQuestions(examId: $examId) { status name startTime endTime questions selectedOptions }
840
+ }`,
841
+ { examId }
842
+ );
843
+ return result.data.getCourseLiveExamQuestions;
844
+ }
845
+ async participateLiveExam(examId) {
846
+ const result = await this.network.mutate(
847
+ `mutation ParticipateLiveExam($examId: ID!) {
848
+ participateCourseLiveExam(examId: $examId) { status }
849
+ }`,
850
+ { examId }
851
+ );
852
+ return result.data.participateCourseLiveExam;
853
+ }
854
+ async selectLiveExamOption(examId, optionId, order) {
855
+ const result = await this.network.mutate(
856
+ `mutation SelectLiveExamOption($examId: ID!, $optionId: ID!, $order: Int!) {
857
+ selectCourseLiveExamOption(examId: $examId, optionId: $optionId, order: $order) { status }
858
+ }`,
859
+ { examId, optionId, order }
860
+ );
861
+ return result.data.selectCourseLiveExamOption;
862
+ }
863
+ async getLiveExamLeaderboard(examId, nextToken) {
864
+ const result = await this.network.query(
865
+ `query GetLiveExamLeaderboard($examId: ID!, $nextToken: String) {
866
+ getCourseLiveExamLeaderboard(examId: $examId, nextToken: $nextToken) { status leaderboard nextToken totalParticipants }
867
+ }`,
868
+ { examId, nextToken }
869
+ );
870
+ return result.data.getCourseLiveExamLeaderboard;
871
+ }
872
+ async publishLiveExamResults(examId) {
873
+ const result = await this.network.mutate(
874
+ `mutation PublishLiveExamResults($examId: ID!) {
875
+ publishCourseLiveExamResults(examId: $examId) { status }
876
+ }`,
877
+ { examId }
878
+ );
879
+ return result.data.publishCourseLiveExamResults;
880
+ }
881
+ };
882
+
883
+ // src/services/curriculum.service.ts
884
+ var CurriculumService = class {
885
+ constructor(network) {
886
+ this.network = network;
887
+ }
888
+ async createSubject(name, level) {
889
+ const result = await this.network.mutate(
890
+ `mutation MakeSubject($name: String!, $level: String!) {
891
+ makeSubject(name: $name, level: $level) { status id }
892
+ }`,
893
+ { name, level }
894
+ );
895
+ return result.data.makeSubject;
896
+ }
897
+ async createChapter(name, subjectId, order) {
898
+ const result = await this.network.mutate(
899
+ `mutation MakeChapter($name: String!, $subjectId: ID!, $order: Int!) {
900
+ makeChapter(name: $name, subjectId: $subjectId, order: $order) { status id }
901
+ }`,
902
+ { name, subjectId, order }
903
+ );
904
+ return result.data.makeChapter;
905
+ }
906
+ async createTopic(name, chapterId) {
907
+ const result = await this.network.mutate(
908
+ `mutation MakeTopic($name: String!, $chapterId: ID!) {
909
+ makeTopic(name: $name, chapterId: $chapterId) { status id }
910
+ }`,
911
+ { name, chapterId }
912
+ );
913
+ return result.data.makeTopic;
914
+ }
915
+ async getSubjects(level) {
916
+ const result = await this.network.query(
917
+ `query ListSubjects($level: String!) {
918
+ listSubjectByLevel(level: $level) {
919
+ items { id name level questionCount }
920
+ }
921
+ }`,
922
+ { level }
923
+ );
924
+ return result.data.listSubjectByLevel.items;
925
+ }
926
+ async getChapters(subjectId) {
927
+ const result = await this.network.query(
928
+ `query ListChapters($subjectId: ID!, $sortDirection: ModelSortDirection) {
929
+ listChapterBySubjectIdAndOrder(subjectId: $subjectId, sortDirection: $sortDirection) {
930
+ items { id name order subjectId questionCount }
931
+ }
932
+ }`,
933
+ { subjectId, sortDirection: "ASC" }
934
+ );
935
+ return result.data.listChapterBySubjectIdAndOrder.items;
936
+ }
937
+ async getTopics(chapterId) {
938
+ const result = await this.network.query(
939
+ `query ListTopics($chapterId: ID!) {
940
+ listTopicByChapterId(chapterId: $chapterId) {
941
+ items { id name chapterId questionCount }
942
+ }
943
+ }`,
944
+ { chapterId }
945
+ );
946
+ return result.data.listTopicByChapterId.items;
947
+ }
948
+ };
949
+
950
+ // src/services/media.service.ts
951
+ var MediaService = class {
952
+ constructor(network, storage) {
953
+ this.network = network;
954
+ this.storage = storage;
955
+ }
956
+ async uploadImage(questionId, image) {
957
+ const result = await this.network.mutate(
958
+ `mutation UploadImage($questionId: ID!, $image: String!) {
959
+ uploadImage(questionId: $questionId, image: $image) { status imageUrl }
960
+ }`,
961
+ { questionId, image }
962
+ );
963
+ return result.data.uploadImage;
964
+ }
965
+ async deleteImage(imageUrl) {
966
+ const result = await this.network.mutate(
967
+ `mutation DeleteImage($imageUrl: ID!) {
968
+ deleteImage(imageUrl: $imageUrl) { status }
969
+ }`,
970
+ { imageUrl }
971
+ );
972
+ return result.data.deleteImage;
973
+ }
974
+ async getSignedURL(input) {
975
+ const result = await this.network.query(
976
+ `query GetR2SignedURL($courseId: ID!, $fileName: String!, $fileType: String!, $parentId: ID) {
977
+ getR2SignedURL(courseId: $courseId, fileName: $fileName, fileType: $fileType, parentId: $parentId) { status signedURL }
978
+ }`,
979
+ input
980
+ );
981
+ return result.data.getR2SignedURL;
982
+ }
983
+ async getSignedFileURL(input) {
984
+ const result = await this.network.query(
985
+ `query GetR2SignedFileURL($courseId: ID!, $itemId: ID!, $key: ID!) {
986
+ getR2SignedFileURL(courseId: $courseId, itemId: $itemId, key: $key) { status signedURL }
987
+ }`,
988
+ input
989
+ );
990
+ return result.data.getR2SignedFileURL;
991
+ }
992
+ async getFileUrl(path) {
993
+ if (!this.storage) throw new Error("StorageProvider not configured");
994
+ return this.storage.getFileUrl(path);
995
+ }
996
+ async uploadFile(path, data, options) {
997
+ if (!this.storage) throw new Error("StorageProvider not configured");
998
+ return this.storage.uploadFile(path, data, options);
999
+ }
1000
+ async createVideo(input) {
1001
+ const result = await this.network.query(
1002
+ `query CreateCourseVideo($courseId: ID!, $fileName: String!, $fileType: String!) {
1003
+ createCourseVideo(courseId: $courseId, fileName: $fileName, fileType: $fileType) { status videoId }
1004
+ }`,
1005
+ input
1006
+ );
1007
+ return result.data.createCourseVideo;
1008
+ }
1009
+ async uploadVideoToBunny(input) {
1010
+ const result = await this.network.mutate(
1011
+ `mutation UploadR2VideoToBunny($key: String!, $videoId: String!, $fileType: String!) {
1012
+ uploadR2VideoToBunny(key: $key, videoId: $videoId, fileType: $fileType) { status }
1013
+ }`,
1014
+ input
1015
+ );
1016
+ return result.data.uploadR2VideoToBunny;
1017
+ }
1018
+ };
1019
+
1020
+ // src/services/progress.service.ts
1021
+ var ProgressService = class {
1022
+ constructor(network) {
1023
+ this.network = network;
1024
+ }
1025
+ async track(input) {
1026
+ const result = await this.network.mutate(
1027
+ `mutation TrackProgress($questionId: ID!, $isCorrect: Boolean!, $subjectId: ID, $chapterId: ID, $topicId: ID) {
1028
+ trackPracticeProgress(questionId: $questionId, isCorrect: $isCorrect, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId) { status }
1029
+ }`,
1030
+ input
1031
+ );
1032
+ return result.data.trackPracticeProgress;
1033
+ }
1034
+ async getSubjectProgress(userId) {
1035
+ const result = await this.network.query(
1036
+ `query ListSubjectProgress($userId: String!) {
1037
+ listUserSubjectProgressByUserIdAndSubjectId(userId: $userId) {
1038
+ items { id userId subjectId practicedCount mistakeCount correctedCount accuracyScore }
1039
+ }
1040
+ }`,
1041
+ { userId }
1042
+ );
1043
+ return result.data.listUserSubjectProgressByUserIdAndSubjectId.items;
1044
+ }
1045
+ async getChapterProgress(userId) {
1046
+ const result = await this.network.query(
1047
+ `query ListChapterProgress($userId: String!) {
1048
+ listUserChapterProgressByUserIdAndChapterId(userId: $userId) {
1049
+ items { id userId chapterId practicedCount mistakeCount correctedCount accuracyScore }
1050
+ }
1051
+ }`,
1052
+ { userId }
1053
+ );
1054
+ return result.data.listUserChapterProgressByUserIdAndChapterId.items;
1055
+ }
1056
+ async getTopicProgress(userId) {
1057
+ const result = await this.network.query(
1058
+ `query ListTopicProgress($userId: String!) {
1059
+ listUserTopicProgressByUserIdAndTopicId(userId: $userId) {
1060
+ items { id userId topicId practicedCount mistakeCount correctedCount accuracyScore }
1061
+ }
1062
+ }`,
1063
+ { userId }
1064
+ );
1065
+ return result.data.listUserTopicProgressByUserIdAndTopicId.items;
1066
+ }
1067
+ async getTopicMetrics(userId) {
1068
+ const result = await this.network.query(
1069
+ `query ListTopicMetrics($filter: ModelUserTopicMetricFilterInput) {
1070
+ listUserTopicMetrics(filter: $filter) {
1071
+ items { id userId topicId totalAttempted totalCorrect accuracy }
1072
+ }
1073
+ }`,
1074
+ { filter: { userId: { eq: userId } } }
1075
+ );
1076
+ return result.data.listUserTopicMetrics.items;
1077
+ }
1078
+ async getMistakenQuestions(userId) {
1079
+ const result = await this.network.query(
1080
+ `query ListMistakes($userId: String!, $filter: ModelQuestionTrackingFilterInput) {
1081
+ listQuestionTrackingByUserIdAndSubjectId(userId: $userId, filter: $filter) {
1082
+ items { id userId questionId subjectId chapterId topicId status attempts }
1083
+ }
1084
+ }`,
1085
+ { userId, filter: { status: { eq: "MISTAKE" } } }
1086
+ );
1087
+ return result.data.listQuestionTrackingByUserIdAndSubjectId.items;
1088
+ }
1089
+ };
1090
+
1091
+ // src/services/ai.service.ts
1092
+ var AIService = class {
1093
+ constructor(network) {
1094
+ this.network = network;
1095
+ }
1096
+ async evaluateWrittenAnswer(input) {
1097
+ const result = await this.network.query(
1098
+ `query EvaluateWrittenAnswer($question: String!, $userAnswer: String!, $correctAnswer: String!, $markingInstructions: String, $topicId: String, $topicName: String, $questionImageUrl: String) {
1099
+ evaluateWrittenAnswer(question: $question, userAnswer: $userAnswer, correctAnswer: $correctAnswer, markingInstructions: $markingInstructions, topicId: $topicId, topicName: $topicName, questionImageUrl: $questionImageUrl) {
1100
+ score maxScore feedback isCorrect markingExplanation improvementFeedback subquestions markLocation
1101
+ }
1102
+ }`,
1103
+ input
1104
+ );
1105
+ return result.data.evaluateWrittenAnswer;
1106
+ }
1107
+ };
1108
+
1109
+ // src/services/news.service.ts
1110
+ var NewsService = class {
1111
+ constructor(network) {
1112
+ this.network = network;
1113
+ }
1114
+ async create(title, content, image, category, excerpt) {
1115
+ const result = await this.network.mutate(
1116
+ `mutation CreateNews($input: CreateNewsArticleInput!) {
1117
+ createNewsArticle(input: $input) { id title content image category excerpt createdAt updatedAt }
1118
+ }`,
1119
+ { input: { title, content, image, category, excerpt } }
1120
+ );
1121
+ return result.data.createNewsArticle;
1122
+ }
1123
+ async list(nextToken) {
1124
+ const result = await this.network.query(
1125
+ `query ListNews($nextToken: String) {
1126
+ listNewsArticles(nextToken: $nextToken) {
1127
+ items { id title content image category excerpt createdAt updatedAt }
1128
+ nextToken
1129
+ }
1130
+ }`,
1131
+ { nextToken }
1132
+ );
1133
+ return result.data.listNewsArticles;
1134
+ }
1135
+ async get(id) {
1136
+ const result = await this.network.query(
1137
+ `query GetNews($id: ID!) {
1138
+ getNewsArticle(id: $id) { id title content image category excerpt createdAt updatedAt }
1139
+ }`,
1140
+ { id }
1141
+ );
1142
+ return result.data.getNewsArticle;
1143
+ }
1144
+ };
1145
+
1146
+ // src/client.ts
1147
+ var OrjokClient = class {
1148
+ constructor(config) {
1149
+ this.auth = config.authProvider;
1150
+ this.users = new UserService(config.networkProvider);
1151
+ this.questions = new QuestionService(config.networkProvider);
1152
+ this.packs = new PackService(config.networkProvider);
1153
+ this.contests = new ContestService(config.networkProvider);
1154
+ this.courses = new CourseService(config.networkProvider);
1155
+ this.curriculum = new CurriculumService(config.networkProvider);
1156
+ this.media = new MediaService(config.networkProvider, config.storageProvider);
1157
+ this.progress = new ProgressService(config.networkProvider);
1158
+ this.ai = new AIService(config.networkProvider);
1159
+ this.news = new NewsService(config.networkProvider);
1160
+ }
1161
+ };
1162
+ function createOrjokClient(config) {
1163
+ return new OrjokClient(config);
1164
+ }
1165
+
1166
+ // src/logic/elo.ts
1167
+ var TIERS = [
1168
+ { name: "Iron", minRating: 0, maxRating: 799, color: "#6B7280" },
1169
+ { name: "Bronze", minRating: 800, maxRating: 999, color: "#CD7F32" },
1170
+ { name: "Silver", minRating: 1e3, maxRating: 1199, color: "#C0C0C0" },
1171
+ { name: "Gold", minRating: 1200, maxRating: 1399, color: "#FFD700" },
1172
+ { name: "Platinum", minRating: 1400, maxRating: 1599, color: "#00CED1" },
1173
+ { name: "Diamond", minRating: 1600, maxRating: 1799, color: "#B9F2FF" },
1174
+ { name: "Master", minRating: 1800, maxRating: 1999, color: "#9B59B6" },
1175
+ { name: "Grandmaster", minRating: 2e3, maxRating: 2399, color: "#E74C3C" },
1176
+ { name: "Challenger", minRating: 2400, maxRating: Infinity, color: "#F1C40F" }
1177
+ ];
1178
+ function getEloTier(rating) {
1179
+ return _nullishCoalesce(TIERS.find((t) => rating >= t.minRating && rating <= t.maxRating), () => ( TIERS[0]));
1180
+ }
1181
+ function getEloProgress(rating) {
1182
+ const tier = getEloTier(rating);
1183
+ if (tier.maxRating === Infinity) return 100;
1184
+ const range = tier.maxRating - tier.minRating;
1185
+ return Math.round((rating - tier.minRating) / range * 100);
1186
+ }
1187
+ function getAllTiers() {
1188
+ return [...TIERS];
1189
+ }
1190
+ function getRatingForSubject(user, subject) {
1191
+ const key = subject;
1192
+ return _nullishCoalesce(user[key], () => ( 1e3));
1193
+ }
1194
+ function computeRatingDelta(beforeRating, afterRating) {
1195
+ if (beforeRating == null || afterRating == null) return 0;
1196
+ return afterRating - beforeRating;
1197
+ }
1198
+
1199
+ // src/logic/exam.ts
1200
+ function filterQuestionsByMode(questions, mode) {
1201
+ if (mode === "BOTH") return questions;
1202
+ return questions.filter((q) => q.type === mode || !q.type && mode === "MCQ");
1203
+ }
1204
+ function calculateExamTime(questionCount, secondsPerQuestion = 60) {
1205
+ return questionCount * secondsPerQuestion;
1206
+ }
1207
+ function formatExamTime(totalSeconds) {
1208
+ const hours = Math.floor(totalSeconds / 3600);
1209
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
1210
+ const seconds = totalSeconds % 60;
1211
+ if (hours > 0) {
1212
+ return `${hours}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
1213
+ }
1214
+ return `${minutes}:${String(seconds).padStart(2, "0")}`;
1215
+ }
1216
+ function scoreExam(selectedOptions, correctAnswers) {
1217
+ let correct = 0;
1218
+ let incorrect = 0;
1219
+ let unanswered = 0;
1220
+ for (let i = 0; i < correctAnswers.length; i++) {
1221
+ const selected = selectedOptions[i];
1222
+ if (!selected) {
1223
+ unanswered++;
1224
+ } else if (selected === correctAnswers[i]) {
1225
+ correct++;
1226
+ } else {
1227
+ incorrect++;
1228
+ }
1229
+ }
1230
+ return { correct, incorrect, unanswered, total: correctAnswers.length };
1231
+ }
1232
+ function isImageAnswer(answer) {
1233
+ if (!answer) return false;
1234
+ return answer.startsWith("image::") || answer.startsWith("images::");
1235
+ }
1236
+ function parseImageKeys(answer) {
1237
+ if (answer.startsWith("images::")) {
1238
+ return answer.slice("images::".length).split(",").filter(Boolean);
1239
+ }
1240
+ if (answer.startsWith("image::")) {
1241
+ const key = answer.slice("image::".length);
1242
+ return key ? [key] : [];
1243
+ }
1244
+ return [];
1245
+ }
1246
+ function buildImageAnswer(keys) {
1247
+ if (keys.length === 0) return "";
1248
+ if (keys.length === 1) return `image::${keys[0]}`;
1249
+ return `images::${keys.join(",")}`;
1250
+ }
1251
+ function normalizeDifficulty(raw) {
1252
+ const trimmed = raw.trim();
1253
+ if (!trimmed) return void 0;
1254
+ const capitalized = trimmed.charAt(0).toUpperCase() + trimmed.slice(1).toLowerCase();
1255
+ if (capitalized === "Easy" || capitalized === "Medium" || capitalized === "Hard") {
1256
+ return capitalized;
1257
+ }
1258
+ return void 0;
1259
+ }
1260
+ function detectQuestionType(option2, option3, option4) {
1261
+ if (!option2.trim() && !option3.trim() && !option4.trim()) {
1262
+ return "WRITTEN";
1263
+ }
1264
+ return "MCQ";
1265
+ }
1266
+
1267
+ // src/logic/import-export.ts
1268
+ var MAX_QUESTIONS = 200;
1269
+ function parseFields(parts) {
1270
+ let extra = "";
1271
+ let difficulty;
1272
+ let subjectId = "";
1273
+ let chapterId = "";
1274
+ let topicId = "";
1275
+ let markingInstructions = "";
1276
+ let id = "";
1277
+ let imageUrl = "";
1278
+ let answerImageUrl = "";
1279
+ let option2ImageUrl = "";
1280
+ let option3ImageUrl = "";
1281
+ let option4ImageUrl = "";
1282
+ if (parts.length >= 13) {
1283
+ extra = _nullishCoalesce(_optionalChain([parts, 'access', _10 => _10[7], 'optionalAccess', _11 => _11.trim, 'call', _12 => _12()]), () => ( ""));
1284
+ const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access', _13 => _13[8], 'optionalAccess', _14 => _14.trim, 'call', _15 => _15()]), () => ( ""));
1285
+ if (rawDiff) {
1286
+ const cap = rawDiff.charAt(0).toUpperCase() + rawDiff.slice(1).toLowerCase();
1287
+ if (cap === "Easy" || cap === "Medium" || cap === "Hard") difficulty = cap;
1288
+ }
1289
+ subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _16 => _16[9], 'optionalAccess', _17 => _17.trim, 'call', _18 => _18()]), () => ( ""));
1290
+ chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _19 => _19[10], 'optionalAccess', _20 => _20.trim, 'call', _21 => _21()]), () => ( ""));
1291
+ topicId = _nullishCoalesce(_optionalChain([parts, 'access', _22 => _22[11], 'optionalAccess', _23 => _23.trim, 'call', _24 => _24()]), () => ( ""));
1292
+ markingInstructions = _nullishCoalesce(_optionalChain([parts, 'access', _25 => _25[12], 'optionalAccess', _26 => _26.trim, 'call', _27 => _27()]), () => ( ""));
1293
+ if (parts.length > 13) id = _nullishCoalesce(_optionalChain([parts, 'access', _28 => _28[13], 'optionalAccess', _29 => _29.trim, 'call', _30 => _30()]), () => ( ""));
1294
+ if (parts.length > 14) imageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _31 => _31[14], 'optionalAccess', _32 => _32.trim, 'call', _33 => _33()]), () => ( ""));
1295
+ if (parts.length > 15) answerImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _34 => _34[15], 'optionalAccess', _35 => _35.trim, 'call', _36 => _36()]), () => ( ""));
1296
+ if (parts.length > 16) option2ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _37 => _37[16], 'optionalAccess', _38 => _38.trim, 'call', _39 => _39()]), () => ( ""));
1297
+ if (parts.length > 17) option3ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _40 => _40[17], 'optionalAccess', _41 => _41.trim, 'call', _42 => _42()]), () => ( ""));
1298
+ if (parts.length > 18) option4ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _43 => _43[18], 'optionalAccess', _44 => _44.trim, 'call', _45 => _45()]), () => ( ""));
1299
+ } else if (parts.length === 8) {
1300
+ extra = _nullishCoalesce(_optionalChain([parts, 'access', _46 => _46[7], 'optionalAccess', _47 => _47.trim, 'call', _48 => _48()]), () => ( ""));
1301
+ } else if (parts.length === 9) {
1302
+ extra = _nullishCoalesce(_optionalChain([parts, 'access', _49 => _49[7], 'optionalAccess', _50 => _50.trim, 'call', _51 => _51()]), () => ( ""));
1303
+ const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access', _52 => _52[8], 'optionalAccess', _53 => _53.trim, 'call', _54 => _54()]), () => ( ""));
1304
+ if (rawDiff) {
1305
+ const cap = rawDiff.charAt(0).toUpperCase() + rawDiff.slice(1).toLowerCase();
1306
+ if (cap === "Easy" || cap === "Medium" || cap === "Hard") difficulty = cap;
1307
+ }
1308
+ } else if (parts.length === 10) {
1309
+ subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _55 => _55[7], 'optionalAccess', _56 => _56.trim, 'call', _57 => _57()]), () => ( ""));
1310
+ chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _58 => _58[8], 'optionalAccess', _59 => _59.trim, 'call', _60 => _60()]), () => ( ""));
1311
+ topicId = _nullishCoalesce(_optionalChain([parts, 'access', _61 => _61[9], 'optionalAccess', _62 => _62.trim, 'call', _63 => _63()]), () => ( ""));
1312
+ } else if (parts.length === 11) {
1313
+ extra = _nullishCoalesce(_optionalChain([parts, 'access', _64 => _64[7], 'optionalAccess', _65 => _65.trim, 'call', _66 => _66()]), () => ( ""));
1314
+ subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _67 => _67[8], 'optionalAccess', _68 => _68.trim, 'call', _69 => _69()]), () => ( ""));
1315
+ chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _70 => _70[9], 'optionalAccess', _71 => _71.trim, 'call', _72 => _72()]), () => ( ""));
1316
+ topicId = _nullishCoalesce(_optionalChain([parts, 'access', _73 => _73[10], 'optionalAccess', _74 => _74.trim, 'call', _75 => _75()]), () => ( ""));
1317
+ } else if (parts.length === 12) {
1318
+ extra = _nullishCoalesce(_optionalChain([parts, 'access', _76 => _76[7], 'optionalAccess', _77 => _77.trim, 'call', _78 => _78()]), () => ( ""));
1319
+ const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access', _79 => _79[8], 'optionalAccess', _80 => _80.trim, 'call', _81 => _81()]), () => ( ""));
1320
+ if (rawDiff) {
1321
+ const cap = rawDiff.charAt(0).toUpperCase() + rawDiff.slice(1).toLowerCase();
1322
+ if (cap === "Easy" || cap === "Medium" || cap === "Hard") difficulty = cap;
1323
+ }
1324
+ subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _82 => _82[9], 'optionalAccess', _83 => _83.trim, 'call', _84 => _84()]), () => ( ""));
1325
+ chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _85 => _85[10], 'optionalAccess', _86 => _86.trim, 'call', _87 => _87()]), () => ( ""));
1326
+ topicId = _nullishCoalesce(_optionalChain([parts, 'access', _88 => _88[11], 'optionalAccess', _89 => _89.trim, 'call', _90 => _90()]), () => ( ""));
1327
+ }
1328
+ return {
1329
+ id: id || void 0,
1330
+ imageUrl: imageUrl || void 0,
1331
+ extra: extra || void 0,
1332
+ difficulty,
1333
+ subjectId: subjectId || void 0,
1334
+ chapterId: chapterId || void 0,
1335
+ topicId: topicId || void 0,
1336
+ markingInstructions: markingInstructions || void 0,
1337
+ answerImageUrl: answerImageUrl || void 0,
1338
+ option2ImageUrl: option2ImageUrl || void 0,
1339
+ option3ImageUrl: option3ImageUrl || void 0,
1340
+ option4ImageUrl: option4ImageUrl || void 0
1341
+ };
1342
+ }
1343
+ function buildQuestion(parts) {
1344
+ const tags = parts.length >= 7 && parts[6] ? parts[6].split(",").map((t) => t.trim()).filter(Boolean) : [];
1345
+ const opt2 = _nullishCoalesce(_optionalChain([parts, 'access', _91 => _91[2], 'optionalAccess', _92 => _92.trim, 'call', _93 => _93()]), () => ( ""));
1346
+ const opt3 = _nullishCoalesce(_optionalChain([parts, 'access', _94 => _94[3], 'optionalAccess', _95 => _95.trim, 'call', _96 => _96()]), () => ( ""));
1347
+ const opt4 = _nullishCoalesce(_optionalChain([parts, 'access', _97 => _97[4], 'optionalAccess', _98 => _98.trim, 'call', _99 => _99()]), () => ( ""));
1348
+ const isWritten = parts.length < 6 || !opt2 && !opt3 && !opt4;
1349
+ const extra = parseFields(parts);
1350
+ return {
1351
+ question: _nullishCoalesce(_optionalChain([parts, 'access', _100 => _100[0], 'optionalAccess', _101 => _101.trim, 'call', _102 => _102()]), () => ( "")),
1352
+ answer: _nullishCoalesce(_optionalChain([parts, 'access', _103 => _103[1], 'optionalAccess', _104 => _104.trim, 'call', _105 => _105()]), () => ( "")),
1353
+ option2: opt2,
1354
+ option3: opt3,
1355
+ option4: opt4,
1356
+ explanation: _nullishCoalesce(_optionalChain([parts, 'access', _106 => _106[5], 'optionalAccess', _107 => _107.trim, 'call', _108 => _108()]), () => ( "")),
1357
+ tags,
1358
+ type: isWritten ? "WRITTEN" : "MCQ",
1359
+ ...extra
1360
+ };
1361
+ }
1362
+ function parseTextQuestions(text, keyword, minParts = 2) {
1363
+ const lines = text.split("\n");
1364
+ const questions = [];
1365
+ const errors = [];
1366
+ if (lines.length > MAX_QUESTIONS) {
1367
+ errors.push(`Can't have more than ${MAX_QUESTIONS} questions/lines`);
1368
+ return { questions, errors };
1369
+ }
1370
+ for (let idx = 0; idx < lines.length; idx++) {
1371
+ const line = lines[idx];
1372
+ const parts = line.split(keyword);
1373
+ if (parts.length === 1 && (parts[0] === "\r" || parts[0] === "\n" || parts[0] === "")) {
1374
+ continue;
1375
+ }
1376
+ if (parts.length < minParts || parts.length > 19) {
1377
+ errors.push(`Line ${idx + 1} doesn't have between ${minParts} and 19 parts`);
1378
+ continue;
1379
+ }
1380
+ questions.push(buildQuestion(parts));
1381
+ }
1382
+ return { questions, errors };
1383
+ }
1384
+ function parseCsvQuestions(rows) {
1385
+ const questions = [];
1386
+ const errors = [];
1387
+ const dataRows = rows.slice(1);
1388
+ if (dataRows.length > MAX_QUESTIONS) {
1389
+ errors.push(`Can't have more than ${MAX_QUESTIONS} questions/lines`);
1390
+ return { questions, errors };
1391
+ }
1392
+ for (let idx = 0; idx < dataRows.length; idx++) {
1393
+ const line = dataRows[idx];
1394
+ if (line.length < 2 || line.length > 19) {
1395
+ errors.push(`Line ${idx + 2} doesn't have between 2 and 19 parts`);
1396
+ continue;
1397
+ }
1398
+ questions.push(buildQuestion(line));
1399
+ }
1400
+ return { questions, errors };
1401
+ }
1402
+ function formatQuestionsToText(questions, keyword, packSubjectId, packChapterId, packTopicId) {
1403
+ const lines = questions.map((q) => {
1404
+ const activeSubject = q.subjectId || packSubjectId;
1405
+ const activeChapter = q.chapterId || packChapterId;
1406
+ const activeTopic = q.topicId || packTopicId;
1407
+ const subjectSlug = activeSubject ? _nullishCoalesce(_optionalChain([activeSubject, 'access', _109 => _109.split, 'call', _110 => _110("::"), 'access', _111 => _111[0], 'optionalAccess', _112 => _112.trim, 'call', _113 => _113()]), () => ( "")) : "";
1408
+ const chapterSlug = activeChapter ? _nullishCoalesce(_optionalChain([activeChapter, 'access', _114 => _114.split, 'call', _115 => _115("::"), 'access', _116 => _116[0], 'optionalAccess', _117 => _117.trim, 'call', _118 => _118()]), () => ( "")) : "";
1409
+ const topicSlug = activeTopic ? _nullishCoalesce(_optionalChain([activeTopic, 'access', _119 => _119.split, 'call', _120 => _120("::"), 'access', _121 => _121[0], 'optionalAccess', _122 => _122.trim, 'call', _123 => _123()]), () => ( "")) : "";
1410
+ const fields = [
1411
+ q.question,
1412
+ q.answer,
1413
+ q.type === "WRITTEN" ? "" : q.option2,
1414
+ q.type === "WRITTEN" ? "" : q.option3,
1415
+ q.type === "WRITTEN" ? "" : q.option4,
1416
+ q.explanation,
1417
+ q.tags.join(", "),
1418
+ _nullishCoalesce(q.extra, () => ( "")),
1419
+ _nullishCoalesce(q.difficulty, () => ( "")),
1420
+ subjectSlug,
1421
+ chapterSlug,
1422
+ topicSlug,
1423
+ _nullishCoalesce(q.markingInstructions, () => ( "")),
1424
+ _nullishCoalesce(q.id, () => ( "")),
1425
+ _nullishCoalesce(q.imageUrl, () => ( "")),
1426
+ _nullishCoalesce(q.answerImageUrl, () => ( "")),
1427
+ _nullishCoalesce(q.option2ImageUrl, () => ( "")),
1428
+ _nullishCoalesce(q.option3ImageUrl, () => ( "")),
1429
+ _nullishCoalesce(q.option4ImageUrl, () => ( ""))
1430
+ ];
1431
+ return fields.map((f) => (f || "").trim()).join(keyword);
1432
+ });
1433
+ return lines.join("\n");
1434
+ }
1435
+ function formatQuestionsToCsv(questions, packSubjectId, packChapterId, packTopicId) {
1436
+ const escapeCSV = (value) => `"${(value || "").replace(/"/g, '""')}"`;
1437
+ const header = "Question,Answer,Option2,Option3,Option4,Explanation,Tags,Extra,Difficulty,Subject,Chapter,Topic,MarkingInstructions,Id,ImageUrl,AnswerImageUrl,Option2ImageUrl,Option3ImageUrl,Option4ImageUrl";
1438
+ const rows = questions.map((q) => {
1439
+ const activeSubject = q.subjectId || packSubjectId;
1440
+ const activeChapter = q.chapterId || packChapterId;
1441
+ const activeTopic = q.topicId || packTopicId;
1442
+ const subjectSlug = activeSubject ? _nullishCoalesce(_optionalChain([activeSubject, 'access', _124 => _124.split, 'call', _125 => _125("::"), 'access', _126 => _126[0], 'optionalAccess', _127 => _127.trim, 'call', _128 => _128()]), () => ( "")) : "";
1443
+ const chapterSlug = activeChapter ? _nullishCoalesce(_optionalChain([activeChapter, 'access', _129 => _129.split, 'call', _130 => _130("::"), 'access', _131 => _131[0], 'optionalAccess', _132 => _132.trim, 'call', _133 => _133()]), () => ( "")) : "";
1444
+ const topicSlug = activeTopic ? _nullishCoalesce(_optionalChain([activeTopic, 'access', _134 => _134.split, 'call', _135 => _135("::"), 'access', _136 => _136[0], 'optionalAccess', _137 => _137.trim, 'call', _138 => _138()]), () => ( "")) : "";
1445
+ return [
1446
+ escapeCSV(q.question),
1447
+ escapeCSV(q.answer),
1448
+ escapeCSV(q.type === "WRITTEN" ? "" : q.option2),
1449
+ escapeCSV(q.type === "WRITTEN" ? "" : q.option3),
1450
+ escapeCSV(q.type === "WRITTEN" ? "" : q.option4),
1451
+ escapeCSV(q.explanation),
1452
+ escapeCSV(q.tags.join(", ")),
1453
+ escapeCSV(q.extra),
1454
+ escapeCSV(q.difficulty),
1455
+ escapeCSV(subjectSlug),
1456
+ escapeCSV(chapterSlug),
1457
+ escapeCSV(topicSlug),
1458
+ escapeCSV(q.markingInstructions),
1459
+ escapeCSV(q.id),
1460
+ escapeCSV(q.imageUrl),
1461
+ escapeCSV(q.answerImageUrl),
1462
+ escapeCSV(q.option2ImageUrl),
1463
+ escapeCSV(q.option3ImageUrl),
1464
+ escapeCSV(q.option4ImageUrl)
1465
+ ].join(",");
1466
+ });
1467
+ return `${header}
1468
+ ${rows.join("\n")}`;
1469
+ }
1470
+
1471
+ // src/logic/media-url.ts
1472
+ function isStorageKey(value) {
1473
+ return !value.startsWith("http://") && !value.startsWith("https://");
1474
+ }
1475
+ var MediaUrlCache = class {
1476
+ constructor(ttlMs = 50 * 60 * 1e3) {
1477
+ this.cache = /* @__PURE__ */ new Map();
1478
+ this.ttlMs = ttlMs;
1479
+ }
1480
+ get(key) {
1481
+ const entry = this.cache.get(key);
1482
+ if (!entry) return void 0;
1483
+ if (Date.now() >= entry.expiresAt) {
1484
+ this.cache.delete(key);
1485
+ return void 0;
1486
+ }
1487
+ return entry.url;
1488
+ }
1489
+ set(key, url) {
1490
+ this.cache.set(key, { url, expiresAt: Date.now() + this.ttlMs });
1491
+ }
1492
+ clear() {
1493
+ this.cache.clear();
1494
+ }
1495
+ };
1496
+ var warnedNoStorage = false;
1497
+ async function resolveMediaUrl(value, storage, cache) {
1498
+ if (!value || value.length === 0) return null;
1499
+ if (!isStorageKey(value)) return value;
1500
+ if (cache) {
1501
+ const cached = cache.get(value);
1502
+ if (cached) return cached;
1503
+ }
1504
+ if (!storage) {
1505
+ if (!warnedNoStorage) {
1506
+ warnedNoStorage = true;
1507
+ console.warn("@orjok/commons: resolveMediaUrl called without a StorageProvider \u2014 returning raw key");
1508
+ }
1509
+ return value;
1510
+ }
1511
+ const { url } = await storage.getFileUrl(value);
1512
+ _optionalChain([cache, 'optionalAccess', _139 => _139.set, 'call', _140 => _140(value, url)]);
1513
+ return url;
1514
+ }
1515
+ async function resolveMediaUrls(obj, fields, storage, cache) {
1516
+ const copy = { ...obj };
1517
+ await Promise.all(
1518
+ fields.map(async (field) => {
1519
+ const val = copy[field];
1520
+ if (typeof val === "string") {
1521
+ copy[field] = await resolveMediaUrl(val, storage, cache);
1522
+ }
1523
+ })
1524
+ );
1525
+ return copy;
1526
+ }
1527
+ function _resetMediaUrlWarning() {
1528
+ warnedNoStorage = false;
1529
+ }
1530
+
1531
+ // src/logic/practice.ts
1532
+ function aggregateSubjectMetrics(progress) {
1533
+ let totalPracticed = 0;
1534
+ let totalMistakes = 0;
1535
+ let totalCorrected = 0;
1536
+ for (const p of progress) {
1537
+ totalPracticed += _nullishCoalesce(p.practicedCount, () => ( 0));
1538
+ totalMistakes += _nullishCoalesce(p.mistakeCount, () => ( 0));
1539
+ totalCorrected += _nullishCoalesce(p.correctedCount, () => ( 0));
1540
+ }
1541
+ const accuracy = totalPracticed > 0 ? Math.round((totalPracticed - totalMistakes) / totalPracticed * 100) : 0;
1542
+ return { totalPracticed, totalMistakes, totalCorrected, accuracy };
1543
+ }
1544
+ function aggregateChapterMetrics(progress) {
1545
+ let totalPracticed = 0;
1546
+ let totalMistakes = 0;
1547
+ let totalCorrected = 0;
1548
+ for (const p of progress) {
1549
+ totalPracticed += _nullishCoalesce(p.practicedCount, () => ( 0));
1550
+ totalMistakes += _nullishCoalesce(p.mistakeCount, () => ( 0));
1551
+ totalCorrected += _nullishCoalesce(p.correctedCount, () => ( 0));
1552
+ }
1553
+ const accuracy = totalPracticed > 0 ? Math.round((totalPracticed - totalMistakes) / totalPracticed * 100) : 0;
1554
+ return { totalPracticed, totalMistakes, totalCorrected, accuracy };
1555
+ }
1556
+ function aggregateTopicMetrics(progress) {
1557
+ let totalPracticed = 0;
1558
+ let totalMistakes = 0;
1559
+ let totalCorrected = 0;
1560
+ for (const p of progress) {
1561
+ totalPracticed += _nullishCoalesce(p.practicedCount, () => ( 0));
1562
+ totalMistakes += _nullishCoalesce(p.mistakeCount, () => ( 0));
1563
+ totalCorrected += _nullishCoalesce(p.correctedCount, () => ( 0));
1564
+ }
1565
+ const accuracy = totalPracticed > 0 ? Math.round((totalPracticed - totalMistakes) / totalPracticed * 100) : 0;
1566
+ return { totalPracticed, totalMistakes, totalCorrected, accuracy };
1567
+ }
1568
+ function calculateAccuracy(practiced, mistakes) {
1569
+ if (practiced <= 0) return 0;
1570
+ return Math.round((practiced - mistakes) / practiced * 100);
1571
+ }
1572
+
1573
+ // src/utils/shuffle.ts
1574
+ function shuffle(array) {
1575
+ const result = [...array];
1576
+ let currentIndex = result.length;
1577
+ while (currentIndex !== 0) {
1578
+ const randomIndex = Math.floor(Math.random() * currentIndex);
1579
+ currentIndex--;
1580
+ [result[currentIndex], result[randomIndex]] = [result[randomIndex], result[currentIndex]];
1581
+ }
1582
+ return result;
1583
+ }
1584
+ function shuffleInPlace(array) {
1585
+ let currentIndex = array.length;
1586
+ while (currentIndex !== 0) {
1587
+ const randomIndex = Math.floor(Math.random() * currentIndex);
1588
+ currentIndex--;
1589
+ [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
1590
+ }
1591
+ }
1592
+
1593
+ // src/utils/bangla-numbers.ts
1594
+ var BANGLA_DIGITS = ["\u09E6", "\u09E7", "\u09E8", "\u09E9", "\u09EA", "\u09EB", "\u09EC", "\u09ED", "\u09EE", "\u09EF"];
1595
+ function engToBanglaNumber(num) {
1596
+ return String(num).split("").map((digit) => {
1597
+ const n = parseInt(digit, 10);
1598
+ return !isNaN(n) ? BANGLA_DIGITS[n] : digit;
1599
+ }).join("");
1600
+ }
1601
+
1602
+ // src/utils/format-curriculum.ts
1603
+ function formatCurriculumName(idString, dbName) {
1604
+ if (dbName) return dbName;
1605
+ if (!idString) return "";
1606
+ const namePart = _nullishCoalesce(idString.split("::")[0], () => ( ""));
1607
+ const clean = namePart.replace(/[-_]/g, " ");
1608
+ return clean.split(/\s+/).map((word) => {
1609
+ if (!word) return "";
1610
+ return word.charAt(0).toUpperCase() + word.slice(1);
1611
+ }).join(" ");
1612
+ }
1613
+
1614
+ // src/utils/relative-time.ts
1615
+ function getRelativeTime(startTime, endTime) {
1616
+ const now = /* @__PURE__ */ new Date();
1617
+ const start = new Date(startTime);
1618
+ const end = endTime ? new Date(endTime) : null;
1619
+ if (end && now >= start && now <= end) {
1620
+ return "";
1621
+ }
1622
+ const diffInSeconds = Math.floor((start.getTime() - now.getTime()) / 1e3);
1623
+ const absDiff = Math.abs(diffInSeconds);
1624
+ const minute = 60;
1625
+ const hour = minute * 60;
1626
+ const day = hour * 24;
1627
+ const week = day * 7;
1628
+ const month = day * 30;
1629
+ const year = day * 365;
1630
+ if (diffInSeconds < 0) {
1631
+ if (absDiff < minute) return "just now";
1632
+ if (absDiff < hour) return `${Math.floor(absDiff / minute)} minutes ago`;
1633
+ if (absDiff < day) return `${Math.floor(absDiff / hour)} hours ago`;
1634
+ if (absDiff < week) return `${Math.floor(absDiff / day)} days ago`;
1635
+ if (absDiff < month) return `${Math.floor(absDiff / week)} weeks ago`;
1636
+ if (absDiff < year) return `${Math.floor(absDiff / month)} months ago`;
1637
+ return `${Math.floor(absDiff / year)} years ago`;
1638
+ } else {
1639
+ if (absDiff < minute) return "in a moment";
1640
+ if (absDiff < hour) return `in ${Math.floor(absDiff / minute)} minutes`;
1641
+ if (absDiff < day) return `in ${Math.floor(absDiff / hour)} hours`;
1642
+ if (absDiff < week) return `in ${Math.floor(absDiff / day)} days`;
1643
+ if (absDiff < month) return `in ${Math.floor(absDiff / week)} weeks`;
1644
+ if (absDiff < year) return `in ${Math.floor(absDiff / month)} months`;
1645
+ return `in ${Math.floor(absDiff / year)} years`;
1646
+ }
1647
+ }
1648
+
1649
+ // src/utils/latex.ts
1650
+ function processLatexText(str) {
1651
+ if (!str) return str;
1652
+ const regex = /(\$\$(.*?)\$\$)|(\$(.*?)\$)/gs;
1653
+ let lastIndex = 0;
1654
+ let result = "";
1655
+ let match;
1656
+ while ((match = regex.exec(str)) !== null) {
1657
+ const textBefore = str.substring(lastIndex, match.index);
1658
+ result += textBefore.replace(/\\n/g, "\n");
1659
+ const isDisplay = match[1] !== void 0;
1660
+ const mathContent = isDisplay ? match[2] : match[4];
1661
+ const delimiter = isDisplay ? "$$" : "$";
1662
+ const processedMath = mathContent.replace(
1663
+ /(\\text\s*\{[^{}]*\})|([\u0980-\u09FF]+(?:\s+[\u0980-\u09FF]+)*)/g,
1664
+ (_, p1, p2) => {
1665
+ if (p1) return p1;
1666
+ return `\\text{${p2}}`;
1667
+ }
1668
+ );
1669
+ result += delimiter + processedMath + delimiter;
1670
+ lastIndex = regex.lastIndex;
1671
+ }
1672
+ const remainingText = str.substring(lastIndex);
1673
+ result += remainingText.replace(/\\n/g, "\n");
1674
+ return result;
1675
+ }
1676
+
1677
+
1678
+
1679
+
1680
+
1681
+
1682
+
1683
+
1684
+
1685
+
1686
+
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+
1693
+
1694
+
1695
+
1696
+
1697
+
1698
+
1699
+
1700
+
1701
+
1702
+
1703
+
1704
+
1705
+
1706
+
1707
+
1708
+
1709
+
1710
+
1711
+
1712
+
1713
+
1714
+
1715
+
1716
+
1717
+
1718
+
1719
+
1720
+
1721
+
1722
+ exports.AIService = AIService; exports.ContestService = ContestService; exports.CourseService = CourseService; exports.CurriculumService = CurriculumService; exports.MediaService = MediaService; exports.MediaUrlCache = MediaUrlCache; exports.NewsService = NewsService; exports.OrjokClient = OrjokClient; exports.PackService = PackService; exports.ProgressService = ProgressService; exports.QuestionService = QuestionService; exports.UserService = UserService; exports._resetMediaUrlWarning = _resetMediaUrlWarning; exports.aggregateChapterMetrics = aggregateChapterMetrics; exports.aggregateSubjectMetrics = aggregateSubjectMetrics; exports.aggregateTopicMetrics = aggregateTopicMetrics; exports.buildImageAnswer = buildImageAnswer; exports.calculateAccuracy = calculateAccuracy; exports.calculateExamTime = calculateExamTime; exports.computeRatingDelta = computeRatingDelta; exports.createOrjokClient = createOrjokClient; exports.detectQuestionType = detectQuestionType; exports.engToBanglaNumber = engToBanglaNumber; exports.filterQuestionsByMode = filterQuestionsByMode; exports.formatCurriculumName = formatCurriculumName; exports.formatExamTime = formatExamTime; exports.formatQuestionsToCsv = formatQuestionsToCsv; exports.formatQuestionsToText = formatQuestionsToText; exports.getAllTiers = getAllTiers; exports.getEloProgress = getEloProgress; exports.getEloTier = getEloTier; exports.getRatingForSubject = getRatingForSubject; exports.getRelativeTime = getRelativeTime; exports.isImageAnswer = isImageAnswer; exports.isStorageKey = isStorageKey; exports.normalizeDifficulty = normalizeDifficulty; exports.parseCsvQuestions = parseCsvQuestions; exports.parseImageKeys = parseImageKeys; exports.parseTextQuestions = parseTextQuestions; exports.processLatexText = processLatexText; exports.resolveMediaUrl = resolveMediaUrl; exports.resolveMediaUrls = resolveMediaUrls; exports.scoreExam = scoreExam; exports.shuffle = shuffle; exports.shuffleInPlace = shuffleInPlace;
1723
+ //# sourceMappingURL=index.cjs.map