@orjok/commons 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { D as Difficulty, L as Language, i as Level, j as QuestionType, Q as QuestionObject } from './practice-QnWtC5A7.cjs';
2
- export { A as AIService, k as AIUsageLog, l as AddQuestionTagInput, C as Chapter, b as CheckParticipationResponse, a as Contest, m as ContestAnswersResponse, n as ContestOption, o as ContestParticipant, p as ContestQuestion, q as ContestQuestionsResponse, r as ContestService, c as Course, s as CourseEnrolled, t as CourseEnrollmentRequest, d as CourseItem, u as CourseItemType, e as CourseLiveExam, v as CourseLiveExamParticipant, w as CourseLiveExamQuestionsResponse, x as CourseService, y as CreateContestInput, z as CreateCourseInput, B as CreateCourseItemInput, E as CreateCourseLiveExamInput, F as CreateCourseResponse, G as CreateCourseVideoInput, H as CreateCourseVideoResponse, I as CreatePackInput, J as CreateQuestionInput, K as CreateQuestionResponse, M as CurriculumService, N as DeleteCourseItemInput, R as EnrollStudentInput, V as EvaluateWrittenAnswerInput, W as EvaluateWrittenAnswerResponse, X as GetSignedFileURLInput, Y as GetSignedURLInput, Z as LeaderboardResponse, _ as ListByCurriculumInput, $ as ListByRandomHashInput, a0 as MediaService, a1 as ModelType, a2 as NewsArticle, a3 as NewsService, a4 as Option, O as OrjokClient, a5 as OrjokClientConfig, P as Pack, a6 as PackExamResults, a7 as PackGroup, a8 as PackReport, a9 as PackService, aa as PackTag, ab as PaginatedList, ac as PaymentStatus, ad as PaymentTransaction, h as PracticeMetrics, ae as ProgressService, af as QuestionReport, ag as QuestionService, ah as QuestionTag, ai as QuestionTracking, aj as QuestionTrackingStatus, ak as QuestionVote, al as SendEnrollmentRequestInput, am as SignedURLResponse, an as SortDirection, ao as StatusIdResponse, ap as StatusResponse, S as Subject, aq as SubmitPackExamInput, ar as Tag, as as Tier, T as Topic, at as TrackPracticeProgressInput, au as UpdateUserAvatarInput, av as UploadImageResponse, aw as UploadVideoToBunnyInput, ax as User, f as UserChapterProgress, ay as UserService, U as UserSubjectProgress, az as UserTopicMetric, g as UserTopicProgress, aA as Verification, aB as VerificationType, aC as VoteInput, aD as VoteType, aE as aggregateChapterMetrics, aF as aggregateSubjectMetrics, aG as aggregateTopicMetrics, aH as calculateAccuracy, aI as createOrjokClient, aJ as isDifficultyMatch, aK as isLanguageMatch, aL as isValidMCQ } from './practice-QnWtC5A7.cjs';
3
- import { S as StorageProvider } from './storage-DLqdJgQt.cjs';
4
- export { A as AuthProvider, a as AuthSession, G as GraphQLResult, N as NetworkProvider, b as UploadOptions, U as UserAttributes } from './storage-DLqdJgQt.cjs';
1
+ import { k as QuestionType, Q as QuestionObject, D as Difficulty, L as Language, l as Level, m as PaginatedList } from './notification-Ctfy0m05.cjs';
2
+ export { n as AIService, o as AIUsageLog, p as AddQuestionTagInput, A as Announcement, C as Chapter, b as CheckParticipationResponse, a as Contest, q as ContestAnswersResponse, r as ContestOption, s as ContestParticipant, t as ContestQuestion, u as ContestQuestionsResponse, v as ContestService, c as Course, w as CourseEnrolled, x as CourseEnrollmentRequest, d as CourseItem, y as CourseItemType, e as CourseLiveExam, z as CourseLiveExamParticipant, B as CourseLiveExamQuestionsResponse, E as CourseService, F as CreateAnnouncementInput, G as CreateContestInput, H as CreateCourseInput, I as CreateCourseItemInput, J as CreateCourseLiveExamInput, K as CreateCourseResponse, M as CreateCourseVideoInput, R as CreateCourseVideoResponse, V as CreatePackGroupInput, W as CreatePackInput, X as CreateQuestionInput, Y as CreateQuestionResponse, Z as CreateSubscriptionRequestInput, _ as CreateUserNotificationInput, $ as CurriculumService, a0 as DeleteCourseItemInput, a1 as EnrollStudentInput, a2 as EvaluateWrittenAnswerInput, a3 as EvaluateWrittenAnswerResponse, a4 as FormatLevelUpParams, a5 as GetSignedFileURLInput, a6 as GetSignedURLInput, a7 as LeaderboardResponse, a8 as LevelUpNotificationResult, a9 as ListByCurriculumInput, aa as ListByLevelInput, ab as ListByPublicExamInput, ac as ListByRandomHashInput, ad as ListPackGroupsInput, ae as ListSubscriptionRequestsInput, af as ListUsersInput, ag as MediaService, ah as MergeTimelineParams, ai as ModelType, aj as NewsArticle, ak as NewsService, al as NotificationService, N as NotificationTimelineItem, am as Option, O as OrjokClient, an as OrjokClientConfig, P as Pack, ao as PackExamResults, ap as PackGroup, aq as PackReport, ar as PackService, as as PackTag, at as PaymentMethod, au as PaymentStatus, av as PaymentTransaction, h as PracticeMetrics, aw as ProgressService, i as PublicExamOption, ax as QuestionReport, ay as QuestionService, az as QuestionTag, aA as QuestionTracking, aB as QuestionTrackingStatus, aC as QuestionVote, aD as SelectOption, aE as SendEnrollmentRequestInput, aF as SignedURLResponse, aG as SortDirection, aH as StatusIdResponse, aI as StatusResponse, S as Subject, aJ as SubmitPackExamInput, aK as SubscriptionRequest, aL as SubscriptionService, aM as Tag, aN as Tier, T as Topic, aO as TrackPracticeProgressInput, aP as UpdateSubscriptionRequestInput, aQ as UpdateUserAvatarInput, aR as UpdateUserNotificationInput, aS as UpdateUserProfileInput, aT as UploadCourseItemInput, aU as UploadImageResponse, aV as UploadVideoToBunnyInput, aW as User, f as UserChapterProgress, j as UserNotification, aX as UserService, U as UserSubjectProgress, aY as UserTopicMetric, g as UserTopicProgress, aZ as Verification, a_ as VerificationType, a$ as VoteInput, b0 as VoteType, b1 as aggregateChapterMetrics, b2 as aggregateSubjectMetrics, b3 as aggregateTopicMetrics, b4 as calculateAccuracy, b5 as calculateUnreadCount, b6 as createOrjokClient, b7 as difficultyOptions, b8 as formatLevelUpNotification, b9 as getPublicExamsByLevel, ba as isDifficultyMatch, bb as isLanguageMatch, bc as isValidMCQ, bd as languageOptions, be as levelOptions, bf as mergeNotificationTimeline, bg as publicExamOptions } from './notification-Ctfy0m05.cjs';
3
+ import { S as StorageProvider } from './storage-9pK8KwIM.cjs';
4
+ export { b as AuthEventListener, A as AuthProvider, a as AuthSession, G as GraphQLResult, N as NetworkProvider, c as UploadOptions, U as UserAttributes } from './storage-9pK8KwIM.cjs';
5
5
 
