@playcademy/vite-plugin 0.2.11 → 0.2.12

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.js CHANGED
@@ -41142,6 +41142,7 @@ import { homedir } from "node:os";
41142
41142
  import { join } from "node:path";
41143
41143
  import { stdout } from "process";
41144
41144
  import crypto3 from "node:crypto";
41145
+ import { stdout as stdout2 } from "process";
41145
41146
  import * as s3 from "fs";
41146
41147
  import * as o3 from "path";
41147
41148
  import fs22 from "node:fs";
@@ -41426,7 +41427,7 @@ var init_auth = __esm(() => {
41426
41427
  TIMEBACK_LTI: "timeback-lti"
41427
41428
  };
41428
41429
  });
41429
- var TSC_PACKAGE = "@typescript/native-preview";
41430
+ var TSC_PACKAGE = "typescript";
41430
41431
  var USE_NATIVE_TSC;
41431
41432
  var init_typescript = __esm(() => {
41432
41433
  USE_NATIVE_TSC = TSC_PACKAGE.includes("native-preview");
@@ -41494,7 +41495,8 @@ var TIMEBACK_ROUTES;
41494
41495
  var TIMEBACK_ORG_SOURCED_ID = "PLAYCADEMY";
41495
41496
  var init_timeback2 = __esm(() => {
41496
41497
  TIMEBACK_ROUTES = {
41497
- END_ACTIVITY: "/integrations/timeback/end-activity"
41498
+ END_ACTIVITY: "/integrations/timeback/end-activity",
41499
+ GET_XP: "/integrations/timeback/xp"
41498
41500
  };
41499
41501
  });
41500
41502
  var WORKER_NAMING;
@@ -42386,7 +42388,7 @@ var package_default;
42386
42388
  var init_package = __esm(() => {
42387
42389
  package_default = {
42388
42390
  name: "@playcademy/sandbox",
42389
- version: "0.3.13",
42391
+ version: "0.3.14",
42390
42392
  description: "Local development server for Playcademy game development",
42391
42393
  type: "module",
42392
42394
  exports: {
@@ -56986,7 +56988,8 @@ var init_constants2 = __esm(() => {
56986
56988
  INDEX: "/api",
56987
56989
  HEALTH: "/api/health",
56988
56990
  TIMEBACK: {
56989
- END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`
56991
+ END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
56992
+ GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`
56990
56993
  }
56991
56994
  };
56992
56995
  });
@@ -57702,7 +57705,7 @@ var ACHIEVEMENT_IDS2;
57702
57705
  var ACHIEVEMENT_DEFINITIONS2;
57703
57706
  var init_achievements2;
57704
57707
  var init_auth2 = () => {};
57705
- var TSC_PACKAGE2 = "@typescript/native-preview";
57708
+ var TSC_PACKAGE2 = "typescript";
57706
57709
  var USE_NATIVE_TSC2;
57707
57710
  var init_typescript2;
57708
57711
  var init_character2 = () => {};
@@ -58667,6 +58670,48 @@ class TimebackService {
58667
58670
  inProgress: result.inProgress
58668
58671
  };
58669
58672
  }
58673
+ async getStudentXp(timebackId, options) {
58674
+ const client = this.requireClient();
58675
+ const db2 = this.ctx.db;
58676
+ let courseIds = [];
58677
+ if (options?.gameId) {
58678
+ const conditions2 = [eq(gameTimebackIntegrations.gameId, options.gameId)];
58679
+ if (options.grade !== undefined && options.subject) {
58680
+ conditions2.push(eq(gameTimebackIntegrations.grade, options.grade));
58681
+ conditions2.push(eq(gameTimebackIntegrations.subject, options.subject));
58682
+ }
58683
+ const integrations = await db2.query.gameTimebackIntegrations.findMany({
58684
+ where: and(...conditions2)
58685
+ });
58686
+ courseIds = integrations.map((i2) => i2.courseId);
58687
+ if (courseIds.length === 0) {
58688
+ logger27.debug("No integrations found for game, returning 0 XP", {
58689
+ timebackId,
58690
+ gameId: options.gameId,
58691
+ grade: options.grade,
58692
+ subject: options.subject
58693
+ });
58694
+ return {
58695
+ totalXp: 0,
58696
+ ...options?.include?.today && { todayXp: 0 },
58697
+ ...options?.include?.perCourse && { courses: [] }
58698
+ };
58699
+ }
58700
+ }
58701
+ const result = await client.getStudentXp(timebackId, {
58702
+ courseIds: courseIds.length > 0 ? courseIds : undefined,
58703
+ include: options?.include
58704
+ });
58705
+ logger27.debug("Retrieved student XP", {
58706
+ timebackId,
58707
+ gameId: options?.gameId,
58708
+ grade: options?.grade,
58709
+ subject: options?.subject,
58710
+ totalXp: result.totalXp,
58711
+ courseCount: result.courses?.length
58712
+ });
58713
+ return result;
58714
+ }
58670
58715
  }
58671
58716
  var logger27;
58672
58717
  var init_timeback_service = __esm(() => {
@@ -59079,6 +59124,117 @@ function isTimebackSubject2(value) {
59079
59124
  function isTimebackGrade2(value) {
59080
59125
  return typeof value === "number" && Number.isInteger(value) && GRADE_VALUES2.includes(value);
59081
59126
  }
59127
+ function stripAnsi2(text3) {
59128
+ return text3.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
59129
+ }
59130
+
59131
+ class Spinner2 {
59132
+ tasks = new Map;
59133
+ frameIndex = 0;
59134
+ intervalId = null;
59135
+ renderCount = 0;
59136
+ previousLineCount = 0;
59137
+ printedTasks = new Set;
59138
+ indent;
59139
+ constructor(taskIds, texts, options) {
59140
+ this.indent = options?.indent ?? 0;
59141
+ taskIds.forEach((id, index2) => {
59142
+ this.tasks.set(id, {
59143
+ text: texts[index2] || "",
59144
+ status: "pending"
59145
+ });
59146
+ });
59147
+ }
59148
+ start() {
59149
+ if (isInteractive2) {
59150
+ stdout2.write(cursor2.hide);
59151
+ this.render();
59152
+ this.intervalId = setInterval(() => {
59153
+ this.frameIndex = (this.frameIndex + 1) % SPINNER_FRAMES2.length;
59154
+ this.render();
59155
+ }, SPINNER_INTERVAL2);
59156
+ }
59157
+ }
59158
+ updateTask(taskId, status, finalText) {
59159
+ const task = this.tasks.get(taskId);
59160
+ if (task) {
59161
+ task.status = status;
59162
+ if (finalText)
59163
+ task.finalText = finalText;
59164
+ if (!isInteractive2) {
59165
+ this.renderNonInteractive(taskId, task);
59166
+ }
59167
+ }
59168
+ }
59169
+ renderNonInteractive(taskId, task) {
59170
+ const key = `${taskId}-${task.status}`;
59171
+ if (this.printedTasks.has(key))
59172
+ return;
59173
+ this.printedTasks.add(key);
59174
+ const indentStr = " ".repeat(this.indent);
59175
+ let line3 = "";
59176
+ switch (task.status) {
59177
+ case "running":
59178
+ line3 = `${indentStr}[RUNNING] ${stripAnsi2(task.text)}`;
59179
+ break;
59180
+ case "success":
59181
+ line3 = `${indentStr}[SUCCESS] ${stripAnsi2(task.finalText || task.text)}`;
59182
+ break;
59183
+ case "error":
59184
+ line3 = `${indentStr}[ERROR] Failed: ${stripAnsi2(task.text)}`;
59185
+ break;
59186
+ }
59187
+ console.log(line3);
59188
+ }
59189
+ render() {
59190
+ if (this.previousLineCount > 0) {
59191
+ stdout2.write(cursor2.up(this.previousLineCount));
59192
+ }
59193
+ const spinner2 = SPINNER_FRAMES2[this.frameIndex];
59194
+ const indentStr = " ".repeat(this.indent);
59195
+ const visibleTasks = Array.from(this.tasks.values()).filter((task) => task.status !== "pending");
59196
+ for (const task of visibleTasks) {
59197
+ stdout2.write(`\r${cursor2.clearLine}`);
59198
+ let line3 = "";
59199
+ switch (task.status) {
59200
+ case "running":
59201
+ line3 = `${indentStr}${colors22.blue}${spinner2}${styles2.reset} ${task.text}`;
59202
+ break;
59203
+ case "success":
59204
+ line3 = `${indentStr}${colors22.green}${CHECK_MARK2}${styles2.reset} ${task.finalText || task.text}`;
59205
+ break;
59206
+ case "error":
59207
+ line3 = `${indentStr}${colors22.red}${CROSS_MARK2}${styles2.reset} Failed: ${task.text}`;
59208
+ break;
59209
+ }
59210
+ console.log(line3);
59211
+ }
59212
+ this.previousLineCount = visibleTasks.length;
59213
+ this.renderCount++;
59214
+ }
59215
+ stop() {
59216
+ if (this.intervalId) {
59217
+ clearInterval(this.intervalId);
59218
+ this.intervalId = null;
59219
+ }
59220
+ if (isInteractive2) {
59221
+ this.render();
59222
+ stdout2.write(cursor2.show);
59223
+ } else {
59224
+ this.tasks.forEach((task, taskId) => {
59225
+ if (task.status !== "pending") {
59226
+ this.renderNonInteractive(taskId, task);
59227
+ }
59228
+ });
59229
+ }
59230
+ }
59231
+ }
59232
+ function kebabToTitleCase(kebabStr) {
59233
+ return kebabStr.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
59234
+ }
59235
+ function formatDateYMD(date3 = new Date) {
59236
+ return date3.toISOString().split("T")[0];
59237
+ }
59082
59238
  async function deleteTimebackResources(client, courseId) {
59083
59239
  const sourcedIds = deriveSourcedIds(courseId);
59084
59240
  const { fetchTimebackConfig: fetchTimebackConfig2 } = await Promise.resolve().then(() => (init_verify(), exports_verify));
@@ -60238,9 +60394,6 @@ class MasteryTracker {
60238
60394
  return total;
60239
60395
  }
60240
60396
  }
60241
- function kebabToTitleCase(kebabStr) {
60242
- return kebabStr.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
60243
- }
60244
60397
  function validateProgressData(progressData) {
60245
60398
  if (!progressData.subject) {
60246
60399
  throw new ConfigurationError("subject", "Subject is required for Caliper events. Provide it in progressData.subject");
@@ -60263,30 +60416,39 @@ function validateSessionData(sessionData) {
60263
60416
  throw new ConfigurationError("sensorUrl", 'Sensor URL is required for Caliper events. Provide it in sessionData.sensorUrl (e.g., "https://hub.playcademy.net/p/your-game")');
60264
60417
  }
60265
60418
  }
60266
- function calculateXp(durationSeconds, accuracy, isFirstAttempt) {
60267
- const durationMinutes = durationSeconds / 60;
60268
- const baseXp = durationMinutes * 1;
60269
- let multiplier;
60270
- if (isFirstAttempt) {
60271
- if (accuracy === 1) {
60272
- multiplier = 1.25;
60273
- } else if (accuracy >= 0.8) {
60274
- multiplier = 1;
60275
- } else if (accuracy >= 0.65) {
60276
- multiplier = 0.5;
60277
- } else {
60278
- multiplier = 0;
60279
- }
60419
+ function getAttemptMultiplier(attemptNumber) {
60420
+ switch (attemptNumber) {
60421
+ case 1:
60422
+ return 1;
60423
+ case 2:
60424
+ return 0.5;
60425
+ case 3:
60426
+ return 0.25;
60427
+ default:
60428
+ return 0;
60429
+ }
60430
+ }
60431
+ function getAccuracyMultiplier(accuracy) {
60432
+ if (!Number.isFinite(accuracy) || accuracy < 0) {
60433
+ return 0;
60434
+ }
60435
+ if (accuracy >= PERFECT_ACCURACY_THRESHOLD) {
60436
+ return 1.25;
60437
+ } else if (accuracy >= 0.8) {
60438
+ return 1;
60280
60439
  } else {
60281
- if (accuracy === 1) {
60282
- multiplier = 1;
60283
- } else if (accuracy >= 0.8) {
60284
- multiplier = 0.5;
60285
- } else {
60286
- multiplier = 0;
60287
- }
60440
+ return 0;
60288
60441
  }
60289
- return Math.round(baseXp * multiplier * 10) / 10;
60442
+ }
60443
+ function calculateXp(durationSeconds, accuracy, attemptNumber) {
60444
+ if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) {
60445
+ return 0;
60446
+ }
60447
+ const durationMinutes = durationSeconds / 60;
60448
+ const baseXp = durationMinutes * 1;
60449
+ const accuracyMultiplier = getAccuracyMultiplier(accuracy);
60450
+ const attemptMultiplier = getAttemptMultiplier(attemptNumber);
60451
+ return Math.round(baseXp * accuracyMultiplier * attemptMultiplier * 10) / 10;
60290
60452
  }
60291
60453
 
60292
60454
  class ProgressRecorder {
@@ -60309,8 +60471,7 @@ class ProgressRecorder {
60309
60471
  const { score, totalQuestions, correctQuestions, xpEarned, masteredUnits, attemptNumber } = progressData;
60310
60472
  const actualLineItemId = await this.resolveAssessmentLineItem(activityId, activityName, progressData.classId, ids);
60311
60473
  const currentAttemptNumber = await this.resolveAttemptNumber(attemptNumber, score, studentId, actualLineItemId);
60312
- const isFirstActiveAttempt = currentAttemptNumber === 1;
60313
- const calculatedXp = this.calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, isFirstActiveAttempt);
60474
+ const calculatedXp = this.calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, currentAttemptNumber);
60314
60475
  let extensions = progressData.extensions;
60315
60476
  const masteryProgress = await this.masteryTracker.checkProgress({
60316
60477
  studentId,
@@ -60381,18 +60542,18 @@ class ProgressRecorder {
60381
60542
  }
60382
60543
  return 1;
60383
60544
  }
60384
- calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, isFirstAttempt) {
60545
+ calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, attemptNumber) {
60385
60546
  if (xpEarned !== undefined) {
60386
60547
  log3.debug("[ProgressRecorder] Using provided XP", { xpEarned });
60387
60548
  return xpEarned;
60388
60549
  }
60389
60550
  if (progressData.sessionDurationSeconds && totalQuestions && correctQuestions) {
60390
60551
  const accuracy = correctQuestions / totalQuestions;
60391
- const calculatedXp = calculateXp(progressData.sessionDurationSeconds, accuracy, isFirstAttempt);
60552
+ const calculatedXp = calculateXp(progressData.sessionDurationSeconds, accuracy, attemptNumber);
60392
60553
  log3.debug("[ProgressRecorder] Calculated XP", {
60393
60554
  durationSeconds: progressData.sessionDurationSeconds,
60394
60555
  accuracy,
60395
- isFirstAttempt,
60556
+ attemptNumber,
60396
60557
  calculatedXp
60397
60558
  });
60398
60559
  return calculatedXp;
@@ -61349,6 +61510,70 @@ class TimebackClient {
61349
61510
  this.cacheManager.setEnrollments(studentId, enrollments);
61350
61511
  return enrollments;
61351
61512
  }
61513
+ async getStudentXp(studentId, options) {
61514
+ await this._ensureAuthenticated();
61515
+ const enrollments = await this.edubridge.enrollments.listByUser(studentId);
61516
+ const filteredEnrollments = options?.courseIds?.length ? enrollments.filter((e) => options.courseIds.includes(e.course.id)) : enrollments;
61517
+ if (filteredEnrollments.length === 0) {
61518
+ return {
61519
+ totalXp: 0,
61520
+ ...options?.include?.today && { todayXp: 0 },
61521
+ ...options?.include?.perCourse && { courses: [] }
61522
+ };
61523
+ }
61524
+ const analyticsResults = await Promise.all(filteredEnrollments.map(async (enrollment) => {
61525
+ try {
61526
+ const analytics = await this.edubridge.analytics.getEnrollmentFacts(enrollment.id);
61527
+ return { enrollment, analytics };
61528
+ } catch (error) {
61529
+ log3.warn("[TimebackClient] Failed to fetch analytics for enrollment", {
61530
+ enrollmentId: enrollment.id,
61531
+ error
61532
+ });
61533
+ return { enrollment, analytics: null };
61534
+ }
61535
+ }));
61536
+ const today = formatDateYMD();
61537
+ let totalXp = 0;
61538
+ let todayXp = 0;
61539
+ const courses = [];
61540
+ for (const { enrollment, analytics } of analyticsResults) {
61541
+ let courseXp = 0;
61542
+ let courseTodayXp = 0;
61543
+ if (analytics?.facts) {
61544
+ for (const [date3, subjects] of Object.entries(analytics.facts)) {
61545
+ for (const subjectData of Object.values(subjects)) {
61546
+ const xp = subjectData.activityMetrics?.xpEarned ?? 0;
61547
+ courseXp += xp;
61548
+ if (date3 === today) {
61549
+ courseTodayXp += xp;
61550
+ }
61551
+ }
61552
+ }
61553
+ }
61554
+ totalXp += courseXp;
61555
+ todayXp += courseTodayXp;
61556
+ if (options?.include?.perCourse) {
61557
+ const gradeStr = enrollment.course.grades?.[0];
61558
+ const parsedGrade = gradeStr ? parseInt(gradeStr, 10) : 0;
61559
+ const grade = isTimebackGrade2(parsedGrade) ? parsedGrade : 0;
61560
+ const subjectStr = enrollment.course.subjects?.[0];
61561
+ const subject = subjectStr && isTimebackSubject2(subjectStr) ? subjectStr : "None";
61562
+ courses.push({
61563
+ grade,
61564
+ subject,
61565
+ title: enrollment.course.title,
61566
+ totalXp: courseXp,
61567
+ ...options?.include?.today && { todayXp: courseTodayXp }
61568
+ });
61569
+ }
61570
+ }
61571
+ return {
61572
+ totalXp,
61573
+ ...options?.include?.today && { todayXp },
61574
+ ...options?.include?.perCourse && { courses }
61575
+ };
61576
+ }
61352
61577
  clearCaches() {
61353
61578
  this.cacheManager.clearAll();
61354
61579
  }
@@ -61392,7 +61617,7 @@ var ACHIEVEMENT_IDS3;
61392
61617
  var ACHIEVEMENT_DEFINITIONS3;
61393
61618
  var init_achievements3;
61394
61619
  var init_auth3 = () => {};
61395
- var TSC_PACKAGE3 = "@typescript/native-preview";
61620
+ var TSC_PACKAGE3 = "typescript";
61396
61621
  var USE_NATIVE_TSC3;
61397
61622
  var init_typescript3;
61398
61623
  var init_character3 = () => {};
@@ -61628,7 +61853,16 @@ var createLogger2 = (scopeName) => {
61628
61853
  };
61629
61854
  };
61630
61855
  var log3;
61856
+ var colors22;
61857
+ var styles2;
61858
+ var cursor2;
61859
+ var isInteractive2;
61860
+ var SPINNER_FRAMES2;
61861
+ var CHECK_MARK2;
61862
+ var CROSS_MARK2;
61863
+ var SPINNER_INTERVAL2 = 80;
61631
61864
  var TimebackAuthError;
61865
+ var PERFECT_ACCURACY_THRESHOLD = 0.999999;
61632
61866
  var exports_external2;
61633
61867
  var util3;
61634
61868
  var objectUtil2;
@@ -62403,6 +62637,50 @@ var init_dist3 = __esm(() => {
62403
62637
  error: 3
62404
62638
  };
62405
62639
  log3 = createLogger2();
62640
+ colors22 = {
62641
+ black: "\x1B[30m",
62642
+ red: "\x1B[31m",
62643
+ green: "\x1B[32m",
62644
+ yellow: "\x1B[33m",
62645
+ blue: "\x1B[34m",
62646
+ magenta: "\x1B[35m",
62647
+ cyan: "\x1B[36m",
62648
+ white: "\x1B[37m",
62649
+ gray: "\x1B[90m"
62650
+ };
62651
+ styles2 = {
62652
+ reset: "\x1B[0m",
62653
+ bold: "\x1B[1m",
62654
+ dim: "\x1B[2m",
62655
+ italic: "\x1B[3m",
62656
+ underline: "\x1B[4m"
62657
+ };
62658
+ cursor2 = {
62659
+ hide: "\x1B[?25l",
62660
+ show: "\x1B[?25h",
62661
+ up: (n) => `\x1B[${n}A`,
62662
+ down: (n) => `\x1B[${n}B`,
62663
+ forward: (n) => `\x1B[${n}C`,
62664
+ back: (n) => `\x1B[${n}D`,
62665
+ clearLine: "\x1B[K",
62666
+ clearScreen: "\x1B[2J",
62667
+ home: "\x1B[H"
62668
+ };
62669
+ isInteractive2 = typeof process !== "undefined" && process.stdout?.isTTY && !process.env.CI && process.env.TERM !== "dumb";
62670
+ SPINNER_FRAMES2 = [
62671
+ 10251,
62672
+ 10265,
62673
+ 10297,
62674
+ 10296,
62675
+ 10300,
62676
+ 10292,
62677
+ 10278,
62678
+ 10279,
62679
+ 10247,
62680
+ 10255
62681
+ ].map((code) => String.fromCodePoint(code));
62682
+ CHECK_MARK2 = String.fromCodePoint(10004);
62683
+ CROSS_MARK2 = String.fromCodePoint(10006);
62406
62684
  init_verify();
62407
62685
  init_constants4();
62408
62686
  init_constants4();
@@ -75383,29 +75661,29 @@ is not a problem with esbuild. You need to fix your environment instead.
75383
75661
  let responseCallbacks = {};
75384
75662
  let nextRequestID = 0;
75385
75663
  let nextBuildKey = 0;
75386
- let stdout2 = new Uint8Array(16384);
75664
+ let stdout3 = new Uint8Array(16384);
75387
75665
  let stdoutUsed = 0;
75388
75666
  let readFromStdout = (chunk) => {
75389
75667
  let limit = stdoutUsed + chunk.length;
75390
- if (limit > stdout2.length) {
75668
+ if (limit > stdout3.length) {
75391
75669
  let swap = new Uint8Array(limit * 2);
75392
- swap.set(stdout2);
75393
- stdout2 = swap;
75670
+ swap.set(stdout3);
75671
+ stdout3 = swap;
75394
75672
  }
75395
- stdout2.set(chunk, stdoutUsed);
75673
+ stdout3.set(chunk, stdoutUsed);
75396
75674
  stdoutUsed += chunk.length;
75397
75675
  let offset = 0;
75398
75676
  while (offset + 4 <= stdoutUsed) {
75399
- let length = readUInt32LE(stdout2, offset);
75677
+ let length = readUInt32LE(stdout3, offset);
75400
75678
  if (offset + 4 + length > stdoutUsed) {
75401
75679
  break;
75402
75680
  }
75403
75681
  offset += 4;
75404
- handleIncomingPacket(stdout2.subarray(offset, offset + length));
75682
+ handleIncomingPacket(stdout3.subarray(offset, offset + length));
75405
75683
  offset += length;
75406
75684
  }
75407
75685
  if (offset > 0) {
75408
- stdout2.copyWithin(0, offset, stdoutUsed);
75686
+ stdout3.copyWithin(0, offset, stdoutUsed);
75409
75687
  stdoutUsed -= offset;
75410
75688
  }
75411
75689
  };
@@ -76893,12 +77171,12 @@ More information: The file containing the code for esbuild's JavaScript API (${_
76893
77171
  child.stdin.on("error", afterClose);
76894
77172
  child.on("error", afterClose);
76895
77173
  const stdin = child.stdin;
76896
- const stdout2 = child.stdout;
76897
- stdout2.on("data", readFromStdout);
76898
- stdout2.on("end", afterClose);
77174
+ const stdout3 = child.stdout;
77175
+ stdout3.on("data", readFromStdout);
77176
+ stdout3.on("end", afterClose);
76899
77177
  stopService = () => {
76900
77178
  stdin.destroy();
76901
- stdout2.destroy();
77179
+ stdout3.destroy();
76902
77180
  child.kill();
76903
77181
  initializeWasCalled = false;
76904
77182
  longLivedService = undefined;
@@ -76909,8 +77187,8 @@ More information: The file containing the code for esbuild's JavaScript API (${_
76909
77187
  if (stdin.unref) {
76910
77188
  stdin.unref();
76911
77189
  }
76912
- if (stdout2.unref) {
76913
- stdout2.unref();
77190
+ if (stdout3.unref) {
77191
+ stdout3.unref();
76914
77192
  }
76915
77193
  const refs = {
76916
77194
  ref() {
@@ -76981,13 +77259,13 @@ More information: The file containing the code for esbuild's JavaScript API (${_
76981
77259
  esbuild: node_exports
76982
77260
  });
76983
77261
  callback(service);
76984
- let stdout2 = child_process.execFileSync(command, args2.concat("--service=0.25.10"), {
77262
+ let stdout3 = child_process.execFileSync(command, args2.concat("--service=0.25.10"), {
76985
77263
  cwd: defaultWD,
76986
77264
  windowsHide: true,
76987
77265
  input: stdin,
76988
77266
  maxBuffer: +process.env.ESBUILD_MAX_BUFFER || 16777216
76989
77267
  });
76990
- readFromStdout(stdout2);
77268
+ readFromStdout(stdout3);
76991
77269
  afterClose(null);
76992
77270
  };
76993
77271
  var randomFileName = () => {
@@ -82701,33 +82979,33 @@ __export(exports_api, {
82701
82979
  });
82702
82980
  function assembleStyles() {
82703
82981
  const codes = /* @__PURE__ */ new Map;
82704
- for (const [groupName, group] of Object.entries(styles2)) {
82982
+ for (const [groupName, group] of Object.entries(styles3)) {
82705
82983
  for (const [styleName, style] of Object.entries(group)) {
82706
- styles2[styleName] = {
82984
+ styles3[styleName] = {
82707
82985
  open: `\x1B[${style[0]}m`,
82708
82986
  close: `\x1B[${style[1]}m`
82709
82987
  };
82710
- group[styleName] = styles2[styleName];
82988
+ group[styleName] = styles3[styleName];
82711
82989
  codes.set(style[0], style[1]);
82712
82990
  }
82713
- Object.defineProperty(styles2, groupName, {
82991
+ Object.defineProperty(styles3, groupName, {
82714
82992
  value: group,
82715
82993
  enumerable: false
82716
82994
  });
82717
82995
  }
82718
- Object.defineProperty(styles2, "codes", {
82996
+ Object.defineProperty(styles3, "codes", {
82719
82997
  value: codes,
82720
82998
  enumerable: false
82721
82999
  });
82722
- styles2.color.close = "\x1B[39m";
82723
- styles2.bgColor.close = "\x1B[49m";
82724
- styles2.color.ansi = wrapAnsi16();
82725
- styles2.color.ansi256 = wrapAnsi256();
82726
- styles2.color.ansi16m = wrapAnsi16m();
82727
- styles2.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
82728
- styles2.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
82729
- styles2.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
82730
- Object.defineProperties(styles2, {
83000
+ styles3.color.close = "\x1B[39m";
83001
+ styles3.bgColor.close = "\x1B[49m";
83002
+ styles3.color.ansi = wrapAnsi16();
83003
+ styles3.color.ansi256 = wrapAnsi256();
83004
+ styles3.color.ansi16m = wrapAnsi16m();
83005
+ styles3.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
83006
+ styles3.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
83007
+ styles3.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
83008
+ Object.defineProperties(styles3, {
82731
83009
  rgbToAnsi256: {
82732
83010
  value(red, green, blue) {
82733
83011
  if (red === green && green === blue) {
@@ -82763,7 +83041,7 @@ function assembleStyles() {
82763
83041
  enumerable: false
82764
83042
  },
82765
83043
  hexToAnsi256: {
82766
- value: (hex) => styles2.rgbToAnsi256(...styles2.hexToRgb(hex)),
83044
+ value: (hex) => styles3.rgbToAnsi256(...styles3.hexToRgb(hex)),
82767
83045
  enumerable: false
82768
83046
  },
82769
83047
  ansi256ToAnsi: {
@@ -82801,15 +83079,15 @@ function assembleStyles() {
82801
83079
  enumerable: false
82802
83080
  },
82803
83081
  rgbToAnsi: {
82804
- value: (red, green, blue) => styles2.ansi256ToAnsi(styles2.rgbToAnsi256(red, green, blue)),
83082
+ value: (red, green, blue) => styles3.ansi256ToAnsi(styles3.rgbToAnsi256(red, green, blue)),
82805
83083
  enumerable: false
82806
83084
  },
82807
83085
  hexToAnsi: {
82808
- value: (hex) => styles2.ansi256ToAnsi(styles2.hexToAnsi256(hex)),
83086
+ value: (hex) => styles3.ansi256ToAnsi(styles3.hexToAnsi256(hex)),
82809
83087
  enumerable: false
82810
83088
  }
82811
83089
  });
82812
- return styles2;
83090
+ return styles3;
82813
83091
  }
82814
83092
  function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
82815
83093
  const prefix2 = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
@@ -85391,7 +85669,7 @@ var ANSI_BACKGROUND_OFFSET;
85391
85669
  var wrapAnsi16;
85392
85670
  var wrapAnsi256;
85393
85671
  var wrapAnsi16m;
85394
- var styles2;
85672
+ var styles3;
85395
85673
  var modifierNames;
85396
85674
  var foregroundColorNames;
85397
85675
  var backgroundColorNames;
@@ -85768,7 +86046,7 @@ var tableKey;
85768
86046
  var ResolveSelectNamed;
85769
86047
  var ResolveSelect;
85770
86048
  var ResolveSchemasSelect;
85771
- var Spinner2;
86049
+ var Spinner3;
85772
86050
  var ProgressView;
85773
86051
  var init_views;
85774
86052
  var glob;
@@ -88269,7 +88547,7 @@ var init_api2 = __esm(() => {
88269
88547
  wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
88270
88548
  wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
88271
88549
  wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
88272
- styles2 = {
88550
+ styles3 = {
88273
88551
  modifier: {
88274
88552
  reset: [0, 0],
88275
88553
  bold: [1, 22],
@@ -88322,9 +88600,9 @@ var init_api2 = __esm(() => {
88322
88600
  bgWhiteBright: [107, 49]
88323
88601
  }
88324
88602
  };
88325
- modifierNames = Object.keys(styles2.modifier);
88326
- foregroundColorNames = Object.keys(styles2.color);
88327
- backgroundColorNames = Object.keys(styles2.bgColor);
88603
+ modifierNames = Object.keys(styles3.modifier);
88604
+ foregroundColorNames = Object.keys(styles3.color);
88605
+ backgroundColorNames = Object.keys(styles3.bgColor);
88328
88606
  colorNames = [...foregroundColorNames, ...backgroundColorNames];
88329
88607
  ansiStyles = assembleStyles();
88330
88608
  ansi_styles_default = ansiStyles;
@@ -90803,7 +91081,7 @@ See: https://github.com/isaacs/node-glob/issues/167`);
90803
91081
  exports.prepareReadLine = undefined;
90804
91082
  var prepareReadLine = () => {
90805
91083
  const stdin = process.stdin;
90806
- const stdout2 = process.stdout;
91084
+ const stdout3 = process.stdout;
90807
91085
  const readline = __require22("readline");
90808
91086
  const rl = readline.createInterface({
90809
91087
  input: stdin,
@@ -90812,7 +91090,7 @@ See: https://github.com/isaacs/node-glob/issues/167`);
90812
91090
  readline.emitKeypressEvents(stdin, rl);
90813
91091
  return {
90814
91092
  stdin,
90815
- stdout: stdout2,
91093
+ stdout: stdout3,
90816
91094
  closable: rl
90817
91095
  };
90818
91096
  };
@@ -90824,7 +91102,7 @@ See: https://github.com/isaacs/node-glob/issues/167`);
90824
91102
  var ESC = "\x1B";
90825
91103
  var CSI = `${ESC}[`;
90826
91104
  var beep = "\x07";
90827
- var cursor2 = {
91105
+ var cursor3 = {
90828
91106
  to(x5, y3) {
90829
91107
  if (!y3)
90830
91108
  return `${CSI}${x5 + 1}G`;
@@ -90868,13 +91146,13 @@ See: https://github.com/isaacs/node-glob/issues/167`);
90868
91146
  lines(count2) {
90869
91147
  let clear = "";
90870
91148
  for (let i3 = 0;i3 < count2; i3++)
90871
- clear += this.line + (i3 < count2 - 1 ? cursor2.up() : "");
91149
+ clear += this.line + (i3 < count2 - 1 ? cursor3.up() : "");
90872
91150
  if (count2)
90873
- clear += cursor2.left;
91151
+ clear += cursor3.left;
90874
91152
  return clear;
90875
91153
  }
90876
91154
  };
90877
- module2.exports = { cursor: cursor2, scroll, erase, beep };
91155
+ module2.exports = { cursor: cursor3, scroll, erase, beep };
90878
91156
  }
90879
91157
  });
90880
91158
  require_utils5 = __commonJS22({
@@ -91162,10 +91440,10 @@ See: https://github.com/isaacs/node-glob/issues/167`);
91162
91440
  };
91163
91441
  exports.deferred = deferred;
91164
91442
  var Terminal = class {
91165
- constructor(view5, stdin, stdout2, closable) {
91443
+ constructor(view5, stdin, stdout3, closable) {
91166
91444
  this.view = view5;
91167
91445
  this.stdin = stdin;
91168
- this.stdout = stdout2;
91446
+ this.stdout = stdout3;
91169
91447
  this.closable = closable;
91170
91448
  this.text = "";
91171
91449
  this.status = "idle";
@@ -91263,9 +91541,9 @@ See: https://github.com/isaacs/node-glob/issues/167`);
91263
91541
  };
91264
91542
  exports.TaskView = TaskView2;
91265
91543
  var TaskTerminal = class {
91266
- constructor(view5, stdout2) {
91544
+ constructor(view5, stdout3) {
91267
91545
  this.view = view5;
91268
- this.stdout = stdout2;
91546
+ this.stdout = stdout3;
91269
91547
  this.text = "";
91270
91548
  this.view.attach(this);
91271
91549
  }
@@ -91284,13 +91562,13 @@ See: https://github.com/isaacs/node-glob/issues/167`);
91284
91562
  };
91285
91563
  exports.TaskTerminal = TaskTerminal;
91286
91564
  function render7(view5) {
91287
- const { stdin, stdout: stdout2, closable } = (0, readline_1.prepareReadLine)();
91565
+ const { stdin, stdout: stdout3, closable } = (0, readline_1.prepareReadLine)();
91288
91566
  if (view5 instanceof Prompt3) {
91289
- const terminal = new Terminal(view5, stdin, stdout2, closable);
91567
+ const terminal = new Terminal(view5, stdin, stdout3, closable);
91290
91568
  terminal.requestLayout();
91291
91569
  return terminal.result();
91292
91570
  }
91293
- stdout2.write(`${view5}
91571
+ stdout3.write(`${view5}
91294
91572
  `);
91295
91573
  closable.close();
91296
91574
  return;
@@ -96948,7 +97226,7 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
96948
97226
  return this.state.items[this.state.selectedIdx];
96949
97227
  }
96950
97228
  };
96951
- Spinner2 = class {
97229
+ Spinner3 = class {
96952
97230
  constructor(frames) {
96953
97231
  this.frames = frames;
96954
97232
  this.offset = 0;
@@ -96969,7 +97247,7 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
96969
97247
  super();
96970
97248
  this.progressText = progressText;
96971
97249
  this.successText = successText;
96972
- this.spinner = new Spinner2("⣷⣯⣟⡿⢿⣻⣽⣾".split(""));
97250
+ this.spinner = new Spinner3("⣷⣯⣟⡿⢿⣻⣽⣾".split(""));
96973
97251
  this.timeout = setInterval(() => {
96974
97252
  this.spinner.tick();
96975
97253
  this.requestLayout();
@@ -98059,8 +98337,8 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
98059
98337
  });
98060
98338
  require_styles = __commonJS22({
98061
98339
  "../node_modules/.pnpm/colors@1.4.0/node_modules/colors/lib/styles.js"(exports, module2) {
98062
- var styles3 = {};
98063
- module2["exports"] = styles3;
98340
+ var styles32 = {};
98341
+ module2["exports"] = styles32;
98064
98342
  var codes = {
98065
98343
  reset: [0, 0],
98066
98344
  bold: [1, 22],
@@ -98115,7 +98393,7 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
98115
98393
  };
98116
98394
  Object.keys(codes).forEach(function(key) {
98117
98395
  var val = codes[key];
98118
- var style = styles3[key] = [];
98396
+ var style = styles32[key] = [];
98119
98397
  style.open = "\x1B[" + val[0] + "m";
98120
98398
  style.close = "\x1B[" + val[1] + "m";
98121
98399
  });
@@ -98593,7 +98871,7 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
98593
98871
  builder.__proto__ = proto2;
98594
98872
  return builder;
98595
98873
  }
98596
- var styles3 = function() {
98874
+ var styles32 = function() {
98597
98875
  var ret = {};
98598
98876
  ansiStyles2.grey = ansiStyles2.gray;
98599
98877
  Object.keys(ansiStyles2).forEach(function(key) {
@@ -98606,7 +98884,7 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
98606
98884
  });
98607
98885
  return ret;
98608
98886
  }();
98609
- var proto2 = defineProps(function colors2() {}, styles3);
98887
+ var proto2 = defineProps(function colors2() {}, styles32);
98610
98888
  function applyStyle2() {
98611
98889
  var args2 = Array.prototype.slice.call(arguments);
98612
98890
  var str = args2.map(function(arg) {
@@ -98656,7 +98934,7 @@ Is ${source_default.bold.blue(this.base.name)} schema created or renamed from an
98656
98934
  };
98657
98935
  function init2() {
98658
98936
  var ret = {};
98659
- Object.keys(styles3).forEach(function(name22) {
98937
+ Object.keys(styles32).forEach(function(name22) {
98660
98938
  ret[name22] = {
98661
98939
  get: function() {
98662
98940
  return build([name22]);
@@ -125924,23 +126202,23 @@ var require_lexer = __commonJS2((exports) => {
125924
126202
  ];
125925
126203
  function tokenize(input) {
125926
126204
  const tokens = [];
125927
- let cursor2 = 0;
125928
- while (cursor2 < input.length) {
126205
+ let cursor3 = 0;
126206
+ while (cursor3 < input.length) {
125929
126207
  let matched = false;
125930
126208
  for (const tokenType of tokenTypes) {
125931
- const match3 = input.slice(cursor2).match(tokenType.regex);
126209
+ const match3 = input.slice(cursor3).match(tokenType.regex);
125932
126210
  if (match3) {
125933
126211
  tokens.push({
125934
126212
  type: tokenType.tokenType,
125935
126213
  value: match3[0]
125936
126214
  });
125937
- cursor2 += match3[0].length;
126215
+ cursor3 += match3[0].length;
125938
126216
  matched = true;
125939
126217
  break;
125940
126218
  }
125941
126219
  }
125942
126220
  if (!matched) {
125943
- throw new Error(`Unexpected character at position ${cursor2}`);
126221
+ throw new Error(`Unexpected character at position ${cursor3}`);
125944
126222
  }
125945
126223
  }
125946
126224
  return tokens;
@@ -126197,13 +126475,13 @@ var require_picocolors2 = __commonJS2((exports, module2) => {
126197
126475
  return ~index6 ? open + replaceClose(string2, close, replace, index6) + close : open + string2 + close;
126198
126476
  };
126199
126477
  var replaceClose = (string2, close, replace, index6) => {
126200
- let result = "", cursor2 = 0;
126478
+ let result = "", cursor3 = 0;
126201
126479
  do {
126202
- result += string2.substring(cursor2, index6) + replace;
126203
- cursor2 = index6 + close.length;
126204
- index6 = string2.indexOf(close, cursor2);
126480
+ result += string2.substring(cursor3, index6) + replace;
126481
+ cursor3 = index6 + close.length;
126482
+ index6 = string2.indexOf(close, cursor3);
126205
126483
  } while (~index6);
126206
- return result + string2.substring(cursor2);
126484
+ return result + string2.substring(cursor3);
126207
126485
  };
126208
126486
  var createColors = (enabled = isColorSupported) => {
126209
126487
  let f3 = enabled ? formatter : () => String;
@@ -127033,6 +127311,16 @@ var init_schemas11 = __esm(() => {
127033
127311
  offset: exports_external.number().int().min(0).default(0)
127034
127312
  });
127035
127313
  });
127314
+ function isTimebackGrade3(value) {
127315
+ return Number.isInteger(value) && TIMEBACK_GRADES.includes(value);
127316
+ }
127317
+ function isTimebackSubject3(value) {
127318
+ return TIMEBACK_SUBJECTS3.includes(value);
127319
+ }
127320
+ var TIMEBACK_GRADES;
127321
+ var TIMEBACK_SUBJECTS3;
127322
+ var TimebackGradeSchema;
127323
+ var TimebackSubjectSchema;
127036
127324
  var UpdateTimebackXpRequestSchema;
127037
127325
  var EndActivityRequestSchema;
127038
127326
  var PopulateStudentRequestSchema;
@@ -127041,6 +127329,22 @@ var TimebackBaseConfigSchema;
127041
127329
  var PlatformTimebackSetupRequestSchema;
127042
127330
  var init_schemas12 = __esm(() => {
127043
127331
  init_esm();
127332
+ TIMEBACK_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
127333
+ TIMEBACK_SUBJECTS3 = [
127334
+ "Reading",
127335
+ "Language",
127336
+ "Vocabulary",
127337
+ "Social Studies",
127338
+ "Writing",
127339
+ "Science",
127340
+ "FastMath",
127341
+ "Math",
127342
+ "None"
127343
+ ];
127344
+ TimebackGradeSchema = exports_external.number().int().refine((val) => TIMEBACK_GRADES.includes(val), {
127345
+ message: `Grade must be one of: ${TIMEBACK_GRADES.join(", ")}`
127346
+ });
127347
+ TimebackSubjectSchema = exports_external.enum(TIMEBACK_SUBJECTS3);
127044
127348
  UpdateTimebackXpRequestSchema = exports_external.object({
127045
127349
  xp: exports_external.number().min(0, "XP must be a non-negative number"),
127046
127350
  userTimestamp: exports_external.string().datetime().optional()
@@ -138163,6 +138467,7 @@ var verifyIntegration;
138163
138467
  var getConfig2;
138164
138468
  var deleteIntegrations;
138165
138469
  var endActivity;
138470
+ var getStudentXp;
138166
138471
  var timeback2;
138167
138472
  var init_timeback_controller = __esm(() => {
138168
138473
  init_esm();
@@ -138306,6 +138611,46 @@ var init_timeback_controller = __esm(() => {
138306
138611
  logger60.debug("Ending activity", { userId: ctx.user.id, gameId });
138307
138612
  return ctx.services.timeback.endActivity(gameId, studentId, activityData, scoreData, timingData, xpEarned, masteredUnits, ctx.user);
138308
138613
  });
138614
+ getStudentXp = requireDeveloper(async (ctx) => {
138615
+ const timebackId = ctx.params.timebackId;
138616
+ if (!timebackId) {
138617
+ throw ApiError.badRequest("Missing timebackId parameter");
138618
+ }
138619
+ const gameId = ctx.url.searchParams.get("gameId") || undefined;
138620
+ const gradeParam = ctx.url.searchParams.get("grade");
138621
+ const subjectParam = ctx.url.searchParams.get("subject");
138622
+ if (gradeParam !== null !== (subjectParam !== null)) {
138623
+ throw ApiError.badRequest("Both grade and subject must be provided together");
138624
+ }
138625
+ let grade;
138626
+ let subject;
138627
+ if (gradeParam !== null && subjectParam !== null) {
138628
+ const parsedGrade = parseInt(gradeParam, 10);
138629
+ if (!isTimebackGrade3(parsedGrade)) {
138630
+ throw ApiError.badRequest(`Invalid grade: ${gradeParam}. Valid grades: ${TIMEBACK_GRADES.join(", ")}`);
138631
+ }
138632
+ if (!isTimebackSubject3(subjectParam)) {
138633
+ throw ApiError.badRequest(`Invalid subject: ${subjectParam}. Valid subjects: ${TIMEBACK_SUBJECTS3.join(", ")}`);
138634
+ }
138635
+ grade = parsedGrade;
138636
+ subject = subjectParam;
138637
+ }
138638
+ const includeParam = ctx.url.searchParams.get("include");
138639
+ const includeOptions = includeParam ? includeParam.split(",").map((opt) => opt.trim().toLowerCase()) : [];
138640
+ const include = {
138641
+ perCourse: includeOptions.includes("percourse"),
138642
+ today: includeOptions.includes("today")
138643
+ };
138644
+ logger60.debug("Getting student XP", {
138645
+ requesterId: ctx.user.id,
138646
+ timebackId,
138647
+ gameId,
138648
+ grade,
138649
+ subject,
138650
+ include
138651
+ });
138652
+ return ctx.services.timeback.getStudentXp(timebackId, { gameId, grade, subject, include });
138653
+ });
138309
138654
  timeback2 = {
138310
138655
  getTodayXp,
138311
138656
  getTotalXp,
@@ -138319,7 +138664,8 @@ var init_timeback_controller = __esm(() => {
138319
138664
  verifyIntegration,
138320
138665
  getConfig: getConfig2,
138321
138666
  deleteIntegrations,
138322
- endActivity
138667
+ endActivity,
138668
+ getStudentXp
138323
138669
  };
138324
138670
  });
138325
138671
  var logger61;
@@ -139396,6 +139742,56 @@ var init_timeback8 = __esm(() => {
139396
139742
  }
139397
139743
  return handle2(timeback2.getUserById)(c2);
139398
139744
  });
139745
+ timebackRouter.get("/student-xp/:timebackId", async (c2) => {
139746
+ const user = c2.get("user");
139747
+ if (!user) {
139748
+ const error2 = ApiError.unauthorized("Must be logged in to get student XP");
139749
+ return c2.json(createErrorResponse(error2), error2.status);
139750
+ }
139751
+ if (shouldMockTimeback()) {
139752
+ const url = new URL(c2.req.url);
139753
+ const gradeParam = url.searchParams.get("grade");
139754
+ const subjectParam = url.searchParams.get("subject");
139755
+ const includeParam = url.searchParams.get("include") || "";
139756
+ const includeOptions = includeParam.split(",").map((opt) => opt.trim().toLowerCase());
139757
+ const includePerCourse = includeOptions.includes("percourse");
139758
+ const includeToday = includeOptions.includes("today");
139759
+ const db2 = c2.get("db");
139760
+ let enrollments = await getMockEnrollments(db2);
139761
+ if (gradeParam !== null && subjectParam !== null) {
139762
+ const grade = parseInt(gradeParam, 10);
139763
+ enrollments = enrollments.filter((e) => e.grade === grade && e.subject === subjectParam);
139764
+ }
139765
+ const hashCode = (str) => {
139766
+ let hash = 0;
139767
+ for (let i3 = 0;i3 < str.length; i3++) {
139768
+ hash = (hash << 5) - hash + str.charCodeAt(i3);
139769
+ hash |= 0;
139770
+ }
139771
+ return Math.abs(hash);
139772
+ };
139773
+ const mockCourses = enrollments.map((e) => {
139774
+ const seed3 = hashCode(`${e.grade}-${e.subject}`);
139775
+ const totalXp2 = 100 + seed3 % 900;
139776
+ const todayXp2 = seed3 % 50;
139777
+ return {
139778
+ grade: e.grade,
139779
+ subject: e.subject,
139780
+ title: `${e.subject} Grade ${e.grade}`,
139781
+ totalXp: totalXp2,
139782
+ ...includeToday && { todayXp: todayXp2 }
139783
+ };
139784
+ });
139785
+ const totalXp = mockCourses.reduce((sum3, c3) => sum3 + c3.totalXp, 0);
139786
+ const todayXp = includeToday ? mockCourses.reduce((sum3, c3) => sum3 + (c3.todayXp ?? 0), 0) : undefined;
139787
+ return c2.json({
139788
+ totalXp,
139789
+ ...includeToday && { todayXp },
139790
+ ...includePerCourse && { courses: mockCourses }
139791
+ });
139792
+ }
139793
+ return handle2(timeback2.getStudentXp)(c2);
139794
+ });
139399
139795
  });
139400
139796
  function verifyMockToken(idToken) {
139401
139797
  if (!idToken.startsWith("mock:")) {
@@ -139848,7 +140244,7 @@ var ACHIEVEMENT_DEFINITIONS4 = [
139848
140244
  }
139849
140245
  ];
139850
140246
  // ../constants/src/typescript.ts
139851
- var TSC_PACKAGE4 = "@typescript/native-preview";
140247
+ var TSC_PACKAGE4 = "typescript";
139852
140248
  var USE_NATIVE_TSC4 = TSC_PACKAGE4.includes("native-preview");
139853
140249
  // ../constants/src/overworld.ts
139854
140250
  var ITEM_SLUGS4 = {
@@ -140147,7 +140543,7 @@ var init_auth5 = __esm5(() => {
140147
140543
  TIMEBACK_LTI: "timeback-lti"
140148
140544
  };
140149
140545
  });
140150
- var TSC_PACKAGE6 = "@typescript/native-preview";
140546
+ var TSC_PACKAGE6 = "typescript";
140151
140547
  var USE_NATIVE_TSC6;
140152
140548
  var init_typescript4 = __esm5(() => {
140153
140549
  USE_NATIVE_TSC6 = TSC_PACKAGE6.includes("native-preview");
@@ -140212,7 +140608,8 @@ var init_overworld4 = __esm5(() => {
140212
140608
  var TIMEBACK_ROUTES2;
140213
140609
  var init_timeback9 = __esm5(() => {
140214
140610
  TIMEBACK_ROUTES2 = {
140215
- END_ACTIVITY: "/integrations/timeback/end-activity"
140611
+ END_ACTIVITY: "/integrations/timeback/end-activity",
140612
+ GET_XP: "/integrations/timeback/xp"
140216
140613
  };
140217
140614
  });
140218
140615
  var WORKER_NAMING2;
@@ -140816,7 +141213,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
140816
141213
  // package.json
140817
141214
  var package_default2 = {
140818
141215
  name: "@playcademy/vite-plugin",
140819
- version: "0.2.11",
141216
+ version: "0.2.12",
140820
141217
  type: "module",
140821
141218
  exports: {
140822
141219
  ".": {
@@ -6,6 +6,6 @@ import type { ResolvedConfig } from 'vite';
6
6
  * Creates hot reload callbacks for logging backend updates.
7
7
  */
8
8
  export declare function createHotReloadCallbacks(viteConfig: ResolvedConfig): {
9
- onSuccess: (changedPath?: string | undefined) => void;
9
+ onSuccess: (changedPath?: string) => void;
10
10
  onError: (error: unknown) => void;
11
11
  };
@@ -17,8 +17,8 @@ export declare const serverState: {
17
17
  backend: CliServerManager | null;
18
18
  viteServer: ViteDevServer | null;
19
19
  currentMode: PlaycademyMode;
20
- timebackRoleOverride: "administrator" | "parent" | "student" | "teacher" | null;
21
- platformRoleOverride: "admin" | "developer" | "player" | null;
20
+ timebackRoleOverride: TimebackRoleOverride | null;
21
+ platformRoleOverride: PlatformRoleOverride | null;
22
22
  };
23
23
  /**
24
24
  * Get sandbox server reference
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/vite-plugin",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -22,11 +22,11 @@
22
22
  "dependencies": {
23
23
  "archiver": "^7.0.1",
24
24
  "picocolors": "^1.1.1",
25
- "playcademy": "0.16.4"
25
+ "playcademy": "0.16.6"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@inquirer/prompts": "^7.8.6",
29
- "@playcademy/sandbox": "0.3.13",
29
+ "@playcademy/sandbox": "0.3.14",
30
30
  "@playcademy/utils": "0.0.1",
31
31
  "@types/archiver": "^6.0.3",
32
32
  "@types/bun": "latest"