@playcademy/vite-plugin 0.2.34 → 0.2.35-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +830 -499
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25353,7 +25353,7 @@ var package_default;
25353
25353
  var init_package = __esm(() => {
25354
25354
  package_default = {
25355
25355
  name: "@playcademy/sandbox",
25356
- version: "0.3.18",
25356
+ version: "0.3.19-beta.1",
25357
25357
  description: "Local development server for Playcademy game development",
25358
25358
  type: "module",
25359
25359
  exports: {
@@ -55125,6 +55125,8 @@ var TIMEBACK_SUBJECTS4;
55125
55125
  var TimebackGradeSchema;
55126
55126
  var TimebackSubjectSchema;
55127
55127
  var UpdateTimebackXpRequestSchema;
55128
+ var CourseGoalsSchema;
55129
+ var UpdateGameTimebackIntegrationRequestSchema;
55128
55130
  var TimebackActivityDataSchema;
55129
55131
  var EndActivityRequestSchema;
55130
55132
  var GameActivityMetricsSchema;
@@ -55144,6 +55146,7 @@ var ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE;
55144
55146
  var GrantTimebackXpRequestSchema;
55145
55147
  var AdjustTimebackTimeRequestSchema;
55146
55148
  var AdjustTimebackMasteryRequestSchema;
55149
+ var ReconcileMasteryForConfigChangeSchema;
55147
55150
  var EnrollStudentRequestSchema;
55148
55151
  var UnenrollStudentRequestSchema;
55149
55152
  var ReactivateEnrollmentRequestSchema;
@@ -55175,6 +55178,24 @@ var init_schemas11 = __esm(() => {
55175
55178
  xp: exports_external.number().min(0, "XP must be a non-negative number"),
55176
55179
  userTimestamp: exports_external.string().datetime().optional()
55177
55180
  });
55181
+ CourseGoalsSchema = exports_external.object({
55182
+ dailyXp: exports_external.number().int().nonnegative().nullable().optional(),
55183
+ dailyLessons: exports_external.number().int().nonnegative().nullable().optional(),
55184
+ dailyActiveMinutes: exports_external.number().int().nonnegative().nullable().optional(),
55185
+ dailyAccuracy: exports_external.number().int().min(0).max(100).nullable().optional(),
55186
+ dailyMasteredUnits: exports_external.number().int().nonnegative().nullable().optional()
55187
+ });
55188
+ UpdateGameTimebackIntegrationRequestSchema = exports_external.object({
55189
+ title: exports_external.string().trim().min(1).optional(),
55190
+ courseCode: exports_external.string().trim().min(1).optional(),
55191
+ subject: TimebackSubjectSchema.optional(),
55192
+ totalXp: exports_external.number().int().nonnegative().nullable().optional(),
55193
+ masterableUnits: exports_external.number().int().nonnegative().nullable().optional(),
55194
+ goals: CourseGoalsSchema.optional(),
55195
+ publishStatus: exports_external.enum(["draft", "testing", "published", "deactivated"]).nullable().optional(),
55196
+ isSupplemental: exports_external.boolean().optional(),
55197
+ timebackVisible: exports_external.boolean().nullable().optional()
55198
+ });
55178
55199
  TimebackActivityDataSchema = exports_external.object({
55179
55200
  activityId: exports_external.string().min(1),
55180
55201
  activityName: exports_external.string().optional(),
@@ -55344,6 +55365,13 @@ var init_schemas11 = __esm(() => {
55344
55365
  date: AdminAttributionDateSchema.optional(),
55345
55366
  useCurrentTime: exports_external.boolean().optional()
55346
55367
  });
55368
+ ReconcileMasteryForConfigChangeSchema = exports_external.object({
55369
+ gameId: exports_external.string().uuid(),
55370
+ courseId: exports_external.string().min(1),
55371
+ oldMasterableUnits: exports_external.number().int().positive(),
55372
+ newMasterableUnits: exports_external.number().int().positive(),
55373
+ affectedStudentIds: exports_external.array(exports_external.string().min(1)).min(1).max(500)
55374
+ });
55347
55375
  EnrollStudentRequestSchema = exports_external.object({
55348
55376
  gameId: exports_external.string().uuid(),
55349
55377
  courseId: exports_external.string().min(1),
@@ -55492,6 +55520,63 @@ function compareEnrollmentsByRecency(a, b) {
55492
55520
  var init_timeback_admin_util = __esm(() => {
55493
55521
  init_errors();
55494
55522
  });
55523
+ async function upsertMasteryCompletionEntry(params) {
55524
+ const { client, courseId, studentId, appName, action } = params;
55525
+ const ids = deriveSourcedIds(courseId);
55526
+ const lineItemId = `${ids.course}-mastery-completion-assessment`;
55527
+ const resultId = `${lineItemId}:${studentId}:completion`;
55528
+ if (action === "complete") {
55529
+ await client.oneroster.assessmentLineItems.findOrCreate(lineItemId, {
55530
+ sourcedId: lineItemId,
55531
+ title: "Mastery Completion",
55532
+ status: ONEROSTER_STATUS.active,
55533
+ course: { sourcedId: ids.course },
55534
+ ...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
55535
+ });
55536
+ await client.oneroster.assessmentResults.upsert(resultId, {
55537
+ sourcedId: resultId,
55538
+ status: ONEROSTER_STATUS.active,
55539
+ assessmentLineItem: { sourcedId: lineItemId },
55540
+ student: { sourcedId: studentId },
55541
+ score: 100,
55542
+ scoreDate: new Date().toISOString(),
55543
+ scoreStatus: SCORE_STATUS.fullyGraded,
55544
+ inProgress: "false",
55545
+ metadata: {
55546
+ isMasteryCompletion: true,
55547
+ adminAction: true,
55548
+ appName
55549
+ }
55550
+ });
55551
+ } else {
55552
+ try {
55553
+ await client.oneroster.assessmentResults.upsert(resultId, {
55554
+ sourcedId: resultId,
55555
+ status: ONEROSTER_STATUS.active,
55556
+ assessmentLineItem: { sourcedId: lineItemId },
55557
+ student: { sourcedId: studentId },
55558
+ score: 0,
55559
+ scoreDate: new Date().toISOString(),
55560
+ scoreStatus: SCORE_STATUS.notSubmitted,
55561
+ inProgress: "true",
55562
+ metadata: {
55563
+ isMasteryCompletion: true,
55564
+ adminAction: true,
55565
+ appName
55566
+ }
55567
+ });
55568
+ } catch {
55569
+ logger17.debug("No completion entry to revoke", { studentId, courseId });
55570
+ }
55571
+ }
55572
+ }
55573
+ var logger17;
55574
+ var init_timeback_mastery_completion_util = __esm(() => {
55575
+ init_src2();
55576
+ init_constants4();
55577
+ init_utils6();
55578
+ logger17 = log.scope("timeback-mastery-completion");
55579
+ });
55495
55580
  function isRecord2(value) {
55496
55581
  return typeof value === "object" && value !== null;
55497
55582
  }
@@ -55847,7 +55932,7 @@ class TimebackAdminService {
55847
55932
  }
55848
55933
  requireClient() {
55849
55934
  if (!this.deps.timeback) {
55850
- logger17.error("Timeback client not available in context");
55935
+ logger18.error("Timeback client not available in context");
55851
55936
  throw new ValidationError("Timeback integration not available in this environment");
55852
55937
  }
55853
55938
  return this.deps.timeback;
@@ -56067,7 +56152,7 @@ class TimebackAdminService {
56067
56152
  });
56068
56153
  return [enrollmentId, this.summarizeAnalyticsFacts(analytics.facts)];
56069
56154
  } catch (error) {
56070
- logger17.warn("Failed to load enrollment analytics summary", {
56155
+ logger18.warn("Failed to load enrollment analytics summary", {
56071
56156
  enrollmentId,
56072
56157
  error: error instanceof Error ? error.message : String(error)
56073
56158
  });
@@ -56097,7 +56182,7 @@ class TimebackAdminService {
56097
56182
  const events = await this.fetchCaliperEventsForStudent(client, studentId, source, eventLimit);
56098
56183
  return TimebackAdminService.mapRecentActivityItems(events, relevantCourseIds).slice(0, maxResults);
56099
56184
  } catch (error) {
56100
- logger17.warn("Failed to load recent Caliper activity", {
56185
+ logger18.warn("Failed to load recent Caliper activity", {
56101
56186
  studentId,
56102
56187
  gameId: source.gameId,
56103
56188
  sourceMode: source.sourceMode,
@@ -56423,60 +56508,44 @@ class TimebackAdminService {
56423
56508
  const wasMastered = currentMastered >= masterableUnits;
56424
56509
  const willBeMastered = currentMastered + data.units >= masterableUnits;
56425
56510
  if (wasMastered !== willBeMastered) {
56426
- const ids = deriveSourcedIds(data.courseId);
56427
- const lineItemId = `${ids.course}-mastery-completion-assessment`;
56428
- const resultId = `${lineItemId}:${data.studentId}:completion`;
56429
- if (willBeMastered) {
56430
- await client.oneroster.assessmentLineItems.findOrCreate(lineItemId, {
56431
- sourcedId: lineItemId,
56432
- title: "Mastery Completion",
56433
- status: ONEROSTER_STATUS.active,
56434
- course: { sourcedId: ids.course },
56435
- ...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
56436
- });
56437
- await client.oneroster.assessmentResults.upsert(resultId, {
56438
- sourcedId: resultId,
56439
- status: ONEROSTER_STATUS.active,
56440
- assessmentLineItem: { sourcedId: lineItemId },
56441
- student: { sourcedId: data.studentId },
56442
- score: 100,
56443
- scoreDate: new Date().toISOString(),
56444
- scoreStatus: SCORE_STATUS.fullyGraded,
56445
- inProgress: "false",
56446
- metadata: {
56447
- isMasteryCompletion: true,
56448
- adminAction: true,
56449
- appName
56450
- }
56451
- });
56452
- } else {
56453
- try {
56454
- await client.oneroster.assessmentResults.upsert(resultId, {
56455
- sourcedId: resultId,
56456
- status: ONEROSTER_STATUS.active,
56457
- assessmentLineItem: { sourcedId: lineItemId },
56458
- student: { sourcedId: data.studentId },
56459
- score: 0,
56460
- scoreDate: new Date().toISOString(),
56461
- scoreStatus: SCORE_STATUS.notSubmitted,
56462
- inProgress: "true",
56463
- metadata: {
56464
- isMasteryCompletion: true,
56465
- adminAction: true,
56466
- appName
56467
- }
56468
- });
56469
- } catch {
56470
- logger17.debug("No completion entry to revoke", {
56471
- studentId: data.studentId,
56472
- courseId: data.courseId
56473
- });
56474
- }
56475
- }
56511
+ await upsertMasteryCompletionEntry({
56512
+ client,
56513
+ courseId: data.courseId,
56514
+ studentId: data.studentId,
56515
+ appName,
56516
+ action: willBeMastered ? "complete" : "revoke"
56517
+ });
56476
56518
  }
56477
56519
  }
56478
56520
  return { status: "ok" };
56479
56521
  }
56522
+ async reconcileMasteryForConfigChange(gameId, courseId, user, context) {
56523
+ const { client, appName } = await this.resolveAdminMutationContext(gameId, courseId, user);
56524
+ const action = context.newMasterableUnits < context.oldMasterableUnits ? "complete" : "revoke";
56525
+ const failed = [];
56526
+ let processed = 0;
56527
+ await TimebackAdminService.runWithConcurrency(context.affectedStudentIds, 8, async (studentId) => {
56528
+ try {
56529
+ await upsertMasteryCompletionEntry({
56530
+ client,
56531
+ courseId,
56532
+ studentId,
56533
+ appName,
56534
+ action
56535
+ });
56536
+ processed++;
56537
+ } catch (error) {
56538
+ logger18.warn("Failed to reconcile mastery completion for student", {
56539
+ studentId,
56540
+ courseId,
56541
+ action,
56542
+ error: error instanceof Error ? error.message : String(error)
56543
+ });
56544
+ failed.push(studentId);
56545
+ }
56546
+ });
56547
+ return { processed, failed };
56548
+ }
56480
56549
  async searchStudentsForEnrollment(gameId, courseId, query, user) {
56481
56550
  const client = this.requireClient();
56482
56551
  await this.deps.validateGameManagementAccess(user, gameId);
@@ -56503,7 +56572,7 @@ class TimebackAdminService {
56503
56572
  const response = await client["request"](endpoint, "GET");
56504
56573
  allUsers = response.users || [];
56505
56574
  } catch (error) {
56506
- logger17.warn("Failed to search OneRoster users", {
56575
+ logger18.warn("Failed to search OneRoster users", {
56507
56576
  query: trimmedQuery,
56508
56577
  error: error instanceof Error ? error.message : String(error)
56509
56578
  });
@@ -56648,7 +56717,7 @@ class TimebackAdminService {
56648
56717
  return results;
56649
56718
  }
56650
56719
  }
56651
- var logger17;
56720
+ var logger18;
56652
56721
  var init_timeback_admin_service = __esm(() => {
56653
56722
  init_drizzle_orm();
56654
56723
  init_src();
@@ -56661,8 +56730,9 @@ var init_timeback_admin_service = __esm(() => {
56661
56730
  init_errors();
56662
56731
  init_timeback_admin_metrics_util();
56663
56732
  init_timeback_admin_util();
56733
+ init_timeback_mastery_completion_util();
56664
56734
  init_timeback_util();
56665
- logger17 = log.scope("TimebackAdminService");
56735
+ logger18 = log.scope("TimebackAdminService");
56666
56736
  });
56667
56737
  var __esm5 = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
56668
56738
  var TIMEBACK_API_URLS4;
@@ -56935,7 +57005,7 @@ class TimebackAssessmentsService {
56935
57005
  isActive: row.bankActive
56936
57006
  };
56937
57007
  } catch {
56938
- logger18.warn("Failed to fetch QTI test metadata", {
57008
+ logger19.warn("Failed to fetch QTI test metadata", {
56939
57009
  identifier: row.qtiTestIdentifier
56940
57010
  });
56941
57011
  return {
@@ -56989,7 +57059,7 @@ class TimebackAssessmentsService {
56989
57059
  });
56990
57060
  } catch (error) {
56991
57061
  if (error instanceof TimebackApiError && error.status === 409) {
56992
- logger18.info("QTI test already exists (idempotent retry)", {
57062
+ logger19.info("QTI test already exists (idempotent retry)", {
56993
57063
  qtiTestIdentifier: input.qtiTestIdentifier
56994
57064
  });
56995
57065
  } else {
@@ -57002,7 +57072,7 @@ class TimebackAssessmentsService {
57002
57072
  qtiTestIdentifier: input.qtiTestIdentifier,
57003
57073
  sortOrder: maxSortOrder + 1
57004
57074
  }).returning();
57005
- logger18.info("Assessment created", {
57075
+ logger19.info("Assessment created", {
57006
57076
  integrationId,
57007
57077
  qtiTestIdentifier: input.qtiTestIdentifier
57008
57078
  });
@@ -57024,13 +57094,13 @@ class TimebackAssessmentsService {
57024
57094
  }
57025
57095
  await client.qti.tests.delete(qtiTestIdentifier);
57026
57096
  } catch (error) {
57027
- logger18.warn("Partial QTI cleanup during assessment deletion", {
57097
+ logger19.warn("Partial QTI cleanup during assessment deletion", {
57028
57098
  qtiTestIdentifier,
57029
57099
  error: error instanceof Error ? error.message : String(error)
57030
57100
  });
57031
57101
  }
57032
57102
  await this.deps.db.delete(gameTimebackAssessmentTests).where(eq(gameTimebackAssessmentTests.id, row.id));
57033
- logger18.info("Assessment deleted", { integrationId, qtiTestIdentifier });
57103
+ logger19.info("Assessment deleted", { integrationId, qtiTestIdentifier });
57034
57104
  }
57035
57105
  async reorderAssessments(integrationId, identifiers) {
57036
57106
  await this.requireIntegration(integrationId);
@@ -57075,7 +57145,7 @@ class TimebackAssessmentsService {
57075
57145
  return client.qti.tests.reorderItems(qtiTestIdentifier, partId, sectionId, items2);
57076
57146
  }
57077
57147
  async activateAssessment(integrationId, qtiTestIdentifier) {
57078
- logger18.debug("Activating assessment", { integrationId, qtiTestIdentifier });
57148
+ logger19.debug("Activating assessment", { integrationId, qtiTestIdentifier });
57079
57149
  const client = this.requireClient();
57080
57150
  const integration = await this.requireIntegration(integrationId);
57081
57151
  const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
@@ -57113,7 +57183,7 @@ class TimebackAssessmentsService {
57113
57183
  });
57114
57184
  }
57115
57185
  } catch {
57116
- logger18.warn("Failed to reactivate existing child resource, will create new", {
57186
+ logger19.warn("Failed to reactivate existing child resource, will create new", {
57117
57187
  childResourceId
57118
57188
  });
57119
57189
  childResourceId = null;
@@ -57126,7 +57196,7 @@ class TimebackAssessmentsService {
57126
57196
  const resourceUrl = resource.metadata?.url;
57127
57197
  if (resourceUrl === qtiTestUrl) {
57128
57198
  childResourceId = resourceId;
57129
- logger18.info("Found existing child Resource for QTI test (idempotent retry)", {
57199
+ logger19.info("Found existing child Resource for QTI test (idempotent retry)", {
57130
57200
  qtiTestIdentifier,
57131
57201
  childResourceId
57132
57202
  });
@@ -57135,7 +57205,7 @@ class TimebackAssessmentsService {
57135
57205
  } catch {}
57136
57206
  }
57137
57207
  if (!childResourceId) {
57138
- logger18.debug("Creating child resource", { qtiTestIdentifier, qtiTestUrl });
57208
+ logger19.debug("Creating child resource", { qtiTestIdentifier, qtiTestUrl });
57139
57209
  const childResult = await client.oneroster.resources.create({
57140
57210
  resource: {
57141
57211
  status: "active",
@@ -57163,10 +57233,10 @@ class TimebackAssessmentsService {
57163
57233
  }
57164
57234
  }
57165
57235
  await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: childResourceId, bankActive: true }).where(eq(gameTimebackAssessmentTests.id, row.id));
57166
- logger18.info("Assessment activated", { integrationId, qtiTestIdentifier, childResourceId });
57236
+ logger19.info("Assessment activated", { integrationId, qtiTestIdentifier, childResourceId });
57167
57237
  }
57168
57238
  async deactivateAssessment(integrationId, qtiTestIdentifier) {
57169
- logger18.debug("Deactivating assessment", { integrationId, qtiTestIdentifier });
57239
+ logger19.debug("Deactivating assessment", { integrationId, qtiTestIdentifier });
57170
57240
  const client = this.requireClient();
57171
57241
  const integration = await this.requireIntegration(integrationId);
57172
57242
  const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
@@ -57179,7 +57249,7 @@ class TimebackAssessmentsService {
57179
57249
  const childResourceId = row.bankResourceId;
57180
57250
  const bankIds = deriveAssessmentBankIds(integration.courseId);
57181
57251
  try {
57182
- logger18.debug("Reading parent resource for deactivation", {
57252
+ logger19.debug("Reading parent resource for deactivation", {
57183
57253
  resourceId: bankIds.resource
57184
57254
  });
57185
57255
  const parentResource = await client.oneroster.resources.get(bankIds.resource);
@@ -57198,22 +57268,22 @@ class TimebackAssessmentsService {
57198
57268
  });
57199
57269
  }
57200
57270
  } catch (error) {
57201
- logger18.warn("Failed to update parent resource during deactivation", {
57271
+ logger19.warn("Failed to update parent resource during deactivation", {
57202
57272
  bankResourceId: bankIds.resource,
57203
57273
  error: error instanceof Error ? error.message : String(error)
57204
57274
  });
57205
57275
  }
57206
57276
  try {
57207
- logger18.debug("Deleting child resource", { childResourceId });
57277
+ logger19.debug("Deleting child resource", { childResourceId });
57208
57278
  await client.oneroster.resources.delete(childResourceId);
57209
57279
  } catch (error) {
57210
- logger18.warn("Failed to delete child resource (may already be deleted)", {
57280
+ logger19.warn("Failed to delete child resource (may already be deleted)", {
57211
57281
  childResourceId,
57212
57282
  error: error instanceof Error ? error.message : String(error)
57213
57283
  });
57214
57284
  }
57215
57285
  await this.deps.db.update(gameTimebackAssessmentTests).set({ bankActive: false }).where(eq(gameTimebackAssessmentTests.id, row.id));
57216
- logger18.info("Assessment deactivated", { integrationId, qtiTestIdentifier });
57286
+ logger19.info("Assessment deactivated", { integrationId, qtiTestIdentifier });
57217
57287
  }
57218
57288
  isAssessmentActive(row) {
57219
57289
  return row.bankActive;
@@ -57244,14 +57314,14 @@ class TimebackAssessmentsService {
57244
57314
  status: "tobedeleted"
57245
57315
  });
57246
57316
  } catch (error) {
57247
- logger18.warn("Failed to delete component resource", { error });
57317
+ logger19.warn("Failed to delete component resource", { error });
57248
57318
  }
57249
57319
  for (const row of activeRows) {
57250
57320
  if (row.bankResourceId) {
57251
57321
  try {
57252
57322
  await client.oneroster.resources.delete(row.bankResourceId);
57253
57323
  } catch (error) {
57254
- logger18.warn("Failed to delete child resource", {
57324
+ logger19.warn("Failed to delete child resource", {
57255
57325
  childResourceId: row.bankResourceId,
57256
57326
  error
57257
57327
  });
@@ -57261,17 +57331,17 @@ class TimebackAssessmentsService {
57261
57331
  try {
57262
57332
  await client.oneroster.resources.delete(bankIds.resource);
57263
57333
  } catch (error) {
57264
- logger18.warn("Failed to delete parent resource", { error });
57334
+ logger19.warn("Failed to delete parent resource", { error });
57265
57335
  }
57266
57336
  try {
57267
57337
  await client.oneroster.courseComponents.update(bankIds.component, {
57268
57338
  status: "tobedeleted"
57269
57339
  });
57270
57340
  } catch (error) {
57271
- logger18.warn("Failed to delete course component", { error });
57341
+ logger19.warn("Failed to delete course component", { error });
57272
57342
  }
57273
57343
  await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: null, bankActive: false }).where(eq(gameTimebackAssessmentTests.integrationId, integrationId));
57274
- logger18.info("Bank destroyed", { integrationId });
57344
+ logger19.info("Bank destroyed", { integrationId });
57275
57345
  }
57276
57346
  requireClient() {
57277
57347
  if (!this.deps.timeback) {
@@ -57300,7 +57370,7 @@ class TimebackAssessmentsService {
57300
57370
  async ensureBank(integration) {
57301
57371
  const client = this.requireClient();
57302
57372
  const bankIds = deriveAssessmentBankIds(integration.courseId);
57303
- logger18.debug("Ensuring assessment bank hierarchy", {
57373
+ logger19.debug("Ensuring assessment bank hierarchy", {
57304
57374
  courseId: integration.courseId,
57305
57375
  bankIds
57306
57376
  });
@@ -57317,7 +57387,7 @@ class TimebackAssessmentsService {
57317
57387
  });
57318
57388
  } catch (error) {
57319
57389
  if (error instanceof TimebackApiError && error.status === 409) {
57320
- logger18.debug("Course component already exists", { sourcedId: bankIds.component });
57390
+ logger19.debug("Course component already exists", { sourcedId: bankIds.component });
57321
57391
  } else {
57322
57392
  throw error;
57323
57393
  }
@@ -57341,7 +57411,7 @@ class TimebackAssessmentsService {
57341
57411
  });
57342
57412
  } catch (error) {
57343
57413
  if (error instanceof TimebackApiError && error.status === 409) {
57344
- logger18.debug("Parent resource already exists", { sourcedId: bankIds.resource });
57414
+ logger19.debug("Parent resource already exists", { sourcedId: bankIds.resource });
57345
57415
  } else {
57346
57416
  throw error;
57347
57417
  }
@@ -57361,14 +57431,14 @@ class TimebackAssessmentsService {
57361
57431
  });
57362
57432
  } catch (error) {
57363
57433
  if (error instanceof TimebackApiError && error.status === 409) {
57364
- logger18.debug("Component resource already exists", {
57434
+ logger19.debug("Component resource already exists", {
57365
57435
  sourcedId: bankIds.componentResource
57366
57436
  });
57367
57437
  } else {
57368
57438
  throw error;
57369
57439
  }
57370
57440
  }
57371
- logger18.info("Assessment bank hierarchy created", {
57441
+ logger19.info("Assessment bank hierarchy created", {
57372
57442
  courseId: integration.courseId
57373
57443
  });
57374
57444
  }
@@ -57383,7 +57453,7 @@ class TimebackAssessmentsService {
57383
57453
  return Math.max(...rows.map((r) => r.sortOrder));
57384
57454
  }
57385
57455
  }
57386
- var logger18;
57456
+ var logger19;
57387
57457
  var init_timeback_assessments_service = __esm(() => {
57388
57458
  init_drizzle_orm();
57389
57459
  init_tables_index();
@@ -57392,7 +57462,7 @@ var init_timeback_assessments_service = __esm(() => {
57392
57462
  init_errors4();
57393
57463
  init_utils6();
57394
57464
  init_errors();
57395
- logger18 = log.scope("TimebackAssessmentsService");
57465
+ logger19 = log.scope("TimebackAssessmentsService");
57396
57466
  });
57397
57467
  async function promoteCompletedCourse({
57398
57468
  db: db2,
@@ -57406,7 +57476,7 @@ async function promoteCompletedCourse({
57406
57476
  });
57407
57477
  const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
57408
57478
  if (!nextIntegration) {
57409
- logger19.debug("Skipping promotion because no next course is configured", {
57479
+ logger20.debug("Skipping promotion because no next course is configured", {
57410
57480
  gameId: currentIntegration.gameId,
57411
57481
  studentId,
57412
57482
  grade: currentIntegration.grade,
@@ -57423,7 +57493,7 @@ async function promoteCompletedCourse({
57423
57493
  const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
57424
57494
  if (!currentEnrollment) {
57425
57495
  if (nextEnrollment) {
57426
- logger19.debug("Skipping promotion because student is already on the next course", {
57496
+ logger20.debug("Skipping promotion because student is already on the next course", {
57427
57497
  gameId: currentIntegration.gameId,
57428
57498
  studentId,
57429
57499
  grade: currentIntegration.grade,
@@ -57437,7 +57507,7 @@ async function promoteCompletedCourse({
57437
57507
  nextCourseId: nextIntegration.courseId
57438
57508
  };
57439
57509
  }
57440
- logger19.debug("Skipping promotion because student is not enrolled in the current course", {
57510
+ logger20.debug("Skipping promotion because student is not enrolled in the current course", {
57441
57511
  gameId: currentIntegration.gameId,
57442
57512
  studentId,
57443
57513
  grade: currentIntegration.grade,
@@ -57468,7 +57538,7 @@ async function promoteCompletedCourse({
57468
57538
  client.invalidateEnrollments(studentId);
57469
57539
  }
57470
57540
  }
57471
- logger19.info("Promoted student to next course", {
57541
+ logger20.info("Promoted student to next course", {
57472
57542
  gameId: currentIntegration.gameId,
57473
57543
  studentId,
57474
57544
  subject: currentIntegration.subject,
@@ -57483,14 +57553,14 @@ async function promoteCompletedCourse({
57483
57553
  nextCourseId: nextIntegration.courseId
57484
57554
  };
57485
57555
  }
57486
- var logger19;
57556
+ var logger20;
57487
57557
  var init_timeback_promotion_util = __esm(() => {
57488
57558
  init_drizzle_orm();
57489
57559
  init_tables_index();
57490
57560
  init_src2();
57491
- logger19 = log.scope("TimebackPromotion");
57561
+ logger20 = log.scope("TimebackPromotion");
57492
57562
  });
57493
- var logger20;
57563
+ var logger21;
57494
57564
  var TimebackService;
57495
57565
  var init_timeback_service = __esm(() => {
57496
57566
  init_drizzle_orm();
@@ -57502,7 +57572,7 @@ var init_timeback_service = __esm(() => {
57502
57572
  init_errors();
57503
57573
  init_timeback_promotion_util();
57504
57574
  init_timeback_util();
57505
- logger20 = log.scope("TimebackService");
57575
+ logger21 = log.scope("TimebackService");
57506
57576
  TimebackService = class TimebackService2 {
57507
57577
  static HEARTBEAT_DEDUPE_TTL_MS = 300000;
57508
57578
  static processedHeartbeatWindows = new Map;
@@ -57548,7 +57618,7 @@ var init_timeback_service = __esm(() => {
57548
57618
  }
57549
57619
  requireClient() {
57550
57620
  if (!this.deps.timeback) {
57551
- logger20.error("Timeback client not available in context");
57621
+ logger21.error("Timeback client not available in context");
57552
57622
  throw new ValidationError("Timeback integration not available in this environment");
57553
57623
  }
57554
57624
  return this.deps.timeback;
@@ -57601,7 +57671,7 @@ var init_timeback_service = __esm(() => {
57601
57671
  set: { xp: sql`excluded.xp`, updatedAt: new Date }
57602
57672
  }).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
57603
57673
  if (!result) {
57604
- logger20.error("Daily XP upsert returned no rows", { userId, date: targetDate });
57674
+ logger21.error("Daily XP upsert returned no rows", { userId, date: targetDate });
57605
57675
  throw new InternalError("Failed to update daily XP record");
57606
57676
  }
57607
57677
  return { xp: result.xp, date: result.date.toISOString() };
@@ -57632,7 +57702,7 @@ var init_timeback_service = __esm(() => {
57632
57702
  columns: { id: true, timebackId: true }
57633
57703
  });
57634
57704
  if (dbUser?.timebackId) {
57635
- logger20.info("Student already onboarded", { userId: user.id });
57705
+ logger21.info("Student already onboarded", { userId: user.id });
57636
57706
  return { status: "already_populated" };
57637
57707
  }
57638
57708
  let timebackId;
@@ -57641,7 +57711,7 @@ var init_timeback_service = __esm(() => {
57641
57711
  const existingUser = await client.oneroster.users.findByEmail(user.email);
57642
57712
  timebackId = existingUser.sourcedId;
57643
57713
  name3 = `${existingUser.givenName} ${existingUser.familyName}`;
57644
- logger20.info("Found existing student in OneRoster", {
57714
+ logger21.info("Found existing student in OneRoster", {
57645
57715
  userId: user.id,
57646
57716
  timebackId
57647
57717
  });
@@ -57670,7 +57740,7 @@ var init_timeback_service = __esm(() => {
57670
57740
  }
57671
57741
  timebackId = response.sourcedIdPairs.allocatedSourcedId;
57672
57742
  name3 = `${providedNames.firstName} ${providedNames.lastName}`;
57673
- logger20.info("Created student in OneRoster", { userId: user.id, timebackId });
57743
+ logger21.info("Created student in OneRoster", { userId: user.id, timebackId });
57674
57744
  }
57675
57745
  const assessments = await this.fetchAssessments(timebackId);
57676
57746
  await db2.transaction(async (tx) => {
@@ -57704,7 +57774,7 @@ var init_timeback_service = __esm(() => {
57704
57774
  }
57705
57775
  const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
57706
57776
  if (!updated) {
57707
- logger20.error("User Timeback ID update returned no rows", {
57777
+ logger21.error("User Timeback ID update returned no rows", {
57708
57778
  userId: user.id,
57709
57779
  timebackId
57710
57780
  });
@@ -57728,13 +57798,13 @@ var init_timeback_service = __esm(() => {
57728
57798
  }
57729
57799
  offset += limit;
57730
57800
  }
57731
- logger20.debug("Fetched assessments", {
57801
+ logger21.debug("Fetched assessments", {
57732
57802
  studentSourcedId,
57733
57803
  totalCount: allAssessments.length
57734
57804
  });
57735
57805
  return allAssessments;
57736
57806
  } catch (error) {
57737
- logger20.warn("Failed to fetch assessments", { studentSourcedId, error });
57807
+ logger21.warn("Failed to fetch assessments", { studentSourcedId, error });
57738
57808
  return [];
57739
57809
  }
57740
57810
  }
@@ -57847,7 +57917,7 @@ var init_timeback_service = __esm(() => {
57847
57917
  masterableUnits: derivedMasterableUnits
57848
57918
  } = courseConfig;
57849
57919
  if (!isTimebackSubject(subjectInput)) {
57850
- logger20.warn("Invalid Timeback subject in course config", {
57920
+ logger21.warn("Invalid Timeback subject in course config", {
57851
57921
  subject: subjectInput,
57852
57922
  courseCode,
57853
57923
  title
@@ -57855,7 +57925,7 @@ var init_timeback_service = __esm(() => {
57855
57925
  throw new ValidationError(`Invalid subject "${subjectInput}"`);
57856
57926
  }
57857
57927
  if (!isTimebackGrade(grade)) {
57858
- logger20.warn("Invalid Timeback grade in course config", {
57928
+ logger21.warn("Invalid Timeback grade in course config", {
57859
57929
  grade,
57860
57930
  courseCode,
57861
57931
  title
@@ -57867,7 +57937,7 @@ var init_timeback_service = __esm(() => {
57867
57937
  const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
57868
57938
  const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
57869
57939
  if (typeof totalXp !== "number") {
57870
- logger20.warn("Course missing totalXp in Timeback config", {
57940
+ logger21.warn("Course missing totalXp in Timeback config", {
57871
57941
  courseCode,
57872
57942
  title
57873
57943
  });
@@ -57883,7 +57953,9 @@ var init_timeback_service = __esm(() => {
57883
57953
  courseCode,
57884
57954
  level,
57885
57955
  gradingScheme: "STANDARD",
57886
- metadata: metadata2
57956
+ metadata: TimebackService2.patchCourseMetadata(metadata2, totalXp, {
57957
+ masterableUnits: masterableUnits ?? null
57958
+ })
57887
57959
  },
57888
57960
  component: {
57889
57961
  ...baseConfig.component,
@@ -57908,7 +57980,7 @@ var init_timeback_service = __esm(() => {
57908
57980
  const existingIntegration = existing.find((i2) => i2.grade === grade && i2.subject === subject);
57909
57981
  if (existingIntegration) {
57910
57982
  await client.update(existingIntegration.courseId, fullConfig);
57911
- const [updated] = await db2.update(gameTimebackIntegrations).set({ totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
57983
+ const [updated] = await db2.update(gameTimebackIntegrations).set({ subject, totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
57912
57984
  if (updated) {
57913
57985
  integrations.push(this.toGameTimebackIntegration(updated));
57914
57986
  }
@@ -57933,6 +58005,60 @@ var init_timeback_service = __esm(() => {
57933
58005
  });
57934
58006
  return rows.map((row) => this.toGameTimebackIntegration(row));
57935
58007
  }
58008
+ async getIntegrationConfig(gameId, courseId, user) {
58009
+ const client = this.requireClient();
58010
+ await this.deps.validateGameManagementAccess(user, gameId);
58011
+ const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
58012
+ where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
58013
+ });
58014
+ if (!integration) {
58015
+ throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
58016
+ }
58017
+ const config2 = await client.getConfig(courseId);
58018
+ return this.toGameTimebackIntegrationConfig(integration, config2);
58019
+ }
58020
+ async updateIntegration(gameId, courseId, user, patch) {
58021
+ const client = this.requireClient();
58022
+ await this.deps.validateDeveloperAccess(user, gameId);
58023
+ const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
58024
+ where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
58025
+ });
58026
+ if (!integration) {
58027
+ throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
58028
+ }
58029
+ const timebackConfig = await client.getConfig(courseId);
58030
+ const liveSubject = timebackConfig.course.subjects[0];
58031
+ const subject = patch.subject ?? (isTimebackSubject(liveSubject) ? liveSubject : integration.subject);
58032
+ if (!isTimebackSubject(subject)) {
58033
+ throw new ValidationError(`Invalid subject "${subject}"`);
58034
+ }
58035
+ if (subject !== integration.subject) {
58036
+ const subjectConflict = await this.deps.db.query.gameTimebackIntegrations.findFirst({
58037
+ where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.grade, integration.grade), eq(gameTimebackIntegrations.subject, subject))
58038
+ });
58039
+ if (subjectConflict && subjectConflict.id !== integration.id) {
58040
+ throw new ValidationError(`A TimeBack integration already exists for ${subject} Grade ${integration.grade}`);
58041
+ }
58042
+ }
58043
+ const totalXp = "totalXp" in patch ? patch.totalXp ?? null : TimebackService2.getTotalXpFromConfig(timebackConfig) ?? integration.totalXp ?? null;
58044
+ const masterableUnits = "masterableUnits" in patch ? patch.masterableUnits ?? null : TimebackService2.getMasterableUnitsFromConfig(timebackConfig);
58045
+ await client.update(courseId, TimebackService2.patchTimebackConfig(timebackConfig, {
58046
+ ...patch,
58047
+ subject,
58048
+ totalXp,
58049
+ masterableUnits,
58050
+ grade: integration.grade
58051
+ }));
58052
+ const [updated] = await this.deps.db.update(gameTimebackIntegrations).set({
58053
+ subject,
58054
+ totalXp,
58055
+ updatedAt: new Date
58056
+ }).where(eq(gameTimebackIntegrations.id, integration.id)).returning();
58057
+ if (!updated) {
58058
+ throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
58059
+ }
58060
+ return this.toGameTimebackIntegration(updated);
58061
+ }
57936
58062
  async verifyIntegration(gameId, user) {
57937
58063
  const client = this.requireClient();
57938
58064
  const db2 = this.deps.db;
@@ -57990,6 +58116,146 @@ var init_timeback_service = __esm(() => {
57990
58116
  }
57991
58117
  await db2.delete(gameTimebackIntegrations).where(eq(gameTimebackIntegrations.gameId, gameId));
57992
58118
  }
58119
+ static getMasterableUnitsFromConfig(config2) {
58120
+ const playcademyMetadata = config2.resource.metadata?.playcademy;
58121
+ if (!isPlaycademyResourceMetadata(playcademyMetadata)) {
58122
+ return null;
58123
+ }
58124
+ return playcademyMetadata?.mastery?.masterableUnits ?? null;
58125
+ }
58126
+ static getTotalXpFromConfig(config2) {
58127
+ const courseMetadata = isCourseMetadata(config2.course.metadata) ? config2.course.metadata : undefined;
58128
+ if (typeof courseMetadata?.metrics?.totalXp === "number") {
58129
+ return courseMetadata.metrics.totalXp;
58130
+ }
58131
+ const resourceMetadata = config2.resource.metadata;
58132
+ if (isRecord2(resourceMetadata) && typeof resourceMetadata.xp === "number") {
58133
+ return resourceMetadata.xp;
58134
+ }
58135
+ return null;
58136
+ }
58137
+ static patchCourseMetadata(metadata2, totalXp, options) {
58138
+ const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
58139
+ const currentMetrics = isRecord2(nextMetadata.metrics) ? nextMetadata.metrics : {};
58140
+ const metrics = { ...currentMetrics };
58141
+ if (totalXp === null) {
58142
+ delete metrics.totalXp;
58143
+ } else {
58144
+ metrics.totalXp = totalXp;
58145
+ }
58146
+ if (options?.masterableUnits !== undefined) {
58147
+ if (options.masterableUnits === null) {
58148
+ delete metrics.totalLessons;
58149
+ } else {
58150
+ metrics.totalLessons = options.masterableUnits;
58151
+ }
58152
+ }
58153
+ metrics.totalGrades = 1;
58154
+ if (Object.keys(metrics).length > 0) {
58155
+ nextMetadata.metrics = metrics;
58156
+ } else {
58157
+ delete nextMetadata.metrics;
58158
+ }
58159
+ const goals = options?.goals;
58160
+ if (goals !== undefined) {
58161
+ if (goals === null) {
58162
+ delete nextMetadata.goals;
58163
+ } else {
58164
+ const currentGoals = isRecord2(nextMetadata.goals) ? nextMetadata.goals : {};
58165
+ const nextGoals = { ...currentGoals };
58166
+ for (const [key, value] of Object.entries(goals)) {
58167
+ if (value === null) {
58168
+ delete nextGoals[key];
58169
+ } else if (value !== undefined) {
58170
+ nextGoals[key] = value;
58171
+ }
58172
+ }
58173
+ if (Object.keys(nextGoals).length > 0) {
58174
+ nextMetadata.goals = nextGoals;
58175
+ } else {
58176
+ delete nextMetadata.goals;
58177
+ }
58178
+ }
58179
+ }
58180
+ if (options?.publishStatus !== undefined) {
58181
+ if (options.publishStatus === null) {
58182
+ delete nextMetadata.publishStatus;
58183
+ const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
58184
+ delete alphaLearn.publishStatus;
58185
+ if (Object.keys(alphaLearn).length > 0) {
58186
+ nextMetadata.AlphaLearn = alphaLearn;
58187
+ } else {
58188
+ delete nextMetadata.AlphaLearn;
58189
+ }
58190
+ } else {
58191
+ nextMetadata.publishStatus = options.publishStatus;
58192
+ const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
58193
+ alphaLearn.publishStatus = options.publishStatus === "published" ? "active" : options.publishStatus;
58194
+ nextMetadata.AlphaLearn = alphaLearn;
58195
+ }
58196
+ }
58197
+ if (options?.isSupplemental !== undefined) {
58198
+ nextMetadata.isSupplemental = options.isSupplemental;
58199
+ }
58200
+ if (options?.timebackVisible !== undefined) {
58201
+ if (options.timebackVisible === null) {
58202
+ delete nextMetadata.timebackVisible;
58203
+ } else {
58204
+ nextMetadata.timebackVisible = options.timebackVisible;
58205
+ }
58206
+ }
58207
+ return Object.keys(nextMetadata).length > 0 ? nextMetadata : undefined;
58208
+ }
58209
+ static patchResourceMetadata(metadata2, options) {
58210
+ const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
58211
+ const playcademyMetadata = isRecord2(nextMetadata.playcademy) ? { ...nextMetadata.playcademy } : {};
58212
+ const masteryMetadata = isRecord2(playcademyMetadata.mastery) ? { ...playcademyMetadata.mastery } : {};
58213
+ nextMetadata.subject = options.subject;
58214
+ nextMetadata.grades = [options.grade];
58215
+ if (options.totalXp === null) {
58216
+ delete nextMetadata.xp;
58217
+ } else {
58218
+ nextMetadata.xp = options.totalXp;
58219
+ }
58220
+ if (options.masterableUnits === null) {
58221
+ delete masteryMetadata.masterableUnits;
58222
+ } else {
58223
+ masteryMetadata.masterableUnits = options.masterableUnits;
58224
+ }
58225
+ if (Object.keys(masteryMetadata).length > 0) {
58226
+ playcademyMetadata.mastery = masteryMetadata;
58227
+ } else {
58228
+ delete playcademyMetadata.mastery;
58229
+ }
58230
+ if (Object.keys(playcademyMetadata).length > 0) {
58231
+ nextMetadata.playcademy = playcademyMetadata;
58232
+ } else {
58233
+ delete nextMetadata.playcademy;
58234
+ }
58235
+ return nextMetadata;
58236
+ }
58237
+ static patchTimebackConfig(config2, patch) {
58238
+ return {
58239
+ ...config2,
58240
+ course: {
58241
+ ...config2.course,
58242
+ title: patch.title ?? config2.course.title,
58243
+ courseCode: patch.courseCode ?? config2.course.courseCode,
58244
+ subjects: [patch.subject],
58245
+ metadata: TimebackService2.patchCourseMetadata(config2.course.metadata, patch.totalXp, {
58246
+ masterableUnits: patch.masterableUnits,
58247
+ goals: patch.goals,
58248
+ publishStatus: patch.publishStatus,
58249
+ isSupplemental: patch.isSupplemental,
58250
+ timebackVisible: patch.timebackVisible
58251
+ })
58252
+ },
58253
+ resource: {
58254
+ ...config2.resource,
58255
+ metadata: TimebackService2.patchResourceMetadata(config2.resource.metadata, patch)
58256
+ }
58257
+ };
58258
+ }
57993
58259
  toGameTimebackIntegration(integration) {
57994
58260
  return {
57995
58261
  id: integration.id,
@@ -58003,6 +58269,21 @@ var init_timeback_service = __esm(() => {
58003
58269
  lastVerifiedAt: integration.lastVerifiedAt ?? null
58004
58270
  };
58005
58271
  }
58272
+ toGameTimebackIntegrationConfig(integration, config2) {
58273
+ const subject = config2.course.subjects[0] ?? integration.subject;
58274
+ if (!isTimebackSubject(subject)) {
58275
+ throw new ValidationError(`Invalid subject "${subject}"`);
58276
+ }
58277
+ return {
58278
+ integration: this.toGameTimebackIntegration(integration),
58279
+ title: config2.course.title,
58280
+ courseCode: config2.course.courseCode,
58281
+ subject,
58282
+ totalXp: TimebackService2.getTotalXpFromConfig(config2) ?? integration.totalXp ?? null,
58283
+ masterableUnits: TimebackService2.getMasterableUnitsFromConfig(config2),
58284
+ metadata: isCourseMetadata(config2.course.metadata) ? config2.course.metadata : null
58285
+ };
58286
+ }
58006
58287
  async endActivity({
58007
58288
  gameId,
58008
58289
  studentId,
@@ -58068,7 +58349,7 @@ var init_timeback_service = __esm(() => {
58068
58349
  ...runId ? { runId } : {}
58069
58350
  });
58070
58351
  }
58071
- logger20.info("Recorded activity completion", {
58352
+ logger21.info("Recorded activity completion", {
58072
58353
  gameId,
58073
58354
  courseId: integration.courseId,
58074
58355
  studentId,
@@ -58122,7 +58403,7 @@ var init_timeback_service = __esm(() => {
58122
58403
  masteredUnits: masteryStatus.masteredUnits,
58123
58404
  masterableUnits: masteryStatus.masterableUnits
58124
58405
  };
58125
- logger20.debug("Skipping course advancement because mastery is incomplete", {
58406
+ logger21.debug("Skipping course advancement because mastery is incomplete", {
58126
58407
  gameId,
58127
58408
  studentId,
58128
58409
  subject: currentIntegration.subject,
@@ -58140,7 +58421,7 @@ var init_timeback_service = __esm(() => {
58140
58421
  studentId,
58141
58422
  enrollments
58142
58423
  });
58143
- logger20.info("Manually advanced student", {
58424
+ logger21.info("Manually advanced student", {
58144
58425
  gameId,
58145
58426
  studentId,
58146
58427
  subject: currentIntegration.subject,
@@ -58173,7 +58454,7 @@ var init_timeback_service = __esm(() => {
58173
58454
  const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
58174
58455
  const effectiveResumeId = resumeId ?? runId;
58175
58456
  if (TimebackService2.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
58176
- logger20.debug("Skipping duplicate heartbeat window", {
58457
+ logger21.debug("Skipping duplicate heartbeat window", {
58177
58458
  gameId,
58178
58459
  studentId,
58179
58460
  runId,
@@ -58186,7 +58467,7 @@ var init_timeback_service = __esm(() => {
58186
58467
  await this.deps.validateDeveloperAccess(user, gameId);
58187
58468
  const inFlightHeartbeat = TimebackService2.getInFlightHeartbeatWindow(heartbeatWindowKey);
58188
58469
  if (inFlightHeartbeat) {
58189
- logger20.debug("Joining in-flight heartbeat window", {
58470
+ logger21.debug("Joining in-flight heartbeat window", {
58190
58471
  gameId,
58191
58472
  studentId,
58192
58473
  runId,
@@ -58223,7 +58504,7 @@ var init_timeback_service = __esm(() => {
58223
58504
  });
58224
58505
  }
58225
58506
  TimebackService2.markHeartbeatWindowProcessed(heartbeatWindowKey);
58226
- logger20.debug("Recorded heartbeat", {
58507
+ logger21.debug("Recorded heartbeat", {
58227
58508
  gameId,
58228
58509
  courseId: integration.courseId,
58229
58510
  studentId,
@@ -58258,7 +58539,7 @@ var init_timeback_service = __esm(() => {
58258
58539
  });
58259
58540
  courseIds = integrations.map((i2) => i2.courseId);
58260
58541
  if (courseIds.length === 0) {
58261
- logger20.debug("No integrations found for game, returning 0 XP", {
58542
+ logger21.debug("No integrations found for game, returning 0 XP", {
58262
58543
  timebackId,
58263
58544
  gameId: options.gameId,
58264
58545
  grade: options.grade,
@@ -58275,7 +58556,7 @@ var init_timeback_service = __esm(() => {
58275
58556
  courseIds: courseIds.length > 0 ? courseIds : undefined,
58276
58557
  include: options?.include
58277
58558
  });
58278
- logger20.debug("Retrieved student XP", {
58559
+ logger21.debug("Retrieved student XP", {
58279
58560
  timebackId,
58280
58561
  gameId: options?.gameId,
58281
58562
  grade: options?.grade,
@@ -58303,15 +58584,15 @@ class UploadService {
58303
58584
  const { fileName, gameId } = request;
58304
58585
  const bucketName = this.deps.uploadBucket;
58305
58586
  if (!bucketName) {
58306
- logger21.error("Upload bucket not configured in environment");
58587
+ logger22.error("Upload bucket not configured in environment");
58307
58588
  throw new ValidationError("Upload bucket not configured");
58308
58589
  }
58309
58590
  await this.deps.validateDeveloperAccess(user, gameId);
58310
58591
  const version2 = ulid();
58311
58592
  const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
58312
- logger21.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
58593
+ logger22.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
58313
58594
  const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
58314
- logger21.info("Presigned URL generated", {
58595
+ logger22.info("Presigned URL generated", {
58315
58596
  userId: user.id,
58316
58597
  gameId,
58317
58598
  version: version2
@@ -58324,12 +58605,12 @@ class UploadService {
58324
58605
  };
58325
58606
  }
58326
58607
  }
58327
- var logger21;
58608
+ var logger22;
58328
58609
  var init_upload_service = __esm(() => {
58329
58610
  init_node();
58330
58611
  init_src2();
58331
58612
  init_errors();
58332
- logger21 = log.scope("UploadService");
58613
+ logger22 = log.scope("UploadService");
58333
58614
  });
58334
58615
  function createPlatformServices(deps) {
58335
58616
  const {
@@ -58630,7 +58911,7 @@ class AchievementService {
58630
58911
  results.push(result);
58631
58912
  }
58632
58913
  }
58633
- logger22.debug("Listed current achievements", { userId: user.id, count: results.length });
58914
+ logger23.debug("Listed current achievements", { userId: user.id, count: results.length });
58634
58915
  return results;
58635
58916
  }
58636
58917
  async listHistory(user, limit) {
@@ -58648,14 +58929,14 @@ class AchievementService {
58648
58929
  createdAt: c.createdAt,
58649
58930
  scopeKey: c.scopeKey
58650
58931
  }));
58651
- logger22.debug("Listed achievement history", { userId: user.id, count: results.length });
58932
+ logger23.debug("Listed achievement history", { userId: user.id, count: results.length });
58652
58933
  return results;
58653
58934
  }
58654
58935
  async submitProgress(achievementId, user) {
58655
58936
  const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
58656
58937
  broadcast: false
58657
58938
  });
58658
- logger22.debug("Submitted progress", {
58939
+ logger23.debug("Submitted progress", {
58659
58940
  userId: user.id,
58660
58941
  achievementId,
58661
58942
  wasNewClaim
@@ -58687,7 +58968,7 @@ class AchievementService {
58687
58968
  rewardCredits
58688
58969
  }).returning();
58689
58970
  if (!newClaim) {
58690
- logger22.error("Achievement claim insert returned no rows", {
58971
+ logger23.error("Achievement claim insert returned no rows", {
58691
58972
  userId,
58692
58973
  achievementId,
58693
58974
  scopeKey
@@ -58696,7 +58977,7 @@ class AchievementService {
58696
58977
  }
58697
58978
  await this.deps.addCredits(userId, rewardCredits);
58698
58979
  await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
58699
- logger22.info("Awarded achievement", {
58980
+ logger23.info("Awarded achievement", {
58700
58981
  userId,
58701
58982
  achievementId,
58702
58983
  scopeKey,
@@ -58733,7 +59014,7 @@ class AchievementService {
58733
59014
  return { title, body: body2 };
58734
59015
  }
58735
59016
  }
58736
- var logger22;
59017
+ var logger23;
58737
59018
  var init_achievement_service = __esm(() => {
58738
59019
  init_drizzle_orm();
58739
59020
  init_tables_index();
@@ -58742,7 +59023,7 @@ var init_achievement_service = __esm(() => {
58742
59023
  init_errors();
58743
59024
  init_leaderboard_util();
58744
59025
  init_scope_util();
58745
- logger22 = log.scope("AchievementService");
59026
+ logger23 = log.scope("AchievementService");
58746
59027
  });
58747
59028
 
58748
59029
  class InventoryService {
@@ -58769,7 +59050,7 @@ class InventoryService {
58769
59050
  },
58770
59051
  updatedAt: inventoryItems.updatedAt
58771
59052
  }).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
58772
- logger23.debug("Listed inventory", { userId: user.id, count: inventory.length });
59053
+ logger24.debug("Listed inventory", { userId: user.id, count: inventory.length });
58773
59054
  return inventory;
58774
59055
  }
58775
59056
  async addItem(itemId, quantity, user) {
@@ -58786,7 +59067,7 @@ class InventoryService {
58786
59067
  const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
58787
59068
  return inserted?.quantity ?? 0;
58788
59069
  });
58789
- logger23.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
59070
+ logger24.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
58790
59071
  return { newTotal };
58791
59072
  }
58792
59073
  async removeItem(itemId, quantity, user) {
@@ -58797,7 +59078,7 @@ class InventoryService {
58797
59078
  }
58798
59079
  const [currentItem] = await tx.select({ id: inventoryItems.id, quantity: inventoryItems.quantity }).from(inventoryItems).where(and(eq(inventoryItems.userId, user.id), eq(inventoryItems.itemId, itemId), gte(inventoryItems.quantity, quantity))).limit(1);
58799
59080
  if (!currentItem) {
58800
- logger23.warn("Insufficient inventory for removal", {
59081
+ logger24.warn("Insufficient inventory for removal", {
58801
59082
  userId: user.id,
58802
59083
  itemId,
58803
59084
  requestedQuantity: quantity
@@ -58807,13 +59088,13 @@ class InventoryService {
58807
59088
  const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
58808
59089
  return updated?.quantity ?? 0;
58809
59090
  });
58810
- logger23.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
59091
+ logger24.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
58811
59092
  return { newTotal };
58812
59093
  }
58813
59094
  async addCredits(userId, amount) {
58814
59095
  const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
58815
59096
  if (!creditsItem) {
58816
- logger23.error("Primary currency not found", {
59097
+ logger24.error("Primary currency not found", {
58817
59098
  userId,
58818
59099
  amount
58819
59100
  });
@@ -58826,17 +59107,17 @@ class InventoryService {
58826
59107
  updatedAt: new Date
58827
59108
  }
58828
59109
  });
58829
- logger23.debug("Added credits", { userId, amount });
59110
+ logger24.debug("Added credits", { userId, amount });
58830
59111
  }
58831
59112
  }
58832
- var logger23;
59113
+ var logger24;
58833
59114
  var init_inventory_service = __esm(() => {
58834
59115
  init_drizzle_orm();
58835
59116
  init_src();
58836
59117
  init_tables_index();
58837
59118
  init_src2();
58838
59119
  init_errors();
58839
- logger23 = log.scope("InventoryService");
59120
+ logger24 = log.scope("InventoryService");
58840
59121
  });
58841
59122
 
58842
59123
  class LeaderboardService {
@@ -58867,7 +59148,7 @@ class LeaderboardService {
58867
59148
  sessionId
58868
59149
  }).returning();
58869
59150
  if (!newScore) {
58870
- logger24.error("Score insert returned no rows", { userId, gameId, score: input.score });
59151
+ logger25.error("Score insert returned no rows", { userId, gameId, score: input.score });
58871
59152
  throw new InternalError("Failed to insert score");
58872
59153
  }
58873
59154
  const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
@@ -58895,7 +59176,7 @@ class LeaderboardService {
58895
59176
  movedUpWithinTop3
58896
59177
  });
58897
59178
  }
58898
- logger24.info("Score submitted", {
59179
+ logger25.info("Score submitted", {
58899
59180
  gameId,
58900
59181
  userId,
58901
59182
  isAnonymousUser,
@@ -58972,7 +59253,7 @@ class LeaderboardService {
58972
59253
  });
58973
59254
  }
58974
59255
  } catch (error) {
58975
- logger24.warn("Failed to publish notification", { error });
59256
+ logger25.warn("Failed to publish notification", { error });
58976
59257
  }
58977
59258
  }
58978
59259
  async getLeaderboard(gameId, query, isAnonymousUser) {
@@ -59091,7 +59372,7 @@ class LeaderboardService {
59091
59372
  return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
59092
59373
  }
59093
59374
  }
59094
- var logger24;
59375
+ var logger25;
59095
59376
  var init_leaderboard_service = __esm(() => {
59096
59377
  init_drizzle_orm();
59097
59378
  init_src();
@@ -59101,7 +59382,7 @@ var init_leaderboard_service = __esm(() => {
59101
59382
  init_notification();
59102
59383
  init_errors();
59103
59384
  init_leaderboard_util();
59104
- logger24 = log.scope("LeaderboardService");
59385
+ logger25 = log.scope("LeaderboardService");
59105
59386
  });
59106
59387
 
59107
59388
  class LevelService {
@@ -59116,9 +59397,9 @@ class LevelService {
59116
59397
  for (const config2 of configs) {
59117
59398
  levelConfigCache.set(config2.level, config2);
59118
59399
  }
59119
- logger25.info("Cache pre-warmed", { count: configs.length });
59400
+ logger26.info("Cache pre-warmed", { count: configs.length });
59120
59401
  } catch (error) {
59121
- logger25.error("Cache pre-warm failed", { error });
59402
+ logger26.error("Cache pre-warm failed", { error });
59122
59403
  }
59123
59404
  }
59124
59405
  async getConfig(level) {
@@ -59152,7 +59433,7 @@ class LevelService {
59152
59433
  totalXP
59153
59434
  }).returning();
59154
59435
  if (!newUserLevel) {
59155
- logger25.error("User level insert returned no rows", { userId: user.id });
59436
+ logger26.error("User level insert returned no rows", { userId: user.id });
59156
59437
  throw new InternalError("Failed to create user level cache record");
59157
59438
  }
59158
59439
  userLevel = newUserLevel;
@@ -59167,7 +59448,7 @@ class LevelService {
59167
59448
  userLevel = updatedUserLevel;
59168
59449
  }
59169
59450
  }
59170
- logger25.debug("Retrieved user level", {
59451
+ logger26.debug("Retrieved user level", {
59171
59452
  userId: user.id,
59172
59453
  totalXP,
59173
59454
  currentLevel,
@@ -59178,7 +59459,7 @@ class LevelService {
59178
59459
  async getProgress(user) {
59179
59460
  const userLevel = await this.getByUser(user);
59180
59461
  const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
59181
- logger25.debug("Retrieved progress", { userId: user.id });
59462
+ logger26.debug("Retrieved progress", { userId: user.id });
59182
59463
  return {
59183
59464
  level: userLevel.currentLevel,
59184
59465
  currentXp: userLevel.currentXp,
@@ -59212,7 +59493,7 @@ class LevelService {
59212
59493
  if (leveledUp && previousUserLevel) {
59213
59494
  await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
59214
59495
  }
59215
- logger25.info("Synced from Timeback", {
59496
+ logger26.info("Synced from Timeback", {
59216
59497
  userId,
59217
59498
  totalXP,
59218
59499
  currentLevel,
@@ -59253,7 +59534,7 @@ class LevelService {
59253
59534
  }
59254
59535
  if (totalCredits > 0) {
59255
59536
  await this.deps.addCredits(userId, totalCredits);
59256
- logger25.info("Awarded level-up credits", {
59537
+ logger26.info("Awarded level-up credits", {
59257
59538
  userId,
59258
59539
  fromLevel,
59259
59540
  toLevel,
@@ -59291,7 +59572,7 @@ class LevelService {
59291
59572
  };
59292
59573
  }
59293
59574
  }
59294
- var logger25;
59575
+ var logger26;
59295
59576
  var levelConfigCache = null;
59296
59577
  var init_level_service = __esm(() => {
59297
59578
  init_drizzle_orm();
@@ -59299,7 +59580,7 @@ var init_level_service = __esm(() => {
59299
59580
  init_tables_index();
59300
59581
  init_src2();
59301
59582
  init_errors();
59302
- logger25 = log.scope("LevelService");
59583
+ logger26 = log.scope("LevelService");
59303
59584
  });
59304
59585
  var init_events = () => {};
59305
59586
  function convertWebSocketUrlToHttp(wsUrl) {
@@ -59316,13 +59597,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
59316
59597
  });
59317
59598
  if (!res.ok) {
59318
59599
  const text3 = await res.text().catch(() => "");
59319
- logger26.warn("Failed to publish to user", {
59600
+ logger27.warn("Failed to publish to user", {
59320
59601
  status: res.status,
59321
59602
  body: text3
59322
59603
  });
59323
59604
  }
59324
59605
  } catch (error) {
59325
- logger26.error("Publish to user error", { error });
59606
+ logger27.error("Publish to user error", { error });
59326
59607
  }
59327
59608
  }
59328
59609
 
@@ -59344,7 +59625,7 @@ class NotificationService {
59344
59625
  conditions2.push(eq(notifications.type, type));
59345
59626
  }
59346
59627
  const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
59347
- logger26.debug("Listed notifications", { userId: user.id, count: results.length });
59628
+ logger27.debug("Listed notifications", { userId: user.id, count: results.length });
59348
59629
  return results;
59349
59630
  }
59350
59631
  async updateStatus(notificationId, status, method) {
@@ -59363,7 +59644,7 @@ class NotificationService {
59363
59644
  if (!updated) {
59364
59645
  throw new NotFoundError("Notification", notificationId);
59365
59646
  }
59366
- logger26.debug("Updated status", { notificationId, status });
59647
+ logger27.debug("Updated status", { notificationId, status });
59367
59648
  return updated;
59368
59649
  }
59369
59650
  async getStats(user, options) {
@@ -59389,7 +59670,7 @@ class NotificationService {
59389
59670
  const clicked = statsMap.clicked || 0;
59390
59671
  const dismissed = statsMap.dismissed || 0;
59391
59672
  const expired = statsMap.expired || 0;
59392
- logger26.debug("Retrieved stats", { userId: user.id, total });
59673
+ logger27.debug("Retrieved stats", { userId: user.id, total });
59393
59674
  return {
59394
59675
  total,
59395
59676
  delivered,
@@ -59438,7 +59719,7 @@ class NotificationService {
59438
59719
  options: { data, clickUrl, metadata: metadata2 }
59439
59720
  });
59440
59721
  }
59441
- logger26.debug("Created notification", {
59722
+ logger27.debug("Created notification", {
59442
59723
  userId,
59443
59724
  type,
59444
59725
  id: notificationId,
@@ -59446,7 +59727,7 @@ class NotificationService {
59446
59727
  });
59447
59728
  return notificationId;
59448
59729
  } catch (error) {
59449
- logger26.error("Failed to create notification", { userId, type, error });
59730
+ logger27.error("Failed to create notification", { userId, type, error });
59450
59731
  return null;
59451
59732
  }
59452
59733
  }
@@ -59460,7 +59741,7 @@ class NotificationService {
59460
59741
  }) {
59461
59742
  const realtimeConfig = this.deps.realtime;
59462
59743
  if (!realtimeConfig) {
59463
- logger26.warn("No realtime config for publish");
59744
+ logger27.warn("No realtime config for publish");
59464
59745
  return;
59465
59746
  }
59466
59747
  const { relayUrl, publishSecret } = realtimeConfig;
@@ -59502,13 +59783,13 @@ class NotificationService {
59502
59783
  metadata: data.metadata || {}
59503
59784
  }).returning();
59504
59785
  if (!notification) {
59505
- logger26.error("Notification insert returned no rows", {
59786
+ logger27.error("Notification insert returned no rows", {
59506
59787
  userId: data.userId,
59507
59788
  type: data.type
59508
59789
  });
59509
59790
  throw new InternalError("Failed to create notification");
59510
59791
  }
59511
- logger26.info("Inserted notification", {
59792
+ logger27.info("Inserted notification", {
59512
59793
  notificationId: notification.id,
59513
59794
  userId: notification.userId,
59514
59795
  type: notification.type
@@ -59518,7 +59799,7 @@ class NotificationService {
59518
59799
  async deliverPending(userId) {
59519
59800
  const realtimeConfig = this.deps.realtime;
59520
59801
  if (!realtimeConfig) {
59521
- logger26.warn("No realtime config for delivery");
59802
+ logger27.warn("No realtime config for delivery");
59522
59803
  return;
59523
59804
  }
59524
59805
  const { relayUrl, publishSecret } = realtimeConfig;
@@ -59545,13 +59826,13 @@ class NotificationService {
59545
59826
  metadata: notification.metadata,
59546
59827
  clickUrl: notification.clickUrl
59547
59828
  });
59548
- logger26.info("Delivered notification", {
59829
+ logger27.info("Delivered notification", {
59549
59830
  notificationId: notification.id,
59550
59831
  userId,
59551
59832
  type: notification.type
59552
59833
  });
59553
59834
  } catch (error) {
59554
- logger26.warn("Failed to deliver", {
59835
+ logger27.warn("Failed to deliver", {
59555
59836
  notificationId: notification.id,
59556
59837
  error
59557
59838
  });
@@ -59559,7 +59840,7 @@ class NotificationService {
59559
59840
  }
59560
59841
  }
59561
59842
  }
59562
- var logger26;
59843
+ var logger27;
59563
59844
  var init_notification_service = __esm(() => {
59564
59845
  init_drizzle_orm();
59565
59846
  init_src();
@@ -59568,7 +59849,7 @@ var init_notification_service = __esm(() => {
59568
59849
  init_events();
59569
59850
  init_notification();
59570
59851
  init_errors();
59571
- logger26 = log.scope("NotificationService");
59852
+ logger27 = log.scope("NotificationService");
59572
59853
  });
59573
59854
  function createPlayerServices(deps) {
59574
59855
  const { db: db2, realtime } = deps;
@@ -59687,7 +59968,7 @@ class CharacterService {
59687
59968
  createdAt: characterComponents.createdAt,
59688
59969
  updatedAt: characterComponents.updatedAt
59689
59970
  }).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
59690
- logger27.debug("Listed available components", {
59971
+ logger28.debug("Listed available components", {
59691
59972
  level,
59692
59973
  count: components.length
59693
59974
  });
@@ -59705,7 +59986,7 @@ class CharacterService {
59705
59986
  }
59706
59987
  }
59707
59988
  });
59708
- logger27.debug("Retrieved character", { userId: user.id, found: Boolean(pc3) });
59989
+ logger28.debug("Retrieved character", { userId: user.id, found: Boolean(pc3) });
59709
59990
  return pc3 ?? null;
59710
59991
  }
59711
59992
  async getByUserId(userId) {
@@ -59720,7 +60001,7 @@ class CharacterService {
59720
60001
  }
59721
60002
  }
59722
60003
  });
59723
- logger27.debug("Retrieved character by ID", { userId, found: Boolean(pc3) });
60004
+ logger28.debug("Retrieved character by ID", { userId, found: Boolean(pc3) });
59724
60005
  return pc3 ?? null;
59725
60006
  }
59726
60007
  async create(input, user) {
@@ -59735,13 +60016,13 @@ class CharacterService {
59735
60016
  }
59736
60017
  const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
59737
60018
  if (!characterRow) {
59738
- logger27.error("Character insert returned no rows", { userId: user.id });
60019
+ logger28.error("Character insert returned no rows", { userId: user.id });
59739
60020
  throw new InternalError("Failed to create character in database");
59740
60021
  }
59741
60022
  await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
59742
60023
  return characterRow;
59743
60024
  });
59744
- logger27.info("Created character", { userId: user.id, characterId: result.id });
60025
+ logger28.info("Created character", { userId: user.id, characterId: result.id });
59745
60026
  return result;
59746
60027
  }
59747
60028
  async update(input, user) {
@@ -59753,7 +60034,7 @@ class CharacterService {
59753
60034
  if (!row) {
59754
60035
  throw new NotFoundError("Player character");
59755
60036
  }
59756
- logger27.info("Updated character", {
60037
+ logger28.info("Updated character", {
59757
60038
  userId: user.id,
59758
60039
  characterId: row.id,
59759
60040
  updatedFields: Object.keys(input)
@@ -59775,7 +60056,7 @@ class CharacterService {
59775
60056
  const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
59776
60057
  const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
59777
60058
  if (!validation.isValid) {
59778
- logger27.warn("Accessory validation failed", {
60059
+ logger28.warn("Accessory validation failed", {
59779
60060
  userId: user.id,
59780
60061
  slot,
59781
60062
  accessoryComponentId,
@@ -59791,14 +60072,14 @@ class CharacterService {
59791
60072
  slot
59792
60073
  }).returning();
59793
60074
  if (!result) {
59794
- logger27.error("Accessory insert returned no rows", {
60075
+ logger28.error("Accessory insert returned no rows", {
59795
60076
  userId: user.id,
59796
60077
  slot,
59797
60078
  accessoryComponentId
59798
60079
  });
59799
60080
  throw new InternalError("Failed to equip accessory");
59800
60081
  }
59801
- logger27.info("Equipped accessory", {
60082
+ logger28.info("Equipped accessory", {
59802
60083
  userId: user.id,
59803
60084
  slot,
59804
60085
  accessoryComponentId
@@ -59819,7 +60100,7 @@ class CharacterService {
59819
60100
  const playerLevel = userLevel?.currentLevel ?? 1;
59820
60101
  const validation = validateAccessoryRemoval(slot, playerLevel);
59821
60102
  if (!validation.isValid) {
59822
- logger27.warn("Accessory removal validation failed", {
60103
+ logger28.warn("Accessory removal validation failed", {
59823
60104
  userId: user.id,
59824
60105
  slot,
59825
60106
  playerLevel,
@@ -59828,17 +60109,17 @@ class CharacterService {
59828
60109
  throw new ValidationError(validation.error ?? "Invalid accessory removal");
59829
60110
  }
59830
60111
  await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
59831
- logger27.info("Removed accessory", { userId: user.id, slot });
60112
+ logger28.info("Removed accessory", { userId: user.id, slot });
59832
60113
  }
59833
60114
  }
59834
- var logger27;
60115
+ var logger28;
59835
60116
  var init_character_service = __esm(() => {
59836
60117
  init_drizzle_orm();
59837
60118
  init_tables_index();
59838
60119
  init_src2();
59839
60120
  init_errors();
59840
60121
  init_accessory_util();
59841
- logger27 = log.scope("CharacterService");
60122
+ logger28 = log.scope("CharacterService");
59842
60123
  });
59843
60124
 
59844
60125
  class CurrencyService {
@@ -59849,7 +60130,7 @@ class CurrencyService {
59849
60130
  async list() {
59850
60131
  const db2 = this.deps.db;
59851
60132
  const allCurrencies = await db2.query.currencies.findMany();
59852
- logger28.debug("Listed currencies", { count: allCurrencies.length });
60133
+ logger29.debug("Listed currencies", { count: allCurrencies.length });
59853
60134
  return allCurrencies;
59854
60135
  }
59855
60136
  async getById(currencyId) {
@@ -59860,7 +60141,7 @@ class CurrencyService {
59860
60141
  if (!currency) {
59861
60142
  throw new NotFoundError("Currency", currencyId);
59862
60143
  }
59863
- logger28.debug("Retrieved currency", { currencyId });
60144
+ logger29.debug("Retrieved currency", { currencyId });
59864
60145
  return currency;
59865
60146
  }
59866
60147
  async create(data) {
@@ -59868,13 +60149,13 @@ class CurrencyService {
59868
60149
  try {
59869
60150
  const [newCurrency] = await db2.insert(currencies).values(data).returning();
59870
60151
  if (!newCurrency) {
59871
- logger28.error("Currency insert returned no rows", {
60152
+ logger29.error("Currency insert returned no rows", {
59872
60153
  itemId: data.itemId,
59873
60154
  symbol: data.symbol
59874
60155
  });
59875
60156
  throw new InternalError("Failed to create currency");
59876
60157
  }
59877
- logger28.info("Created currency", {
60158
+ logger29.info("Created currency", {
59878
60159
  currencyId: newCurrency.id,
59879
60160
  itemId: newCurrency.itemId,
59880
60161
  symbol: newCurrency.symbol,
@@ -59903,7 +60184,7 @@ class CurrencyService {
59903
60184
  if (!updatedCurrency) {
59904
60185
  throw new NotFoundError("Currency", currencyId);
59905
60186
  }
59906
- logger28.info("Updated currency", {
60187
+ logger29.info("Updated currency", {
59907
60188
  currencyId: updatedCurrency.id,
59908
60189
  updatedFields: Object.keys(data)
59909
60190
  });
@@ -59929,16 +60210,16 @@ class CurrencyService {
59929
60210
  if (result.length === 0) {
59930
60211
  throw new NotFoundError("Currency", currencyId);
59931
60212
  }
59932
- logger28.info("Deleted currency", { currencyId });
60213
+ logger29.info("Deleted currency", { currencyId });
59933
60214
  }
59934
60215
  }
59935
- var logger28;
60216
+ var logger29;
59936
60217
  var init_currency_service = __esm(() => {
59937
60218
  init_drizzle_orm();
59938
60219
  init_tables_index();
59939
60220
  init_src2();
59940
60221
  init_errors();
59941
- logger28 = log.scope("CurrencyService");
60222
+ logger29 = log.scope("CurrencyService");
59942
60223
  });
59943
60224
 
59944
60225
  class LogsService {
@@ -59956,11 +60237,11 @@ class LogsService {
59956
60237
  if (!game) {
59957
60238
  throw new NotFoundError("Game", slug2);
59958
60239
  }
59959
- logger29.info("Admin accessing game logs", { adminId: user.id, slug: slug2, sstStage });
60240
+ logger30.info("Admin accessing game logs", { adminId: user.id, slug: slug2, sstStage });
59960
60241
  } else {
59961
60242
  const isApprovedDev = user.developerStatus === "approved";
59962
60243
  if (!isApprovedDev) {
59963
- logger29.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
60244
+ logger30.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
59964
60245
  throw new AccessDeniedError("Must be an approved developer");
59965
60246
  }
59966
60247
  const game = await db2.query.games.findFirst({
@@ -59975,7 +60256,7 @@ class LogsService {
59975
60256
  columns: { id: true }
59976
60257
  });
59977
60258
  if (!membership) {
59978
- logger29.warn("Developer attempted access to unowned game logs", {
60259
+ logger30.warn("Developer attempted access to unowned game logs", {
59979
60260
  userId: user.id,
59980
60261
  slug: slug2
59981
60262
  });
@@ -59984,7 +60265,7 @@ class LogsService {
59984
60265
  }
59985
60266
  const workerId = getDeploymentId(slug2, sstStage);
59986
60267
  const token = await this.deps.mintLogStreamToken(user.id, workerId);
59987
- logger29.debug("Generated log stream token", {
60268
+ logger30.debug("Generated log stream token", {
59988
60269
  userId: user.id,
59989
60270
  slug: slug2,
59990
60271
  workerId
@@ -59992,14 +60273,14 @@ class LogsService {
59992
60273
  return { token, workerId };
59993
60274
  }
59994
60275
  }
59995
- var logger29;
60276
+ var logger30;
59996
60277
  var init_logs_service = __esm(() => {
59997
60278
  init_drizzle_orm();
59998
60279
  init_tables_index();
59999
60280
  init_src2();
60000
60281
  init_errors();
60001
60282
  init_deployment_util();
60002
- logger29 = log.scope("LogsService");
60283
+ logger30 = log.scope("LogsService");
60003
60284
  });
60004
60285
 
60005
60286
  class LtiService {
@@ -60050,7 +60331,7 @@ class MapService {
60050
60331
  if (!mapDetails) {
60051
60332
  throw new NotFoundError("Map", identifier);
60052
60333
  }
60053
- logger30.debug("Retrieved map", { identifier });
60334
+ logger31.debug("Retrieved map", { identifier });
60054
60335
  return mapDetails;
60055
60336
  }
60056
60337
  async getElements(mapId) {
@@ -60066,7 +60347,7 @@ class MapService {
60066
60347
  }
60067
60348
  }
60068
60349
  });
60069
- logger30.debug("Retrieved elements", { mapId, count: elements.length });
60350
+ logger31.debug("Retrieved elements", { mapId, count: elements.length });
60070
60351
  return elements;
60071
60352
  }
60072
60353
  async getObjects(mapId, userId) {
@@ -60087,7 +60368,7 @@ class MapService {
60087
60368
  }
60088
60369
  }
60089
60370
  });
60090
- logger30.debug("Retrieved objects", { mapId, userId, count: objects.length });
60371
+ logger31.debug("Retrieved objects", { mapId, userId, count: objects.length });
60091
60372
  return objects.map((object) => this.formatMapObjectWithItem(object));
60092
60373
  }
60093
60374
  async createObject(mapId, data, user) {
@@ -60114,7 +60395,7 @@ class MapService {
60114
60395
  throw new NotFoundError("Item", data.itemId);
60115
60396
  }
60116
60397
  if (!item.isPlaceable) {
60117
- logger30.warn("Attempted to place non-placeable item", {
60398
+ logger31.warn("Attempted to place non-placeable item", {
60118
60399
  userId: user.id,
60119
60400
  itemId: data.itemId,
60120
60401
  mapId
@@ -60128,7 +60409,7 @@ class MapService {
60128
60409
  };
60129
60410
  const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
60130
60411
  if (!createdObject) {
60131
- logger30.error("Map object insert returned no rows", {
60412
+ logger31.error("Map object insert returned no rows", {
60132
60413
  userId: user.id,
60133
60414
  mapId,
60134
60415
  itemId: data.itemId
@@ -60152,12 +60433,12 @@ class MapService {
60152
60433
  }
60153
60434
  });
60154
60435
  if (!objectWithItem) {
60155
- logger30.error("Map object query after insert returned no rows", {
60436
+ logger31.error("Map object query after insert returned no rows", {
60156
60437
  objectId: createdObject.id
60157
60438
  });
60158
60439
  throw new InternalError("Failed to retrieve created object");
60159
60440
  }
60160
- logger30.info("Created object", {
60441
+ logger31.info("Created object", {
60161
60442
  userId: user.id,
60162
60443
  mapId,
60163
60444
  objectId: createdObject.id,
@@ -60181,7 +60462,7 @@ class MapService {
60181
60462
  if (result.length === 0) {
60182
60463
  throw new NotFoundError("MapObject", objectId);
60183
60464
  }
60184
- logger30.info("Deleted object", {
60465
+ logger31.info("Deleted object", {
60185
60466
  userId: user.id,
60186
60467
  mapId,
60187
60468
  objectId
@@ -60210,13 +60491,13 @@ class MapService {
60210
60491
  };
60211
60492
  }
60212
60493
  }
60213
- var logger30;
60494
+ var logger31;
60214
60495
  var init_map_service = __esm(() => {
60215
60496
  init_drizzle_orm();
60216
60497
  init_tables_index();
60217
60498
  init_src2();
60218
60499
  init_errors();
60219
- logger30 = log.scope("MapService");
60500
+ logger31 = log.scope("MapService");
60220
60501
  });
60221
60502
 
60222
60503
  class RealtimeService {
@@ -60250,20 +60531,20 @@ class RealtimeService {
60250
60531
  }
60251
60532
  const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
60252
60533
  const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
60253
- logger31.info("Generated token", {
60534
+ logger32.info("Generated token", {
60254
60535
  userId: user.id,
60255
60536
  gameId: resolvedGameId || "global"
60256
60537
  });
60257
60538
  return { token };
60258
60539
  }
60259
60540
  }
60260
- var logger31;
60541
+ var logger32;
60261
60542
  var init_realtime_service = __esm(() => {
60262
60543
  init_drizzle_orm();
60263
60544
  init_tables_index();
60264
60545
  init_src2();
60265
60546
  init_errors();
60266
- logger31 = log.scope("RealtimeService");
60547
+ logger32 = log.scope("RealtimeService");
60267
60548
  });
60268
60549
 
60269
60550
  class SessionService {
@@ -60297,10 +60578,10 @@ class SessionService {
60297
60578
  };
60298
60579
  const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
60299
60580
  if (!newSession?.sessionId) {
60300
- logger32.error("Game session insert returned no rows", { userId, gameId });
60581
+ logger33.error("Game session insert returned no rows", { userId, gameId });
60301
60582
  throw new InternalError("Failed to create game session");
60302
60583
  }
60303
- logger32.info("Started new session", {
60584
+ logger33.info("Started new session", {
60304
60585
  sessionId: newSession.sessionId,
60305
60586
  gameId,
60306
60587
  userId
@@ -60321,23 +60602,23 @@ class SessionService {
60321
60602
  return { success: true, message: "Session already ended" };
60322
60603
  }
60323
60604
  await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
60324
- logger32.info("Ended session", { sessionId, gameId, userId });
60605
+ logger33.info("Ended session", { sessionId, gameId, userId });
60325
60606
  return { success: true };
60326
60607
  }
60327
60608
  async mintToken(gameIdOrSlug, userId) {
60328
60609
  const gameId = await this.resolveGameId(gameIdOrSlug);
60329
60610
  const result = await this.deps.mintGameToken(gameId, userId);
60330
- logger32.debug("Minted game token", { gameId, userId });
60611
+ logger33.debug("Minted game token", { gameId, userId });
60331
60612
  return result;
60332
60613
  }
60333
60614
  }
60334
- var logger32;
60615
+ var logger33;
60335
60616
  var init_session_service = __esm(() => {
60336
60617
  init_drizzle_orm();
60337
60618
  init_tables_index();
60338
60619
  init_src2();
60339
60620
  init_errors();
60340
- logger32 = log.scope("SessionService");
60621
+ logger33 = log.scope("SessionService");
60341
60622
  });
60342
60623
 
60343
60624
  class ShopService {
@@ -60382,7 +60663,7 @@ class ShopService {
60382
60663
  const shopItems = [];
60383
60664
  for (const listing of listingsWithRelations) {
60384
60665
  if (!listing.item || !listing.currency) {
60385
- logger33.warn("Listing missing item or currency, skipping", {
60666
+ logger34.warn("Listing missing item or currency, skipping", {
60386
60667
  listingId: listing.id
60387
60668
  });
60388
60669
  } else {
@@ -60399,7 +60680,7 @@ class ShopService {
60399
60680
  });
60400
60681
  }
60401
60682
  }
60402
- logger33.debug("Retrieved shop view", {
60683
+ logger34.debug("Retrieved shop view", {
60403
60684
  userId: user.id,
60404
60685
  itemCount: shopItems.length,
60405
60686
  currencyCount: shopCurrencies.length
@@ -60410,12 +60691,12 @@ class ShopService {
60410
60691
  };
60411
60692
  }
60412
60693
  }
60413
- var logger33;
60694
+ var logger34;
60414
60695
  var init_shop_service = __esm(() => {
60415
60696
  init_drizzle_orm();
60416
60697
  init_tables_index();
60417
60698
  init_src2();
60418
- logger33 = log.scope("ShopService");
60699
+ logger34 = log.scope("ShopService");
60419
60700
  });
60420
60701
 
60421
60702
  class SpriteService {
@@ -60431,17 +60712,17 @@ class SpriteService {
60431
60712
  if (!template) {
60432
60713
  throw new NotFoundError("SpriteTemplate", slug2);
60433
60714
  }
60434
- logger34.debug("Retrieved sprite", { slug: slug2 });
60715
+ logger35.debug("Retrieved sprite", { slug: slug2 });
60435
60716
  return template;
60436
60717
  }
60437
60718
  }
60438
- var logger34;
60719
+ var logger35;
60439
60720
  var init_sprite_service = __esm(() => {
60440
60721
  init_drizzle_orm();
60441
60722
  init_tables_index();
60442
60723
  init_src2();
60443
60724
  init_errors();
60444
- logger34 = log.scope("SpriteService");
60725
+ logger35 = log.scope("SpriteService");
60445
60726
  });
60446
60727
 
60447
60728
  class UserService {
@@ -60455,12 +60736,12 @@ class UserService {
60455
60736
  where: eq(users.id, user.id)
60456
60737
  });
60457
60738
  if (!userData) {
60458
- logger35.error("User not found", { userId: user.id });
60739
+ logger36.error("User not found", { userId: user.id });
60459
60740
  throw new NotFoundError("User", user.id);
60460
60741
  }
60461
60742
  const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
60462
60743
  if (gameId) {
60463
- logger35.debug("Fetched user profile (game context)", { userId: user.id, gameId });
60744
+ logger36.debug("Fetched user profile (game context)", { userId: user.id, gameId });
60464
60745
  return {
60465
60746
  id: userData.id,
60466
60747
  name: userData.name,
@@ -60473,7 +60754,7 @@ class UserService {
60473
60754
  const timebackAccount = await db2.query.accounts.findFirst({
60474
60755
  where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
60475
60756
  });
60476
- logger35.debug("Fetched user profile (platform context)", { userId: user.id });
60757
+ logger36.debug("Fetched user profile (platform context)", { userId: user.id });
60477
60758
  return {
60478
60759
  id: userData.id,
60479
60760
  name: userData.name,
@@ -60496,7 +60777,7 @@ class UserService {
60496
60777
  columns: { name: true }
60497
60778
  });
60498
60779
  if (!userData) {
60499
- logger35.error("Demo user not found", { userId });
60780
+ logger36.error("Demo user not found", { userId });
60500
60781
  throw new NotFoundError("User", userId);
60501
60782
  }
60502
60783
  return {
@@ -60510,10 +60791,10 @@ class UserService {
60510
60791
  updatedAt: new Date
60511
60792
  }).where(eq(users.id, userId)).returning({ name: users.name });
60512
60793
  if (!updatedUser) {
60513
- logger35.error("Demo user not found for profile update", { userId });
60794
+ logger36.error("Demo user not found for profile update", { userId });
60514
60795
  throw new NotFoundError("User", userId);
60515
60796
  }
60516
- logger35.debug("Updated demo profile", { userId, displayName });
60797
+ logger36.debug("Updated demo profile", { userId, displayName });
60517
60798
  return {
60518
60799
  displayName: updatedUser.name,
60519
60800
  isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
@@ -60526,7 +60807,7 @@ class UserService {
60526
60807
  ]);
60527
60808
  const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
60528
60809
  const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
60529
- logger35.debug("Fetched Timeback data", {
60810
+ logger36.debug("Fetched Timeback data", {
60530
60811
  timebackId,
60531
60812
  role,
60532
60813
  enrollmentCount: enrollments.length,
@@ -60535,9 +60816,9 @@ class UserService {
60535
60816
  return { id: timebackId, role, enrollments, organizations };
60536
60817
  }
60537
60818
  async fetchStudentProfile(timebackId) {
60538
- logger35.debug("Fetching student profile", { timebackId });
60819
+ logger36.debug("Fetching student profile", { timebackId });
60539
60820
  if (!this.deps.timeback) {
60540
- logger35.warn("Timeback client not available");
60821
+ logger36.warn("Timeback client not available");
60541
60822
  return { role: "student", organizations: [] };
60542
60823
  }
60543
60824
  try {
@@ -60565,14 +60846,14 @@ class UserService {
60565
60846
  }
60566
60847
  return { role, organizations: [...orgMap.values()] };
60567
60848
  } catch (error) {
60568
- logger35.warn("Failed to fetch student profile", { error, timebackId });
60849
+ logger36.warn("Failed to fetch student profile", { error, timebackId });
60569
60850
  return { role: "student", organizations: [] };
60570
60851
  }
60571
60852
  }
60572
60853
  async fetchEnrollments(timebackId) {
60573
- logger35.debug("Fetching enrollments", { timebackId });
60854
+ logger36.debug("Fetching enrollments", { timebackId });
60574
60855
  if (!this.deps.timeback) {
60575
- logger35.warn("Timeback client not available");
60856
+ logger36.warn("Timeback client not available");
60576
60857
  return [];
60577
60858
  }
60578
60859
  try {
@@ -60593,7 +60874,7 @@ class UserService {
60593
60874
  orgId: courseToSchool.get(i2.courseId)
60594
60875
  }));
60595
60876
  } catch (error) {
60596
- logger35.warn("Failed to fetch enrollments", { error, timebackId });
60877
+ logger36.warn("Failed to fetch enrollments", { error, timebackId });
60597
60878
  return [];
60598
60879
  }
60599
60880
  }
@@ -60608,14 +60889,14 @@ class UserService {
60608
60889
  return organizations.filter((o) => enrollmentOrgIds.has(o.id));
60609
60890
  }
60610
60891
  }
60611
- var logger35;
60892
+ var logger36;
60612
60893
  var init_user_service = __esm(() => {
60613
60894
  init_drizzle_orm();
60614
60895
  init_src();
60615
60896
  init_tables_index();
60616
60897
  init_src2();
60617
60898
  init_errors();
60618
- logger35 = log.scope("UserService");
60899
+ logger36 = log.scope("UserService");
60619
60900
  });
60620
60901
 
60621
60902
  class VerifyService {
@@ -60624,16 +60905,16 @@ class VerifyService {
60624
60905
  this.deps = deps;
60625
60906
  }
60626
60907
  async verifyGameToken(token) {
60627
- logger36.debug("Verifying game token");
60908
+ logger37.debug("Verifying game token");
60628
60909
  const payload = await this.deps.validateGameToken(token);
60629
60910
  if (!payload) {
60630
- logger36.warn("Invalid or expired game token presented");
60911
+ logger37.warn("Invalid or expired game token presented");
60631
60912
  throw new ValidationError("Invalid or expired token");
60632
60913
  }
60633
60914
  const gameId = payload.sub;
60634
60915
  const userId = payload.uid;
60635
60916
  if (typeof gameId !== "string" || typeof userId !== "string") {
60636
- logger36.warn("Game token missing required claims", {
60917
+ logger37.warn("Game token missing required claims", {
60637
60918
  hasGameId: typeof gameId === "string",
60638
60919
  hasUserId: typeof userId === "string"
60639
60920
  });
@@ -60644,7 +60925,7 @@ class VerifyService {
60644
60925
  where: eq(users.id, userId)
60645
60926
  });
60646
60927
  if (!userData) {
60647
- logger36.error("User not found for valid token", {
60928
+ logger37.error("User not found for valid token", {
60648
60929
  userId
60649
60930
  });
60650
60931
  throw new NotFoundError("User", userId);
@@ -60658,7 +60939,7 @@ class VerifyService {
60658
60939
  family_name: undefined,
60659
60940
  timeback_id: userData.timebackId || undefined
60660
60941
  };
60661
- logger36.info("Token verified", { gameId, userId });
60942
+ logger37.info("Token verified", { gameId, userId });
60662
60943
  return {
60663
60944
  claims: payload,
60664
60945
  gameId,
@@ -60666,13 +60947,13 @@ class VerifyService {
60666
60947
  };
60667
60948
  }
60668
60949
  }
60669
- var logger36;
60950
+ var logger37;
60670
60951
  var init_verify_service = __esm(() => {
60671
60952
  init_drizzle_orm();
60672
60953
  init_tables_index();
60673
60954
  init_src2();
60674
60955
  init_errors();
60675
- logger36 = log.scope("VerifyService");
60956
+ logger37 = log.scope("VerifyService");
60676
60957
  });
60677
60958
  function createStandaloneServices(deps) {
60678
60959
  const { db: db2, auth: auth2, timeback: timeback2 } = deps;
@@ -65804,7 +66085,7 @@ var colorStatus = async (status) => {
65804
66085
  }
65805
66086
  return `${status}`;
65806
66087
  };
65807
- var logger37 = (fn = console.log) => {
66088
+ var logger38 = (fn = console.log) => {
65808
66089
  return async function logger2(c, next) {
65809
66090
  const { method, url: url2 } = c.req;
65810
66091
  const path2 = url2.slice(url2.indexOf("/", 8));
@@ -65981,7 +66262,7 @@ function createApp(db2, options) {
65981
66262
  const app = new Hono2;
65982
66263
  app.use("*", cors({ origin: "*", credentials: true }));
65983
66264
  if (options.verbose && !options.quiet) {
65984
- app.use("*", logger37());
66265
+ app.use("*", logger38());
65985
66266
  }
65986
66267
  app.use("/api/*", async (c, next) => {
65987
66268
  c.set("db", db2);
@@ -72683,12 +72964,12 @@ var init_session2 = __esm(() => {
72683
72964
  init_utils();
72684
72965
  init_dist5();
72685
72966
  PglitePreparedQuery = class PglitePreparedQuery2 extends PgPreparedQuery {
72686
- constructor(client, queryString, params, logger38, fields, name3, _isResponseInArrayMode, customResultMapper) {
72967
+ constructor(client, queryString, params, logger39, fields, name3, _isResponseInArrayMode, customResultMapper) {
72687
72968
  super({ sql: queryString, params });
72688
72969
  this.client = client;
72689
72970
  this.queryString = queryString;
72690
72971
  this.params = params;
72691
- this.logger = logger38;
72972
+ this.logger = logger39;
72692
72973
  this.fields = fields;
72693
72974
  this._isResponseInArrayMode = _isResponseInArrayMode;
72694
72975
  this.customResultMapper = customResultMapper;
@@ -72790,11 +73071,11 @@ var init_session2 = __esm(() => {
72790
73071
  });
72791
73072
  function construct(client, config2 = {}) {
72792
73073
  const dialect2 = new PgDialect({ casing: config2.casing });
72793
- let logger38;
73074
+ let logger39;
72794
73075
  if (config2.logger === true) {
72795
- logger38 = new DefaultLogger;
73076
+ logger39 = new DefaultLogger;
72796
73077
  } else if (config2.logger !== false) {
72797
- logger38 = config2.logger;
73078
+ logger39 = config2.logger;
72798
73079
  }
72799
73080
  let schema2;
72800
73081
  if (config2.schema) {
@@ -72805,7 +73086,7 @@ function construct(client, config2 = {}) {
72805
73086
  tableNamesMap: tablesConfig.tableNamesMap
72806
73087
  };
72807
73088
  }
72808
- const driver = new PgliteDriver(client, dialect2, { logger: logger38 });
73089
+ const driver = new PgliteDriver(client, dialect2, { logger: logger39 });
72809
73090
  const session2 = driver.createSession(schema2);
72810
73091
  const db2 = new PgliteDatabase(dialect2, session2, schema2);
72811
73092
  db2.$client = client;
@@ -121410,8 +121691,8 @@ var init_currencies = __esm(() => {
121410
121691
  init_tables_index();
121411
121692
  init_constants();
121412
121693
  });
121413
- function setLogger(logger38) {
121414
- customLogger = logger38;
121694
+ function setLogger(logger39) {
121695
+ customLogger = logger39;
121415
121696
  }
121416
121697
  function getLogger() {
121417
121698
  if (customLogger) {
@@ -121424,10 +121705,10 @@ function getLogger() {
121424
121705
  };
121425
121706
  }
121426
121707
  var customLogger;
121427
- var logger38;
121708
+ var logger39;
121428
121709
  var init_adapter = __esm(() => {
121429
121710
  init_config();
121430
- logger38 = {
121711
+ logger39 = {
121431
121712
  info: (msg) => {
121432
121713
  if (customLogger || !config.embedded) {
121433
121714
  getLogger().info(msg);
@@ -121511,7 +121792,7 @@ async function seedCoreGames(db2) {
121511
121792
  role: "owner"
121512
121793
  }).onConflictDoNothing();
121513
121794
  } catch (error2) {
121514
- logger38.error(`Error seeding core game '${gameData.slug}': ${error2}`);
121795
+ logger39.error(`Error seeding core game '${gameData.slug}': ${error2}`);
121515
121796
  }
121516
121797
  }
121517
121798
  }
@@ -121561,7 +121842,7 @@ async function seedCurrentProjectGame(db2, project) {
121561
121842
  }
121562
121843
  return newGame;
121563
121844
  } catch (error2) {
121564
- logger38.error(`❌ Error seeding project game: ${error2}`);
121845
+ logger39.error(`❌ Error seeding project game: ${error2}`);
121565
121846
  throw error2;
121566
121847
  }
121567
121848
  }
@@ -122324,7 +122605,7 @@ async function provisionLtiUser(db2, claims) {
122324
122605
  where: eq(users.id, existingAccount.userId)
122325
122606
  });
122326
122607
  if (user) {
122327
- logger39.info("Found user by LTI account", {
122608
+ logger40.info("Found user by LTI account", {
122328
122609
  userId: user.id,
122329
122610
  ltiTimebackId
122330
122611
  });
@@ -122353,13 +122634,13 @@ async function provisionLtiUser(db2, claims) {
122353
122634
  updatedAt: new Date
122354
122635
  }).returning({ id: accounts.id });
122355
122636
  if (!account) {
122356
- logger39.error("LTI account link insert returned no rows", {
122637
+ logger40.error("LTI account link insert returned no rows", {
122357
122638
  userId: existingUser.id,
122358
122639
  ltiTimebackId
122359
122640
  });
122360
122641
  throw new InternalError("Failed to link LTI account");
122361
122642
  }
122362
- logger39.info("Linked LTI account to existing user", {
122643
+ logger40.info("Linked LTI account to existing user", {
122363
122644
  userId: existingUser.id,
122364
122645
  ltiTimebackId
122365
122646
  });
@@ -122379,7 +122660,7 @@ async function provisionLtiUser(db2, claims) {
122379
122660
  updatedAt: new Date
122380
122661
  }).returning();
122381
122662
  if (!insertedUser) {
122382
- logger39.error("LTI user insert returned no rows", { email, ltiTimebackId });
122663
+ logger40.error("LTI user insert returned no rows", { email, ltiTimebackId });
122383
122664
  throw new InternalError("Failed to create user");
122384
122665
  }
122385
122666
  await tx.insert(accounts).values({
@@ -122394,7 +122675,7 @@ async function provisionLtiUser(db2, claims) {
122394
122675
  createdAt: new Date,
122395
122676
  updatedAt: new Date
122396
122677
  });
122397
- logger39.info("Provisioned new user from LTI", {
122678
+ logger40.info("Provisioned new user from LTI", {
122398
122679
  userId: insertedUser.id,
122399
122680
  ltiTimebackId
122400
122681
  });
@@ -122402,7 +122683,7 @@ async function provisionLtiUser(db2, claims) {
122402
122683
  });
122403
122684
  return createdUser;
122404
122685
  }
122405
- var logger39;
122686
+ var logger40;
122406
122687
  var init_lti_provisioning = __esm(() => {
122407
122688
  init_drizzle_orm();
122408
122689
  init_src();
@@ -122410,7 +122691,7 @@ var init_lti_provisioning = __esm(() => {
122410
122691
  init_src2();
122411
122692
  init_errors();
122412
122693
  init_lti_util();
122413
- logger39 = log.scope("LtiProvisioning");
122694
+ logger40 = log.scope("LtiProvisioning");
122414
122695
  });
122415
122696
  function formatZodError(error2) {
122416
122697
  const flat = error2.flatten();
@@ -122453,7 +122734,7 @@ var init_utils11 = __esm(() => {
122453
122734
  init_timeback_util();
122454
122735
  init_validation_util();
122455
122736
  });
122456
- var logger40;
122737
+ var logger41;
122457
122738
  var listCurrent;
122458
122739
  var listHistory;
122459
122740
  var postProgress;
@@ -122464,14 +122745,14 @@ var init_achievement_controller = __esm(() => {
122464
122745
  init_src2();
122465
122746
  init_errors();
122466
122747
  init_utils11();
122467
- logger40 = log.scope("AchievementController");
122748
+ logger41 = log.scope("AchievementController");
122468
122749
  listCurrent = requireNonAnonymous(async (ctx) => {
122469
- logger40.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
122750
+ logger41.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
122470
122751
  return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
122471
122752
  });
122472
122753
  listHistory = requireNonAnonymous(async (ctx) => {
122473
122754
  const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
122474
- logger40.debug("Listing achievement history", { userId: ctx.user.id, limit });
122755
+ logger41.debug("Listing achievement history", { userId: ctx.user.id, limit });
122475
122756
  return ctx.services.achievement.listHistory(ctx.user, limit);
122476
122757
  });
122477
122758
  postProgress = requireNonAnonymous(async (ctx) => {
@@ -122482,12 +122763,12 @@ var init_achievement_controller = __esm(() => {
122482
122763
  } catch (error2) {
122483
122764
  if (error2 instanceof exports_external.ZodError) {
122484
122765
  const details = formatZodError(error2);
122485
- logger40.warn("Submit achievement progress validation failed", { details });
122766
+ logger41.warn("Submit achievement progress validation failed", { details });
122486
122767
  throw ApiError.unprocessableEntity("Invalid request body", details);
122487
122768
  }
122488
122769
  throw ApiError.badRequest("Invalid JSON body");
122489
122770
  }
122490
- logger40.debug("Submitting progress", {
122771
+ logger41.debug("Submitting progress", {
122491
122772
  userId: ctx.user.id,
122492
122773
  achievementId: body2.achievementId
122493
122774
  });
@@ -122499,15 +122780,15 @@ var init_achievement_controller = __esm(() => {
122499
122780
  postProgress
122500
122781
  };
122501
122782
  });
122502
- var logger41;
122783
+ var logger42;
122503
122784
  var getAllowedOrigins;
122504
122785
  var init_admin_controller = __esm(() => {
122505
122786
  init_src2();
122506
122787
  init_utils11();
122507
- logger41 = log.scope("AdminController");
122788
+ logger42 = log.scope("AdminController");
122508
122789
  getAllowedOrigins = requireAdmin(async (ctx) => {
122509
122790
  const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
122510
- logger41.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
122791
+ logger42.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
122511
122792
  if (shouldRefresh) {
122512
122793
  await ctx.providers.cache.refreshGameOrigins();
122513
122794
  }
@@ -122520,7 +122801,7 @@ var init_admin_controller = __esm(() => {
122520
122801
  };
122521
122802
  });
122522
122803
  });
122523
- var logger42;
122804
+ var logger43;
122524
122805
  var listFiles;
122525
122806
  var getFile;
122526
122807
  var putFile;
@@ -122532,7 +122813,7 @@ var init_bucket_controller = __esm(() => {
122532
122813
  init_src2();
122533
122814
  init_errors();
122534
122815
  init_utils11();
122535
- logger42 = log.scope("BucketController");
122816
+ logger43 = log.scope("BucketController");
122536
122817
  listFiles = requireDeveloper(async (ctx) => {
122537
122818
  const slug2 = ctx.params.slug;
122538
122819
  if (!slug2) {
@@ -122540,7 +122821,7 @@ var init_bucket_controller = __esm(() => {
122540
122821
  }
122541
122822
  const url2 = ctx.url;
122542
122823
  const prefix2 = url2.searchParams.get("prefix") || undefined;
122543
- logger42.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
122824
+ logger43.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
122544
122825
  const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
122545
122826
  return { files };
122546
122827
  });
@@ -122550,7 +122831,7 @@ var init_bucket_controller = __esm(() => {
122550
122831
  if (!slug2 || !key) {
122551
122832
  throw ApiError.badRequest("Missing game slug or file key");
122552
122833
  }
122553
- logger42.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
122834
+ logger43.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
122554
122835
  const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
122555
122836
  return new Response(Buffer.from(object.body), {
122556
122837
  status: 200,
@@ -122569,7 +122850,7 @@ var init_bucket_controller = __esm(() => {
122569
122850
  const arrayBuffer = await ctx.request.arrayBuffer();
122570
122851
  const body2 = new Uint8Array(arrayBuffer);
122571
122852
  const contentType = ctx.request.headers.get("content-type") || undefined;
122572
- logger42.debug("Uploading file", {
122853
+ logger43.debug("Uploading file", {
122573
122854
  userId: ctx.user.id,
122574
122855
  slug: slug2,
122575
122856
  key,
@@ -122585,7 +122866,7 @@ var init_bucket_controller = __esm(() => {
122585
122866
  if (!slug2 || !key) {
122586
122867
  throw ApiError.badRequest("Missing game slug or file key");
122587
122868
  }
122588
- logger42.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
122869
+ logger43.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
122589
122870
  await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
122590
122871
  return { success: true, key };
122591
122872
  });
@@ -122597,12 +122878,12 @@ var init_bucket_controller = __esm(() => {
122597
122878
  } catch (error2) {
122598
122879
  if (error2 instanceof exports_external.ZodError) {
122599
122880
  const details = formatZodError(error2);
122600
- logger42.warn("Initiate upload validation failed", { details });
122881
+ logger43.warn("Initiate upload validation failed", { details });
122601
122882
  throw ApiError.unprocessableEntity("Validation failed", details);
122602
122883
  }
122603
122884
  throw ApiError.badRequest("Invalid JSON body");
122604
122885
  }
122605
- logger42.debug("Initiating multipart upload", {
122886
+ logger43.debug("Initiating multipart upload", {
122606
122887
  userId: ctx.user.id,
122607
122888
  gameId: body2.gameId,
122608
122889
  fileName: body2.fileName
@@ -122617,10 +122898,10 @@ async function listComponents(ctx) {
122617
122898
  if (!isNaN(parsed) && isFinite(parsed)) {
122618
122899
  level = Math.floor(Math.max(0, parsed));
122619
122900
  }
122620
- logger43.debug("Listing components", { level });
122901
+ logger44.debug("Listing components", { level });
122621
122902
  return ctx.services.character.listAvailableComponents(level);
122622
122903
  }
122623
- var logger43;
122904
+ var logger44;
122624
122905
  var get;
122625
122906
  var getByUserId;
122626
122907
  var create;
@@ -122634,9 +122915,9 @@ var init_character_controller = __esm(() => {
122634
122915
  init_src2();
122635
122916
  init_errors();
122636
122917
  init_utils11();
122637
- logger43 = log.scope("CharacterController");
122918
+ logger44 = log.scope("CharacterController");
122638
122919
  get = requireNonAnonymous(async (ctx) => {
122639
- logger43.debug("Getting character", { userId: ctx.user.id });
122920
+ logger44.debug("Getting character", { userId: ctx.user.id });
122640
122921
  return ctx.services.character.getByUser(ctx.user);
122641
122922
  });
122642
122923
  getByUserId = requireNonAnonymous(async (ctx) => {
@@ -122644,7 +122925,7 @@ var init_character_controller = __esm(() => {
122644
122925
  if (!userId) {
122645
122926
  throw ApiError.badRequest("User ID is required in the URL path");
122646
122927
  }
122647
- logger43.debug("Getting character by user ID", { requestedUserId: userId });
122928
+ logger44.debug("Getting character by user ID", { requestedUserId: userId });
122648
122929
  return ctx.services.character.getByUserId(userId);
122649
122930
  });
122650
122931
  create = requireNonAnonymous(async (ctx) => {
@@ -122655,12 +122936,12 @@ var init_character_controller = __esm(() => {
122655
122936
  } catch (error2) {
122656
122937
  if (error2 instanceof exports_external.ZodError) {
122657
122938
  const details = formatZodError(error2);
122658
- logger43.warn("Create character validation failed", { details });
122939
+ logger44.warn("Create character validation failed", { details });
122659
122940
  throw ApiError.unprocessableEntity("Invalid request body", details);
122660
122941
  }
122661
122942
  throw ApiError.badRequest("Invalid JSON body");
122662
122943
  }
122663
- logger43.debug("Creating character", {
122944
+ logger44.debug("Creating character", {
122664
122945
  userId: ctx.user.id,
122665
122946
  bodyComponentId: body2.bodyComponentId,
122666
122947
  hairstyleComponentId: body2.hairstyleComponentId
@@ -122675,12 +122956,12 @@ var init_character_controller = __esm(() => {
122675
122956
  } catch (error2) {
122676
122957
  if (error2 instanceof exports_external.ZodError) {
122677
122958
  const details = formatZodError(error2);
122678
- logger43.warn("Update character validation failed", { details });
122959
+ logger44.warn("Update character validation failed", { details });
122679
122960
  throw ApiError.unprocessableEntity("Invalid request body", details);
122680
122961
  }
122681
122962
  throw ApiError.badRequest("Invalid JSON body");
122682
122963
  }
122683
- logger43.debug("Updating character", {
122964
+ logger44.debug("Updating character", {
122684
122965
  userId: ctx.user.id,
122685
122966
  bodyComponentId: body2.bodyComponentId,
122686
122967
  hairstyleComponentId: body2.hairstyleComponentId,
@@ -122696,12 +122977,12 @@ var init_character_controller = __esm(() => {
122696
122977
  } catch (error2) {
122697
122978
  if (error2 instanceof exports_external.ZodError) {
122698
122979
  const details = formatZodError(error2);
122699
- logger43.warn("Equip accessory validation failed", { details });
122980
+ logger44.warn("Equip accessory validation failed", { details });
122700
122981
  throw ApiError.unprocessableEntity("Invalid request body", details);
122701
122982
  }
122702
122983
  throw ApiError.badRequest("Invalid JSON body");
122703
122984
  }
122704
- logger43.debug("Equipping accessory", {
122985
+ logger44.debug("Equipping accessory", {
122705
122986
  userId: ctx.user.id,
122706
122987
  slot: body2.slot,
122707
122988
  accessoryComponentId: body2.accessoryComponentId
@@ -122713,7 +122994,7 @@ var init_character_controller = __esm(() => {
122713
122994
  if (!slot) {
122714
122995
  throw ApiError.badRequest("Slot is required in the URL path");
122715
122996
  }
122716
- logger43.debug("Removing accessory", { userId: ctx.user.id, slot });
122997
+ logger44.debug("Removing accessory", { userId: ctx.user.id, slot });
122717
122998
  await ctx.services.character.removeAccessory(slot, ctx.user);
122718
122999
  return { success: true };
122719
123000
  });
@@ -122727,7 +123008,7 @@ var init_character_controller = __esm(() => {
122727
123008
  removeAccessory
122728
123009
  };
122729
123010
  });
122730
- var logger44;
123011
+ var logger45;
122731
123012
  var list;
122732
123013
  var getById;
122733
123014
  var create2;
@@ -122741,9 +123022,9 @@ var init_currency_controller = __esm(() => {
122741
123022
  init_src4();
122742
123023
  init_errors();
122743
123024
  init_utils11();
122744
- logger44 = log.scope("CurrencyController");
123025
+ logger45 = log.scope("CurrencyController");
122745
123026
  list = requireNonAnonymous(async (ctx) => {
122746
- logger44.debug("Listing currencies", { userId: ctx.user.id });
123027
+ logger45.debug("Listing currencies", { userId: ctx.user.id });
122747
123028
  return ctx.services.currency.list();
122748
123029
  });
122749
123030
  getById = requireNonAnonymous(async (ctx) => {
@@ -122754,7 +123035,7 @@ var init_currency_controller = __esm(() => {
122754
123035
  if (!isValidUUID(currencyId)) {
122755
123036
  throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
122756
123037
  }
122757
- logger44.debug("Getting currency", { userId: ctx.user.id, currencyId });
123038
+ logger45.debug("Getting currency", { userId: ctx.user.id, currencyId });
122758
123039
  return ctx.services.currency.getById(currencyId);
122759
123040
  });
122760
123041
  create2 = requireAdmin(async (ctx) => {
@@ -122765,12 +123046,12 @@ var init_currency_controller = __esm(() => {
122765
123046
  } catch (error2) {
122766
123047
  if (error2 instanceof exports_external.ZodError) {
122767
123048
  const details = formatZodError(error2);
122768
- logger44.warn("Create currency validation failed", { details });
123049
+ logger45.warn("Create currency validation failed", { details });
122769
123050
  throw ApiError.unprocessableEntity("Validation failed", details);
122770
123051
  }
122771
123052
  throw ApiError.badRequest("Invalid JSON body");
122772
123053
  }
122773
- logger44.debug("Creating currency", {
123054
+ logger45.debug("Creating currency", {
122774
123055
  userId: ctx.user.id,
122775
123056
  symbol: body2.symbol,
122776
123057
  itemId: body2.itemId,
@@ -122793,12 +123074,12 @@ var init_currency_controller = __esm(() => {
122793
123074
  } catch (error2) {
122794
123075
  if (error2 instanceof exports_external.ZodError) {
122795
123076
  const details = formatZodError(error2);
122796
- logger44.warn("Update currency validation failed", { details });
123077
+ logger45.warn("Update currency validation failed", { details });
122797
123078
  throw ApiError.unprocessableEntity("Validation failed", details);
122798
123079
  }
122799
123080
  throw ApiError.badRequest("Invalid JSON body");
122800
123081
  }
122801
- logger44.debug("Updating currency", {
123082
+ logger45.debug("Updating currency", {
122802
123083
  userId: ctx.user.id,
122803
123084
  currencyId,
122804
123085
  symbol: body2.symbol,
@@ -122815,7 +123096,7 @@ var init_currency_controller = __esm(() => {
122815
123096
  if (!isValidUUID(currencyId)) {
122816
123097
  throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
122817
123098
  }
122818
- logger44.debug("Deleting currency", { userId: ctx.user.id, currencyId });
123099
+ logger45.debug("Deleting currency", { userId: ctx.user.id, currencyId });
122819
123100
  await ctx.services.currency.delete(currencyId);
122820
123101
  });
122821
123102
  currencyController = {
@@ -122826,7 +123107,7 @@ var init_currency_controller = __esm(() => {
122826
123107
  remove
122827
123108
  };
122828
123109
  });
122829
- var logger45;
123110
+ var logger46;
122830
123111
  var reset;
122831
123112
  var init_database_controller = __esm(() => {
122832
123113
  init_esm();
@@ -122834,7 +123115,7 @@ var init_database_controller = __esm(() => {
122834
123115
  init_src2();
122835
123116
  init_errors();
122836
123117
  init_utils11();
122837
- logger45 = log.scope("DatabaseController");
123118
+ logger46 = log.scope("DatabaseController");
122838
123119
  reset = requireDeveloper(async (ctx) => {
122839
123120
  const slug2 = ctx.params.slug;
122840
123121
  if (!slug2) {
@@ -122847,11 +123128,11 @@ var init_database_controller = __esm(() => {
122847
123128
  } catch (error2) {
122848
123129
  if (error2 instanceof exports_external.ZodError) {
122849
123130
  const details = formatZodError(error2);
122850
- logger45.warn("Database reset validation failed", { details });
123131
+ logger46.warn("Database reset validation failed", { details });
122851
123132
  throw ApiError.unprocessableEntity("Validation failed", details);
122852
123133
  }
122853
123134
  }
122854
- logger45.debug("Resetting database", {
123135
+ logger46.debug("Resetting database", {
122855
123136
  userId: ctx.user.id,
122856
123137
  slug: slug2,
122857
123138
  hasSchema: Boolean(body2.schema)
@@ -122867,7 +123148,7 @@ async function createJob(ctx) {
122867
123148
  let body2;
122868
123149
  try {
122869
123150
  const json4 = await ctx.request.json();
122870
- logger46.debug("Deploy request body", {
123151
+ logger47.debug("Deploy request body", {
122871
123152
  keys: Object.keys(json4 || {}),
122872
123153
  hasUploadToken: Boolean(json4?.uploadToken),
122873
123154
  hasCode: Boolean(json4?.code),
@@ -122877,7 +123158,7 @@ async function createJob(ctx) {
122877
123158
  } catch (error2) {
122878
123159
  if (error2 instanceof exports_external.ZodError) {
122879
123160
  const details = formatZodError(error2);
122880
- logger46.warn("Deploy validation failed", { details });
123161
+ logger47.warn("Deploy validation failed", { details });
122881
123162
  throw ApiError.unprocessableEntity("Invalid deploy request", details);
122882
123163
  }
122883
123164
  throw ApiError.badRequest("Invalid JSON body");
@@ -122898,7 +123179,7 @@ async function getJob(ctx) {
122898
123179
  }
122899
123180
  return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
122900
123181
  }
122901
- var logger46;
123182
+ var logger47;
122902
123183
  var deploy;
122903
123184
  var init_deploy_controller = __esm(() => {
122904
123185
  init_esm();
@@ -122906,26 +123187,26 @@ var init_deploy_controller = __esm(() => {
122906
123187
  init_src2();
122907
123188
  init_errors();
122908
123189
  init_utils11();
122909
- logger46 = log.scope("DeployController");
123190
+ logger47 = log.scope("DeployController");
122910
123191
  deploy = {
122911
123192
  createJob: requireDeveloper(createJob),
122912
123193
  getJob: requireDeveloper(getJob)
122913
123194
  };
122914
123195
  });
122915
- var logger47;
123196
+ var logger48;
122916
123197
  var apply;
122917
123198
  var getStatus;
122918
123199
  var developer;
122919
123200
  var init_developer_controller = __esm(() => {
122920
123201
  init_src2();
122921
123202
  init_utils11();
122922
- logger47 = log.scope("DeveloperController");
123203
+ logger48 = log.scope("DeveloperController");
122923
123204
  apply = requireNonAnonymous(async (ctx) => {
122924
- logger47.debug("Applying for developer status", { userId: ctx.user.id });
123205
+ logger48.debug("Applying for developer status", { userId: ctx.user.id });
122925
123206
  await ctx.services.developer.apply(ctx.user);
122926
123207
  });
122927
123208
  getStatus = requireNonAnonymous(async (ctx) => {
122928
- logger47.debug("Getting developer status", { userId: ctx.user.id });
123209
+ logger48.debug("Getting developer status", { userId: ctx.user.id });
122929
123210
  const status = await ctx.services.developer.getStatus(ctx.user.id);
122930
123211
  return { status };
122931
123212
  });
@@ -122934,7 +123215,7 @@ var init_developer_controller = __esm(() => {
122934
123215
  getStatus
122935
123216
  };
122936
123217
  });
122937
- var logger48;
123218
+ var logger49;
122938
123219
  var add;
122939
123220
  var list2;
122940
123221
  var getStatus2;
@@ -122947,7 +123228,7 @@ var init_domain_controller = __esm(() => {
122947
123228
  init_config2();
122948
123229
  init_errors();
122949
123230
  init_utils11();
122950
- logger48 = log.scope("DomainController");
123231
+ logger49 = log.scope("DomainController");
122951
123232
  add = requireDeveloper(async (ctx) => {
122952
123233
  const slug2 = ctx.params.slug;
122953
123234
  if (!slug2) {
@@ -122960,13 +123241,13 @@ var init_domain_controller = __esm(() => {
122960
123241
  } catch (error2) {
122961
123242
  if (error2 instanceof exports_external.ZodError) {
122962
123243
  const details = formatZodError(error2);
122963
- logger48.warn("Add domain validation failed", { details });
123244
+ logger49.warn("Add domain validation failed", { details });
122964
123245
  throw ApiError.unprocessableEntity("Validation failed", details);
122965
123246
  }
122966
123247
  throw ApiError.badRequest("Invalid JSON body");
122967
123248
  }
122968
123249
  const environment = getPlatformEnvironment(ctx.config);
122969
- logger48.debug("Adding domain", {
123250
+ logger49.debug("Adding domain", {
122970
123251
  userId: ctx.user.id,
122971
123252
  slug: slug2,
122972
123253
  hostname: body2.hostname,
@@ -122980,7 +123261,7 @@ var init_domain_controller = __esm(() => {
122980
123261
  throw ApiError.badRequest("Missing game slug");
122981
123262
  }
122982
123263
  const environment = getPlatformEnvironment(ctx.config);
122983
- logger48.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
123264
+ logger49.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
122984
123265
  const domains22 = await ctx.services.domain.list(slug2, environment, ctx.user);
122985
123266
  return { domains: domains22 };
122986
123267
  });
@@ -122995,7 +123276,7 @@ var init_domain_controller = __esm(() => {
122995
123276
  }
122996
123277
  const refresh = ctx.url.searchParams.get("refresh") === "true";
122997
123278
  const environment = getPlatformEnvironment(ctx.config);
122998
- logger48.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
123279
+ logger49.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
122999
123280
  return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
123000
123281
  });
123001
123282
  remove2 = requireDeveloper(async (ctx) => {
@@ -123008,7 +123289,7 @@ var init_domain_controller = __esm(() => {
123008
123289
  throw ApiError.badRequest("Missing hostname");
123009
123290
  }
123010
123291
  const environment = getPlatformEnvironment(ctx.config);
123011
- logger48.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
123292
+ logger49.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
123012
123293
  await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
123013
123294
  });
123014
123295
  domains2 = {
@@ -123018,7 +123299,7 @@ var init_domain_controller = __esm(() => {
123018
123299
  remove: remove2
123019
123300
  };
123020
123301
  });
123021
- var logger49;
123302
+ var logger50;
123022
123303
  var list3;
123023
123304
  var listAccessible;
123024
123305
  var getSubjects;
@@ -123035,17 +123316,17 @@ var init_game_controller = __esm(() => {
123035
123316
  init_src4();
123036
123317
  init_errors();
123037
123318
  init_utils11();
123038
- logger49 = log.scope("GameController");
123319
+ logger50 = log.scope("GameController");
123039
123320
  list3 = requireNonAnonymous(async (ctx) => {
123040
- logger49.debug("Listing games", { userId: ctx.user.id });
123321
+ logger50.debug("Listing games", { userId: ctx.user.id });
123041
123322
  return ctx.services.game.list(ctx.user);
123042
123323
  });
123043
123324
  listAccessible = requireNonAnonymous(async (ctx) => {
123044
- logger49.debug("Listing accessible games", { userId: ctx.user.id });
123325
+ logger50.debug("Listing accessible games", { userId: ctx.user.id });
123045
123326
  return ctx.services.game.listAccessible(ctx.user);
123046
123327
  });
123047
123328
  getSubjects = requireNonAnonymous(async (ctx) => {
123048
- logger49.debug("Getting game subjects", { userId: ctx.user.id });
123329
+ logger50.debug("Getting game subjects", { userId: ctx.user.id });
123049
123330
  return ctx.services.game.getSubjects();
123050
123331
  });
123051
123332
  getById2 = requireNonAnonymous(async (ctx) => {
@@ -123056,7 +123337,7 @@ var init_game_controller = __esm(() => {
123056
123337
  if (!isValidUUID(gameId)) {
123057
123338
  throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
123058
123339
  }
123059
- logger49.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
123340
+ logger50.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
123060
123341
  return ctx.services.game.getById(gameId, ctx.user);
123061
123342
  });
123062
123343
  getBySlug = requireNonAnonymous(async (ctx) => {
@@ -123064,7 +123345,7 @@ var init_game_controller = __esm(() => {
123064
123345
  if (!slug2) {
123065
123346
  throw ApiError.badRequest("Missing game slug");
123066
123347
  }
123067
- logger49.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
123348
+ logger50.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
123068
123349
  return ctx.services.game.getBySlug(slug2, ctx.user);
123069
123350
  });
123070
123351
  getManifest = requireNonAnonymous(async (ctx) => {
@@ -123075,7 +123356,7 @@ var init_game_controller = __esm(() => {
123075
123356
  if (!isValidUUID(gameId)) {
123076
123357
  throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
123077
123358
  }
123078
- logger49.debug("Getting game manifest by ID", {
123359
+ logger50.debug("Getting game manifest by ID", {
123079
123360
  userId: ctx.user.id,
123080
123361
  gameId,
123081
123362
  launchId: ctx.launchId
@@ -123094,12 +123375,12 @@ var init_game_controller = __esm(() => {
123094
123375
  } catch (error2) {
123095
123376
  if (error2 instanceof exports_external.ZodError) {
123096
123377
  const details = formatZodError(error2);
123097
- logger49.warn("Upsert game validation failed", { details });
123378
+ logger50.warn("Upsert game validation failed", { details });
123098
123379
  throw ApiError.unprocessableEntity("Validation failed", details);
123099
123380
  }
123100
123381
  throw ApiError.badRequest("Invalid JSON body");
123101
123382
  }
123102
- logger49.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
123383
+ logger50.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
123103
123384
  return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
123104
123385
  });
123105
123386
  remove3 = requireNonAnonymous(async (ctx) => {
@@ -123110,7 +123391,7 @@ var init_game_controller = __esm(() => {
123110
123391
  if (!isValidUUID(gameId)) {
123111
123392
  throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
123112
123393
  }
123113
- logger49.debug("Deleting game", { userId: ctx.user.id, gameId });
123394
+ logger50.debug("Deleting game", { userId: ctx.user.id, gameId });
123114
123395
  await ctx.services.game.delete(gameId, ctx.user);
123115
123396
  });
123116
123397
  games2 = {
@@ -123124,7 +123405,7 @@ var init_game_controller = __esm(() => {
123124
123405
  remove: remove3
123125
123406
  };
123126
123407
  });
123127
- var logger50;
123408
+ var logger51;
123128
123409
  var list4;
123129
123410
  var addItem;
123130
123411
  var removeItem;
@@ -123135,9 +123416,9 @@ var init_inventory_controller = __esm(() => {
123135
123416
  init_src2();
123136
123417
  init_errors();
123137
123418
  init_utils11();
123138
- logger50 = log.scope("InventoryController");
123419
+ logger51 = log.scope("InventoryController");
123139
123420
  list4 = requireNonAnonymous(async (ctx) => {
123140
- logger50.debug("Listing inventory", { userId: ctx.user.id });
123421
+ logger51.debug("Listing inventory", { userId: ctx.user.id });
123141
123422
  return ctx.services.inventory.list(ctx.user);
123142
123423
  });
123143
123424
  addItem = requireNonAnonymous(async (ctx) => {
@@ -123148,12 +123429,12 @@ var init_inventory_controller = __esm(() => {
123148
123429
  } catch (error2) {
123149
123430
  if (error2 instanceof exports_external.ZodError) {
123150
123431
  const details = formatZodError(error2);
123151
- logger50.warn("Add inventory item validation failed", { details });
123432
+ logger51.warn("Add inventory item validation failed", { details });
123152
123433
  throw ApiError.unprocessableEntity("Invalid request body", details);
123153
123434
  }
123154
123435
  throw ApiError.badRequest("Invalid JSON body");
123155
123436
  }
123156
- logger50.debug("Adding item", {
123437
+ logger51.debug("Adding item", {
123157
123438
  userId: ctx.user.id,
123158
123439
  itemId: body2.itemId,
123159
123440
  qty: body2.qty
@@ -123168,12 +123449,12 @@ var init_inventory_controller = __esm(() => {
123168
123449
  } catch (error2) {
123169
123450
  if (error2 instanceof exports_external.ZodError) {
123170
123451
  const details = formatZodError(error2);
123171
- logger50.warn("Remove inventory item validation failed", { details });
123452
+ logger51.warn("Remove inventory item validation failed", { details });
123172
123453
  throw ApiError.unprocessableEntity("Invalid request body", details);
123173
123454
  }
123174
123455
  throw ApiError.badRequest("Invalid JSON body");
123175
123456
  }
123176
- logger50.debug("Removing item", {
123457
+ logger51.debug("Removing item", {
123177
123458
  userId: ctx.user.id,
123178
123459
  itemId: body2.itemId,
123179
123460
  qty: body2.qty
@@ -123186,7 +123467,7 @@ var init_inventory_controller = __esm(() => {
123186
123467
  removeItem
123187
123468
  };
123188
123469
  });
123189
- var logger51;
123470
+ var logger52;
123190
123471
  var list5;
123191
123472
  var getById3;
123192
123473
  var resolve2;
@@ -123205,10 +123486,10 @@ var init_item_controller = __esm(() => {
123205
123486
  init_src4();
123206
123487
  init_errors();
123207
123488
  init_utils11();
123208
- logger51 = log.scope("ItemController");
123489
+ logger52 = log.scope("ItemController");
123209
123490
  list5 = requireNonAnonymous(async (ctx) => {
123210
123491
  const gameId = ctx.url.searchParams.get("gameId") || undefined;
123211
- logger51.debug("Listing items", { userId: ctx.user.id, gameId });
123492
+ logger52.debug("Listing items", { userId: ctx.user.id, gameId });
123212
123493
  return ctx.services.item.list(gameId);
123213
123494
  });
123214
123495
  getById3 = requireNonAnonymous(async (ctx) => {
@@ -123219,7 +123500,7 @@ var init_item_controller = __esm(() => {
123219
123500
  if (!isValidUUID(itemId)) {
123220
123501
  throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
123221
123502
  }
123222
- logger51.debug("Getting item", { userId: ctx.user.id, itemId });
123503
+ logger52.debug("Getting item", { userId: ctx.user.id, itemId });
123223
123504
  return ctx.services.item.getById(itemId);
123224
123505
  });
123225
123506
  resolve2 = requireNonAnonymous(async (ctx) => {
@@ -123231,7 +123512,7 @@ var init_item_controller = __esm(() => {
123231
123512
  if (gameId && !isValidUUID(gameId)) {
123232
123513
  throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
123233
123514
  }
123234
- logger51.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
123515
+ logger52.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
123235
123516
  return ctx.services.item.resolveBySlug(slug2, gameId);
123236
123517
  });
123237
123518
  create3 = requireRole(["admin"], async (ctx) => {
@@ -123242,12 +123523,12 @@ var init_item_controller = __esm(() => {
123242
123523
  } catch (error2) {
123243
123524
  if (error2 instanceof exports_external.ZodError) {
123244
123525
  const details = formatZodError(error2);
123245
- logger51.warn("Create item validation failed", { details });
123526
+ logger52.warn("Create item validation failed", { details });
123246
123527
  throw ApiError.unprocessableEntity("Validation failed", details);
123247
123528
  }
123248
123529
  throw ApiError.badRequest("Invalid JSON body");
123249
123530
  }
123250
- logger51.debug("Creating item", {
123531
+ logger52.debug("Creating item", {
123251
123532
  userId: ctx.user.id,
123252
123533
  slug: body2.slug,
123253
123534
  displayName: body2.displayName
@@ -123269,7 +123550,7 @@ var init_item_controller = __esm(() => {
123269
123550
  } catch (error2) {
123270
123551
  if (error2 instanceof exports_external.ZodError) {
123271
123552
  const details = formatZodError(error2);
123272
- logger51.warn("Update item validation failed", { details });
123553
+ logger52.warn("Update item validation failed", { details });
123273
123554
  throw ApiError.unprocessableEntity("Validation failed", details);
123274
123555
  }
123275
123556
  throw ApiError.badRequest("Invalid JSON body");
@@ -123277,7 +123558,7 @@ var init_item_controller = __esm(() => {
123277
123558
  if (Object.keys(body2).length === 0) {
123278
123559
  throw ApiError.badRequest("No update data provided");
123279
123560
  }
123280
- logger51.debug("Updating item", {
123561
+ logger52.debug("Updating item", {
123281
123562
  userId: ctx.user.id,
123282
123563
  itemId,
123283
123564
  slug: body2.slug,
@@ -123294,7 +123575,7 @@ var init_item_controller = __esm(() => {
123294
123575
  if (!isValidUUID(itemId)) {
123295
123576
  throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
123296
123577
  }
123297
- logger51.debug("Deleting item", { userId: ctx.user.id, itemId });
123578
+ logger52.debug("Deleting item", { userId: ctx.user.id, itemId });
123298
123579
  await ctx.services.item.delete(itemId);
123299
123580
  });
123300
123581
  listByGame = requireNonAnonymous(async (ctx) => {
@@ -123305,7 +123586,7 @@ var init_item_controller = __esm(() => {
123305
123586
  if (!isValidUUID(gameId)) {
123306
123587
  throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
123307
123588
  }
123308
- logger51.debug("Listing game items", { userId: ctx.user.id, gameId });
123589
+ logger52.debug("Listing game items", { userId: ctx.user.id, gameId });
123309
123590
  return ctx.services.item.listByGame(gameId);
123310
123591
  });
123311
123592
  createForGame = requireNonAnonymous(async (ctx) => {
@@ -123323,12 +123604,12 @@ var init_item_controller = __esm(() => {
123323
123604
  } catch (error2) {
123324
123605
  if (error2 instanceof exports_external.ZodError) {
123325
123606
  const details = formatZodError(error2);
123326
- logger51.warn("Create game item validation failed", { details });
123607
+ logger52.warn("Create game item validation failed", { details });
123327
123608
  throw ApiError.unprocessableEntity("Validation failed", details);
123328
123609
  }
123329
123610
  throw ApiError.badRequest("Invalid JSON body");
123330
123611
  }
123331
- logger51.debug("Creating game item", {
123612
+ logger52.debug("Creating game item", {
123332
123613
  userId: ctx.user.id,
123333
123614
  gameId,
123334
123615
  slug: body2.slug,
@@ -123355,7 +123636,7 @@ var init_item_controller = __esm(() => {
123355
123636
  } catch (error2) {
123356
123637
  if (error2 instanceof exports_external.ZodError) {
123357
123638
  const details = formatZodError(error2);
123358
- logger51.warn("Update game item validation failed", { details });
123639
+ logger52.warn("Update game item validation failed", { details });
123359
123640
  throw ApiError.unprocessableEntity("Validation failed", details);
123360
123641
  }
123361
123642
  throw ApiError.badRequest("Invalid JSON body");
@@ -123363,7 +123644,7 @@ var init_item_controller = __esm(() => {
123363
123644
  if (Object.keys(body2).length === 0) {
123364
123645
  throw ApiError.badRequest("No update data provided");
123365
123646
  }
123366
- logger51.debug("Updating game item", {
123647
+ logger52.debug("Updating game item", {
123367
123648
  userId: ctx.user.id,
123368
123649
  gameId,
123369
123650
  itemId,
@@ -123385,7 +123666,7 @@ var init_item_controller = __esm(() => {
123385
123666
  if (!isValidUUID(itemId)) {
123386
123667
  throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
123387
123668
  }
123388
- logger51.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
123669
+ logger52.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
123389
123670
  await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
123390
123671
  });
123391
123672
  items2 = {
@@ -123401,7 +123682,7 @@ var init_item_controller = __esm(() => {
123401
123682
  deleteForGame
123402
123683
  };
123403
123684
  });
123404
- var logger52;
123685
+ var logger53;
123405
123686
  var listKeys;
123406
123687
  var getStats;
123407
123688
  var seed;
@@ -123416,7 +123697,7 @@ var init_kv_controller = __esm(() => {
123416
123697
  init_src2();
123417
123698
  init_errors();
123418
123699
  init_utils11();
123419
- logger52 = log.scope("KVController");
123700
+ logger53 = log.scope("KVController");
123420
123701
  listKeys = requireDeveloper(async (ctx) => {
123421
123702
  const slug2 = ctx.params.slug;
123422
123703
  if (!slug2) {
@@ -123424,7 +123705,7 @@ var init_kv_controller = __esm(() => {
123424
123705
  }
123425
123706
  const url2 = ctx.url;
123426
123707
  const prefix2 = url2.searchParams.get("prefix") || undefined;
123427
- logger52.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
123708
+ logger53.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
123428
123709
  const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
123429
123710
  return { keys };
123430
123711
  });
@@ -123433,7 +123714,7 @@ var init_kv_controller = __esm(() => {
123433
123714
  if (!slug2) {
123434
123715
  throw ApiError.badRequest("Missing game slug");
123435
123716
  }
123436
- logger52.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
123717
+ logger53.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
123437
123718
  return ctx.services.kv.getStats(slug2, ctx.user);
123438
123719
  });
123439
123720
  seed = requireDeveloper(async (ctx) => {
@@ -123448,12 +123729,12 @@ var init_kv_controller = __esm(() => {
123448
123729
  } catch (error2) {
123449
123730
  if (error2 instanceof exports_external.ZodError) {
123450
123731
  const details = formatZodError(error2);
123451
- logger52.warn("Seed validation failed", { details });
123732
+ logger53.warn("Seed validation failed", { details });
123452
123733
  throw ApiError.unprocessableEntity("Validation failed", details);
123453
123734
  }
123454
123735
  throw ApiError.badRequest("Invalid JSON body");
123455
123736
  }
123456
- logger52.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
123737
+ logger53.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
123457
123738
  await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
123458
123739
  return { success: true, count: body2.entries.length };
123459
123740
  });
@@ -123463,7 +123744,7 @@ var init_kv_controller = __esm(() => {
123463
123744
  if (!slug2 || !key) {
123464
123745
  throw ApiError.badRequest("Missing game slug or key");
123465
123746
  }
123466
- logger52.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
123747
+ logger53.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
123467
123748
  const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
123468
123749
  return { key, value };
123469
123750
  });
@@ -123477,7 +123758,7 @@ var init_kv_controller = __esm(() => {
123477
123758
  if (!value) {
123478
123759
  throw ApiError.badRequest("Missing value in request body");
123479
123760
  }
123480
- logger52.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
123761
+ logger53.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
123481
123762
  await ctx.services.kv.setValue(slug2, key, value, ctx.user);
123482
123763
  return { success: true, key };
123483
123764
  });
@@ -123487,7 +123768,7 @@ var init_kv_controller = __esm(() => {
123487
123768
  if (!slug2 || !key) {
123488
123769
  throw ApiError.badRequest("Missing game slug or key");
123489
123770
  }
123490
- logger52.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
123771
+ logger53.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
123491
123772
  await ctx.services.kv.deleteValue(slug2, key, ctx.user);
123492
123773
  return { success: true, key };
123493
123774
  });
@@ -123497,7 +123778,7 @@ var init_kv_controller = __esm(() => {
123497
123778
  if (!slug2 || !key) {
123498
123779
  throw ApiError.badRequest("Missing game slug or key");
123499
123780
  }
123500
- logger52.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
123781
+ logger53.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
123501
123782
  const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
123502
123783
  return { key, metadata: metadata2 };
123503
123784
  });
@@ -123506,12 +123787,12 @@ var init_kv_controller = __esm(() => {
123506
123787
  if (!slug2) {
123507
123788
  throw ApiError.badRequest("Missing game slug");
123508
123789
  }
123509
- logger52.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
123790
+ logger53.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
123510
123791
  const deleted = await ctx.services.kv.clear(slug2, ctx.user);
123511
123792
  return { success: true, deleted };
123512
123793
  });
123513
123794
  });
123514
- var logger53;
123795
+ var logger54;
123515
123796
  var submitScore;
123516
123797
  var getGlobalLeaderboard;
123517
123798
  var getLeaderboard;
@@ -123525,7 +123806,7 @@ var init_leaderboard_controller = __esm(() => {
123525
123806
  init_src2();
123526
123807
  init_errors();
123527
123808
  init_utils11();
123528
- logger53 = log.scope("LeaderboardController");
123809
+ logger54 = log.scope("LeaderboardController");
123529
123810
  submitScore = requireAuth(async (ctx) => {
123530
123811
  const gameId = ctx.params.gameId;
123531
123812
  if (!gameId) {
@@ -123538,12 +123819,12 @@ var init_leaderboard_controller = __esm(() => {
123538
123819
  } catch (error2) {
123539
123820
  if (error2 instanceof exports_external.ZodError) {
123540
123821
  const details = formatZodError(error2);
123541
- logger53.warn("Submit score validation failed", { details });
123822
+ logger54.warn("Submit score validation failed", { details });
123542
123823
  throw ApiError.unprocessableEntity("Validation failed", details);
123543
123824
  }
123544
123825
  throw ApiError.badRequest("Invalid JSON body");
123545
123826
  }
123546
- logger53.debug("Submitting score", {
123827
+ logger54.debug("Submitting score", {
123547
123828
  userId: ctx.user.id,
123548
123829
  gameId,
123549
123830
  score: body2.score
@@ -123566,12 +123847,12 @@ var init_leaderboard_controller = __esm(() => {
123566
123847
  } catch (error2) {
123567
123848
  if (error2 instanceof exports_external.ZodError) {
123568
123849
  const details = formatZodError(error2);
123569
- logger53.warn("Get global leaderboard query validation failed", { details });
123850
+ logger54.warn("Get global leaderboard query validation failed", { details });
123570
123851
  throw ApiError.badRequest("Invalid query parameters", details);
123571
123852
  }
123572
123853
  throw ApiError.badRequest("Invalid query parameters");
123573
123854
  }
123574
- logger53.debug("Getting global leaderboard", {
123855
+ logger54.debug("Getting global leaderboard", {
123575
123856
  userId: ctx.user.id,
123576
123857
  gameId,
123577
123858
  ...query
@@ -123594,12 +123875,12 @@ var init_leaderboard_controller = __esm(() => {
123594
123875
  } catch (error2) {
123595
123876
  if (error2 instanceof exports_external.ZodError) {
123596
123877
  const details = formatZodError(error2);
123597
- logger53.warn("Get leaderboard query validation failed", { details });
123878
+ logger54.warn("Get leaderboard query validation failed", { details });
123598
123879
  throw ApiError.badRequest("Invalid query parameters", details);
123599
123880
  }
123600
123881
  throw ApiError.badRequest("Invalid query parameters");
123601
123882
  }
123602
- logger53.debug("Getting leaderboard", {
123883
+ logger54.debug("Getting leaderboard", {
123603
123884
  userId: ctx.user.id,
123604
123885
  gameId,
123605
123886
  ...query
@@ -123611,7 +123892,7 @@ var init_leaderboard_controller = __esm(() => {
123611
123892
  if (!gameId || !userId) {
123612
123893
  throw ApiError.badRequest("Game ID and User ID are required");
123613
123894
  }
123614
- logger53.debug("Getting user rank", {
123895
+ logger54.debug("Getting user rank", {
123615
123896
  requesterId: ctx.user.id,
123616
123897
  gameId,
123617
123898
  targetUserId: userId
@@ -123626,7 +123907,7 @@ var init_leaderboard_controller = __esm(() => {
123626
123907
  const url2 = ctx.url;
123627
123908
  const limit = Math.min(Number(url2.searchParams.get("limit") || "50"), 100);
123628
123909
  const gameId = url2.searchParams.get("gameId") || undefined;
123629
- logger53.debug("Getting user all scores", {
123910
+ logger54.debug("Getting user all scores", {
123630
123911
  requesterId: ctx.user.id,
123631
123912
  targetUserId: userId,
123632
123913
  gameId,
@@ -123641,7 +123922,7 @@ var init_leaderboard_controller = __esm(() => {
123641
123922
  }
123642
123923
  const url2 = ctx.url;
123643
123924
  const limit = Math.min(Number(url2.searchParams.get("limit") || "10"), 100);
123644
- logger53.debug("Getting user scores", {
123925
+ logger54.debug("Getting user scores", {
123645
123926
  requesterId: ctx.user.id,
123646
123927
  gameId,
123647
123928
  targetUserId: userId,
@@ -123659,7 +123940,7 @@ var init_leaderboard_controller = __esm(() => {
123659
123940
  };
123660
123941
  });
123661
123942
  async function listConfigs(ctx) {
123662
- logger54.debug("Listing level configs");
123943
+ logger55.debug("Listing level configs");
123663
123944
  return ctx.services.level.listConfigs();
123664
123945
  }
123665
123946
  async function getConfig(ctx) {
@@ -123671,10 +123952,10 @@ async function getConfig(ctx) {
123671
123952
  if (isNaN(level) || level < 1) {
123672
123953
  throw ApiError.badRequest("Level must be a positive integer");
123673
123954
  }
123674
- logger54.debug("Getting level config", { level });
123955
+ logger55.debug("Getting level config", { level });
123675
123956
  return ctx.services.level.getConfig(level);
123676
123957
  }
123677
- var logger54;
123958
+ var logger55;
123678
123959
  var getByUser;
123679
123960
  var getProgress;
123680
123961
  var levels;
@@ -123682,13 +123963,13 @@ var init_level_controller = __esm(() => {
123682
123963
  init_src2();
123683
123964
  init_errors();
123684
123965
  init_utils11();
123685
- logger54 = log.scope("LevelController");
123966
+ logger55 = log.scope("LevelController");
123686
123967
  getByUser = requireNonAnonymous(async (ctx) => {
123687
- logger54.debug("Getting user level", { userId: ctx.user.id });
123968
+ logger55.debug("Getting user level", { userId: ctx.user.id });
123688
123969
  return ctx.services.level.getByUser(ctx.user);
123689
123970
  });
123690
123971
  getProgress = requireNonAnonymous(async (ctx) => {
123691
- logger54.debug("Getting level progress", { userId: ctx.user.id });
123972
+ logger55.debug("Getting level progress", { userId: ctx.user.id });
123692
123973
  return ctx.services.level.getProgress(ctx.user);
123693
123974
  });
123694
123975
  levels = {
@@ -123698,14 +123979,14 @@ var init_level_controller = __esm(() => {
123698
123979
  getProgress
123699
123980
  };
123700
123981
  });
123701
- var logger55;
123982
+ var logger56;
123702
123983
  var generateToken;
123703
123984
  var logs;
123704
123985
  var init_logs_controller = __esm(() => {
123705
123986
  init_src2();
123706
123987
  init_errors();
123707
123988
  init_utils11();
123708
- logger55 = log.scope("LogsController");
123989
+ logger56 = log.scope("LogsController");
123709
123990
  generateToken = requireDeveloper(async (ctx) => {
123710
123991
  const slug2 = ctx.params.slug;
123711
123992
  if (!slug2) {
@@ -123724,7 +124005,7 @@ var init_logs_controller = __esm(() => {
123724
124005
  }
123725
124006
  throw ApiError.badRequest("Invalid JSON body");
123726
124007
  }
123727
- logger55.debug("Generating log stream token", {
124008
+ logger56.debug("Generating log stream token", {
123728
124009
  userId: ctx.user.id,
123729
124010
  slug: slug2,
123730
124011
  environment: body2.environment
@@ -123741,22 +124022,22 @@ var init_logs_controller = __esm(() => {
123741
124022
  generateToken
123742
124023
  };
123743
124024
  });
123744
- var logger56;
124025
+ var logger57;
123745
124026
  var getStatus3;
123746
124027
  var lti;
123747
124028
  var init_lti_controller = __esm(() => {
123748
124029
  init_src2();
123749
124030
  init_utils11();
123750
- logger56 = log.scope("LtiController");
124031
+ logger57 = log.scope("LtiController");
123751
124032
  getStatus3 = requireNonAnonymous(async (ctx) => {
123752
- logger56.debug("Getting status", { userId: ctx.user.id });
124033
+ logger57.debug("Getting status", { userId: ctx.user.id });
123753
124034
  return ctx.services.lti.getStatus(ctx.user);
123754
124035
  });
123755
124036
  lti = {
123756
124037
  getStatus: getStatus3
123757
124038
  };
123758
124039
  });
123759
- var logger57;
124040
+ var logger58;
123760
124041
  var getByIdentifier;
123761
124042
  var getElements;
123762
124043
  var getObjects;
@@ -123770,13 +124051,13 @@ var init_map_controller = __esm(() => {
123770
124051
  init_src4();
123771
124052
  init_errors();
123772
124053
  init_utils11();
123773
- logger57 = log.scope("MapController");
124054
+ logger58 = log.scope("MapController");
123774
124055
  getByIdentifier = requireNonAnonymous(async (ctx) => {
123775
124056
  const identifier = ctx.params.identifier;
123776
124057
  if (!identifier) {
123777
124058
  throw ApiError.badRequest("Missing map identifier");
123778
124059
  }
123779
- logger57.debug("Getting map", { userId: ctx.user.id, identifier });
124060
+ logger58.debug("Getting map", { userId: ctx.user.id, identifier });
123780
124061
  return ctx.services.map.getByIdentifier(identifier);
123781
124062
  });
123782
124063
  getElements = requireNonAnonymous(async (ctx) => {
@@ -123787,7 +124068,7 @@ var init_map_controller = __esm(() => {
123787
124068
  if (!isValidUUID(mapId)) {
123788
124069
  throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
123789
124070
  }
123790
- logger57.debug("Getting map elements", { userId: ctx.user.id, mapId });
124071
+ logger58.debug("Getting map elements", { userId: ctx.user.id, mapId });
123791
124072
  return ctx.services.map.getElements(mapId);
123792
124073
  });
123793
124074
  getObjects = requireNonAnonymous(async (ctx) => {
@@ -123798,7 +124079,7 @@ var init_map_controller = __esm(() => {
123798
124079
  if (!isValidUUID(mapId)) {
123799
124080
  throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
123800
124081
  }
123801
- logger57.debug("Getting map objects", { userId: ctx.user.id, mapId });
124082
+ logger58.debug("Getting map objects", { userId: ctx.user.id, mapId });
123802
124083
  return ctx.services.map.getObjects(mapId, ctx.user.id);
123803
124084
  });
123804
124085
  createObject = requireNonAnonymous(async (ctx) => {
@@ -123820,12 +124101,12 @@ var init_map_controller = __esm(() => {
123820
124101
  } catch (error2) {
123821
124102
  if (error2 instanceof exports_external.ZodError) {
123822
124103
  const details = formatZodError(error2);
123823
- logger57.warn("Create map object validation failed", { details });
124104
+ logger58.warn("Create map object validation failed", { details });
123824
124105
  throw ApiError.unprocessableEntity("Validation failed", details);
123825
124106
  }
123826
124107
  throw ApiError.badRequest("Invalid JSON body");
123827
124108
  }
123828
- logger57.debug("Creating map object", {
124109
+ logger58.debug("Creating map object", {
123829
124110
  userId: ctx.user.id,
123830
124111
  mapId,
123831
124112
  itemId: body2.itemId,
@@ -123849,7 +124130,7 @@ var init_map_controller = __esm(() => {
123849
124130
  if (!isValidUUID(objectId)) {
123850
124131
  throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
123851
124132
  }
123852
- logger57.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
124133
+ logger58.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
123853
124134
  await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
123854
124135
  });
123855
124136
  maps2 = {
@@ -123860,7 +124141,7 @@ var init_map_controller = __esm(() => {
123860
124141
  deleteObject
123861
124142
  };
123862
124143
  });
123863
- var logger58;
124144
+ var logger59;
123864
124145
  var list6;
123865
124146
  var updateStatus;
123866
124147
  var getStats2;
@@ -123873,7 +124154,7 @@ var init_notification_controller = __esm(() => {
123873
124154
  init_src2();
123874
124155
  init_errors();
123875
124156
  init_utils11();
123876
- logger58 = log.scope("NotificationController");
124157
+ logger59 = log.scope("NotificationController");
123877
124158
  list6 = requireNonAnonymous(async (ctx) => {
123878
124159
  const query = {
123879
124160
  status: ctx.url.searchParams.get("status") || undefined,
@@ -123884,10 +124165,10 @@ var init_notification_controller = __esm(() => {
123884
124165
  const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
123885
124166
  if (!result.success) {
123886
124167
  const details = formatZodError(result.error);
123887
- logger58.warn("List notifications query validation failed", { details });
124168
+ logger59.warn("List notifications query validation failed", { details });
123888
124169
  throw ApiError.badRequest("Invalid query parameters", details);
123889
124170
  }
123890
- logger58.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
124171
+ logger59.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
123891
124172
  return ctx.services.notification.list(ctx.user, result.data);
123892
124173
  });
123893
124174
  updateStatus = requireNonAnonymous(async (ctx) => {
@@ -123902,12 +124183,12 @@ var init_notification_controller = __esm(() => {
123902
124183
  } catch (error2) {
123903
124184
  if (error2 instanceof exports_external.ZodError) {
123904
124185
  const details = formatZodError(error2);
123905
- logger58.warn("Update notification status validation failed", { details });
124186
+ logger59.warn("Update notification status validation failed", { details });
123906
124187
  throw ApiError.unprocessableEntity("Invalid request body", details);
123907
124188
  }
123908
124189
  throw ApiError.badRequest("Invalid JSON body");
123909
124190
  }
123910
- logger58.debug("Updating status", {
124191
+ logger59.debug("Updating status", {
123911
124192
  userId: ctx.user.id,
123912
124193
  notificationId,
123913
124194
  status: body2.status
@@ -123917,7 +124198,7 @@ var init_notification_controller = __esm(() => {
123917
124198
  getStats2 = requireNonAnonymous(async (ctx) => {
123918
124199
  const startDate = ctx.url.searchParams.get("startDate");
123919
124200
  const endDate = ctx.url.searchParams.get("endDate");
123920
- logger58.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
124201
+ logger59.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
123921
124202
  return ctx.services.notification.getStats(ctx.user, {
123922
124203
  startDate: startDate ? new Date(startDate) : undefined,
123923
124204
  endDate: endDate ? new Date(endDate) : undefined
@@ -123931,12 +124212,12 @@ var init_notification_controller = __esm(() => {
123931
124212
  } catch (error2) {
123932
124213
  if (error2 instanceof exports_external.ZodError) {
123933
124214
  const details = formatZodError(error2);
123934
- logger58.warn("Create notification validation failed", { details });
124215
+ logger59.warn("Create notification validation failed", { details });
123935
124216
  throw ApiError.unprocessableEntity("Invalid request body", details);
123936
124217
  }
123937
124218
  throw ApiError.badRequest("Invalid JSON body");
123938
124219
  }
123939
- logger58.debug("Creating notification", {
124220
+ logger59.debug("Creating notification", {
123940
124221
  userId: ctx.user.id,
123941
124222
  targetUserId: body2.userId,
123942
124223
  type: body2.type
@@ -123954,12 +124235,12 @@ var init_notification_controller = __esm(() => {
123954
124235
  });
123955
124236
  });
123956
124237
  deliver = requireNonAnonymous(async (ctx) => {
123957
- logger58.debug("Delivering notifications", { userId: ctx.user.id });
124238
+ logger59.debug("Delivering notifications", { userId: ctx.user.id });
123958
124239
  try {
123959
124240
  await ctx.services.notification.deliverPending(ctx.user.id);
123960
124241
  return { success: true };
123961
124242
  } catch (error2) {
123962
- logger58.error("Failed to deliver notifications", { error: error2 });
124243
+ logger59.error("Failed to deliver notifications", { error: error2 });
123963
124244
  throw ApiError.internal("Failed to deliver notifications");
123964
124245
  }
123965
124246
  });
@@ -123971,16 +124252,16 @@ var init_notification_controller = __esm(() => {
123971
124252
  deliver
123972
124253
  };
123973
124254
  });
123974
- var logger59;
124255
+ var logger60;
123975
124256
  var generateToken2;
123976
124257
  var realtime;
123977
124258
  var init_realtime_controller = __esm(() => {
123978
124259
  init_src2();
123979
124260
  init_utils11();
123980
- logger59 = log.scope("RealtimeController");
124261
+ logger60 = log.scope("RealtimeController");
123981
124262
  generateToken2 = requireNonAnonymous(async (ctx) => {
123982
124263
  const gameIdOrSlug = ctx.params.gameId;
123983
- logger59.debug("Generating token", {
124264
+ logger60.debug("Generating token", {
123984
124265
  userId: ctx.user.id,
123985
124266
  gameId: gameIdOrSlug || "global",
123986
124267
  launchId: ctx.launchId
@@ -123991,7 +124272,7 @@ var init_realtime_controller = __esm(() => {
123991
124272
  generateToken: generateToken2
123992
124273
  };
123993
124274
  });
123994
- var logger60;
124275
+ var logger61;
123995
124276
  var listKeys2;
123996
124277
  var setSecrets;
123997
124278
  var deleteSecret;
@@ -124002,13 +124283,13 @@ var init_secrets_controller = __esm(() => {
124002
124283
  init_src2();
124003
124284
  init_errors();
124004
124285
  init_utils11();
124005
- logger60 = log.scope("SecretsController");
124286
+ logger61 = log.scope("SecretsController");
124006
124287
  listKeys2 = requireDeveloper(async (ctx) => {
124007
124288
  const slug2 = ctx.params.slug;
124008
124289
  if (!slug2) {
124009
124290
  throw ApiError.badRequest("Missing game slug");
124010
124291
  }
124011
- logger60.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
124292
+ logger61.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
124012
124293
  const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
124013
124294
  return { keys };
124014
124295
  });
@@ -124024,12 +124305,12 @@ var init_secrets_controller = __esm(() => {
124024
124305
  } catch (error2) {
124025
124306
  if (error2 instanceof exports_external.ZodError) {
124026
124307
  const details = formatZodError(error2);
124027
- logger60.warn("Set secrets validation failed", { details });
124308
+ logger61.warn("Set secrets validation failed", { details });
124028
124309
  throw ApiError.unprocessableEntity("Validation failed", details);
124029
124310
  }
124030
124311
  throw ApiError.badRequest("Invalid JSON body");
124031
124312
  }
124032
- logger60.debug("Setting secrets", {
124313
+ logger61.debug("Setting secrets", {
124033
124314
  userId: ctx.user.id,
124034
124315
  slug: slug2,
124035
124316
  keyCount: Object.keys(body2).length
@@ -124046,7 +124327,7 @@ var init_secrets_controller = __esm(() => {
124046
124327
  if (!key) {
124047
124328
  throw ApiError.badRequest("Missing secret key");
124048
124329
  }
124049
- logger60.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
124330
+ logger61.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
124050
124331
  await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
124051
124332
  return { success: true };
124052
124333
  });
@@ -124056,7 +124337,7 @@ var init_secrets_controller = __esm(() => {
124056
124337
  deleteSecret
124057
124338
  };
124058
124339
  });
124059
- var logger61;
124340
+ var logger62;
124060
124341
  var seed2;
124061
124342
  var init_seed_controller = __esm(() => {
124062
124343
  init_esm();
@@ -124064,7 +124345,7 @@ var init_seed_controller = __esm(() => {
124064
124345
  init_src2();
124065
124346
  init_errors();
124066
124347
  init_utils11();
124067
- logger61 = log.scope("SeedController");
124348
+ logger62 = log.scope("SeedController");
124068
124349
  seed2 = requireDeveloper(async (ctx) => {
124069
124350
  const slug2 = ctx.params.slug;
124070
124351
  if (!slug2) {
@@ -124077,12 +124358,12 @@ var init_seed_controller = __esm(() => {
124077
124358
  } catch (error2) {
124078
124359
  if (error2 instanceof exports_external.ZodError) {
124079
124360
  const details = formatZodError(error2);
124080
- logger61.warn("Seed database validation failed", { details });
124361
+ logger62.warn("Seed database validation failed", { details });
124081
124362
  throw ApiError.unprocessableEntity("Validation failed", details);
124082
124363
  }
124083
124364
  throw ApiError.badRequest("Invalid JSON body");
124084
124365
  }
124085
- logger61.debug("Seeding database", {
124366
+ logger62.debug("Seeding database", {
124086
124367
  userId: ctx.user.id,
124087
124368
  slug: slug2,
124088
124369
  codeLength: body2.code.length,
@@ -124091,7 +124372,7 @@ var init_seed_controller = __esm(() => {
124091
124372
  return ctx.services.seed.seed(slug2, body2.code, ctx.user, body2.secrets);
124092
124373
  });
124093
124374
  });
124094
- var logger62;
124375
+ var logger63;
124095
124376
  var start2;
124096
124377
  var end;
124097
124378
  var mintToken;
@@ -124101,13 +124382,13 @@ var init_session_controller = __esm(() => {
124101
124382
  init_tunnel();
124102
124383
  init_errors();
124103
124384
  init_utils11();
124104
- logger62 = log.scope("SessionController");
124385
+ logger63 = log.scope("SessionController");
124105
124386
  start2 = requireAuth(async (ctx) => {
124106
124387
  const gameIdOrSlug = ctx.params.gameId;
124107
124388
  if (!gameIdOrSlug) {
124108
124389
  throw ApiError.badRequest("Missing game ID or slug");
124109
124390
  }
124110
- logger62.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
124391
+ logger63.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
124111
124392
  return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
124112
124393
  });
124113
124394
  end = requireAuth(async (ctx) => {
@@ -124119,7 +124400,7 @@ var init_session_controller = __esm(() => {
124119
124400
  if (!sessionId) {
124120
124401
  throw ApiError.badRequest("Missing session ID");
124121
124402
  }
124122
- logger62.debug("Ending session", {
124403
+ logger63.debug("Ending session", {
124123
124404
  userId: ctx.user.id,
124124
124405
  gameIdOrSlug,
124125
124406
  sessionId,
@@ -124132,7 +124413,7 @@ var init_session_controller = __esm(() => {
124132
124413
  if (!gameIdOrSlug) {
124133
124414
  throw ApiError.badRequest("Missing game ID or slug");
124134
124415
  }
124135
- logger62.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
124416
+ logger63.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
124136
124417
  const { token, exp } = await ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
124137
124418
  let baseUrl;
124138
124419
  if (ctx.config.isLocal) {
@@ -124148,22 +124429,22 @@ var init_session_controller = __esm(() => {
124148
124429
  mintToken
124149
124430
  };
124150
124431
  });
124151
- var logger63;
124432
+ var logger64;
124152
124433
  var getShopView;
124153
124434
  var shop;
124154
124435
  var init_shop_controller = __esm(() => {
124155
124436
  init_src2();
124156
124437
  init_utils11();
124157
- logger63 = log.scope("ShopController");
124438
+ logger64 = log.scope("ShopController");
124158
124439
  getShopView = requireNonAnonymous(async (ctx) => {
124159
- logger63.debug("Getting shop view", { userId: ctx.user.id });
124440
+ logger64.debug("Getting shop view", { userId: ctx.user.id });
124160
124441
  return ctx.services.shop.getShopView(ctx.user);
124161
124442
  });
124162
124443
  shop = {
124163
124444
  getShopView
124164
124445
  };
124165
124446
  });
124166
- var logger64;
124447
+ var logger65;
124167
124448
  var list7;
124168
124449
  var getById4;
124169
124450
  var create5;
@@ -124182,9 +124463,9 @@ var init_shop_listing_controller = __esm(() => {
124182
124463
  init_src4();
124183
124464
  init_errors();
124184
124465
  init_utils11();
124185
- logger64 = log.scope("ShopListingController");
124466
+ logger65 = log.scope("ShopListingController");
124186
124467
  list7 = requireAdmin(async (ctx) => {
124187
- logger64.debug("Listing shop listings", { userId: ctx.user.id });
124468
+ logger65.debug("Listing shop listings", { userId: ctx.user.id });
124188
124469
  return ctx.services.shopListing.list();
124189
124470
  });
124190
124471
  getById4 = requireAdmin(async (ctx) => {
@@ -124195,7 +124476,7 @@ var init_shop_listing_controller = __esm(() => {
124195
124476
  if (!isValidUUID(listingId)) {
124196
124477
  throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
124197
124478
  }
124198
- logger64.debug("Getting listing", { userId: ctx.user.id, listingId });
124479
+ logger65.debug("Getting listing", { userId: ctx.user.id, listingId });
124199
124480
  return ctx.services.shopListing.getById(listingId);
124200
124481
  });
124201
124482
  create5 = requireAdmin(async (ctx) => {
@@ -124206,12 +124487,12 @@ var init_shop_listing_controller = __esm(() => {
124206
124487
  } catch (error2) {
124207
124488
  if (error2 instanceof exports_external.ZodError) {
124208
124489
  const details = formatZodError(error2);
124209
- logger64.warn("Create shop listing validation failed", { details });
124490
+ logger65.warn("Create shop listing validation failed", { details });
124210
124491
  throw ApiError.unprocessableEntity("Validation failed", details);
124211
124492
  }
124212
124493
  throw ApiError.badRequest("Invalid JSON body");
124213
124494
  }
124214
- logger64.debug("Creating listing", {
124495
+ logger65.debug("Creating listing", {
124215
124496
  userId: ctx.user.id,
124216
124497
  itemId: body2.itemId,
124217
124498
  currencyId: body2.currencyId,
@@ -124234,12 +124515,12 @@ var init_shop_listing_controller = __esm(() => {
124234
124515
  } catch (error2) {
124235
124516
  if (error2 instanceof exports_external.ZodError) {
124236
124517
  const details = formatZodError(error2);
124237
- logger64.warn("Update shop listing validation failed", { details });
124518
+ logger65.warn("Update shop listing validation failed", { details });
124238
124519
  throw ApiError.unprocessableEntity("Validation failed", details);
124239
124520
  }
124240
124521
  throw ApiError.badRequest("Invalid JSON body");
124241
124522
  }
124242
- logger64.debug("Updating listing", {
124523
+ logger65.debug("Updating listing", {
124243
124524
  userId: ctx.user.id,
124244
124525
  listingId,
124245
124526
  price: body2.price,
@@ -124256,7 +124537,7 @@ var init_shop_listing_controller = __esm(() => {
124256
124537
  if (!isValidUUID(listingId)) {
124257
124538
  throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
124258
124539
  }
124259
- logger64.debug("Deleting listing", { userId: ctx.user.id, listingId });
124540
+ logger65.debug("Deleting listing", { userId: ctx.user.id, listingId });
124260
124541
  await ctx.services.shopListing.delete(listingId);
124261
124542
  });
124262
124543
  listByGame2 = requireNonAnonymous(async (ctx) => {
@@ -124267,7 +124548,7 @@ var init_shop_listing_controller = __esm(() => {
124267
124548
  if (!isValidUUID(gameId)) {
124268
124549
  throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
124269
124550
  }
124270
- logger64.debug("Listing game listings", { userId: ctx.user.id, gameId });
124551
+ logger65.debug("Listing game listings", { userId: ctx.user.id, gameId });
124271
124552
  return ctx.services.shopListing.listByGame(gameId, ctx.user);
124272
124553
  });
124273
124554
  getByGameItem = requireNonAnonymous(async (ctx) => {
@@ -124282,7 +124563,7 @@ var init_shop_listing_controller = __esm(() => {
124282
124563
  if (!isValidUUID(itemId)) {
124283
124564
  throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
124284
124565
  }
124285
- logger64.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
124566
+ logger65.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
124286
124567
  return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
124287
124568
  });
124288
124569
  createForGameItem = requireNonAnonymous(async (ctx) => {
@@ -124304,12 +124585,12 @@ var init_shop_listing_controller = __esm(() => {
124304
124585
  } catch (error2) {
124305
124586
  if (error2 instanceof exports_external.ZodError) {
124306
124587
  const details = formatZodError(error2);
124307
- logger64.warn("Create game item listing validation failed", { details });
124588
+ logger65.warn("Create game item listing validation failed", { details });
124308
124589
  throw ApiError.unprocessableEntity("Validation failed", details);
124309
124590
  }
124310
124591
  throw ApiError.badRequest("Invalid JSON body");
124311
124592
  }
124312
- logger64.debug("Creating game item listing", {
124593
+ logger65.debug("Creating game item listing", {
124313
124594
  userId: ctx.user.id,
124314
124595
  gameId,
124315
124596
  itemId,
@@ -124337,12 +124618,12 @@ var init_shop_listing_controller = __esm(() => {
124337
124618
  } catch (error2) {
124338
124619
  if (error2 instanceof exports_external.ZodError) {
124339
124620
  const details = formatZodError(error2);
124340
- logger64.warn("Update game item listing validation failed", { details });
124621
+ logger65.warn("Update game item listing validation failed", { details });
124341
124622
  throw ApiError.unprocessableEntity("Validation failed", details);
124342
124623
  }
124343
124624
  throw ApiError.badRequest("Invalid JSON body");
124344
124625
  }
124345
- logger64.debug("Updating game item listing", {
124626
+ logger65.debug("Updating game item listing", {
124346
124627
  userId: ctx.user.id,
124347
124628
  gameId,
124348
124629
  itemId,
@@ -124364,7 +124645,7 @@ var init_shop_listing_controller = __esm(() => {
124364
124645
  if (!isValidUUID(itemId)) {
124365
124646
  throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
124366
124647
  }
124367
- logger64.debug("Deleting game item listing", {
124648
+ logger65.debug("Deleting game item listing", {
124368
124649
  userId: ctx.user.id,
124369
124650
  gameId,
124370
124651
  itemId
@@ -124389,20 +124670,20 @@ async function getBySlug2(ctx) {
124389
124670
  if (!slug2) {
124390
124671
  throw ApiError.badRequest("Template slug is required");
124391
124672
  }
124392
- logger65.debug("Getting sprite by slug", { slug: slug2 });
124673
+ logger66.debug("Getting sprite by slug", { slug: slug2 });
124393
124674
  return ctx.services.sprite.getBySlug(slug2);
124394
124675
  }
124395
- var logger65;
124676
+ var logger66;
124396
124677
  var sprites;
124397
124678
  var init_sprite_controller = __esm(() => {
124398
124679
  init_src2();
124399
124680
  init_errors();
124400
- logger65 = log.scope("SpriteController");
124681
+ logger66 = log.scope("SpriteController");
124401
124682
  sprites = {
124402
124683
  getBySlug: getBySlug2
124403
124684
  };
124404
124685
  });
124405
- var logger66;
124686
+ var logger67;
124406
124687
  var getTodayXp;
124407
124688
  var getTotalXp;
124408
124689
  var updateTodayXp;
@@ -124412,6 +124693,8 @@ var getUser;
124412
124693
  var getUserById;
124413
124694
  var setupIntegration;
124414
124695
  var getIntegrations;
124696
+ var updateIntegration;
124697
+ var getIntegrationConfig;
124415
124698
  var verifyIntegration;
124416
124699
  var getConfig2;
124417
124700
  var deleteIntegrations;
@@ -124427,6 +124710,7 @@ var getActivityDetail;
124427
124710
  var grantXp;
124428
124711
  var adjustTime;
124429
124712
  var adjustMastery;
124713
+ var reconcileMasteryForConfigChange;
124430
124714
  var searchStudents;
124431
124715
  var enrollStudent;
124432
124716
  var unenrollStudent;
@@ -124452,15 +124736,15 @@ var init_timeback_controller = __esm(() => {
124452
124736
  init_src4();
124453
124737
  init_errors();
124454
124738
  init_utils11();
124455
- logger66 = log.scope("TimebackController");
124739
+ logger67 = log.scope("TimebackController");
124456
124740
  getTodayXp = requireNonAnonymous(async (ctx) => {
124457
124741
  const date4 = ctx.url.searchParams.get("date") || undefined;
124458
124742
  const tz = ctx.url.searchParams.get("tz") || undefined;
124459
- logger66.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
124743
+ logger67.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
124460
124744
  return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
124461
124745
  });
124462
124746
  getTotalXp = requireNonAnonymous(async (ctx) => {
124463
- logger66.debug("Getting total XP", { userId: ctx.user.id });
124747
+ logger67.debug("Getting total XP", { userId: ctx.user.id });
124464
124748
  return ctx.services.timeback.getTotalXp(ctx.user.id);
124465
124749
  });
124466
124750
  updateTodayXp = requireNonAnonymous(async (ctx) => {
@@ -124471,18 +124755,18 @@ var init_timeback_controller = __esm(() => {
124471
124755
  } catch (error2) {
124472
124756
  if (error2 instanceof exports_external.ZodError) {
124473
124757
  const details = formatZodError(error2);
124474
- logger66.warn("Update today XP validation failed", { details });
124758
+ logger67.warn("Update today XP validation failed", { details });
124475
124759
  throw ApiError.unprocessableEntity("Validation failed", details);
124476
124760
  }
124477
124761
  throw ApiError.badRequest("Invalid JSON body");
124478
124762
  }
124479
- logger66.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
124763
+ logger67.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
124480
124764
  return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
124481
124765
  });
124482
124766
  getXpHistory = requireNonAnonymous(async (ctx) => {
124483
124767
  const startDate = ctx.url.searchParams.get("startDate") || undefined;
124484
124768
  const endDate = ctx.url.searchParams.get("endDate") || undefined;
124485
- logger66.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
124769
+ logger67.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
124486
124770
  return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
124487
124771
  });
124488
124772
  populateStudent = requireNonAnonymous(async (ctx) => {
@@ -124493,18 +124777,18 @@ var init_timeback_controller = __esm(() => {
124493
124777
  } catch (error2) {
124494
124778
  if (error2 instanceof exports_external.ZodError) {
124495
124779
  const details = formatZodError(error2);
124496
- logger66.warn("Populate student validation failed", { details });
124780
+ logger67.warn("Populate student validation failed", { details });
124497
124781
  throw ApiError.unprocessableEntity("Validation failed", details);
124498
124782
  }
124499
124783
  }
124500
- logger66.debug("Populating student", {
124784
+ logger67.debug("Populating student", {
124501
124785
  userId: ctx.user.id,
124502
124786
  hasProvidedNames: Boolean(providedNames)
124503
124787
  });
124504
124788
  return ctx.services.timeback.populateStudent(ctx.user, providedNames);
124505
124789
  });
124506
124790
  getUser = requireNonAnonymous(async (ctx) => {
124507
- logger66.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
124791
+ logger67.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
124508
124792
  return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
124509
124793
  });
124510
124794
  getUserById = requireNonAnonymous(async (ctx) => {
@@ -124512,7 +124796,7 @@ var init_timeback_controller = __esm(() => {
124512
124796
  if (!timebackId) {
124513
124797
  throw ApiError.badRequest("Missing timebackId parameter");
124514
124798
  }
124515
- logger66.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
124799
+ logger67.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
124516
124800
  return ctx.services.timeback.getUserDataByTimebackId(timebackId);
124517
124801
  });
124518
124802
  setupIntegration = requireDeveloper(async (ctx) => {
@@ -124523,12 +124807,12 @@ var init_timeback_controller = __esm(() => {
124523
124807
  } catch (error2) {
124524
124808
  if (error2 instanceof exports_external.ZodError) {
124525
124809
  const details = formatZodError(error2);
124526
- logger66.warn("Setup integration validation failed", { details });
124810
+ logger67.warn("Setup integration validation failed", { details });
124527
124811
  throw ApiError.unprocessableEntity("Validation failed", details);
124528
124812
  }
124529
124813
  throw ApiError.badRequest("Invalid JSON body");
124530
124814
  }
124531
- logger66.debug("Setting up integration", {
124815
+ logger67.debug("Setting up integration", {
124532
124816
  userId: ctx.user.id,
124533
124817
  gameId: body2.gameId
124534
124818
  });
@@ -124542,9 +124826,37 @@ var init_timeback_controller = __esm(() => {
124542
124826
  if (!isValidUUID(gameId)) {
124543
124827
  throw ApiError.unprocessableEntity("Invalid gameId format");
124544
124828
  }
124545
- logger66.debug("Getting integrations", { userId: ctx.user.id, gameId });
124829
+ logger67.debug("Getting integrations", { userId: ctx.user.id, gameId });
124546
124830
  return ctx.services.timeback.getIntegrations(gameId, ctx.user);
124547
124831
  });
124832
+ updateIntegration = requireDeveloper(async (ctx) => {
124833
+ const { gameId, courseId } = ctx.params;
124834
+ if (!gameId || !courseId) {
124835
+ throw ApiError.badRequest("Missing gameId or courseId parameter");
124836
+ }
124837
+ if (!isValidUUID(gameId)) {
124838
+ throw ApiError.unprocessableEntity("Invalid gameId format");
124839
+ }
124840
+ const body2 = await parseRequestBody(ctx.request, UpdateGameTimebackIntegrationRequestSchema);
124841
+ logger67.debug("Updating integration", {
124842
+ userId: ctx.user.id,
124843
+ gameId,
124844
+ courseId,
124845
+ fields: Object.keys(body2)
124846
+ });
124847
+ return ctx.services.timeback.updateIntegration(gameId, courseId, ctx.user, body2);
124848
+ });
124849
+ getIntegrationConfig = requireGameManagementAccess(async (ctx) => {
124850
+ const { gameId, courseId } = ctx.params;
124851
+ if (!gameId || !courseId) {
124852
+ throw ApiError.badRequest("Missing gameId or courseId parameter");
124853
+ }
124854
+ if (!isValidUUID(gameId)) {
124855
+ throw ApiError.unprocessableEntity("Invalid gameId format");
124856
+ }
124857
+ logger67.debug("Getting integration config", { userId: ctx.user.id, gameId, courseId });
124858
+ return ctx.services.timeback.getIntegrationConfig(gameId, courseId, ctx.user);
124859
+ });
124548
124860
  verifyIntegration = requireDeveloper(async (ctx) => {
124549
124861
  const gameId = ctx.params.gameId;
124550
124862
  if (!gameId) {
@@ -124553,7 +124865,7 @@ var init_timeback_controller = __esm(() => {
124553
124865
  if (!isValidUUID(gameId)) {
124554
124866
  throw ApiError.unprocessableEntity("Invalid gameId format");
124555
124867
  }
124556
- logger66.debug("Verifying integration", { userId: ctx.user.id, gameId });
124868
+ logger67.debug("Verifying integration", { userId: ctx.user.id, gameId });
124557
124869
  return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
124558
124870
  });
124559
124871
  getConfig2 = requireDeveloper(async (ctx) => {
@@ -124564,7 +124876,7 @@ var init_timeback_controller = __esm(() => {
124564
124876
  if (!isValidUUID(gameId)) {
124565
124877
  throw ApiError.unprocessableEntity("Invalid gameId format");
124566
124878
  }
124567
- logger66.debug("Getting config", { userId: ctx.user.id, gameId });
124879
+ logger67.debug("Getting config", { userId: ctx.user.id, gameId });
124568
124880
  return ctx.services.timeback.getConfig(gameId, ctx.user);
124569
124881
  });
124570
124882
  deleteIntegrations = requireDeveloper(async (ctx) => {
@@ -124575,7 +124887,7 @@ var init_timeback_controller = __esm(() => {
124575
124887
  if (!isValidUUID(gameId)) {
124576
124888
  throw ApiError.unprocessableEntity("Invalid gameId format");
124577
124889
  }
124578
- logger66.debug("Deleting integrations", { userId: ctx.user.id, gameId });
124890
+ logger67.debug("Deleting integrations", { userId: ctx.user.id, gameId });
124579
124891
  await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
124580
124892
  });
124581
124893
  endActivity = requireDeveloper(async (ctx) => {
@@ -124586,7 +124898,7 @@ var init_timeback_controller = __esm(() => {
124586
124898
  } catch (error2) {
124587
124899
  if (error2 instanceof exports_external.ZodError) {
124588
124900
  const details = formatZodError(error2);
124589
- logger66.warn("End activity validation failed", { details });
124901
+ logger67.warn("End activity validation failed", { details });
124590
124902
  throw ApiError.unprocessableEntity("Validation failed", details);
124591
124903
  }
124592
124904
  throw ApiError.badRequest("Invalid JSON body");
@@ -124604,7 +124916,7 @@ var init_timeback_controller = __esm(() => {
124604
124916
  masteredUnits,
124605
124917
  extensions
124606
124918
  } = body2;
124607
- logger66.debug("Ending activity", { userId: ctx.user.id, gameId });
124919
+ logger67.debug("Ending activity", { userId: ctx.user.id, gameId });
124608
124920
  return ctx.services.timeback.endActivity({
124609
124921
  gameId,
124610
124922
  studentId,
@@ -124628,7 +124940,7 @@ var init_timeback_controller = __esm(() => {
124628
124940
  } catch (error2) {
124629
124941
  if (error2 instanceof exports_external.ZodError) {
124630
124942
  const details = formatZodError(error2);
124631
- logger66.warn("Heartbeat validation failed", { details });
124943
+ logger67.warn("Heartbeat validation failed", { details });
124632
124944
  throw ApiError.unprocessableEntity("Validation failed", details);
124633
124945
  }
124634
124946
  throw ApiError.badRequest("Invalid JSON body");
@@ -124644,7 +124956,7 @@ var init_timeback_controller = __esm(() => {
124644
124956
  windowSequence,
124645
124957
  isFinal
124646
124958
  } = body2;
124647
- logger66.debug("Recording heartbeat", {
124959
+ logger67.debug("Recording heartbeat", {
124648
124960
  userId: ctx.user.id,
124649
124961
  gameId,
124650
124962
  runId,
@@ -124669,7 +124981,7 @@ var init_timeback_controller = __esm(() => {
124669
124981
  });
124670
124982
  advanceCourse = requireDeveloper(async (ctx) => {
124671
124983
  const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
124672
- logger66.debug("Advancing student manually", {
124984
+ logger67.debug("Advancing student manually", {
124673
124985
  userId: ctx.user.id,
124674
124986
  gameId: body2.gameId,
124675
124987
  studentId: body2.studentId,
@@ -124710,7 +125022,7 @@ var init_timeback_controller = __esm(() => {
124710
125022
  perCourse: includeOptions.includes("percourse"),
124711
125023
  today: includeOptions.includes("today")
124712
125024
  };
124713
- logger66.debug("Getting student XP", {
125025
+ logger67.debug("Getting student XP", {
124714
125026
  requesterId: ctx.user.id,
124715
125027
  timebackId,
124716
125028
  gameId,
@@ -124732,7 +125044,7 @@ var init_timeback_controller = __esm(() => {
124732
125044
  if (!gameId || !courseId) {
124733
125045
  throw ApiError.badRequest("Missing gameId or courseId parameter");
124734
125046
  }
124735
- logger66.debug("Getting course roster", {
125047
+ logger67.debug("Getting course roster", {
124736
125048
  requesterId: ctx.user.id,
124737
125049
  gameId,
124738
125050
  courseId,
@@ -124749,7 +125061,7 @@ var init_timeback_controller = __esm(() => {
124749
125061
  if (!timebackId || !gameId) {
124750
125062
  throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
124751
125063
  }
124752
- logger66.debug("Getting student overview", {
125064
+ logger67.debug("Getting student overview", {
124753
125065
  requesterId: ctx.user.id,
124754
125066
  timebackId,
124755
125067
  gameId,
@@ -124763,7 +125075,7 @@ var init_timeback_controller = __esm(() => {
124763
125075
  if (!gameId || !timebackId) {
124764
125076
  throw ApiError.badRequest("Missing gameId or timebackId path parameter");
124765
125077
  }
124766
- logger66.debug("Getting game metrics", {
125078
+ logger67.debug("Getting game metrics", {
124767
125079
  requesterId: ctx.user.id,
124768
125080
  gameId,
124769
125081
  timebackId
@@ -124781,7 +125093,7 @@ var init_timeback_controller = __esm(() => {
124781
125093
  if (!timebackId || !courseId || !gameId) {
124782
125094
  throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
124783
125095
  }
124784
- logger66.debug("Getting student activity", {
125096
+ logger67.debug("Getting student activity", {
124785
125097
  requesterId: ctx.user.id,
124786
125098
  timebackId,
124787
125099
  courseId,
@@ -124806,7 +125118,7 @@ var init_timeback_controller = __esm(() => {
124806
125118
  if (!timebackId || !courseId || !activityId || !gameId) {
124807
125119
  throw ApiError.badRequest("Missing timebackId, courseId, or activityId path parameter, or gameId query parameter");
124808
125120
  }
124809
- logger66.debug("Getting activity detail", {
125121
+ logger67.debug("Getting activity detail", {
124810
125122
  requesterId: ctx.user.id,
124811
125123
  timebackId,
124812
125124
  courseId,
@@ -124824,7 +125136,7 @@ var init_timeback_controller = __esm(() => {
124824
125136
  });
124825
125137
  grantXp = requireDeveloper(async (ctx) => {
124826
125138
  const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
124827
- logger66.debug("Granting manual XP", {
125139
+ logger67.debug("Granting manual XP", {
124828
125140
  requesterId: ctx.user.id,
124829
125141
  gameId: body2.gameId,
124830
125142
  courseId: body2.courseId,
@@ -124836,7 +125148,7 @@ var init_timeback_controller = __esm(() => {
124836
125148
  });
124837
125149
  adjustTime = requireDeveloper(async (ctx) => {
124838
125150
  const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
124839
- logger66.debug("Adjusting time spent", {
125151
+ logger67.debug("Adjusting time spent", {
124840
125152
  requesterId: ctx.user.id,
124841
125153
  gameId: body2.gameId,
124842
125154
  courseId: body2.courseId,
@@ -124848,7 +125160,7 @@ var init_timeback_controller = __esm(() => {
124848
125160
  });
124849
125161
  adjustMastery = requireDeveloper(async (ctx) => {
124850
125162
  const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
124851
- logger66.debug("Adjusting mastered units", {
125163
+ logger67.debug("Adjusting mastered units", {
124852
125164
  requesterId: ctx.user.id,
124853
125165
  gameId: body2.gameId,
124854
125166
  courseId: body2.courseId,
@@ -124858,6 +125170,22 @@ var init_timeback_controller = __esm(() => {
124858
125170
  });
124859
125171
  return ctx.services.timebackAdmin.adjustMasteredUnits(body2, ctx.user);
124860
125172
  });
125173
+ reconcileMasteryForConfigChange = requireDeveloper(async (ctx) => {
125174
+ const body2 = await parseRequestBody(ctx.request, ReconcileMasteryForConfigChangeSchema);
125175
+ logger67.debug("Reconciling mastery completion for config change", {
125176
+ requesterId: ctx.user.id,
125177
+ gameId: body2.gameId,
125178
+ courseId: body2.courseId,
125179
+ oldMasterableUnits: body2.oldMasterableUnits,
125180
+ newMasterableUnits: body2.newMasterableUnits,
125181
+ affectedCount: body2.affectedStudentIds.length
125182
+ });
125183
+ return ctx.services.timebackAdmin.reconcileMasteryForConfigChange(body2.gameId, body2.courseId, ctx.user, {
125184
+ oldMasterableUnits: body2.oldMasterableUnits,
125185
+ newMasterableUnits: body2.newMasterableUnits,
125186
+ affectedStudentIds: body2.affectedStudentIds
125187
+ });
125188
+ });
124861
125189
  searchStudents = requireGameManagementAccess(async (ctx) => {
124862
125190
  const gameId = ctx.params.gameId;
124863
125191
  const courseId = ctx.params.courseId;
@@ -124865,7 +125193,7 @@ var init_timeback_controller = __esm(() => {
124865
125193
  if (!gameId || !courseId) {
124866
125194
  throw ApiError.badRequest("Missing gameId or courseId parameter");
124867
125195
  }
124868
- logger66.debug("Searching students for enrollment", {
125196
+ logger67.debug("Searching students for enrollment", {
124869
125197
  requesterId: ctx.user.id,
124870
125198
  gameId,
124871
125199
  courseId,
@@ -124875,7 +125203,7 @@ var init_timeback_controller = __esm(() => {
124875
125203
  });
124876
125204
  enrollStudent = requireGameManagementAccess(async (ctx) => {
124877
125205
  const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
124878
- logger66.debug("Enrolling student", {
125206
+ logger67.debug("Enrolling student", {
124879
125207
  requesterId: ctx.user.id,
124880
125208
  gameId: body2.gameId,
124881
125209
  courseId: body2.courseId,
@@ -124885,7 +125213,7 @@ var init_timeback_controller = __esm(() => {
124885
125213
  });
124886
125214
  unenrollStudent = requireGameManagementAccess(async (ctx) => {
124887
125215
  const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
124888
- logger66.debug("Unenrolling student", {
125216
+ logger67.debug("Unenrolling student", {
124889
125217
  requesterId: ctx.user.id,
124890
125218
  gameId: body2.gameId,
124891
125219
  courseId: body2.courseId,
@@ -124895,7 +125223,7 @@ var init_timeback_controller = __esm(() => {
124895
125223
  });
124896
125224
  reactivateEnrollment = requireGameManagementAccess(async (ctx) => {
124897
125225
  const body2 = await parseRequestBody(ctx.request, ReactivateEnrollmentRequestSchema);
124898
- logger66.debug("Reactivating enrollment", {
125226
+ logger67.debug("Reactivating enrollment", {
124899
125227
  requesterId: ctx.user.id,
124900
125228
  gameId: body2.gameId,
124901
125229
  courseId: body2.courseId,
@@ -125035,6 +125363,8 @@ var init_timeback_controller = __esm(() => {
125035
125363
  getUserById,
125036
125364
  setupIntegration,
125037
125365
  getIntegrations,
125366
+ updateIntegration,
125367
+ getIntegrationConfig,
125038
125368
  verifyIntegration,
125039
125369
  getConfig: getConfig2,
125040
125370
  deleteIntegrations,
@@ -125050,6 +125380,7 @@ var init_timeback_controller = __esm(() => {
125050
125380
  grantXp,
125051
125381
  adjustTime,
125052
125382
  adjustMastery,
125383
+ reconcileMasteryForConfigChange,
125053
125384
  searchStudents,
125054
125385
  enrollStudent,
125055
125386
  unenrollStudent,
@@ -125069,7 +125400,7 @@ var init_timeback_controller = __esm(() => {
125069
125400
  destroyAssessmentBank
125070
125401
  };
125071
125402
  });
125072
- var logger67;
125403
+ var logger68;
125073
125404
  var initiate;
125074
125405
  var init_upload_controller = __esm(() => {
125075
125406
  init_esm();
@@ -125077,7 +125408,7 @@ var init_upload_controller = __esm(() => {
125077
125408
  init_src2();
125078
125409
  init_errors();
125079
125410
  init_utils11();
125080
- logger67 = log.scope("UploadController");
125411
+ logger68 = log.scope("UploadController");
125081
125412
  initiate = requireDeveloper(async (ctx) => {
125082
125413
  let body2;
125083
125414
  try {
@@ -125086,16 +125417,16 @@ var init_upload_controller = __esm(() => {
125086
125417
  } catch (error2) {
125087
125418
  if (error2 instanceof exports_external.ZodError) {
125088
125419
  const details = formatZodError(error2);
125089
- logger67.warn("Initiate upload validation failed", { details });
125420
+ logger68.warn("Initiate upload validation failed", { details });
125090
125421
  throw ApiError.unprocessableEntity("Validation failed", details);
125091
125422
  }
125092
125423
  throw ApiError.badRequest("Invalid JSON body");
125093
125424
  }
125094
- logger67.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
125425
+ logger68.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
125095
125426
  return ctx.services.upload.initiate(body2, ctx.user);
125096
125427
  });
125097
125428
  });
125098
- var logger68;
125429
+ var logger69;
125099
125430
  var getMe;
125100
125431
  var getDemoProfile;
125101
125432
  var updateDemoProfile;
@@ -125104,18 +125435,18 @@ var init_user_controller = __esm(() => {
125104
125435
  init_schemas_index();
125105
125436
  init_src2();
125106
125437
  init_utils11();
125107
- logger68 = log.scope("UserController");
125438
+ logger69 = log.scope("UserController");
125108
125439
  getMe = requireNonAnonymous(async (ctx) => {
125109
- logger68.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
125440
+ logger69.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
125110
125441
  return ctx.services.user.getMe(ctx.user, ctx.gameId);
125111
125442
  });
125112
125443
  getDemoProfile = requireAnonymous(async (ctx) => {
125113
- logger68.debug("Getting demo profile", { userId: ctx.user.id });
125444
+ logger69.debug("Getting demo profile", { userId: ctx.user.id });
125114
125445
  return ctx.services.user.getDemoProfile(ctx.user.id);
125115
125446
  });
125116
125447
  updateDemoProfile = requireAnonymous(async (ctx) => {
125117
125448
  const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
125118
- logger68.debug("Updating demo profile", {
125449
+ logger69.debug("Updating demo profile", {
125119
125450
  userId: ctx.user.id,
125120
125451
  displayName: body2.displayName
125121
125452
  });
@@ -125127,13 +125458,13 @@ var init_user_controller = __esm(() => {
125127
125458
  updateDemoProfile
125128
125459
  };
125129
125460
  });
125130
- var logger69;
125461
+ var logger70;
125131
125462
  var init_verify_controller = __esm(() => {
125132
125463
  init_schemas_index();
125133
125464
  init_src2();
125134
125465
  init_errors();
125135
125466
  init_utils11();
125136
- logger69 = log.scope("VerifyController");
125467
+ logger70 = log.scope("VerifyController");
125137
125468
  });
125138
125469
  var init_controllers = __esm(() => {
125139
125470
  init_achievement_controller();
@@ -125431,7 +125762,7 @@ var init_uploads = __esm(() => {
125431
125762
  gameUploadsRouter.post("/uploads/finalize", finalizeHandler);
125432
125763
  gameUploadsRouter.post("/uploads/finalize/", finalizeHandler);
125433
125764
  });
125434
- var logger70;
125765
+ var logger71;
125435
125766
  var gameDeployRouter;
125436
125767
  var init_deploy = __esm(() => {
125437
125768
  init_drizzle_orm();
@@ -125442,7 +125773,7 @@ var init_deploy = __esm(() => {
125442
125773
  init_src2();
125443
125774
  init_api();
125444
125775
  init_uploads();
125445
- logger70 = log.scope("SandboxDeploy");
125776
+ logger71 = log.scope("SandboxDeploy");
125446
125777
  gameDeployRouter = new Hono2;
125447
125778
  gameDeployRouter.post("/:slug/deploy", async (c2) => {
125448
125779
  const user = c2.get("user");
@@ -125568,7 +125899,7 @@ var init_deploy = __esm(() => {
125568
125899
  completedAt: now2
125569
125900
  };
125570
125901
  const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
125571
- logger70.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
125902
+ logger71.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
125572
125903
  return c2.json({
125573
125904
  id: insertedJob.id,
125574
125905
  status: "succeeded",
@@ -126166,7 +126497,7 @@ function verifyMockToken(idToken) {
126166
126497
  throw new Error("Invalid LTI token format");
126167
126498
  }
126168
126499
  }
126169
- var logger71;
126500
+ var logger72;
126170
126501
  var ltiRouter;
126171
126502
  var init_lti = __esm(() => {
126172
126503
  init_drizzle_orm();
@@ -126177,7 +126508,7 @@ var init_lti = __esm(() => {
126177
126508
  init_src2();
126178
126509
  init_constants();
126179
126510
  init_api();
126180
- logger71 = log.scope("SandboxLti");
126511
+ logger72 = log.scope("SandboxLti");
126181
126512
  ltiRouter = new Hono2;
126182
126513
  ltiRouter.post("/launch", async (c2) => {
126183
126514
  const db2 = c2.get("db");
@@ -126195,7 +126526,7 @@ var init_lti = __esm(() => {
126195
126526
  claims = verifyMockToken(idToken);
126196
126527
  } catch (error2) {
126197
126528
  const errorMessage = error2 instanceof Error ? error2.message : String(error2);
126198
- logger71.error("LTI token verification failed", { error: errorMessage });
126529
+ logger72.error("LTI token verification failed", { error: errorMessage });
126199
126530
  return c2.json({
126200
126531
  error: "invalid_token",
126201
126532
  message: errorMessage
@@ -126203,7 +126534,7 @@ var init_lti = __esm(() => {
126203
126534
  }
126204
126535
  const validationError = validateLtiClaims(claims);
126205
126536
  if (validationError) {
126206
- logger71.warn("LTI claims validation failed", {
126537
+ logger72.warn("LTI claims validation failed", {
126207
126538
  error: validationError,
126208
126539
  sub: claims.sub
126209
126540
  });
@@ -126223,7 +126554,7 @@ var init_lti = __esm(() => {
126223
126554
  createdAt: new Date,
126224
126555
  updatedAt: new Date
126225
126556
  });
126226
- logger71.info("LTI launch successful", { userId: user.id });
126557
+ logger72.info("LTI launch successful", { userId: user.id });
126227
126558
  const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
126228
126559
  const currentHost = new URL(c2.req.url).hostname;
126229
126560
  const redirectPath = extractRedirectPath(targetUri, currentHost);
@@ -126231,7 +126562,7 @@ var init_lti = __esm(() => {
126231
126562
  return c2.redirect(redirectPath);
126232
126563
  } catch (error2) {
126233
126564
  const errorMessage = error2 instanceof Error ? error2.message : String(error2);
126234
- logger71.error("Unexpected error during LTI launch", { error: errorMessage });
126565
+ logger72.error("Unexpected error during LTI launch", { error: errorMessage });
126235
126566
  return c2.json({
126236
126567
  error: "unexpected_error",
126237
126568
  message: "An unexpected error occurred during LTI launch"
@@ -127905,7 +128236,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
127905
128236
  // package.json
127906
128237
  var package_default2 = {
127907
128238
  name: "@playcademy/vite-plugin",
127908
- version: "0.2.34",
128239
+ version: "0.2.35-beta.1",
127909
128240
  type: "module",
127910
128241
  exports: {
127911
128242
  ".": {