6
6
  type RenderCategory = "Background" | "Hair Back" | "Skin Color Body" | "Skin Color Head" | "Skin Color" | "Clothes Back" | "Clothes Front" | "Accessories" | "Headwears" | "Facial Expression" | "Beard" | "Eyewear" | "Hair Front";
7
7
  type UICategory = "Background" | "Hair" | "Skin Color" | "Clothes" | "Accessories" | "Headwears" | "Eyewear" | "Facial Expression" | "Beard";
@@ -25,16 +25,9 @@ type AvatarConfig = Record<string, AvatarConfigItem[]>;
25
25
  interface AvatarState {
26
26
  selections: Record<string, string>;
27
27
  colors: Record<string, string>;
28
+ gender?: string;
28
29
  }
29
30
 
30
- interface SelectOption<T = string> {
31
- value: T;
32
- label: string;
33
- }
34
- declare const levelOptions: SelectOption<Level>[];
35
- declare const languageOptions: SelectOption<Language>[];
36
- declare const difficultyOptions: SelectOption<Difficulty>[];
37
-
38
31
  declare const HAIR_COLORS: ColorOption[];
39
32
  declare const CLOTHES_COLORS: ColorOption[];
40
33
  declare const COLOR_HUES: Record<string, number>;
@@ -42,7 +35,16 @@ declare const RENDER_ORDER: readonly ["Background", "Hair Back", "Clothes Back",
42
35
  declare const INITIAL_AVATAR_DATA: Record<UICategory, string[]>;
43
36
  declare function getActualOptionFileName(category: string, baseName: string, config: AvatarConfig, selections: Record<string, string>): AvatarConfigItem | null;
44
37
  declare function parseAvatarConfig(configStr: string | null | undefined): AvatarState;
38
+ declare function parseAvatarConfigWithDefaults(configStr: string | null | undefined, seed?: string): AvatarState;
45
39
  declare function serializeAvatarConfig(state: AvatarState): string;
40
+ declare function generateRandomAvatarState(options?: {
41
+ gender?: "Male" | "Female";
42
+ seed?: string;
43
+ }): AvatarState;
44
+ declare function generateRandomAvatarConfig(options?: {
45
+ gender?: "Male" | "Female";
46
+ seed?: string;
47
+ }): string;
46
48
 
47
49
  interface EloTier {
48
50
  name: string;
@@ -86,6 +88,39 @@ declare function reorderObjectKeys<T>(obj: {
86
88
  [key: number]: T;
87
89
  };
88
90
 
91
+ /**
92
+ * Home Logic Utilities
93
+ * Supports Signed-In User Homepage customization, greeting, streak calculation, and level mapping.
94
+ */
95
+ interface SubjectShortcut {
96
+ id: string;
97
+ name: string;
98
+ iconKey: string;
99
+ colorClass: string;
100
+ }
101
+ /**
102
+ * Maps Cognito user level string to standard level enum values: "SSC" | "HSC+Admission" | "BCS"
103
+ */
104
+ declare function mapCognitoLevelToStandardLevel(cognitoLevel?: string | null): string;
105
+ /**
106
+ * Returns contextual time of day greeting
107
+ */
108
+ declare function getTimeOfDayGreeting(customHour?: number, lang?: "en" | "bn"): {
109
+ greeting: string;
110
+ period: "morning" | "afternoon" | "evening" | "night";
111
+ };
112
+ /**
113
+ * Returns recommended subject shortcuts for the given level
114
+ */
115
+ declare function getRecommendedSubjectsForLevel(level: string, lang?: "en" | "bn"): SubjectShortcut[];
116
+ /**
117
+ * Calculates continuous consecutive active study streak in days
118
+ */
119
+ declare function calculateStreakFromDates(activityDates: string[]): {
120
+ streak: number;
121
+ isActiveToday: boolean;
122
+ };
123
+
89
124
  interface ParsedQuestion {
90
125
  id?: string;
91
126
  imageUrl?: string;
@@ -101,6 +136,7 @@ interface ParsedQuestion {
101
136
  subjectId?: string;
102
137
  chapterId?: string;
103
138
  topicId?: string;
139
+ publicExam?: string;
104
140
  type: "MCQ" | "WRITTEN";
105
141
  markingInstructions?: string;
106
142
  answerImageUrl?: string;
@@ -130,6 +166,175 @@ declare function resolveMediaUrl(value: string | null | undefined, storage: Stor
130
166
  declare function resolveMediaUrls<T extends Record<string, unknown>>(obj: T, fields: (keyof T)[], storage: StorageProvider | undefined, cache?: MediaUrlCache): Promise<T>;
131
167
  declare function _resetMediaUrlWarning(): void;
132
168
 
169
+ type BillingCycle = "monthly" | "quarterly" | "biannually" | "annually";
170
+ type SubscriptionTier = "FREE" | "PRO" | "PRO_AI";
171
+ interface PlanCyclePricing {
172
+ monthly: number;
173
+ quarterly: number;
174
+ biannually: number;
175
+ annually: number;
176
+ }
177
+ interface PlanAiQuotaConfig {
178
+ monthly: {
179
+ aiEvals: number;
180
+ aiQuestions: number;
181
+ };
182
+ quarterly: {
183
+ aiEvals: number;
184
+ aiQuestions: number;
185
+ };
186
+ biannually: {
187
+ aiEvals: number;
188
+ aiQuestions: number;
189
+ };
190
+ annually: {
191
+ aiEvals: number;
192
+ aiQuestions: number;
193
+ };
194
+ }
195
+ interface SubscriptionPlan {
196
+ id: SubscriptionTier;
197
+ tier: SubscriptionTier;
198
+ titleKey: string;
199
+ descKey: string;
200
+ pricing: PlanCyclePricing;
201
+ aiQuotas: PlanAiQuotaConfig;
202
+ }
203
+ interface TopUpBoosterPack {
204
+ id: string;
205
+ type: "AI_EVAL" | "AI_QUESTION";
206
+ amount: number;
207
+ price: number;
208
+ titleKey: string;
209
+ descKey: string;
210
+ badgeKey?: string;
211
+ }
212
+ declare const MANUAL_PAYMENT_CONFIG: {
213
+ phoneNumber: string;
214
+ accountType: string;
215
+ methods: readonly ["BKASH", "ROCKET"];
216
+ };
217
+ declare const SUBSCRIPTION_PLANS: Record<SubscriptionTier, SubscriptionPlan>;
218
+ declare const AI_EVAL_BOOSTER_PACKS: TopUpBoosterPack[];
219
+ declare const AI_QUESTION_BOOSTER_PACKS: TopUpBoosterPack[];
220
+ declare function getCycleMultiplier(cycle: BillingCycle): number;
221
+ declare function getPlanOriginalPrice(tier: SubscriptionTier | string, cycle: BillingCycle): number;
222
+ declare function getPlanPrice(tier: SubscriptionTier | string, cycle: BillingCycle): number;
223
+ declare function getPlanMonthlyEquivalentPrice(tier: SubscriptionTier | string, cycle: BillingCycle): number;
224
+ declare function getPlanDiscountPercent(cycle: BillingCycle): number;
225
+ declare function getPlanAiQuotas(tier: SubscriptionTier | string, cycle: BillingCycle): {
226
+ aiEvals: number;
227
+ aiQuestions: number;
228
+ };
229
+ declare function isValidBangladeshiPhone(phone: string): boolean;
230
+ declare function isValidTrxId(trxId: string): boolean;
231
+ declare function hasProAccess(tier?: string | null, expiresAt?: string | null): boolean;
232
+ declare function hasAiTierAccess(tier?: string | null, expiresAt?: string | null): boolean;
233
+ declare const FREE_DAILY_PRACTICE_LIMIT = 30;
234
+ declare function canExportPack(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
235
+ declare function canAccessMistakeVault(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
236
+ declare function canWatchContestSolution(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
237
+ declare function shouldTrackPracticeProgress(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
238
+ declare function getDailyPracticeLimit(tier?: string | null, expiresAt?: string | null): number | null;
239
+ declare function checkDailyPracticeLimit(dailyCount: number, lastPracticeDate: string | null | undefined, tier?: string | null, expiresAt?: string | null, todayStr?: string): {
240
+ allowed: boolean;
241
+ remaining: number;
242
+ currentCount: number;
243
+ isUnlimited: boolean;
244
+ };
245
+ declare function hasSufficientAiQuestionQuota(quota: number | null | undefined, requested: number): boolean;
246
+ declare function hasSufficientAiEvalQuota(quota: number | null | undefined): boolean;
247
+
248
+ /**
249
+ * @file xp.ts
250
+ * @description Experience Points (XP) and Level progression logic for the Orjok platform.
251
+ */
252
+ interface XpTier {
253
+ id: "novice" | "dedicated" | "skilled" | "master" | "grandmaster" | "legend";
254
+ minLevel: number;
255
+ maxLevel: number;
256
+ nameEn: string;
257
+ nameBn: string;
258
+ color: string;
259
+ badgeBg: string;
260
+ badgeBorder: string;
261
+ badgeText: string;
262
+ }
263
+ declare const XP_TIERS: XpTier[];
264
+ declare const XP_REWARDS: {
265
+ readonly PRACTICE_CORRECT: 10;
266
+ readonly PRACTICE_ATTEMPT: 2;
267
+ readonly PACK_EXAM_BASE: 20;
268
+ readonly PACK_EXAM_CORRECT: 5;
269
+ readonly PACK_EXAM_HIGH_SCORE_BONUS: 25;
270
+ readonly CONTEST_PARTICIPATION: 50;
271
+ readonly CONTEST_TOP_10_BONUS: 100;
272
+ readonly CONTEST_TOP_25_BONUS: 50;
273
+ readonly CREATE_QUESTION: 25;
274
+ readonly CREATE_PACK: 50;
275
+ readonly VOTE: 2;
276
+ readonly AI_EVALUATION: 15;
277
+ };
278
+ type XpRewardAction = "practice" | "packExam" | "contest" | "createQuestion" | "createPack" | "vote" | "aiEvaluation";
279
+ interface XpRewardMetadata {
280
+ isCorrect?: boolean;
281
+ correctCount?: number;
282
+ totalQuestions?: number;
283
+ rank?: number;
284
+ totalParticipants?: number;
285
+ }
286
+ interface XpProgressInfo {
287
+ level: number;
288
+ xp: number;
289
+ currentLevelXp: number;
290
+ nextLevelXp: number;
291
+ xpInLevel: number;
292
+ xpRequiredForLevel: number;
293
+ xpToNextLevel: number;
294
+ progressPercent: number;
295
+ tier: XpTier;
296
+ }
297
+ /**
298
+ * Calculates the total cumulative XP required to reach a specific level.
299
+ * Formula: 25 * (L^2 + L - 2) = 25 * (L - 1) * (L + 2)
300
+ * Level 1 = 0 XP
301
+ * Level 2 = 100 XP
302
+ * Level 3 = 250 XP
303
+ * Level 4 = 450 XP
304
+ * Level 5 = 700 XP
305
+ * Level 6 = 1000 XP
306
+ * Level 10 = 2700 XP
307
+ * Level 20 = 10450 XP
308
+ * Level 50 = 63700 XP
309
+ */
310
+ declare function getXpForLevel(level: number): number;
311
+ /**
312
+ * Calculates the user's level based on cumulative XP.
313
+ * Derived by inverting: 25 * L^2 + 25 * L - (50 + XP) = 0
314
+ * L = floor((sqrt(9 + 0.16 * XP) - 1) / 2)
315
+ */
316
+ declare function getLevelFromXp(xp: number): number;
317
+ /**
318
+ * Returns the XP required to advance from `level` to `level + 1`.
319
+ */
320
+ declare function getXpRequiredForNextLevel(level: number): number;
321
+ /**
322
+ * Returns complete progress details for a given cumulative XP value.
323
+ */
324
+ declare function getXpProgress(xp: number): XpProgressInfo;
325
+ /**
326
+ * Returns the tier metadata for a given level.
327
+ */
328
+ declare function getXpTier(level: number): XpTier;
329
+ /**
330
+ * Returns all configured XP tiers.
331
+ */
332
+ declare function getAllXpTiers(): XpTier[];
333
+ /**
334
+ * Calculates the XP reward for a given user activity.
335
+ */
336
+ declare function calculateXpReward(action: XpRewardAction, metadata?: XpRewardMetadata): number;
337
+
133
338
  type PrimaryTab = "home" | "learn" | "contests" | "courses" | "profile";
134
339
  declare function getActiveTab(pathname: string): PrimaryTab;
135
340
  declare function getCanonicalPath(pathname: string): string;
@@ -159,7 +364,7 @@ interface TimeLeft {
159
364
  seconds: number;
160
365
  isEnded: boolean;
161
366
  }
162
- declare function convertToBangladeshTime(isoString: string): string;
367
+ declare function convertToBangladeshTime(isoString: string, locale?: string): string;
163
368
  declare function getDhakaNow(): Date;
164
369
  declare function calculateTimeLeft(endTime: string | Date): TimeLeft;
165
370
  declare function formatDate(date: Date | string, locale?: string): string;
@@ -173,5 +378,16 @@ declare function sanitizeFileName(name: string): string;
173
378
  declare function isQuestionLevel(value: unknown): value is Level;
174
379
  declare function isLanguage(value: unknown): value is Language;
175
380
  declare function isDifficulty(value: unknown): value is Difficulty;
381
+ declare function normalizeLevel(value?: string | null): string;
382
+
383
+ /**
384
+ * Accumulates items across paginated GraphQL queries until targetLimit is reached
385
+ * or nextToken is exhausted (null/undefined).
386
+ *
387
+ * This guarantees that even when DynamoDB evaluates filter expressions post-read
388
+ * and yields fewer than requested items in a single scan batch, the consumer
389
+ * receives up to `targetLimit` matching items and the exact continuation token.
390
+ */
391
+ declare function paginateWithAccumulator<T>(fetchPage: (limit: number, nextToken?: string | null) => Promise<PaginatedList<T>>, targetLimit?: number, initialNextToken?: string | null, maxIterations?: number): Promise<PaginatedList<T>>;
176
392
 
177
- export { type AvatarConfig, type AvatarConfigItem, type AvatarState, CLOTHES_COLORS, COLOR_HUES, type ColorOption, Difficulty, type EloTier, type ExamConfig, type ExamMode, HAIR_COLORS, INITIAL_AVATAR_DATA, Language, Level, MediaUrlCache, type ParseResult, type ParsedQuestion, type PrimaryTab, QuestionObject, QuestionType, RENDER_ORDER, type RatingField, type RenderCategory, type SelectOption, StorageProvider, type TimeLeft, type UICategory, _resetMediaUrlWarning, buildImageAnswer, calculateDefaultExamMinutes, calculateExamTime, calculateTimeLeft, computeRatingDelta, convertToBangladeshTime, detectQuestionType, difficultyOptions, engToBanglaNumber, extractBilingualName, filterQuestionsByMode, formatBDT, formatCurriculumName, formatDate, formatExamTime, formatQuestionsToCsv, formatQuestionsToText, getActiveTab, getActualOptionFileName, getAllTiers, getCanonicalPath, getDhakaNow, getEloProgress, getEloTier, getRatingForSubject, getRelativeTime, getYouTubeId, isAuthGatedRoute, isCorrectAnswer, isDifficulty, isImageAnswer, isLanguage, isQuestionLevel, isStorageKey, languageOptions, levelOptions, normalizeDifficulty, parseAvatarConfig, parseCsvQuestions, parseImageKeys, parseTextQuestions, processLatexText, reorderObjectKeys, resolveMediaUrl, resolveMediaUrls, sanitizeFileName, scoreExam, serializeAvatarConfig, shuffle, shuffleInPlace };
393
+ export { AI_EVAL_BOOSTER_PACKS, AI_QUESTION_BOOSTER_PACKS, type AvatarConfig, type AvatarConfigItem, type AvatarState, type BillingCycle, CLOTHES_COLORS, COLOR_HUES, type ColorOption, Difficulty, type EloTier, type ExamConfig, type ExamMode, FREE_DAILY_PRACTICE_LIMIT, HAIR_COLORS, INITIAL_AVATAR_DATA, Language, Level, MANUAL_PAYMENT_CONFIG, MediaUrlCache, PaginatedList, type ParseResult, type ParsedQuestion, type PlanAiQuotaConfig, type PlanCyclePricing, type PrimaryTab, QuestionObject, QuestionType, RENDER_ORDER, type RatingField, type RenderCategory, SUBSCRIPTION_PLANS, StorageProvider, type SubjectShortcut, type SubscriptionPlan, type SubscriptionTier, type TimeLeft, type TopUpBoosterPack, type UICategory, XP_REWARDS, XP_TIERS, type XpProgressInfo, type XpRewardAction, type XpRewardMetadata, type XpTier, _resetMediaUrlWarning, buildImageAnswer, calculateDefaultExamMinutes, calculateExamTime, calculateStreakFromDates, calculateTimeLeft, calculateXpReward, canAccessMistakeVault, canExportPack, canWatchContestSolution, checkDailyPracticeLimit, computeRatingDelta, convertToBangladeshTime, detectQuestionType, engToBanglaNumber, extractBilingualName, filterQuestionsByMode, formatBDT, formatCurriculumName, formatDate, formatExamTime, formatQuestionsToCsv, formatQuestionsToText, generateRandomAvatarConfig, generateRandomAvatarState, getActiveTab, getActualOptionFileName, getAllTiers, getAllXpTiers, getCanonicalPath, getCycleMultiplier, getDailyPracticeLimit, getDhakaNow, getEloProgress, getEloTier, getLevelFromXp, getPlanAiQuotas, getPlanDiscountPercent, getPlanMonthlyEquivalentPrice, getPlanOriginalPrice, getPlanPrice, getRatingForSubject, getRecommendedSubjectsForLevel, getRelativeTime, getTimeOfDayGreeting, getXpForLevel, getXpProgress, getXpRequiredForNextLevel, getXpTier, getYouTubeId, hasAiTierAccess, hasProAccess, hasSufficientAiEvalQuota, hasSufficientAiQuestionQuota, isAuthGatedRoute, isCorrectAnswer, isDifficulty, isImageAnswer, isLanguage, isQuestionLevel, isStorageKey, isValidBangladeshiPhone, isValidTrxId, mapCognitoLevelToStandardLevel, normalizeDifficulty, normalizeLevel, paginateWithAccumulator, parseAvatarConfig, parseAvatarConfigWithDefaults, parseCsvQuestions, parseImageKeys, parseTextQuestions, processLatexText, reorderObjectKeys, resolveMediaUrl, resolveMediaUrls, sanitizeFileName, scoreExam, serializeAvatarConfig, shouldTrackPracticeProgress, shuffle, shuffleInPlace };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { D as Difficulty, L as Language, i as Level, j as QuestionType, Q as QuestionObject } from './practice-Dh2Tv80G.js';
2
- export { A as AIService, k as AIUsageLog, l as AddQuestionTagInput, C as Chapter, b as CheckParticipationResponse, a as Contest, m as ContestAnswersResponse, n as ContestOption, o as ContestParticipant, p as ContestQuestion, q as ContestQuestionsResponse, r as ContestService, c as Course, s as CourseEnrolled, t as CourseEnrollmentRequest, d as CourseItem, u as CourseItemType, e as CourseLiveExam, v as CourseLiveExamParticipant, w as CourseLiveExamQuestionsResponse, x as CourseService, y as CreateContestInput, z as CreateCourseInput, B as CreateCourseItemInput, E as CreateCourseLiveExamInput, F as CreateCourseResponse, G as CreateCourseVideoInput, H as CreateCourseVideoResponse, I as CreatePackInput, J as CreateQuestionInput, K as CreateQuestionResponse, M as CurriculumService, N as DeleteCourseItemInput, R as EnrollStudentInput, V as EvaluateWrittenAnswerInput, W as EvaluateWrittenAnswerResponse, X as GetSignedFileURLInput, Y as GetSignedURLInput, Z as LeaderboardResponse, _ as ListByCurriculumInput, $ as ListByRandomHashInput, a0 as MediaService, a1 as ModelType, a2 as NewsArticle, a3 as NewsService, a4 as Option, O as OrjokClient, a5 as OrjokClientConfig, P as Pack, a6 as PackExamResults, a7 as PackGroup, a8 as PackReport, a9 as PackService, aa as PackTag, ab as PaginatedList, ac as PaymentStatus, ad as PaymentTransaction, h as PracticeMetrics, ae as ProgressService, af as QuestionReport, ag as QuestionService, ah as QuestionTag, ai as QuestionTracking, aj as QuestionTrackingStatus, ak as QuestionVote, al as SendEnrollmentRequestInput, am as SignedURLResponse, an as SortDirection, ao as StatusIdResponse, ap as StatusResponse, S as Subject, aq as SubmitPackExamInput, ar as Tag, as as Tier, T as Topic, at as TrackPracticeProgressInput, au as UpdateUserAvatarInput, av as UploadImageResponse, aw as UploadVideoToBunnyInput, ax as User, f as UserChapterProgress, ay as UserService, U as UserSubjectProgress, az as UserTopicMetric, g as UserTopicProgress, aA as Verification, aB as VerificationType, aC as VoteInput, aD as VoteType, aE as aggregateChapterMetrics, aF as aggregateSubjectMetrics, aG as aggregateTopicMetrics, aH as calculateAccuracy, aI as createOrjokClient, aJ as isDifficultyMatch, aK as isLanguageMatch, aL as isValidMCQ } from './practice-Dh2Tv80G.js';
3
- import { S as StorageProvider } from './storage-DLqdJgQt.js';
4
- export { A as AuthProvider, a as AuthSession, G as GraphQLResult, N as NetworkProvider, b as UploadOptions, U as UserAttributes } from './storage-DLqdJgQt.js';
1
+ import { k as QuestionType, Q as QuestionObject, D as Difficulty, L as Language, l as Level, m as PaginatedList } from './notification-BoqtkNrc.js';
2
+ export { n as AIService, o as AIUsageLog, p as AddQuestionTagInput, A as Announcement, C as Chapter, b as CheckParticipationResponse, a as Contest, q as ContestAnswersResponse, r as ContestOption, s as ContestParticipant, t as ContestQuestion, u as ContestQuestionsResponse, v as ContestService, c as Course, w as CourseEnrolled, x as CourseEnrollmentRequest, d as CourseItem, y as CourseItemType, e as CourseLiveExam, z as CourseLiveExamParticipant, B as CourseLiveExamQuestionsResponse, E as CourseService, F as CreateAnnouncementInput, G as CreateContestInput, H as CreateCourseInput, I as CreateCourseItemInput, J as CreateCourseLiveExamInput, K as CreateCourseResponse, M as CreateCourseVideoInput, R as CreateCourseVideoResponse, V as CreatePackGroupInput, W as CreatePackInput, X as CreateQuestionInput, Y as CreateQuestionResponse, Z as CreateSubscriptionRequestInput, _ as CreateUserNotificationInput, $ as CurriculumService, a0 as DeleteCourseItemInput, a1 as EnrollStudentInput, a2 as EvaluateWrittenAnswerInput, a3 as EvaluateWrittenAnswerResponse, a4 as FormatLevelUpParams, a5 as GetSignedFileURLInput, a6 as GetSignedURLInput, a7 as LeaderboardResponse, a8 as LevelUpNotificationResult, a9 as ListByCurriculumInput, aa as ListByLevelInput, ab as ListByPublicExamInput, ac as ListByRandomHashInput, ad as ListPackGroupsInput, ae as ListSubscriptionRequestsInput, af as ListUsersInput, ag as MediaService, ah as MergeTimelineParams, ai as ModelType, aj as NewsArticle, ak as NewsService, al as NotificationService, N as NotificationTimelineItem, am as Option, O as OrjokClient, an as OrjokClientConfig, P as Pack, ao as PackExamResults, ap as PackGroup, aq as PackReport, ar as PackService, as as PackTag, at as PaymentMethod, au as PaymentStatus, av as PaymentTransaction, h as PracticeMetrics, aw as ProgressService, i as PublicExamOption, ax as QuestionReport, ay as QuestionService, az as QuestionTag, aA as QuestionTracking, aB as QuestionTrackingStatus, aC as QuestionVote, aD as SelectOption, aE as SendEnrollmentRequestInput, aF as SignedURLResponse, aG as SortDirection, aH as StatusIdResponse, aI as StatusResponse, S as Subject, aJ as SubmitPackExamInput, aK as SubscriptionRequest, aL as SubscriptionService, aM as Tag, aN as Tier, T as Topic, aO as TrackPracticeProgressInput, aP as UpdateSubscriptionRequestInput, aQ as UpdateUserAvatarInput, aR as UpdateUserNotificationInput, aS as UpdateUserProfileInput, aT as UploadCourseItemInput, aU as UploadImageResponse, aV as UploadVideoToBunnyInput, aW as User, f as UserChapterProgress, j as UserNotification, aX as UserService, U as UserSubjectProgress, aY as UserTopicMetric, g as UserTopicProgress, aZ as Verification, a_ as VerificationType, a$ as VoteInput, b0 as VoteType, b1 as aggregateChapterMetrics, b2 as aggregateSubjectMetrics, b3 as aggregateTopicMetrics, b4 as calculateAccuracy, b5 as calculateUnreadCount, b6 as createOrjokClient, b7 as difficultyOptions, b8 as formatLevelUpNotification, b9 as getPublicExamsByLevel, ba as isDifficultyMatch, bb as isLanguageMatch, bc as isValidMCQ, bd as languageOptions, be as levelOptions, bf as mergeNotificationTimeline, bg as publicExamOptions } from './notification-BoqtkNrc.js';
3
+ import { S as StorageProvider } from './storage-9pK8KwIM.js';
4
+ export { b as AuthEventListener, A as AuthProvider, a as AuthSession, G as GraphQLResult, N as NetworkProvider, c as UploadOptions, U as UserAttributes } from './storage-9pK8KwIM.js';
5
5
 
6
6
  type RenderCategory = "Background" | "Hair Back" | "Skin Color Body" | "Skin Color Head" | "Skin Color" | "Clothes Back" | "Clothes Front" | "Accessories" | "Headwears" | "Facial Expression" | "Beard" | "Eyewear" | "Hair Front";
7
7
  type UICategory = "Background" | "Hair" | "Skin Color" | "Clothes" | "Accessories" | "Headwears" | "Eyewear" | "Facial Expression" | "Beard";
@@ -25,16 +25,9 @@ type AvatarConfig = Record<string, AvatarConfigItem[]>;
25
25
  interface AvatarState {
26
26
  selections: Record<string, string>;
27
27
  colors: Record<string, string>;
28
+ gender?: string;
28
29
  }
29
30
 
30
- interface SelectOption<T = string> {
31
- value: T;
32
- label: string;
33
- }
34
- declare const levelOptions: SelectOption<Level>[];
35
- declare const languageOptions: SelectOption<Language>[];
36
- declare const difficultyOptions: SelectOption<Difficulty>[];
37
-
38
31
  declare const HAIR_COLORS: ColorOption[];
39
32
  declare const CLOTHES_COLORS: ColorOption[];
40
33
  declare const COLOR_HUES: Record<string, number>;
@@ -42,7 +35,16 @@ declare const RENDER_ORDER: readonly ["Background", "Hair Back", "Clothes Back",
42
35
  declare const INITIAL_AVATAR_DATA: Record<UICategory, string[]>;
43
36
  declare function getActualOptionFileName(category: string, baseName: string, config: AvatarConfig, selections: Record<string, string>): AvatarConfigItem | null;
44
37
  declare function parseAvatarConfig(configStr: string | null | undefined): AvatarState;
38
+ declare function parseAvatarConfigWithDefaults(configStr: string | null | undefined, seed?: string): AvatarState;
45
39
  declare function serializeAvatarConfig(state: AvatarState): string;
40
+ declare function generateRandomAvatarState(options?: {
41
+ gender?: "Male" | "Female";
42
+ seed?: string;
43
+ }): AvatarState;
44
+ declare function generateRandomAvatarConfig(options?: {
45
+ gender?: "Male" | "Female";
46
+ seed?: string;
47
+ }): string;
46
48
 
47
49
  interface EloTier {
48
50
  name: string;
@@ -86,6 +88,39 @@ declare function reorderObjectKeys<T>(obj: {
86
88
  [key: number]: T;
87
89
  };
88
90
 
91
+ /**
92
+ * Home Logic Utilities
93
+ * Supports Signed-In User Homepage customization, greeting, streak calculation, and level mapping.
94
+ */
95
+ interface SubjectShortcut {
96
+ id: string;
97
+ name: string;
98
+ iconKey: string;
99
+ colorClass: string;
100
+ }
101
+ /**
102
+ * Maps Cognito user level string to standard level enum values: "SSC" | "HSC+Admission" | "BCS"
103
+ */
104
+ declare function mapCognitoLevelToStandardLevel(cognitoLevel?: string | null): string;
105
+ /**
106
+ * Returns contextual time of day greeting
107
+ */
108
+ declare function getTimeOfDayGreeting(customHour?: number, lang?: "en" | "bn"): {
109
+ greeting: string;
110
+ period: "morning" | "afternoon" | "evening" | "night";
111
+ };
112
+ /**
113
+ * Returns recommended subject shortcuts for the given level
114
+ */
115
+ declare function getRecommendedSubjectsForLevel(level: string, lang?: "en" | "bn"): SubjectShortcut[];
116
+ /**
117
+ * Calculates continuous consecutive active study streak in days
118
+ */
119
+ declare function calculateStreakFromDates(activityDates: string[]): {
120
+ streak: number;
121
+ isActiveToday: boolean;
122
+ };
123
+
89
124
  interface ParsedQuestion {
90
125
  id?: string;
91
126
  imageUrl?: string;
@@ -101,6 +136,7 @@ interface ParsedQuestion {
101
136
  subjectId?: string;
102
137
  chapterId?: string;
103
138
  topicId?: string;
139
+ publicExam?: string;
104
140
  type: "MCQ" | "WRITTEN";
105
141
  markingInstructions?: string;
106
142
  answerImageUrl?: string;
@@ -130,6 +166,175 @@ declare function resolveMediaUrl(value: string | null | undefined, storage: Stor
130
166
  declare function resolveMediaUrls<T extends Record<string, unknown>>(obj: T, fields: (keyof T)[], storage: StorageProvider | undefined, cache?: MediaUrlCache): Promise<T>;
131
167
  declare function _resetMediaUrlWarning(): void;
132
168
 
169
+ type BillingCycle = "monthly" | "quarterly" | "biannually" | "annually";
170
+ type SubscriptionTier = "FREE" | "PRO" | "PRO_AI";
171
+ interface PlanCyclePricing {
172
+ monthly: number;
173
+ quarterly: number;
174
+ biannually: number;
175
+ annually: number;
176
+ }
177
+ interface PlanAiQuotaConfig {
178
+ monthly: {
179
+ aiEvals: number;
180
+ aiQuestions: number;
181
+ };
182
+ quarterly: {
183
+ aiEvals: number;
184
+ aiQuestions: number;
185
+ };
186
+ biannually: {
187
+ aiEvals: number;
188
+ aiQuestions: number;
189
+ };
190
+ annually: {
191
+ aiEvals: number;
192
+ aiQuestions: number;
193
+ };
194
+ }
195
+ interface SubscriptionPlan {
196
+ id: SubscriptionTier;
197
+ tier: SubscriptionTier;
198
+ titleKey: string;
199
+ descKey: string;
200
+ pricing: PlanCyclePricing;
201
+ aiQuotas: PlanAiQuotaConfig;
202
+ }
203
+ interface TopUpBoosterPack {
204
+ id: string;
205
+ type: "AI_EVAL" | "AI_QUESTION";
206
+ amount: number;
207
+ price: number;
208
+ titleKey: string;
209
+ descKey: string;
210
+ badgeKey?: string;
211
+ }
212
+ declare const MANUAL_PAYMENT_CONFIG: {
213
+ phoneNumber: string;
214
+ accountType: string;
215
+ methods: readonly ["BKASH", "ROCKET"];
216
+ };
217
+ declare const SUBSCRIPTION_PLANS: Record<SubscriptionTier, SubscriptionPlan>;
218
+ declare const AI_EVAL_BOOSTER_PACKS: TopUpBoosterPack[];
219
+ declare const AI_QUESTION_BOOSTER_PACKS: TopUpBoosterPack[];
220
+ declare function getCycleMultiplier(cycle: BillingCycle): number;
221
+ declare function getPlanOriginalPrice(tier: SubscriptionTier | string, cycle: BillingCycle): number;
222
+ declare function getPlanPrice(tier: SubscriptionTier | string, cycle: BillingCycle): number;
223
+ declare function getPlanMonthlyEquivalentPrice(tier: SubscriptionTier | string, cycle: BillingCycle): number;
224
+ declare function getPlanDiscountPercent(cycle: BillingCycle): number;
225
+ declare function getPlanAiQuotas(tier: SubscriptionTier | string, cycle: BillingCycle): {
226
+ aiEvals: number;
227
+ aiQuestions: number;
228
+ };
229
+ declare function isValidBangladeshiPhone(phone: string): boolean;
230
+ declare function isValidTrxId(trxId: string): boolean;
231
+ declare function hasProAccess(tier?: string | null, expiresAt?: string | null): boolean;
232
+ declare function hasAiTierAccess(tier?: string | null, expiresAt?: string | null): boolean;
233
+ declare const FREE_DAILY_PRACTICE_LIMIT = 30;
234
+ declare function canExportPack(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
235
+ declare function canAccessMistakeVault(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
236
+ declare function canWatchContestSolution(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
237
+ declare function shouldTrackPracticeProgress(tier?: string | null, expiresAt?: string | null, isCreator?: boolean): boolean;
238
+ declare function getDailyPracticeLimit(tier?: string | null, expiresAt?: string | null): number | null;
239
+ declare function checkDailyPracticeLimit(dailyCount: number, lastPracticeDate: string | null | undefined, tier?: string | null, expiresAt?: string | null, todayStr?: string): {
240
+ allowed: boolean;
241
+ remaining: number;
242
+ currentCount: number;
243
+ isUnlimited: boolean;
244
+ };
245
+ declare function hasSufficientAiQuestionQuota(quota: number | null | undefined, requested: number): boolean;
246
+ declare function hasSufficientAiEvalQuota(quota: number | null | undefined): boolean;
247
+
248
+ /**
249
+ * @file xp.ts
250
+ * @description Experience Points (XP) and Level progression logic for the Orjok platform.
251
+ */
252
+ interface XpTier {
253
+ id: "novice" | "dedicated" | "skilled" | "master" | "grandmaster" | "legend";
254
+ minLevel: number;
255
+ maxLevel: number;
256
+ nameEn: string;
257
+ nameBn: string;
258
+ color: string;
259
+ badgeBg: string;
260
+ badgeBorder: string;
261
+ badgeText: string;
262
+ }
263
+ declare const XP_TIERS: XpTier[];
264
+ declare const XP_REWARDS: {
265
+ readonly PRACTICE_CORRECT: 10;
266
+ readonly PRACTICE_ATTEMPT: 2;
267
+ readonly PACK_EXAM_BASE: 20;
268
+ readonly PACK_EXAM_CORRECT: 5;
269
+ readonly PACK_EXAM_HIGH_SCORE_BONUS: 25;
270
+ readonly CONTEST_PARTICIPATION: 50;
271
+ readonly CONTEST_TOP_10_BONUS: 100;
272
+ readonly CONTEST_TOP_25_BONUS: 50;
273
+ readonly CREATE_QUESTION: 25;
274
+ readonly CREATE_PACK: 50;
275
+ readonly VOTE: 2;
276
+ readonly AI_EVALUATION: 15;
277
+ };
278
+ type XpRewardAction = "practice" | "packExam" | "contest" | "createQuestion" | "createPack" | "vote" | "aiEvaluation";
279
+ interface XpRewardMetadata {
280
+ isCorrect?: boolean;
281
+ correctCount?: number;
282
+ totalQuestions?: number;
283
+ rank?: number;
284
+ totalParticipants?: number;
285
+ }
286
+ interface XpProgressInfo {
287
+ level: number;
288
+ xp: number;
289
+ currentLevelXp: number;
290
+ nextLevelXp: number;
291
+ xpInLevel: number;
292
+ xpRequiredForLevel: number;
293
+ xpToNextLevel: number;
294
+ progressPercent: number;
295
+ tier: XpTier;
296
+ }
297
+ /**
298
+ * Calculates the total cumulative XP required to reach a specific level.
299
+ * Formula: 25 * (L^2 + L - 2) = 25 * (L - 1) * (L + 2)
300
+ * Level 1 = 0 XP
301
+ * Level 2 = 100 XP
302
+ * Level 3 = 250 XP
303
+ * Level 4 = 450 XP
304
+ * Level 5 = 700 XP
305
+ * Level 6 = 1000 XP
306
+ * Level 10 = 2700 XP
307
+ * Level 20 = 10450 XP
308
+ * Level 50 = 63700 XP
309
+ */
310
+ declare function getXpForLevel(level: number): number;
311
+ /**
312
+ * Calculates the user's level based on cumulative XP.
313
+ * Derived by inverting: 25 * L^2 + 25 * L - (50 + XP) = 0
314
+ * L = floor((sqrt(9 + 0.16 * XP) - 1) / 2)
315
+ */
316
+ declare function getLevelFromXp(xp: number): number;
317
+ /**
318
+ * Returns the XP required to advance from `level` to `level + 1`.
319
+ */
320
+ declare function getXpRequiredForNextLevel(level: number): number;
321
+ /**
322
+ * Returns complete progress details for a given cumulative XP value.
323
+ */
324
+ declare function getXpProgress(xp: number): XpProgressInfo;
325
+ /**
326
+ * Returns the tier metadata for a given level.
327
+ */
328
+ declare function getXpTier(level: number): XpTier;
329
+ /**
330
+ * Returns all configured XP tiers.
331
+ */
332
+ declare function getAllXpTiers(): XpTier[];
333
+ /**
334
+ * Calculates the XP reward for a given user activity.
335
+ */
336
+ declare function calculateXpReward(action: XpRewardAction, metadata?: XpRewardMetadata): number;
337
+
133
338
  type PrimaryTab = "home" | "learn" | "contests" | "courses" | "profile";
134
339
  declare function getActiveTab(pathname: string): PrimaryTab;
135
340
  declare function getCanonicalPath(pathname: string): string;
@@ -159,7 +364,7 @@ interface TimeLeft {
159
364
  seconds: number;
160
365
  isEnded: boolean;
161
366
  }
162
- declare function convertToBangladeshTime(isoString: string): string;
367
+ declare function convertToBangladeshTime(isoString: string, locale?: string): string;
163
368
  declare function getDhakaNow(): Date;
164
369
  declare function calculateTimeLeft(endTime: string | Date): TimeLeft;
165
370
  declare function formatDate(date: Date | string, locale?: string): string;
@@ -173,5 +378,16 @@ declare function sanitizeFileName(name: string): string;
173
378
  declare function isQuestionLevel(value: unknown): value is Level;
174
379
  declare function isLanguage(value: unknown): value is Language;
175
380
  declare function isDifficulty(value: unknown): value is Difficulty;
381
+ declare function normalizeLevel(value?: string | null): string;
382
+
383
+ /**
384
+ * Accumulates items across paginated GraphQL queries until targetLimit is reached
385
+ * or nextToken is exhausted (null/undefined).
386
+ *
387
+ * This guarantees that even when DynamoDB evaluates filter expressions post-read
388
+ * and yields fewer than requested items in a single scan batch, the consumer
389
+ * receives up to `targetLimit` matching items and the exact continuation token.
390
+ */
391
+ declare function paginateWithAccumulator<T>(fetchPage: (limit: number, nextToken?: string | null) => Promise<PaginatedList<T>>, targetLimit?: number, initialNextToken?: string | null, maxIterations?: number): Promise<PaginatedList<T>>;
176
392
 
177
- export { type AvatarConfig, type AvatarConfigItem, type AvatarState, CLOTHES_COLORS, COLOR_HUES, type ColorOption, Difficulty, type EloTier, type ExamConfig, type ExamMode, HAIR_COLORS, INITIAL_AVATAR_DATA, Language, Level, MediaUrlCache, type ParseResult, type ParsedQuestion, type PrimaryTab, QuestionObject, QuestionType, RENDER_ORDER, type RatingField, type RenderCategory, type SelectOption, StorageProvider, type TimeLeft, type UICategory, _resetMediaUrlWarning, buildImageAnswer, calculateDefaultExamMinutes, calculateExamTime, calculateTimeLeft, computeRatingDelta, convertToBangladeshTime, detectQuestionType, difficultyOptions, engToBanglaNumber, extractBilingualName, filterQuestionsByMode, formatBDT, formatCurriculumName, formatDate, formatExamTime, formatQuestionsToCsv, formatQuestionsToText, getActiveTab, getActualOptionFileName, getAllTiers, getCanonicalPath, getDhakaNow, getEloProgress, getEloTier, getRatingForSubject, getRelativeTime, getYouTubeId, isAuthGatedRoute, isCorrectAnswer, isDifficulty, isImageAnswer, isLanguage, isQuestionLevel, isStorageKey, languageOptions, levelOptions, normalizeDifficulty, parseAvatarConfig, parseCsvQuestions, parseImageKeys, parseTextQuestions, processLatexText, reorderObjectKeys, resolveMediaUrl, resolveMediaUrls, sanitizeFileName, scoreExam, serializeAvatarConfig, shuffle, shuffleInPlace };
393
+ export { AI_EVAL_BOOSTER_PACKS, AI_QUESTION_BOOSTER_PACKS, type AvatarConfig, type AvatarConfigItem, type AvatarState, type BillingCycle, CLOTHES_COLORS, COLOR_HUES, type ColorOption, Difficulty, type EloTier, type ExamConfig, type ExamMode, FREE_DAILY_PRACTICE_LIMIT, HAIR_COLORS, INITIAL_AVATAR_DATA, Language, Level, MANUAL_PAYMENT_CONFIG, MediaUrlCache, PaginatedList, type ParseResult, type ParsedQuestion, type PlanAiQuotaConfig, type PlanCyclePricing, type PrimaryTab, QuestionObject, QuestionType, RENDER_ORDER, type RatingField, type RenderCategory, SUBSCRIPTION_PLANS, StorageProvider, type SubjectShortcut, type SubscriptionPlan, type SubscriptionTier, type TimeLeft, type TopUpBoosterPack, type UICategory, XP_REWARDS, XP_TIERS, type XpProgressInfo, type XpRewardAction, type XpRewardMetadata, type XpTier, _resetMediaUrlWarning, buildImageAnswer, calculateDefaultExamMinutes, calculateExamTime, calculateStreakFromDates, calculateTimeLeft, calculateXpReward, canAccessMistakeVault, canExportPack, canWatchContestSolution, checkDailyPracticeLimit, computeRatingDelta, convertToBangladeshTime, detectQuestionType, engToBanglaNumber, extractBilingualName, filterQuestionsByMode, formatBDT, formatCurriculumName, formatDate, formatExamTime, formatQuestionsToCsv, formatQuestionsToText, generateRandomAvatarConfig, generateRandomAvatarState, getActiveTab, getActualOptionFileName, getAllTiers, getAllXpTiers, getCanonicalPath, getCycleMultiplier, getDailyPracticeLimit, getDhakaNow, getEloProgress, getEloTier, getLevelFromXp, getPlanAiQuotas, getPlanDiscountPercent, getPlanMonthlyEquivalentPrice, getPlanOriginalPrice, getPlanPrice, getRatingForSubject, getRecommendedSubjectsForLevel, getRelativeTime, getTimeOfDayGreeting, getXpForLevel, getXpProgress, getXpRequiredForNextLevel, getXpTier, getYouTubeId, hasAiTierAccess, hasProAccess, hasSufficientAiEvalQuota, hasSufficientAiQuestionQuota, isAuthGatedRoute, isCorrectAnswer, isDifficulty, isImageAnswer, isLanguage, isQuestionLevel, isStorageKey, isValidBangladeshiPhone, isValidTrxId, mapCognitoLevelToStandardLevel, normalizeDifficulty, normalizeLevel, paginateWithAccumulator, parseAvatarConfig, parseAvatarConfigWithDefaults, parseCsvQuestions, parseImageKeys, parseTextQuestions, processLatexText, reorderObjectKeys, resolveMediaUrl, resolveMediaUrls, sanitizeFileName, scoreExam, serializeAvatarConfig, shouldTrackPracticeProgress, shuffle, shuffleInPlace };