@playcademy/sandbox 0.3.17-beta.18 → 0.3.17-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +654 -409
- package/dist/constants.js +2 -1
- package/dist/server.js +654 -409
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -401,7 +401,8 @@ var init_timeback2 = __esm(() => {
|
|
|
401
401
|
TIMEBACK_ROUTES = {
|
|
402
402
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
403
403
|
GET_XP: "/integrations/timeback/xp",
|
|
404
|
-
HEARTBEAT: "/integrations/timeback/heartbeat"
|
|
404
|
+
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
405
|
+
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
405
406
|
};
|
|
406
407
|
TIMEBACK_COURSE_DEFAULTS = {
|
|
407
408
|
gradingScheme: "STANDARD",
|
|
@@ -1329,7 +1330,7 @@ var package_default;
|
|
|
1329
1330
|
var init_package = __esm(() => {
|
|
1330
1331
|
package_default = {
|
|
1331
1332
|
name: "@playcademy/sandbox",
|
|
1332
|
-
version: "0.3.17-beta.
|
|
1333
|
+
version: "0.3.17-beta.19",
|
|
1333
1334
|
description: "Local development server for Playcademy game development",
|
|
1334
1335
|
type: "module",
|
|
1335
1336
|
exports: {
|
|
@@ -28900,7 +28901,8 @@ var init_constants3 = __esm(() => {
|
|
|
28900
28901
|
TIMEBACK: {
|
|
28901
28902
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
28902
28903
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
28903
|
-
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}
|
|
28904
|
+
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
28905
|
+
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`
|
|
28904
28906
|
}
|
|
28905
28907
|
};
|
|
28906
28908
|
});
|
|
@@ -31231,6 +31233,7 @@ class TimebackAdminService {
|
|
|
31231
31233
|
await client.edubridge.enrollments.enroll(data.studentId, data.courseId, {
|
|
31232
31234
|
role: "student"
|
|
31233
31235
|
});
|
|
31236
|
+
client.invalidateEnrollments(data.studentId);
|
|
31234
31237
|
return { status: "ok" };
|
|
31235
31238
|
}
|
|
31236
31239
|
async unenrollStudent(data, user) {
|
|
@@ -31243,6 +31246,7 @@ class TimebackAdminService {
|
|
|
31243
31246
|
throw new NotFoundError("Timeback integration", `${data.gameId}:${data.courseId}`);
|
|
31244
31247
|
}
|
|
31245
31248
|
await client.edubridge.enrollments.unenroll(data.studentId, data.courseId);
|
|
31249
|
+
client.invalidateEnrollments(data.studentId);
|
|
31246
31250
|
return { status: "ok" };
|
|
31247
31251
|
}
|
|
31248
31252
|
async getCompletionStatus(client, courseId, studentId) {
|
|
@@ -31299,8 +31303,106 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
31299
31303
|
logger16 = log.scope("TimebackAdminService");
|
|
31300
31304
|
});
|
|
31301
31305
|
|
|
31306
|
+
// ../api-core/src/utils/timeback-promotion.util.ts
|
|
31307
|
+
async function promoteCompletedCourse({
|
|
31308
|
+
db: db2,
|
|
31309
|
+
client,
|
|
31310
|
+
currentIntegration,
|
|
31311
|
+
studentId,
|
|
31312
|
+
enrollments: prefetchedEnrollments
|
|
31313
|
+
}) {
|
|
31314
|
+
const subjectIntegrations = await db2.query.gameTimebackIntegrations.findMany({
|
|
31315
|
+
where: and(eq(gameTimebackIntegrations.gameId, currentIntegration.gameId), eq(gameTimebackIntegrations.subject, currentIntegration.subject))
|
|
31316
|
+
});
|
|
31317
|
+
const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
|
|
31318
|
+
if (!nextIntegration) {
|
|
31319
|
+
logger17.debug("Skipping promotion because no next course is configured", {
|
|
31320
|
+
gameId: currentIntegration.gameId,
|
|
31321
|
+
studentId,
|
|
31322
|
+
grade: currentIntegration.grade,
|
|
31323
|
+
subject: currentIntegration.subject,
|
|
31324
|
+
currentCourseId: currentIntegration.courseId
|
|
31325
|
+
});
|
|
31326
|
+
return {
|
|
31327
|
+
status: "no-next-course",
|
|
31328
|
+
currentCourseId: currentIntegration.courseId
|
|
31329
|
+
};
|
|
31330
|
+
}
|
|
31331
|
+
const enrollments = prefetchedEnrollments ?? await client.edubridge.enrollments.listByUser(studentId);
|
|
31332
|
+
const currentEnrollment = enrollments.find((enrollment) => enrollment.course.id === currentIntegration.courseId);
|
|
31333
|
+
const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
|
|
31334
|
+
if (!currentEnrollment) {
|
|
31335
|
+
if (nextEnrollment) {
|
|
31336
|
+
logger17.debug("Skipping promotion because student is already on the next course", {
|
|
31337
|
+
gameId: currentIntegration.gameId,
|
|
31338
|
+
studentId,
|
|
31339
|
+
grade: currentIntegration.grade,
|
|
31340
|
+
subject: currentIntegration.subject,
|
|
31341
|
+
currentCourseId: currentIntegration.courseId,
|
|
31342
|
+
nextCourseId: nextIntegration.courseId
|
|
31343
|
+
});
|
|
31344
|
+
return {
|
|
31345
|
+
status: "already-promoted",
|
|
31346
|
+
currentCourseId: currentIntegration.courseId,
|
|
31347
|
+
nextCourseId: nextIntegration.courseId
|
|
31348
|
+
};
|
|
31349
|
+
}
|
|
31350
|
+
logger17.debug("Skipping promotion because student is not enrolled in the current course", {
|
|
31351
|
+
gameId: currentIntegration.gameId,
|
|
31352
|
+
studentId,
|
|
31353
|
+
grade: currentIntegration.grade,
|
|
31354
|
+
subject: currentIntegration.subject,
|
|
31355
|
+
currentCourseId: currentIntegration.courseId,
|
|
31356
|
+
nextCourseId: nextIntegration.courseId
|
|
31357
|
+
});
|
|
31358
|
+
return {
|
|
31359
|
+
status: "not-enrolled",
|
|
31360
|
+
currentCourseId: currentIntegration.courseId,
|
|
31361
|
+
nextCourseId: nextIntegration.courseId
|
|
31362
|
+
};
|
|
31363
|
+
}
|
|
31364
|
+
const schoolId = currentEnrollment.school.id;
|
|
31365
|
+
let mutatedEnrollments = false;
|
|
31366
|
+
try {
|
|
31367
|
+
if (!nextEnrollment) {
|
|
31368
|
+
await client.edubridge.enrollments.enroll(studentId, nextIntegration.courseId, {
|
|
31369
|
+
role: "student",
|
|
31370
|
+
...schoolId ? { schoolId } : {}
|
|
31371
|
+
});
|
|
31372
|
+
mutatedEnrollments = true;
|
|
31373
|
+
}
|
|
31374
|
+
await client.edubridge.enrollments.unenroll(studentId, currentIntegration.courseId, schoolId ? { schoolId } : {});
|
|
31375
|
+
mutatedEnrollments = true;
|
|
31376
|
+
} finally {
|
|
31377
|
+
if (mutatedEnrollments) {
|
|
31378
|
+
client.invalidateEnrollments(studentId);
|
|
31379
|
+
}
|
|
31380
|
+
}
|
|
31381
|
+
logger17.info("Promoted student to next course", {
|
|
31382
|
+
gameId: currentIntegration.gameId,
|
|
31383
|
+
studentId,
|
|
31384
|
+
subject: currentIntegration.subject,
|
|
31385
|
+
fromGrade: currentIntegration.grade,
|
|
31386
|
+
toGrade: nextIntegration.grade,
|
|
31387
|
+
currentCourseId: currentIntegration.courseId,
|
|
31388
|
+
nextCourseId: nextIntegration.courseId
|
|
31389
|
+
});
|
|
31390
|
+
return {
|
|
31391
|
+
status: "promoted",
|
|
31392
|
+
currentCourseId: currentIntegration.courseId,
|
|
31393
|
+
nextCourseId: nextIntegration.courseId
|
|
31394
|
+
};
|
|
31395
|
+
}
|
|
31396
|
+
var logger17;
|
|
31397
|
+
var init_timeback_promotion_util = __esm(() => {
|
|
31398
|
+
init_drizzle_orm();
|
|
31399
|
+
init_tables_index();
|
|
31400
|
+
init_src2();
|
|
31401
|
+
logger17 = log.scope("TimebackPromotion");
|
|
31402
|
+
});
|
|
31403
|
+
|
|
31302
31404
|
// ../api-core/src/services/timeback.service.ts
|
|
31303
|
-
var
|
|
31405
|
+
var logger18, TimebackService;
|
|
31304
31406
|
var init_timeback_service = __esm(() => {
|
|
31305
31407
|
init_drizzle_orm();
|
|
31306
31408
|
init_src();
|
|
@@ -31309,8 +31411,9 @@ var init_timeback_service = __esm(() => {
|
|
|
31309
31411
|
init_types4();
|
|
31310
31412
|
init_src4();
|
|
31311
31413
|
init_errors();
|
|
31414
|
+
init_timeback_promotion_util();
|
|
31312
31415
|
init_timeback_util();
|
|
31313
|
-
|
|
31416
|
+
logger18 = log.scope("TimebackService");
|
|
31314
31417
|
TimebackService = class TimebackService {
|
|
31315
31418
|
static HEARTBEAT_DEDUPE_TTL_MS = 5 * 60 * 1000;
|
|
31316
31419
|
static processedHeartbeatWindows = new Map;
|
|
@@ -31356,7 +31459,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31356
31459
|
}
|
|
31357
31460
|
requireClient() {
|
|
31358
31461
|
if (!this.deps.timeback) {
|
|
31359
|
-
|
|
31462
|
+
logger18.error("Timeback client not available in context");
|
|
31360
31463
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
31361
31464
|
}
|
|
31362
31465
|
return this.deps.timeback;
|
|
@@ -31409,7 +31512,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31409
31512
|
set: { xp: sql`excluded.xp`, updatedAt: new Date }
|
|
31410
31513
|
}).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
|
|
31411
31514
|
if (!result) {
|
|
31412
|
-
|
|
31515
|
+
logger18.error("Daily XP upsert returned no rows", { userId, date: targetDate });
|
|
31413
31516
|
throw new InternalError("Failed to update daily XP record");
|
|
31414
31517
|
}
|
|
31415
31518
|
return { xp: result.xp, date: result.date.toISOString() };
|
|
@@ -31440,7 +31543,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31440
31543
|
columns: { id: true, timebackId: true }
|
|
31441
31544
|
});
|
|
31442
31545
|
if (dbUser?.timebackId) {
|
|
31443
|
-
|
|
31546
|
+
logger18.info("Student already onboarded", { userId: user.id });
|
|
31444
31547
|
return { status: "already_populated" };
|
|
31445
31548
|
}
|
|
31446
31549
|
let timebackId;
|
|
@@ -31449,7 +31552,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31449
31552
|
const existingUser = await client.oneroster.users.findByEmail(user.email);
|
|
31450
31553
|
timebackId = existingUser.sourcedId;
|
|
31451
31554
|
name3 = `${existingUser.givenName} ${existingUser.familyName}`;
|
|
31452
|
-
|
|
31555
|
+
logger18.info("Found existing student in OneRoster", {
|
|
31453
31556
|
userId: user.id,
|
|
31454
31557
|
timebackId
|
|
31455
31558
|
});
|
|
@@ -31478,7 +31581,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31478
31581
|
}
|
|
31479
31582
|
timebackId = response.sourcedIdPairs.allocatedSourcedId;
|
|
31480
31583
|
name3 = `${providedNames.firstName} ${providedNames.lastName}`;
|
|
31481
|
-
|
|
31584
|
+
logger18.info("Created student in OneRoster", { userId: user.id, timebackId });
|
|
31482
31585
|
}
|
|
31483
31586
|
const assessments = await this.fetchAssessments(timebackId);
|
|
31484
31587
|
await db2.transaction(async (tx) => {
|
|
@@ -31512,7 +31615,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31512
31615
|
}
|
|
31513
31616
|
const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
|
|
31514
31617
|
if (!updated) {
|
|
31515
|
-
|
|
31618
|
+
logger18.error("User Timeback ID update returned no rows", {
|
|
31516
31619
|
userId: user.id,
|
|
31517
31620
|
timebackId
|
|
31518
31621
|
});
|
|
@@ -31536,13 +31639,13 @@ var init_timeback_service = __esm(() => {
|
|
|
31536
31639
|
}
|
|
31537
31640
|
offset += limit;
|
|
31538
31641
|
}
|
|
31539
|
-
|
|
31642
|
+
logger18.debug("Fetched assessments", {
|
|
31540
31643
|
studentSourcedId,
|
|
31541
31644
|
totalCount: allAssessments.length
|
|
31542
31645
|
});
|
|
31543
31646
|
return allAssessments;
|
|
31544
31647
|
} catch (error) {
|
|
31545
|
-
|
|
31648
|
+
logger18.warn("Failed to fetch assessments", { studentSourcedId, error });
|
|
31546
31649
|
return [];
|
|
31547
31650
|
}
|
|
31548
31651
|
}
|
|
@@ -31655,7 +31758,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31655
31758
|
masterableUnits: derivedMasterableUnits
|
|
31656
31759
|
} = courseConfig;
|
|
31657
31760
|
if (!isTimebackSubject(subjectInput)) {
|
|
31658
|
-
|
|
31761
|
+
logger18.warn("Invalid Timeback subject in course config", {
|
|
31659
31762
|
subject: subjectInput,
|
|
31660
31763
|
courseCode,
|
|
31661
31764
|
title
|
|
@@ -31663,7 +31766,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31663
31766
|
throw new ValidationError(`Invalid subject "${subjectInput}"`);
|
|
31664
31767
|
}
|
|
31665
31768
|
if (!isTimebackGrade(grade)) {
|
|
31666
|
-
|
|
31769
|
+
logger18.warn("Invalid Timeback grade in course config", {
|
|
31667
31770
|
grade,
|
|
31668
31771
|
courseCode,
|
|
31669
31772
|
title
|
|
@@ -31675,7 +31778,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31675
31778
|
const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
|
|
31676
31779
|
const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
|
|
31677
31780
|
if (typeof totalXp !== "number") {
|
|
31678
|
-
|
|
31781
|
+
logger18.warn("Course missing totalXp in Timeback config", {
|
|
31679
31782
|
courseCode,
|
|
31680
31783
|
title
|
|
31681
31784
|
});
|
|
@@ -31876,7 +31979,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31876
31979
|
...runId ? { runId } : {}
|
|
31877
31980
|
});
|
|
31878
31981
|
}
|
|
31879
|
-
|
|
31982
|
+
logger18.info("Recorded activity completion", {
|
|
31880
31983
|
gameId,
|
|
31881
31984
|
courseId: integration.courseId,
|
|
31882
31985
|
studentId,
|
|
@@ -31893,6 +31996,72 @@ var init_timeback_service = __esm(() => {
|
|
|
31893
31996
|
inProgress: result.inProgress
|
|
31894
31997
|
};
|
|
31895
31998
|
}
|
|
31999
|
+
async advanceCourse({
|
|
32000
|
+
gameId,
|
|
32001
|
+
studentId,
|
|
32002
|
+
subject,
|
|
32003
|
+
user
|
|
32004
|
+
}) {
|
|
32005
|
+
const client = this.requireClient();
|
|
32006
|
+
const db2 = this.deps.db;
|
|
32007
|
+
await this.deps.validateDeveloperAccess(user, gameId);
|
|
32008
|
+
const integrations = await db2.query.gameTimebackIntegrations.findMany({
|
|
32009
|
+
where: subject ? and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.subject, subject)) : eq(gameTimebackIntegrations.gameId, gameId)
|
|
32010
|
+
});
|
|
32011
|
+
if (integrations.length === 0) {
|
|
32012
|
+
throw new NotFoundError(subject ? `Timeback integrations for game (subject ${subject})` : "Timeback integrations for game");
|
|
32013
|
+
}
|
|
32014
|
+
const enrollments = await client.edubridge.enrollments.listByUser(studentId);
|
|
32015
|
+
const enrolledCourseIds = new Set(enrollments.map((e) => e.course.id));
|
|
32016
|
+
const enrolledIntegrations = integrations.filter((integration) => enrolledCourseIds.has(integration.courseId));
|
|
32017
|
+
if (enrolledIntegrations.length === 0) {
|
|
32018
|
+
throw new NotFoundError(subject ? `Active enrollment for game ladder (subject ${subject})` : "Active enrollment for game ladder");
|
|
32019
|
+
}
|
|
32020
|
+
const subjectsInPlay = new Set(enrolledIntegrations.map((i2) => i2.subject));
|
|
32021
|
+
if (subjectsInPlay.size > 1) {
|
|
32022
|
+
throw new ValidationError(`Ambiguous Timeback advance: student is enrolled in ${subjectsInPlay.size} parallel ladders (${[...subjectsInPlay].join(", ")}); pass { subject } to disambiguate`);
|
|
32023
|
+
}
|
|
32024
|
+
const currentIntegration = enrolledIntegrations.toSorted((left, right) => left.grade - right.grade)[0];
|
|
32025
|
+
const masteryStatus = await client.getMasteryStatus(currentIntegration.courseId, studentId);
|
|
32026
|
+
if (!masteryStatus) {
|
|
32027
|
+
throw new ValidationError(`Cannot advance course: mastery status is unavailable for course ${currentIntegration.courseId}. Ensure the course has mastery configuration and the student has enrollment analytics before calling client.timeback.advanceCourse().`);
|
|
32028
|
+
}
|
|
32029
|
+
if (!masteryStatus.isComplete) {
|
|
32030
|
+
const promotion2 = {
|
|
32031
|
+
status: "not-mastered",
|
|
32032
|
+
currentCourseId: currentIntegration.courseId,
|
|
32033
|
+
masteredUnits: masteryStatus.masteredUnits,
|
|
32034
|
+
masterableUnits: masteryStatus.masterableUnits
|
|
32035
|
+
};
|
|
32036
|
+
logger18.debug("Skipping course advancement because mastery is incomplete", {
|
|
32037
|
+
gameId,
|
|
32038
|
+
studentId,
|
|
32039
|
+
subject: currentIntegration.subject,
|
|
32040
|
+
grade: currentIntegration.grade,
|
|
32041
|
+
currentCourseId: currentIntegration.courseId,
|
|
32042
|
+
masteredUnits: masteryStatus.masteredUnits,
|
|
32043
|
+
masterableUnits: masteryStatus.masterableUnits
|
|
32044
|
+
});
|
|
32045
|
+
return { status: "ok", promotion: promotion2 };
|
|
32046
|
+
}
|
|
32047
|
+
const promotion = await promoteCompletedCourse({
|
|
32048
|
+
db: db2,
|
|
32049
|
+
client,
|
|
32050
|
+
currentIntegration,
|
|
32051
|
+
studentId,
|
|
32052
|
+
enrollments
|
|
32053
|
+
});
|
|
32054
|
+
logger18.info("Manually advanced student", {
|
|
32055
|
+
gameId,
|
|
32056
|
+
studentId,
|
|
32057
|
+
subject: currentIntegration.subject,
|
|
32058
|
+
grade: currentIntegration.grade,
|
|
32059
|
+
promotionStatus: promotion.status,
|
|
32060
|
+
currentCourseId: promotion.currentCourseId,
|
|
32061
|
+
nextCourseId: promotion.nextCourseId
|
|
32062
|
+
});
|
|
32063
|
+
return { status: "ok", promotion };
|
|
32064
|
+
}
|
|
31896
32065
|
async recordHeartbeat({
|
|
31897
32066
|
gameId,
|
|
31898
32067
|
studentId,
|
|
@@ -31915,7 +32084,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31915
32084
|
const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
|
|
31916
32085
|
const effectiveResumeId = resumeId ?? runId;
|
|
31917
32086
|
if (TimebackService.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
|
|
31918
|
-
|
|
32087
|
+
logger18.debug("Skipping duplicate heartbeat window", {
|
|
31919
32088
|
gameId,
|
|
31920
32089
|
studentId,
|
|
31921
32090
|
runId,
|
|
@@ -31928,7 +32097,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31928
32097
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
31929
32098
|
const inFlightHeartbeat = TimebackService.getInFlightHeartbeatWindow(heartbeatWindowKey);
|
|
31930
32099
|
if (inFlightHeartbeat) {
|
|
31931
|
-
|
|
32100
|
+
logger18.debug("Joining in-flight heartbeat window", {
|
|
31932
32101
|
gameId,
|
|
31933
32102
|
studentId,
|
|
31934
32103
|
runId,
|
|
@@ -31965,7 +32134,7 @@ var init_timeback_service = __esm(() => {
|
|
|
31965
32134
|
});
|
|
31966
32135
|
}
|
|
31967
32136
|
TimebackService.markHeartbeatWindowProcessed(heartbeatWindowKey);
|
|
31968
|
-
|
|
32137
|
+
logger18.debug("Recorded heartbeat", {
|
|
31969
32138
|
gameId,
|
|
31970
32139
|
courseId: integration.courseId,
|
|
31971
32140
|
studentId,
|
|
@@ -32000,7 +32169,7 @@ var init_timeback_service = __esm(() => {
|
|
|
32000
32169
|
});
|
|
32001
32170
|
courseIds = integrations.map((i2) => i2.courseId);
|
|
32002
32171
|
if (courseIds.length === 0) {
|
|
32003
|
-
|
|
32172
|
+
logger18.debug("No integrations found for game, returning 0 XP", {
|
|
32004
32173
|
timebackId,
|
|
32005
32174
|
gameId: options.gameId,
|
|
32006
32175
|
grade: options.grade,
|
|
@@ -32017,7 +32186,7 @@ var init_timeback_service = __esm(() => {
|
|
|
32017
32186
|
courseIds: courseIds.length > 0 ? courseIds : undefined,
|
|
32018
32187
|
include: options?.include
|
|
32019
32188
|
});
|
|
32020
|
-
|
|
32189
|
+
logger18.debug("Retrieved student XP", {
|
|
32021
32190
|
timebackId,
|
|
32022
32191
|
gameId: options?.gameId,
|
|
32023
32192
|
grade: options?.grade,
|
|
@@ -32046,15 +32215,15 @@ class UploadService {
|
|
|
32046
32215
|
const { fileName, gameId } = request;
|
|
32047
32216
|
const bucketName = this.deps.uploadBucket;
|
|
32048
32217
|
if (!bucketName) {
|
|
32049
|
-
|
|
32218
|
+
logger19.error("Upload bucket not configured in environment");
|
|
32050
32219
|
throw new ValidationError("Upload bucket not configured");
|
|
32051
32220
|
}
|
|
32052
32221
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
32053
32222
|
const version2 = ulid();
|
|
32054
32223
|
const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
|
|
32055
|
-
|
|
32224
|
+
logger19.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
|
|
32056
32225
|
const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
|
|
32057
|
-
|
|
32226
|
+
logger19.info("Presigned URL generated", {
|
|
32058
32227
|
userId: user.id,
|
|
32059
32228
|
gameId,
|
|
32060
32229
|
version: version2
|
|
@@ -32067,12 +32236,12 @@ class UploadService {
|
|
|
32067
32236
|
};
|
|
32068
32237
|
}
|
|
32069
32238
|
}
|
|
32070
|
-
var
|
|
32239
|
+
var logger19;
|
|
32071
32240
|
var init_upload_service = __esm(() => {
|
|
32072
32241
|
init_node();
|
|
32073
32242
|
init_src2();
|
|
32074
32243
|
init_errors();
|
|
32075
|
-
|
|
32244
|
+
logger19 = log.scope("UploadService");
|
|
32076
32245
|
});
|
|
32077
32246
|
|
|
32078
32247
|
// ../api-core/src/services/factory/platform.ts
|
|
@@ -32377,7 +32546,7 @@ class AchievementService {
|
|
|
32377
32546
|
results.push(result);
|
|
32378
32547
|
}
|
|
32379
32548
|
}
|
|
32380
|
-
|
|
32549
|
+
logger20.debug("Listed current achievements", { userId: user.id, count: results.length });
|
|
32381
32550
|
return results;
|
|
32382
32551
|
}
|
|
32383
32552
|
async listHistory(user, limit) {
|
|
@@ -32395,14 +32564,14 @@ class AchievementService {
|
|
|
32395
32564
|
createdAt: c.createdAt,
|
|
32396
32565
|
scopeKey: c.scopeKey
|
|
32397
32566
|
}));
|
|
32398
|
-
|
|
32567
|
+
logger20.debug("Listed achievement history", { userId: user.id, count: results.length });
|
|
32399
32568
|
return results;
|
|
32400
32569
|
}
|
|
32401
32570
|
async submitProgress(achievementId, user) {
|
|
32402
32571
|
const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
|
|
32403
32572
|
broadcast: false
|
|
32404
32573
|
});
|
|
32405
|
-
|
|
32574
|
+
logger20.debug("Submitted progress", {
|
|
32406
32575
|
userId: user.id,
|
|
32407
32576
|
achievementId,
|
|
32408
32577
|
wasNewClaim
|
|
@@ -32434,7 +32603,7 @@ class AchievementService {
|
|
|
32434
32603
|
rewardCredits
|
|
32435
32604
|
}).returning();
|
|
32436
32605
|
if (!newClaim) {
|
|
32437
|
-
|
|
32606
|
+
logger20.error("Achievement claim insert returned no rows", {
|
|
32438
32607
|
userId,
|
|
32439
32608
|
achievementId,
|
|
32440
32609
|
scopeKey
|
|
@@ -32443,7 +32612,7 @@ class AchievementService {
|
|
|
32443
32612
|
}
|
|
32444
32613
|
await this.deps.addCredits(userId, rewardCredits);
|
|
32445
32614
|
await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
|
|
32446
|
-
|
|
32615
|
+
logger20.info("Awarded achievement", {
|
|
32447
32616
|
userId,
|
|
32448
32617
|
achievementId,
|
|
32449
32618
|
scopeKey,
|
|
@@ -32480,7 +32649,7 @@ class AchievementService {
|
|
|
32480
32649
|
return { title, body: body2 };
|
|
32481
32650
|
}
|
|
32482
32651
|
}
|
|
32483
|
-
var
|
|
32652
|
+
var logger20;
|
|
32484
32653
|
var init_achievement_service = __esm(() => {
|
|
32485
32654
|
init_drizzle_orm();
|
|
32486
32655
|
init_tables_index();
|
|
@@ -32489,7 +32658,7 @@ var init_achievement_service = __esm(() => {
|
|
|
32489
32658
|
init_errors();
|
|
32490
32659
|
init_leaderboard_util();
|
|
32491
32660
|
init_scope_util();
|
|
32492
|
-
|
|
32661
|
+
logger20 = log.scope("AchievementService");
|
|
32493
32662
|
});
|
|
32494
32663
|
|
|
32495
32664
|
// ../api-core/src/services/inventory.service.ts
|
|
@@ -32517,7 +32686,7 @@ class InventoryService {
|
|
|
32517
32686
|
},
|
|
32518
32687
|
updatedAt: inventoryItems.updatedAt
|
|
32519
32688
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
32520
|
-
|
|
32689
|
+
logger21.debug("Listed inventory", { userId: user.id, count: inventory.length });
|
|
32521
32690
|
return inventory;
|
|
32522
32691
|
}
|
|
32523
32692
|
async addItem(itemId, quantity, user) {
|
|
@@ -32534,7 +32703,7 @@ class InventoryService {
|
|
|
32534
32703
|
const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
|
|
32535
32704
|
return inserted?.quantity ?? 0;
|
|
32536
32705
|
});
|
|
32537
|
-
|
|
32706
|
+
logger21.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
|
|
32538
32707
|
return { newTotal };
|
|
32539
32708
|
}
|
|
32540
32709
|
async removeItem(itemId, quantity, user) {
|
|
@@ -32545,7 +32714,7 @@ class InventoryService {
|
|
|
32545
32714
|
}
|
|
32546
32715
|
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);
|
|
32547
32716
|
if (!currentItem) {
|
|
32548
|
-
|
|
32717
|
+
logger21.warn("Insufficient inventory for removal", {
|
|
32549
32718
|
userId: user.id,
|
|
32550
32719
|
itemId,
|
|
32551
32720
|
requestedQuantity: quantity
|
|
@@ -32555,13 +32724,13 @@ class InventoryService {
|
|
|
32555
32724
|
const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
|
|
32556
32725
|
return updated?.quantity ?? 0;
|
|
32557
32726
|
});
|
|
32558
|
-
|
|
32727
|
+
logger21.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
|
|
32559
32728
|
return { newTotal };
|
|
32560
32729
|
}
|
|
32561
32730
|
async addCredits(userId, amount) {
|
|
32562
32731
|
const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
32563
32732
|
if (!creditsItem) {
|
|
32564
|
-
|
|
32733
|
+
logger21.error("Primary currency not found", {
|
|
32565
32734
|
userId,
|
|
32566
32735
|
amount
|
|
32567
32736
|
});
|
|
@@ -32574,17 +32743,17 @@ class InventoryService {
|
|
|
32574
32743
|
updatedAt: new Date
|
|
32575
32744
|
}
|
|
32576
32745
|
});
|
|
32577
|
-
|
|
32746
|
+
logger21.debug("Added credits", { userId, amount });
|
|
32578
32747
|
}
|
|
32579
32748
|
}
|
|
32580
|
-
var
|
|
32749
|
+
var logger21;
|
|
32581
32750
|
var init_inventory_service = __esm(() => {
|
|
32582
32751
|
init_drizzle_orm();
|
|
32583
32752
|
init_src();
|
|
32584
32753
|
init_tables_index();
|
|
32585
32754
|
init_src2();
|
|
32586
32755
|
init_errors();
|
|
32587
|
-
|
|
32756
|
+
logger21 = log.scope("InventoryService");
|
|
32588
32757
|
});
|
|
32589
32758
|
|
|
32590
32759
|
// ../types/src/notification.ts
|
|
@@ -32639,7 +32808,7 @@ class LeaderboardService {
|
|
|
32639
32808
|
sessionId
|
|
32640
32809
|
}).returning();
|
|
32641
32810
|
if (!newScore) {
|
|
32642
|
-
|
|
32811
|
+
logger22.error("Score insert returned no rows", { userId, gameId, score: input.score });
|
|
32643
32812
|
throw new InternalError("Failed to insert score");
|
|
32644
32813
|
}
|
|
32645
32814
|
const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
|
|
@@ -32667,7 +32836,7 @@ class LeaderboardService {
|
|
|
32667
32836
|
movedUpWithinTop3
|
|
32668
32837
|
});
|
|
32669
32838
|
}
|
|
32670
|
-
|
|
32839
|
+
logger22.info("Score submitted", {
|
|
32671
32840
|
gameId,
|
|
32672
32841
|
userId,
|
|
32673
32842
|
isAnonymousUser,
|
|
@@ -32744,7 +32913,7 @@ class LeaderboardService {
|
|
|
32744
32913
|
});
|
|
32745
32914
|
}
|
|
32746
32915
|
} catch (error) {
|
|
32747
|
-
|
|
32916
|
+
logger22.warn("Failed to publish notification", { error });
|
|
32748
32917
|
}
|
|
32749
32918
|
}
|
|
32750
32919
|
async getLeaderboard(gameId, query, isAnonymousUser) {
|
|
@@ -32863,7 +33032,7 @@ class LeaderboardService {
|
|
|
32863
33032
|
return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
|
|
32864
33033
|
}
|
|
32865
33034
|
}
|
|
32866
|
-
var
|
|
33035
|
+
var logger22;
|
|
32867
33036
|
var init_leaderboard_service = __esm(() => {
|
|
32868
33037
|
init_drizzle_orm();
|
|
32869
33038
|
init_src();
|
|
@@ -32873,7 +33042,7 @@ var init_leaderboard_service = __esm(() => {
|
|
|
32873
33042
|
init_notification();
|
|
32874
33043
|
init_errors();
|
|
32875
33044
|
init_leaderboard_util();
|
|
32876
|
-
|
|
33045
|
+
logger22 = log.scope("LeaderboardService");
|
|
32877
33046
|
});
|
|
32878
33047
|
|
|
32879
33048
|
// ../api-core/src/services/level.service.ts
|
|
@@ -32889,9 +33058,9 @@ class LevelService {
|
|
|
32889
33058
|
for (const config2 of configs) {
|
|
32890
33059
|
levelConfigCache.set(config2.level, config2);
|
|
32891
33060
|
}
|
|
32892
|
-
|
|
33061
|
+
logger23.info("Cache pre-warmed", { count: configs.length });
|
|
32893
33062
|
} catch (error) {
|
|
32894
|
-
|
|
33063
|
+
logger23.error("Cache pre-warm failed", { error });
|
|
32895
33064
|
}
|
|
32896
33065
|
}
|
|
32897
33066
|
async getConfig(level) {
|
|
@@ -32925,7 +33094,7 @@ class LevelService {
|
|
|
32925
33094
|
totalXP
|
|
32926
33095
|
}).returning();
|
|
32927
33096
|
if (!newUserLevel) {
|
|
32928
|
-
|
|
33097
|
+
logger23.error("User level insert returned no rows", { userId: user.id });
|
|
32929
33098
|
throw new InternalError("Failed to create user level cache record");
|
|
32930
33099
|
}
|
|
32931
33100
|
userLevel = newUserLevel;
|
|
@@ -32940,7 +33109,7 @@ class LevelService {
|
|
|
32940
33109
|
userLevel = updatedUserLevel;
|
|
32941
33110
|
}
|
|
32942
33111
|
}
|
|
32943
|
-
|
|
33112
|
+
logger23.debug("Retrieved user level", {
|
|
32944
33113
|
userId: user.id,
|
|
32945
33114
|
totalXP,
|
|
32946
33115
|
currentLevel,
|
|
@@ -32951,7 +33120,7 @@ class LevelService {
|
|
|
32951
33120
|
async getProgress(user) {
|
|
32952
33121
|
const userLevel = await this.getByUser(user);
|
|
32953
33122
|
const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
|
|
32954
|
-
|
|
33123
|
+
logger23.debug("Retrieved progress", { userId: user.id });
|
|
32955
33124
|
return {
|
|
32956
33125
|
level: userLevel.currentLevel,
|
|
32957
33126
|
currentXp: userLevel.currentXp,
|
|
@@ -32985,7 +33154,7 @@ class LevelService {
|
|
|
32985
33154
|
if (leveledUp && previousUserLevel) {
|
|
32986
33155
|
await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
|
|
32987
33156
|
}
|
|
32988
|
-
|
|
33157
|
+
logger23.info("Synced from Timeback", {
|
|
32989
33158
|
userId,
|
|
32990
33159
|
totalXP,
|
|
32991
33160
|
currentLevel,
|
|
@@ -33026,7 +33195,7 @@ class LevelService {
|
|
|
33026
33195
|
}
|
|
33027
33196
|
if (totalCredits > 0) {
|
|
33028
33197
|
await this.deps.addCredits(userId, totalCredits);
|
|
33029
|
-
|
|
33198
|
+
logger23.info("Awarded level-up credits", {
|
|
33030
33199
|
userId,
|
|
33031
33200
|
fromLevel,
|
|
33032
33201
|
toLevel,
|
|
@@ -33064,14 +33233,14 @@ class LevelService {
|
|
|
33064
33233
|
};
|
|
33065
33234
|
}
|
|
33066
33235
|
}
|
|
33067
|
-
var
|
|
33236
|
+
var logger23, levelConfigCache = null;
|
|
33068
33237
|
var init_level_service = __esm(() => {
|
|
33069
33238
|
init_drizzle_orm();
|
|
33070
33239
|
init_src();
|
|
33071
33240
|
init_tables_index();
|
|
33072
33241
|
init_src2();
|
|
33073
33242
|
init_errors();
|
|
33074
|
-
|
|
33243
|
+
logger23 = log.scope("LevelService");
|
|
33075
33244
|
});
|
|
33076
33245
|
|
|
33077
33246
|
// ../realtime/src/server/domain/events.ts
|
|
@@ -33092,13 +33261,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
|
|
|
33092
33261
|
});
|
|
33093
33262
|
if (!res.ok) {
|
|
33094
33263
|
const text3 = await res.text().catch(() => "");
|
|
33095
|
-
|
|
33264
|
+
logger24.warn("Failed to publish to user", {
|
|
33096
33265
|
status: res.status,
|
|
33097
33266
|
body: text3
|
|
33098
33267
|
});
|
|
33099
33268
|
}
|
|
33100
33269
|
} catch (error) {
|
|
33101
|
-
|
|
33270
|
+
logger24.error("Publish to user error", { error });
|
|
33102
33271
|
}
|
|
33103
33272
|
}
|
|
33104
33273
|
|
|
@@ -33120,7 +33289,7 @@ class NotificationService {
|
|
|
33120
33289
|
conditions2.push(eq(notifications.type, type));
|
|
33121
33290
|
}
|
|
33122
33291
|
const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
|
|
33123
|
-
|
|
33292
|
+
logger24.debug("Listed notifications", { userId: user.id, count: results.length });
|
|
33124
33293
|
return results;
|
|
33125
33294
|
}
|
|
33126
33295
|
async updateStatus(notificationId, status, method) {
|
|
@@ -33139,7 +33308,7 @@ class NotificationService {
|
|
|
33139
33308
|
if (!updated) {
|
|
33140
33309
|
throw new NotFoundError("Notification", notificationId);
|
|
33141
33310
|
}
|
|
33142
|
-
|
|
33311
|
+
logger24.debug("Updated status", { notificationId, status });
|
|
33143
33312
|
return updated;
|
|
33144
33313
|
}
|
|
33145
33314
|
async getStats(user, options) {
|
|
@@ -33165,7 +33334,7 @@ class NotificationService {
|
|
|
33165
33334
|
const clicked = statsMap.clicked || 0;
|
|
33166
33335
|
const dismissed = statsMap.dismissed || 0;
|
|
33167
33336
|
const expired = statsMap.expired || 0;
|
|
33168
|
-
|
|
33337
|
+
logger24.debug("Retrieved stats", { userId: user.id, total });
|
|
33169
33338
|
return {
|
|
33170
33339
|
total,
|
|
33171
33340
|
delivered,
|
|
@@ -33214,7 +33383,7 @@ class NotificationService {
|
|
|
33214
33383
|
options: { data, clickUrl, metadata: metadata2 }
|
|
33215
33384
|
});
|
|
33216
33385
|
}
|
|
33217
|
-
|
|
33386
|
+
logger24.debug("Created notification", {
|
|
33218
33387
|
userId,
|
|
33219
33388
|
type,
|
|
33220
33389
|
id: notificationId,
|
|
@@ -33222,7 +33391,7 @@ class NotificationService {
|
|
|
33222
33391
|
});
|
|
33223
33392
|
return notificationId;
|
|
33224
33393
|
} catch (error) {
|
|
33225
|
-
|
|
33394
|
+
logger24.error("Failed to create notification", { userId, type, error });
|
|
33226
33395
|
return null;
|
|
33227
33396
|
}
|
|
33228
33397
|
}
|
|
@@ -33236,7 +33405,7 @@ class NotificationService {
|
|
|
33236
33405
|
}) {
|
|
33237
33406
|
const realtimeConfig = this.deps.realtime;
|
|
33238
33407
|
if (!realtimeConfig) {
|
|
33239
|
-
|
|
33408
|
+
logger24.warn("No realtime config for publish");
|
|
33240
33409
|
return;
|
|
33241
33410
|
}
|
|
33242
33411
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -33278,13 +33447,13 @@ class NotificationService {
|
|
|
33278
33447
|
metadata: data.metadata || {}
|
|
33279
33448
|
}).returning();
|
|
33280
33449
|
if (!notification) {
|
|
33281
|
-
|
|
33450
|
+
logger24.error("Notification insert returned no rows", {
|
|
33282
33451
|
userId: data.userId,
|
|
33283
33452
|
type: data.type
|
|
33284
33453
|
});
|
|
33285
33454
|
throw new InternalError("Failed to create notification");
|
|
33286
33455
|
}
|
|
33287
|
-
|
|
33456
|
+
logger24.info("Inserted notification", {
|
|
33288
33457
|
notificationId: notification.id,
|
|
33289
33458
|
userId: notification.userId,
|
|
33290
33459
|
type: notification.type
|
|
@@ -33294,7 +33463,7 @@ class NotificationService {
|
|
|
33294
33463
|
async deliverPending(userId) {
|
|
33295
33464
|
const realtimeConfig = this.deps.realtime;
|
|
33296
33465
|
if (!realtimeConfig) {
|
|
33297
|
-
|
|
33466
|
+
logger24.warn("No realtime config for delivery");
|
|
33298
33467
|
return;
|
|
33299
33468
|
}
|
|
33300
33469
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -33321,13 +33490,13 @@ class NotificationService {
|
|
|
33321
33490
|
metadata: notification.metadata,
|
|
33322
33491
|
clickUrl: notification.clickUrl
|
|
33323
33492
|
});
|
|
33324
|
-
|
|
33493
|
+
logger24.info("Delivered notification", {
|
|
33325
33494
|
notificationId: notification.id,
|
|
33326
33495
|
userId,
|
|
33327
33496
|
type: notification.type
|
|
33328
33497
|
});
|
|
33329
33498
|
} catch (error) {
|
|
33330
|
-
|
|
33499
|
+
logger24.warn("Failed to deliver", {
|
|
33331
33500
|
notificationId: notification.id,
|
|
33332
33501
|
error
|
|
33333
33502
|
});
|
|
@@ -33335,7 +33504,7 @@ class NotificationService {
|
|
|
33335
33504
|
}
|
|
33336
33505
|
}
|
|
33337
33506
|
}
|
|
33338
|
-
var
|
|
33507
|
+
var logger24;
|
|
33339
33508
|
var init_notification_service = __esm(() => {
|
|
33340
33509
|
init_drizzle_orm();
|
|
33341
33510
|
init_src();
|
|
@@ -33344,7 +33513,7 @@ var init_notification_service = __esm(() => {
|
|
|
33344
33513
|
init_events();
|
|
33345
33514
|
init_notification();
|
|
33346
33515
|
init_errors();
|
|
33347
|
-
|
|
33516
|
+
logger24 = log.scope("NotificationService");
|
|
33348
33517
|
});
|
|
33349
33518
|
|
|
33350
33519
|
// ../api-core/src/services/factory/player.ts
|
|
@@ -33468,7 +33637,7 @@ class CharacterService {
|
|
|
33468
33637
|
createdAt: characterComponents.createdAt,
|
|
33469
33638
|
updatedAt: characterComponents.updatedAt
|
|
33470
33639
|
}).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
|
|
33471
|
-
|
|
33640
|
+
logger25.debug("Listed available components", {
|
|
33472
33641
|
level,
|
|
33473
33642
|
count: components.length
|
|
33474
33643
|
});
|
|
@@ -33486,7 +33655,7 @@ class CharacterService {
|
|
|
33486
33655
|
}
|
|
33487
33656
|
}
|
|
33488
33657
|
});
|
|
33489
|
-
|
|
33658
|
+
logger25.debug("Retrieved character", { userId: user.id, found: Boolean(pc) });
|
|
33490
33659
|
return pc ?? null;
|
|
33491
33660
|
}
|
|
33492
33661
|
async getByUserId(userId) {
|
|
@@ -33501,7 +33670,7 @@ class CharacterService {
|
|
|
33501
33670
|
}
|
|
33502
33671
|
}
|
|
33503
33672
|
});
|
|
33504
|
-
|
|
33673
|
+
logger25.debug("Retrieved character by ID", { userId, found: Boolean(pc) });
|
|
33505
33674
|
return pc ?? null;
|
|
33506
33675
|
}
|
|
33507
33676
|
async create(input, user) {
|
|
@@ -33516,13 +33685,13 @@ class CharacterService {
|
|
|
33516
33685
|
}
|
|
33517
33686
|
const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
|
|
33518
33687
|
if (!characterRow) {
|
|
33519
|
-
|
|
33688
|
+
logger25.error("Character insert returned no rows", { userId: user.id });
|
|
33520
33689
|
throw new InternalError("Failed to create character in database");
|
|
33521
33690
|
}
|
|
33522
33691
|
await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
|
|
33523
33692
|
return characterRow;
|
|
33524
33693
|
});
|
|
33525
|
-
|
|
33694
|
+
logger25.info("Created character", { userId: user.id, characterId: result.id });
|
|
33526
33695
|
return result;
|
|
33527
33696
|
}
|
|
33528
33697
|
async update(input, user) {
|
|
@@ -33534,7 +33703,7 @@ class CharacterService {
|
|
|
33534
33703
|
if (!row) {
|
|
33535
33704
|
throw new NotFoundError("Player character");
|
|
33536
33705
|
}
|
|
33537
|
-
|
|
33706
|
+
logger25.info("Updated character", {
|
|
33538
33707
|
userId: user.id,
|
|
33539
33708
|
characterId: row.id,
|
|
33540
33709
|
updatedFields: Object.keys(input)
|
|
@@ -33556,7 +33725,7 @@ class CharacterService {
|
|
|
33556
33725
|
const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
|
|
33557
33726
|
const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
|
|
33558
33727
|
if (!validation.isValid) {
|
|
33559
|
-
|
|
33728
|
+
logger25.warn("Accessory validation failed", {
|
|
33560
33729
|
userId: user.id,
|
|
33561
33730
|
slot,
|
|
33562
33731
|
accessoryComponentId,
|
|
@@ -33572,14 +33741,14 @@ class CharacterService {
|
|
|
33572
33741
|
slot
|
|
33573
33742
|
}).returning();
|
|
33574
33743
|
if (!result) {
|
|
33575
|
-
|
|
33744
|
+
logger25.error("Accessory insert returned no rows", {
|
|
33576
33745
|
userId: user.id,
|
|
33577
33746
|
slot,
|
|
33578
33747
|
accessoryComponentId
|
|
33579
33748
|
});
|
|
33580
33749
|
throw new InternalError("Failed to equip accessory");
|
|
33581
33750
|
}
|
|
33582
|
-
|
|
33751
|
+
logger25.info("Equipped accessory", {
|
|
33583
33752
|
userId: user.id,
|
|
33584
33753
|
slot,
|
|
33585
33754
|
accessoryComponentId
|
|
@@ -33600,7 +33769,7 @@ class CharacterService {
|
|
|
33600
33769
|
const playerLevel = userLevel?.currentLevel ?? 1;
|
|
33601
33770
|
const validation = validateAccessoryRemoval(slot, playerLevel);
|
|
33602
33771
|
if (!validation.isValid) {
|
|
33603
|
-
|
|
33772
|
+
logger25.warn("Accessory removal validation failed", {
|
|
33604
33773
|
userId: user.id,
|
|
33605
33774
|
slot,
|
|
33606
33775
|
playerLevel,
|
|
@@ -33609,17 +33778,17 @@ class CharacterService {
|
|
|
33609
33778
|
throw new ValidationError(validation.error ?? "Invalid accessory removal");
|
|
33610
33779
|
}
|
|
33611
33780
|
await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
|
|
33612
|
-
|
|
33781
|
+
logger25.info("Removed accessory", { userId: user.id, slot });
|
|
33613
33782
|
}
|
|
33614
33783
|
}
|
|
33615
|
-
var
|
|
33784
|
+
var logger25;
|
|
33616
33785
|
var init_character_service = __esm(() => {
|
|
33617
33786
|
init_drizzle_orm();
|
|
33618
33787
|
init_tables_index();
|
|
33619
33788
|
init_src2();
|
|
33620
33789
|
init_errors();
|
|
33621
33790
|
init_accessory_util();
|
|
33622
|
-
|
|
33791
|
+
logger25 = log.scope("CharacterService");
|
|
33623
33792
|
});
|
|
33624
33793
|
|
|
33625
33794
|
// ../api-core/src/services/currency.service.ts
|
|
@@ -33631,7 +33800,7 @@ class CurrencyService {
|
|
|
33631
33800
|
async list() {
|
|
33632
33801
|
const db2 = this.deps.db;
|
|
33633
33802
|
const allCurrencies = await db2.query.currencies.findMany();
|
|
33634
|
-
|
|
33803
|
+
logger26.debug("Listed currencies", { count: allCurrencies.length });
|
|
33635
33804
|
return allCurrencies;
|
|
33636
33805
|
}
|
|
33637
33806
|
async getById(currencyId) {
|
|
@@ -33642,7 +33811,7 @@ class CurrencyService {
|
|
|
33642
33811
|
if (!currency) {
|
|
33643
33812
|
throw new NotFoundError("Currency", currencyId);
|
|
33644
33813
|
}
|
|
33645
|
-
|
|
33814
|
+
logger26.debug("Retrieved currency", { currencyId });
|
|
33646
33815
|
return currency;
|
|
33647
33816
|
}
|
|
33648
33817
|
async create(data) {
|
|
@@ -33650,13 +33819,13 @@ class CurrencyService {
|
|
|
33650
33819
|
try {
|
|
33651
33820
|
const [newCurrency] = await db2.insert(currencies).values(data).returning();
|
|
33652
33821
|
if (!newCurrency) {
|
|
33653
|
-
|
|
33822
|
+
logger26.error("Currency insert returned no rows", {
|
|
33654
33823
|
itemId: data.itemId,
|
|
33655
33824
|
symbol: data.symbol
|
|
33656
33825
|
});
|
|
33657
33826
|
throw new InternalError("Failed to create currency");
|
|
33658
33827
|
}
|
|
33659
|
-
|
|
33828
|
+
logger26.info("Created currency", {
|
|
33660
33829
|
currencyId: newCurrency.id,
|
|
33661
33830
|
itemId: newCurrency.itemId,
|
|
33662
33831
|
symbol: newCurrency.symbol,
|
|
@@ -33685,7 +33854,7 @@ class CurrencyService {
|
|
|
33685
33854
|
if (!updatedCurrency) {
|
|
33686
33855
|
throw new NotFoundError("Currency", currencyId);
|
|
33687
33856
|
}
|
|
33688
|
-
|
|
33857
|
+
logger26.info("Updated currency", {
|
|
33689
33858
|
currencyId: updatedCurrency.id,
|
|
33690
33859
|
updatedFields: Object.keys(data)
|
|
33691
33860
|
});
|
|
@@ -33711,16 +33880,16 @@ class CurrencyService {
|
|
|
33711
33880
|
if (result.length === 0) {
|
|
33712
33881
|
throw new NotFoundError("Currency", currencyId);
|
|
33713
33882
|
}
|
|
33714
|
-
|
|
33883
|
+
logger26.info("Deleted currency", { currencyId });
|
|
33715
33884
|
}
|
|
33716
33885
|
}
|
|
33717
|
-
var
|
|
33886
|
+
var logger26;
|
|
33718
33887
|
var init_currency_service = __esm(() => {
|
|
33719
33888
|
init_drizzle_orm();
|
|
33720
33889
|
init_tables_index();
|
|
33721
33890
|
init_src2();
|
|
33722
33891
|
init_errors();
|
|
33723
|
-
|
|
33892
|
+
logger26 = log.scope("CurrencyService");
|
|
33724
33893
|
});
|
|
33725
33894
|
|
|
33726
33895
|
// ../api-core/src/services/logs.service.ts
|
|
@@ -33739,11 +33908,11 @@ class LogsService {
|
|
|
33739
33908
|
if (!game) {
|
|
33740
33909
|
throw new NotFoundError("Game", slug2);
|
|
33741
33910
|
}
|
|
33742
|
-
|
|
33911
|
+
logger27.info("Admin accessing game logs", { adminId: user.id, slug: slug2, environment });
|
|
33743
33912
|
} else {
|
|
33744
33913
|
const isApprovedDev = user.developerStatus === "approved";
|
|
33745
33914
|
if (!isApprovedDev) {
|
|
33746
|
-
|
|
33915
|
+
logger27.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
|
|
33747
33916
|
throw new AccessDeniedError("Must be an approved developer");
|
|
33748
33917
|
}
|
|
33749
33918
|
const game = await db2.query.games.findFirst({
|
|
@@ -33751,7 +33920,7 @@ class LogsService {
|
|
|
33751
33920
|
columns: { id: true }
|
|
33752
33921
|
});
|
|
33753
33922
|
if (!game) {
|
|
33754
|
-
|
|
33923
|
+
logger27.warn("Developer attempted access to unowned game logs", {
|
|
33755
33924
|
userId: user.id,
|
|
33756
33925
|
slug: slug2
|
|
33757
33926
|
});
|
|
@@ -33761,7 +33930,7 @@ class LogsService {
|
|
|
33761
33930
|
const isProduction3 = environment === "production";
|
|
33762
33931
|
const workerId = getDeploymentId(slug2, isProduction3);
|
|
33763
33932
|
const token = await this.deps.mintLogStreamToken(user.id, workerId);
|
|
33764
|
-
|
|
33933
|
+
logger27.debug("Generated log stream token", {
|
|
33765
33934
|
userId: user.id,
|
|
33766
33935
|
slug: slug2,
|
|
33767
33936
|
workerId
|
|
@@ -33769,14 +33938,14 @@ class LogsService {
|
|
|
33769
33938
|
return { token, workerId };
|
|
33770
33939
|
}
|
|
33771
33940
|
}
|
|
33772
|
-
var
|
|
33941
|
+
var logger27;
|
|
33773
33942
|
var init_logs_service = __esm(() => {
|
|
33774
33943
|
init_drizzle_orm();
|
|
33775
33944
|
init_tables_index();
|
|
33776
33945
|
init_src2();
|
|
33777
33946
|
init_errors();
|
|
33778
33947
|
init_deployment_util();
|
|
33779
|
-
|
|
33948
|
+
logger27 = log.scope("LogsService");
|
|
33780
33949
|
});
|
|
33781
33950
|
|
|
33782
33951
|
// ../api-core/src/services/lti.service.ts
|
|
@@ -33829,7 +33998,7 @@ class MapService {
|
|
|
33829
33998
|
if (!mapDetails) {
|
|
33830
33999
|
throw new NotFoundError("Map", identifier);
|
|
33831
34000
|
}
|
|
33832
|
-
|
|
34001
|
+
logger28.debug("Retrieved map", { identifier });
|
|
33833
34002
|
return mapDetails;
|
|
33834
34003
|
}
|
|
33835
34004
|
async getElements(mapId) {
|
|
@@ -33845,7 +34014,7 @@ class MapService {
|
|
|
33845
34014
|
}
|
|
33846
34015
|
}
|
|
33847
34016
|
});
|
|
33848
|
-
|
|
34017
|
+
logger28.debug("Retrieved elements", { mapId, count: elements.length });
|
|
33849
34018
|
return elements;
|
|
33850
34019
|
}
|
|
33851
34020
|
async getObjects(mapId, userId) {
|
|
@@ -33866,7 +34035,7 @@ class MapService {
|
|
|
33866
34035
|
}
|
|
33867
34036
|
}
|
|
33868
34037
|
});
|
|
33869
|
-
|
|
34038
|
+
logger28.debug("Retrieved objects", { mapId, userId, count: objects.length });
|
|
33870
34039
|
return objects.map((object) => this.formatMapObjectWithItem(object));
|
|
33871
34040
|
}
|
|
33872
34041
|
async createObject(mapId, data, user) {
|
|
@@ -33893,7 +34062,7 @@ class MapService {
|
|
|
33893
34062
|
throw new NotFoundError("Item", data.itemId);
|
|
33894
34063
|
}
|
|
33895
34064
|
if (!item.isPlaceable) {
|
|
33896
|
-
|
|
34065
|
+
logger28.warn("Attempted to place non-placeable item", {
|
|
33897
34066
|
userId: user.id,
|
|
33898
34067
|
itemId: data.itemId,
|
|
33899
34068
|
mapId
|
|
@@ -33907,7 +34076,7 @@ class MapService {
|
|
|
33907
34076
|
};
|
|
33908
34077
|
const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
|
|
33909
34078
|
if (!createdObject) {
|
|
33910
|
-
|
|
34079
|
+
logger28.error("Map object insert returned no rows", {
|
|
33911
34080
|
userId: user.id,
|
|
33912
34081
|
mapId,
|
|
33913
34082
|
itemId: data.itemId
|
|
@@ -33931,12 +34100,12 @@ class MapService {
|
|
|
33931
34100
|
}
|
|
33932
34101
|
});
|
|
33933
34102
|
if (!objectWithItem) {
|
|
33934
|
-
|
|
34103
|
+
logger28.error("Map object query after insert returned no rows", {
|
|
33935
34104
|
objectId: createdObject.id
|
|
33936
34105
|
});
|
|
33937
34106
|
throw new InternalError("Failed to retrieve created object");
|
|
33938
34107
|
}
|
|
33939
|
-
|
|
34108
|
+
logger28.info("Created object", {
|
|
33940
34109
|
userId: user.id,
|
|
33941
34110
|
mapId,
|
|
33942
34111
|
objectId: createdObject.id,
|
|
@@ -33960,7 +34129,7 @@ class MapService {
|
|
|
33960
34129
|
if (result.length === 0) {
|
|
33961
34130
|
throw new NotFoundError("MapObject", objectId);
|
|
33962
34131
|
}
|
|
33963
|
-
|
|
34132
|
+
logger28.info("Deleted object", {
|
|
33964
34133
|
userId: user.id,
|
|
33965
34134
|
mapId,
|
|
33966
34135
|
objectId
|
|
@@ -33989,13 +34158,13 @@ class MapService {
|
|
|
33989
34158
|
};
|
|
33990
34159
|
}
|
|
33991
34160
|
}
|
|
33992
|
-
var
|
|
34161
|
+
var logger28;
|
|
33993
34162
|
var init_map_service = __esm(() => {
|
|
33994
34163
|
init_drizzle_orm();
|
|
33995
34164
|
init_tables_index();
|
|
33996
34165
|
init_src2();
|
|
33997
34166
|
init_errors();
|
|
33998
|
-
|
|
34167
|
+
logger28 = log.scope("MapService");
|
|
33999
34168
|
});
|
|
34000
34169
|
|
|
34001
34170
|
// ../api-core/src/services/realtime.service.ts
|
|
@@ -34030,20 +34199,20 @@ class RealtimeService {
|
|
|
34030
34199
|
}
|
|
34031
34200
|
const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
|
|
34032
34201
|
const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
|
|
34033
|
-
|
|
34202
|
+
logger29.info("Generated token", {
|
|
34034
34203
|
userId: user.id,
|
|
34035
34204
|
gameId: resolvedGameId || "global"
|
|
34036
34205
|
});
|
|
34037
34206
|
return { token };
|
|
34038
34207
|
}
|
|
34039
34208
|
}
|
|
34040
|
-
var
|
|
34209
|
+
var logger29;
|
|
34041
34210
|
var init_realtime_service = __esm(() => {
|
|
34042
34211
|
init_drizzle_orm();
|
|
34043
34212
|
init_tables_index();
|
|
34044
34213
|
init_src2();
|
|
34045
34214
|
init_errors();
|
|
34046
|
-
|
|
34215
|
+
logger29 = log.scope("RealtimeService");
|
|
34047
34216
|
});
|
|
34048
34217
|
|
|
34049
34218
|
// ../api-core/src/services/session.service.ts
|
|
@@ -34078,10 +34247,10 @@ class SessionService {
|
|
|
34078
34247
|
};
|
|
34079
34248
|
const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
|
|
34080
34249
|
if (!newSession?.sessionId) {
|
|
34081
|
-
|
|
34250
|
+
logger30.error("Game session insert returned no rows", { userId, gameId });
|
|
34082
34251
|
throw new InternalError("Failed to create game session");
|
|
34083
34252
|
}
|
|
34084
|
-
|
|
34253
|
+
logger30.info("Started new session", {
|
|
34085
34254
|
sessionId: newSession.sessionId,
|
|
34086
34255
|
gameId,
|
|
34087
34256
|
userId
|
|
@@ -34102,23 +34271,23 @@ class SessionService {
|
|
|
34102
34271
|
return { success: true, message: "Session already ended" };
|
|
34103
34272
|
}
|
|
34104
34273
|
await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
|
|
34105
|
-
|
|
34274
|
+
logger30.info("Ended session", { sessionId, gameId, userId });
|
|
34106
34275
|
return { success: true };
|
|
34107
34276
|
}
|
|
34108
34277
|
async mintToken(gameIdOrSlug, userId) {
|
|
34109
34278
|
const gameId = await this.resolveGameId(gameIdOrSlug);
|
|
34110
34279
|
const result = await this.deps.mintGameToken(gameId, userId);
|
|
34111
|
-
|
|
34280
|
+
logger30.debug("Minted game token", { gameId, userId });
|
|
34112
34281
|
return result;
|
|
34113
34282
|
}
|
|
34114
34283
|
}
|
|
34115
|
-
var
|
|
34284
|
+
var logger30;
|
|
34116
34285
|
var init_session_service = __esm(() => {
|
|
34117
34286
|
init_drizzle_orm();
|
|
34118
34287
|
init_tables_index();
|
|
34119
34288
|
init_src2();
|
|
34120
34289
|
init_errors();
|
|
34121
|
-
|
|
34290
|
+
logger30 = log.scope("SessionService");
|
|
34122
34291
|
});
|
|
34123
34292
|
|
|
34124
34293
|
// ../api-core/src/services/shop.service.ts
|
|
@@ -34164,7 +34333,7 @@ class ShopService {
|
|
|
34164
34333
|
const shopItems = [];
|
|
34165
34334
|
for (const listing of listingsWithRelations) {
|
|
34166
34335
|
if (!listing.item || !listing.currency) {
|
|
34167
|
-
|
|
34336
|
+
logger31.warn("Listing missing item or currency, skipping", {
|
|
34168
34337
|
listingId: listing.id
|
|
34169
34338
|
});
|
|
34170
34339
|
} else {
|
|
@@ -34181,7 +34350,7 @@ class ShopService {
|
|
|
34181
34350
|
});
|
|
34182
34351
|
}
|
|
34183
34352
|
}
|
|
34184
|
-
|
|
34353
|
+
logger31.debug("Retrieved shop view", {
|
|
34185
34354
|
userId: user.id,
|
|
34186
34355
|
itemCount: shopItems.length,
|
|
34187
34356
|
currencyCount: shopCurrencies.length
|
|
@@ -34192,12 +34361,12 @@ class ShopService {
|
|
|
34192
34361
|
};
|
|
34193
34362
|
}
|
|
34194
34363
|
}
|
|
34195
|
-
var
|
|
34364
|
+
var logger31;
|
|
34196
34365
|
var init_shop_service = __esm(() => {
|
|
34197
34366
|
init_drizzle_orm();
|
|
34198
34367
|
init_tables_index();
|
|
34199
34368
|
init_src2();
|
|
34200
|
-
|
|
34369
|
+
logger31 = log.scope("ShopService");
|
|
34201
34370
|
});
|
|
34202
34371
|
|
|
34203
34372
|
// ../api-core/src/services/sprite.service.ts
|
|
@@ -34214,17 +34383,17 @@ class SpriteService {
|
|
|
34214
34383
|
if (!template) {
|
|
34215
34384
|
throw new NotFoundError("SpriteTemplate", slug2);
|
|
34216
34385
|
}
|
|
34217
|
-
|
|
34386
|
+
logger32.debug("Retrieved sprite", { slug: slug2 });
|
|
34218
34387
|
return template;
|
|
34219
34388
|
}
|
|
34220
34389
|
}
|
|
34221
|
-
var
|
|
34390
|
+
var logger32;
|
|
34222
34391
|
var init_sprite_service = __esm(() => {
|
|
34223
34392
|
init_drizzle_orm();
|
|
34224
34393
|
init_tables_index();
|
|
34225
34394
|
init_src2();
|
|
34226
34395
|
init_errors();
|
|
34227
|
-
|
|
34396
|
+
logger32 = log.scope("SpriteService");
|
|
34228
34397
|
});
|
|
34229
34398
|
|
|
34230
34399
|
// ../api-core/src/services/user.service.ts
|
|
@@ -34239,12 +34408,12 @@ class UserService {
|
|
|
34239
34408
|
where: eq(users.id, user.id)
|
|
34240
34409
|
});
|
|
34241
34410
|
if (!userData) {
|
|
34242
|
-
|
|
34411
|
+
logger33.error("User not found", { userId: user.id });
|
|
34243
34412
|
throw new NotFoundError("User", user.id);
|
|
34244
34413
|
}
|
|
34245
34414
|
const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
|
|
34246
34415
|
if (gameId) {
|
|
34247
|
-
|
|
34416
|
+
logger33.debug("Fetched user profile (game context)", { userId: user.id, gameId });
|
|
34248
34417
|
return {
|
|
34249
34418
|
id: userData.id,
|
|
34250
34419
|
name: userData.name,
|
|
@@ -34257,7 +34426,7 @@ class UserService {
|
|
|
34257
34426
|
const timebackAccount = await db2.query.accounts.findFirst({
|
|
34258
34427
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
34259
34428
|
});
|
|
34260
|
-
|
|
34429
|
+
logger33.debug("Fetched user profile (platform context)", { userId: user.id });
|
|
34261
34430
|
return {
|
|
34262
34431
|
id: userData.id,
|
|
34263
34432
|
name: userData.name,
|
|
@@ -34280,7 +34449,7 @@ class UserService {
|
|
|
34280
34449
|
columns: { name: true }
|
|
34281
34450
|
});
|
|
34282
34451
|
if (!userData) {
|
|
34283
|
-
|
|
34452
|
+
logger33.error("Demo user not found", { userId });
|
|
34284
34453
|
throw new NotFoundError("User", userId);
|
|
34285
34454
|
}
|
|
34286
34455
|
return {
|
|
@@ -34294,10 +34463,10 @@ class UserService {
|
|
|
34294
34463
|
updatedAt: new Date
|
|
34295
34464
|
}).where(eq(users.id, userId)).returning({ name: users.name });
|
|
34296
34465
|
if (!updatedUser) {
|
|
34297
|
-
|
|
34466
|
+
logger33.error("Demo user not found for profile update", { userId });
|
|
34298
34467
|
throw new NotFoundError("User", userId);
|
|
34299
34468
|
}
|
|
34300
|
-
|
|
34469
|
+
logger33.debug("Updated demo profile", { userId, displayName });
|
|
34301
34470
|
return {
|
|
34302
34471
|
displayName: updatedUser.name,
|
|
34303
34472
|
isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
|
|
@@ -34310,7 +34479,7 @@ class UserService {
|
|
|
34310
34479
|
]);
|
|
34311
34480
|
const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
34312
34481
|
const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
34313
|
-
|
|
34482
|
+
logger33.debug("Fetched Timeback data", {
|
|
34314
34483
|
timebackId,
|
|
34315
34484
|
role,
|
|
34316
34485
|
enrollmentCount: enrollments.length,
|
|
@@ -34319,9 +34488,9 @@ class UserService {
|
|
|
34319
34488
|
return { id: timebackId, role, enrollments, organizations };
|
|
34320
34489
|
}
|
|
34321
34490
|
async fetchStudentProfile(timebackId) {
|
|
34322
|
-
|
|
34491
|
+
logger33.debug("Fetching student profile", { timebackId });
|
|
34323
34492
|
if (!this.deps.timeback) {
|
|
34324
|
-
|
|
34493
|
+
logger33.warn("Timeback client not available");
|
|
34325
34494
|
return { role: "student", organizations: [] };
|
|
34326
34495
|
}
|
|
34327
34496
|
try {
|
|
@@ -34349,14 +34518,14 @@ class UserService {
|
|
|
34349
34518
|
}
|
|
34350
34519
|
return { role, organizations: [...orgMap.values()] };
|
|
34351
34520
|
} catch (error) {
|
|
34352
|
-
|
|
34521
|
+
logger33.warn("Failed to fetch student profile", { error, timebackId });
|
|
34353
34522
|
return { role: "student", organizations: [] };
|
|
34354
34523
|
}
|
|
34355
34524
|
}
|
|
34356
34525
|
async fetchEnrollments(timebackId) {
|
|
34357
|
-
|
|
34526
|
+
logger33.debug("Fetching enrollments", { timebackId });
|
|
34358
34527
|
if (!this.deps.timeback) {
|
|
34359
|
-
|
|
34528
|
+
logger33.warn("Timeback client not available");
|
|
34360
34529
|
return [];
|
|
34361
34530
|
}
|
|
34362
34531
|
try {
|
|
@@ -34377,7 +34546,7 @@ class UserService {
|
|
|
34377
34546
|
orgId: courseToSchool.get(i2.courseId)
|
|
34378
34547
|
}));
|
|
34379
34548
|
} catch (error) {
|
|
34380
|
-
|
|
34549
|
+
logger33.warn("Failed to fetch enrollments", { error, timebackId });
|
|
34381
34550
|
return [];
|
|
34382
34551
|
}
|
|
34383
34552
|
}
|
|
@@ -34392,14 +34561,14 @@ class UserService {
|
|
|
34392
34561
|
return organizations.filter((o) => enrollmentOrgIds.has(o.id));
|
|
34393
34562
|
}
|
|
34394
34563
|
}
|
|
34395
|
-
var
|
|
34564
|
+
var logger33;
|
|
34396
34565
|
var init_user_service = __esm(() => {
|
|
34397
34566
|
init_drizzle_orm();
|
|
34398
34567
|
init_src();
|
|
34399
34568
|
init_tables_index();
|
|
34400
34569
|
init_src2();
|
|
34401
34570
|
init_errors();
|
|
34402
|
-
|
|
34571
|
+
logger33 = log.scope("UserService");
|
|
34403
34572
|
});
|
|
34404
34573
|
|
|
34405
34574
|
// ../api-core/src/services/verify.service.ts
|
|
@@ -34409,16 +34578,16 @@ class VerifyService {
|
|
|
34409
34578
|
this.deps = deps;
|
|
34410
34579
|
}
|
|
34411
34580
|
async verifyGameToken(token) {
|
|
34412
|
-
|
|
34581
|
+
logger34.debug("Verifying game token");
|
|
34413
34582
|
const payload = await this.deps.validateGameToken(token);
|
|
34414
34583
|
if (!payload) {
|
|
34415
|
-
|
|
34584
|
+
logger34.warn("Invalid or expired game token presented");
|
|
34416
34585
|
throw new ValidationError("Invalid or expired token");
|
|
34417
34586
|
}
|
|
34418
34587
|
const gameId = payload.sub;
|
|
34419
34588
|
const userId = payload.uid;
|
|
34420
34589
|
if (typeof gameId !== "string" || typeof userId !== "string") {
|
|
34421
|
-
|
|
34590
|
+
logger34.warn("Game token missing required claims", {
|
|
34422
34591
|
hasGameId: typeof gameId === "string",
|
|
34423
34592
|
hasUserId: typeof userId === "string"
|
|
34424
34593
|
});
|
|
@@ -34429,7 +34598,7 @@ class VerifyService {
|
|
|
34429
34598
|
where: eq(users.id, userId)
|
|
34430
34599
|
});
|
|
34431
34600
|
if (!userData) {
|
|
34432
|
-
|
|
34601
|
+
logger34.error("User not found for valid token", {
|
|
34433
34602
|
userId
|
|
34434
34603
|
});
|
|
34435
34604
|
throw new NotFoundError("User", userId);
|
|
@@ -34443,7 +34612,7 @@ class VerifyService {
|
|
|
34443
34612
|
family_name: undefined,
|
|
34444
34613
|
timeback_id: userData.timebackId || undefined
|
|
34445
34614
|
};
|
|
34446
|
-
|
|
34615
|
+
logger34.info("Token verified", { gameId, userId });
|
|
34447
34616
|
return {
|
|
34448
34617
|
claims: payload,
|
|
34449
34618
|
gameId,
|
|
@@ -34451,13 +34620,13 @@ class VerifyService {
|
|
|
34451
34620
|
};
|
|
34452
34621
|
}
|
|
34453
34622
|
}
|
|
34454
|
-
var
|
|
34623
|
+
var logger34;
|
|
34455
34624
|
var init_verify_service = __esm(() => {
|
|
34456
34625
|
init_drizzle_orm();
|
|
34457
34626
|
init_tables_index();
|
|
34458
34627
|
init_src2();
|
|
34459
34628
|
init_errors();
|
|
34460
|
-
|
|
34629
|
+
logger34 = log.scope("VerifyService");
|
|
34461
34630
|
});
|
|
34462
34631
|
|
|
34463
34632
|
// ../api-core/src/services/factory/standalone.ts
|
|
@@ -36043,6 +36212,9 @@ class TimebackCacheManager {
|
|
|
36043
36212
|
setEnrollments(studentId, enrollments) {
|
|
36044
36213
|
this.enrollmentCache.set(studentId, enrollments);
|
|
36045
36214
|
}
|
|
36215
|
+
clearEnrollments(studentId) {
|
|
36216
|
+
return this.enrollmentCache.delete(studentId);
|
|
36217
|
+
}
|
|
36046
36218
|
clearAll() {
|
|
36047
36219
|
this.studentCache.clear();
|
|
36048
36220
|
this.assessmentLineItemCache.clear();
|
|
@@ -36081,6 +36253,41 @@ class MasteryTracker {
|
|
|
36081
36253
|
if (typeof masteredUnits !== "number" || masteredUnits <= 0) {
|
|
36082
36254
|
return;
|
|
36083
36255
|
}
|
|
36256
|
+
const status = await this.calculateStatus({
|
|
36257
|
+
studentId,
|
|
36258
|
+
courseId,
|
|
36259
|
+
resourceId,
|
|
36260
|
+
additionalMasteredUnits: masteredUnits
|
|
36261
|
+
});
|
|
36262
|
+
if (!status) {
|
|
36263
|
+
return;
|
|
36264
|
+
}
|
|
36265
|
+
return {
|
|
36266
|
+
pctCompleteApp: status.pctCompleteApp,
|
|
36267
|
+
masteryAchieved: status.historicalMasteredUnits < status.masterableUnits && status.isComplete
|
|
36268
|
+
};
|
|
36269
|
+
}
|
|
36270
|
+
async getStatus(input) {
|
|
36271
|
+
const status = await this.calculateStatus({
|
|
36272
|
+
...input,
|
|
36273
|
+
additionalMasteredUnits: 0
|
|
36274
|
+
});
|
|
36275
|
+
if (!status) {
|
|
36276
|
+
return;
|
|
36277
|
+
}
|
|
36278
|
+
return {
|
|
36279
|
+
masteredUnits: status.masteredUnits,
|
|
36280
|
+
masterableUnits: status.masterableUnits,
|
|
36281
|
+
pctCompleteApp: status.pctCompleteApp,
|
|
36282
|
+
isComplete: status.isComplete
|
|
36283
|
+
};
|
|
36284
|
+
}
|
|
36285
|
+
async calculateStatus({
|
|
36286
|
+
studentId,
|
|
36287
|
+
courseId,
|
|
36288
|
+
resourceId,
|
|
36289
|
+
additionalMasteredUnits
|
|
36290
|
+
}) {
|
|
36084
36291
|
const masterableUnits = await this.resolveMasterableUnits(resourceId);
|
|
36085
36292
|
if (!masterableUnits || masterableUnits <= 0) {
|
|
36086
36293
|
log.warn("[MasteryTracker] No masterableUnits configured for course", {
|
|
@@ -36098,11 +36305,16 @@ class MasteryTracker {
|
|
|
36098
36305
|
return;
|
|
36099
36306
|
}
|
|
36100
36307
|
const historicalMasteredUnits = this.sumAnalyticsMetric(facts, "masteredUnits");
|
|
36101
|
-
const totalMastered = historicalMasteredUnits +
|
|
36308
|
+
const totalMastered = historicalMasteredUnits + additionalMasteredUnits;
|
|
36102
36309
|
const rawPct = totalMastered / masterableUnits * 100;
|
|
36103
36310
|
const pctCompleteApp = Math.min(100, Math.max(0, Math.round(rawPct)));
|
|
36104
|
-
|
|
36105
|
-
|
|
36311
|
+
return {
|
|
36312
|
+
masteredUnits: totalMastered,
|
|
36313
|
+
masterableUnits,
|
|
36314
|
+
pctCompleteApp,
|
|
36315
|
+
isComplete: totalMastered >= masterableUnits,
|
|
36316
|
+
historicalMasteredUnits
|
|
36317
|
+
};
|
|
36106
36318
|
}
|
|
36107
36319
|
async createCompletionEntry(studentId, courseId, classId, appName) {
|
|
36108
36320
|
const ids = deriveSourcedIds2(courseId);
|
|
@@ -36698,6 +36910,7 @@ class TimebackClient {
|
|
|
36698
36910
|
progressRecorder;
|
|
36699
36911
|
sessionRecorder;
|
|
36700
36912
|
adminEventRecorder;
|
|
36913
|
+
masteryTracker;
|
|
36701
36914
|
constructor(config2) {
|
|
36702
36915
|
this.baseUrl = TimebackClient.resolveBaseUrl(config2?.baseUrl);
|
|
36703
36916
|
this.environment = process.env[ENV_VARS4.environment] === "staging" ? "staging" : "production";
|
|
@@ -36715,8 +36928,8 @@ class TimebackClient {
|
|
|
36715
36928
|
this.edubridge = createEduBridgeNamespace(this);
|
|
36716
36929
|
this.cacheManager = new TimebackCacheManager;
|
|
36717
36930
|
this.studentResolver = new StudentResolver(this.cacheManager, this.oneroster);
|
|
36718
|
-
|
|
36719
|
-
this.progressRecorder = new ProgressRecorder(this.studentResolver, this.cacheManager, this.oneroster, this.caliper, masteryTracker);
|
|
36931
|
+
this.masteryTracker = new MasteryTracker(this.cacheManager, this.oneroster, this.edubridge);
|
|
36932
|
+
this.progressRecorder = new ProgressRecorder(this.studentResolver, this.cacheManager, this.oneroster, this.caliper, this.masteryTracker);
|
|
36720
36933
|
this.sessionRecorder = new SessionRecorder(this.studentResolver, this.caliper);
|
|
36721
36934
|
this.adminEventRecorder = new AdminEventRecorder(this.studentResolver, this.oneroster, this.caliper, this.environment);
|
|
36722
36935
|
if (this.credentials) {
|
|
@@ -36874,6 +37087,18 @@ class TimebackClient {
|
|
|
36874
37087
|
this.cacheManager.setEnrollments(studentId, enrollments);
|
|
36875
37088
|
return enrollments;
|
|
36876
37089
|
}
|
|
37090
|
+
invalidateEnrollments(studentId) {
|
|
37091
|
+
this.cacheManager.clearEnrollments(studentId);
|
|
37092
|
+
}
|
|
37093
|
+
async getMasteryStatus(courseId, studentId) {
|
|
37094
|
+
await this._ensureAuthenticated();
|
|
37095
|
+
const ids = deriveSourcedIds2(courseId);
|
|
37096
|
+
return this.masteryTracker.getStatus({
|
|
37097
|
+
studentId,
|
|
37098
|
+
courseId,
|
|
37099
|
+
resourceId: ids.resource
|
|
37100
|
+
});
|
|
37101
|
+
}
|
|
36877
37102
|
async getStudentXp(studentId, options) {
|
|
36878
37103
|
await this._ensureAuthenticated();
|
|
36879
37104
|
const enrollments = await this.edubridge.enrollments.listByUser(studentId);
|
|
@@ -39401,7 +39626,7 @@ var humanize = (times) => {
|
|
|
39401
39626
|
}
|
|
39402
39627
|
}
|
|
39403
39628
|
return `${status}`;
|
|
39404
|
-
},
|
|
39629
|
+
}, logger35 = (fn = console.log) => {
|
|
39405
39630
|
return async function logger2(c, next) {
|
|
39406
39631
|
const { method, url } = c.req;
|
|
39407
39632
|
const path = url.slice(url.indexOf("/", 8));
|
|
@@ -39582,7 +39807,7 @@ function createApp(db2, options) {
|
|
|
39582
39807
|
const app = new Hono2;
|
|
39583
39808
|
app.use("*", cors({ origin: "*", credentials: true }));
|
|
39584
39809
|
if (options.verbose && !options.quiet) {
|
|
39585
|
-
app.use("*",
|
|
39810
|
+
app.use("*", logger35());
|
|
39586
39811
|
}
|
|
39587
39812
|
app.use("/api/*", async (c, next) => {
|
|
39588
39813
|
c.set("db", db2);
|
|
@@ -46015,12 +46240,12 @@ var init_session2 = __esm(() => {
|
|
|
46015
46240
|
init_utils();
|
|
46016
46241
|
init_dist5();
|
|
46017
46242
|
PglitePreparedQuery = class PglitePreparedQuery extends PgPreparedQuery {
|
|
46018
|
-
constructor(client, queryString, params,
|
|
46243
|
+
constructor(client, queryString, params, logger36, fields, name3, _isResponseInArrayMode, customResultMapper) {
|
|
46019
46244
|
super({ sql: queryString, params });
|
|
46020
46245
|
this.client = client;
|
|
46021
46246
|
this.queryString = queryString;
|
|
46022
46247
|
this.params = params;
|
|
46023
|
-
this.logger =
|
|
46248
|
+
this.logger = logger36;
|
|
46024
46249
|
this.fields = fields;
|
|
46025
46250
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
46026
46251
|
this.customResultMapper = customResultMapper;
|
|
@@ -46124,11 +46349,11 @@ var init_session2 = __esm(() => {
|
|
|
46124
46349
|
// ../../node_modules/.bun/drizzle-orm@0.42.0+15de9685f71e59a4/node_modules/drizzle-orm/pglite/driver.js
|
|
46125
46350
|
function construct(client, config2 = {}) {
|
|
46126
46351
|
const dialect2 = new PgDialect({ casing: config2.casing });
|
|
46127
|
-
let
|
|
46352
|
+
let logger36;
|
|
46128
46353
|
if (config2.logger === true) {
|
|
46129
|
-
|
|
46354
|
+
logger36 = new DefaultLogger;
|
|
46130
46355
|
} else if (config2.logger !== false) {
|
|
46131
|
-
|
|
46356
|
+
logger36 = config2.logger;
|
|
46132
46357
|
}
|
|
46133
46358
|
let schema2;
|
|
46134
46359
|
if (config2.schema) {
|
|
@@ -46139,7 +46364,7 @@ function construct(client, config2 = {}) {
|
|
|
46139
46364
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
46140
46365
|
};
|
|
46141
46366
|
}
|
|
46142
|
-
const driver = new PgliteDriver(client, dialect2, { logger:
|
|
46367
|
+
const driver = new PgliteDriver(client, dialect2, { logger: logger36 });
|
|
46143
46368
|
const session2 = driver.createSession(schema2);
|
|
46144
46369
|
const db2 = new PgliteDatabase(dialect2, session2, schema2);
|
|
46145
46370
|
db2.$client = client;
|
|
@@ -92391,8 +92616,8 @@ var init_currencies = __esm(() => {
|
|
|
92391
92616
|
});
|
|
92392
92617
|
|
|
92393
92618
|
// src/lib/logging/adapter.ts
|
|
92394
|
-
function setLogger(
|
|
92395
|
-
customLogger =
|
|
92619
|
+
function setLogger(logger36) {
|
|
92620
|
+
customLogger = logger36;
|
|
92396
92621
|
}
|
|
92397
92622
|
function getLogger() {
|
|
92398
92623
|
if (customLogger) {
|
|
@@ -92404,10 +92629,10 @@ function getLogger() {
|
|
|
92404
92629
|
error: (msg) => console.error(msg)
|
|
92405
92630
|
};
|
|
92406
92631
|
}
|
|
92407
|
-
var customLogger,
|
|
92632
|
+
var customLogger, logger36;
|
|
92408
92633
|
var init_adapter = __esm(() => {
|
|
92409
92634
|
init_config();
|
|
92410
|
-
|
|
92635
|
+
logger36 = {
|
|
92411
92636
|
info: (msg) => {
|
|
92412
92637
|
if (customLogger || !config.embedded) {
|
|
92413
92638
|
getLogger().info(msg);
|
|
@@ -92493,7 +92718,7 @@ async function seedCoreGames(db2) {
|
|
|
92493
92718
|
try {
|
|
92494
92719
|
await db2.insert(games).values(gameData).onConflictDoNothing();
|
|
92495
92720
|
} catch (error2) {
|
|
92496
|
-
|
|
92721
|
+
logger36.error(`Error seeding core game '${gameData.slug}': ${error2}`);
|
|
92497
92722
|
}
|
|
92498
92723
|
}
|
|
92499
92724
|
}
|
|
@@ -92539,7 +92764,7 @@ async function seedCurrentProjectGame(db2, project) {
|
|
|
92539
92764
|
}
|
|
92540
92765
|
return newGame;
|
|
92541
92766
|
} catch (error2) {
|
|
92542
|
-
|
|
92767
|
+
logger36.error(`❌ Error seeding project game: ${error2}`);
|
|
92543
92768
|
throw error2;
|
|
92544
92769
|
}
|
|
92545
92770
|
}
|
|
@@ -93879,7 +94104,7 @@ function isValidAdminAttributionDate(value) {
|
|
|
93879
94104
|
const date4 = new Date(Date.UTC(year3, month - 1, day, 12, 0, 0));
|
|
93880
94105
|
return date4.getUTCFullYear() === year3 && date4.getUTCMonth() + 1 === month && date4.getUTCDate() === day;
|
|
93881
94106
|
}
|
|
93882
|
-
var TIMEBACK_GRADES, TIMEBACK_SUBJECTS5, TimebackGradeSchema, TimebackSubjectSchema, UpdateTimebackXpRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, HeartbeatRequestSchema, PopulateStudentRequestSchema, DerivedPlatformCourseConfigSchema, TimebackBaseConfigSchema, PlatformTimebackSetupRequestSchema, AdminTimebackMutationBaseSchema, AdminAttributionDateSchema, GrantTimebackXpRequestSchema, AdjustTimebackTimeRequestSchema, AdjustTimebackMasteryRequestSchema, ToggleCourseCompletionRequestSchema, EnrollStudentRequestSchema, UnenrollStudentRequestSchema;
|
|
94107
|
+
var TIMEBACK_GRADES, TIMEBACK_SUBJECTS5, TimebackGradeSchema, TimebackSubjectSchema, UpdateTimebackXpRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, AdvanceCourseRequestSchema, HeartbeatRequestSchema, PopulateStudentRequestSchema, DerivedPlatformCourseConfigSchema, TimebackBaseConfigSchema, PlatformTimebackSetupRequestSchema, AdminTimebackMutationBaseSchema, AdminAttributionDateSchema, GrantTimebackXpRequestSchema, AdjustTimebackTimeRequestSchema, AdjustTimebackMasteryRequestSchema, ToggleCourseCompletionRequestSchema, EnrollStudentRequestSchema, UnenrollStudentRequestSchema;
|
|
93883
94108
|
var init_schemas11 = __esm(() => {
|
|
93884
94109
|
init_esm();
|
|
93885
94110
|
TIMEBACK_GRADES = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
|
|
@@ -93934,6 +94159,11 @@ var init_schemas11 = __esm(() => {
|
|
|
93934
94159
|
masteredUnits: exports_external.number().nonnegative().optional(),
|
|
93935
94160
|
extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
93936
94161
|
});
|
|
94162
|
+
AdvanceCourseRequestSchema = exports_external.object({
|
|
94163
|
+
gameId: exports_external.string().uuid(),
|
|
94164
|
+
studentId: exports_external.string().min(1),
|
|
94165
|
+
subject: TimebackSubjectSchema.optional()
|
|
94166
|
+
});
|
|
93937
94167
|
HeartbeatRequestSchema = exports_external.object({
|
|
93938
94168
|
gameId: exports_external.string().uuid(),
|
|
93939
94169
|
studentId: exports_external.string().min(1),
|
|
@@ -94216,7 +94446,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
94216
94446
|
where: eq(users.id, existingAccount.userId)
|
|
94217
94447
|
});
|
|
94218
94448
|
if (user) {
|
|
94219
|
-
|
|
94449
|
+
logger37.info("Found user by LTI account", {
|
|
94220
94450
|
userId: user.id,
|
|
94221
94451
|
ltiTimebackId
|
|
94222
94452
|
});
|
|
@@ -94245,13 +94475,13 @@ async function provisionLtiUser(db2, claims) {
|
|
|
94245
94475
|
updatedAt: new Date
|
|
94246
94476
|
}).returning({ id: accounts.id });
|
|
94247
94477
|
if (!account) {
|
|
94248
|
-
|
|
94478
|
+
logger37.error("LTI account link insert returned no rows", {
|
|
94249
94479
|
userId: existingUser.id,
|
|
94250
94480
|
ltiTimebackId
|
|
94251
94481
|
});
|
|
94252
94482
|
throw new InternalError("Failed to link LTI account");
|
|
94253
94483
|
}
|
|
94254
|
-
|
|
94484
|
+
logger37.info("Linked LTI account to existing user", {
|
|
94255
94485
|
userId: existingUser.id,
|
|
94256
94486
|
ltiTimebackId
|
|
94257
94487
|
});
|
|
@@ -94271,7 +94501,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
94271
94501
|
updatedAt: new Date
|
|
94272
94502
|
}).returning();
|
|
94273
94503
|
if (!insertedUser) {
|
|
94274
|
-
|
|
94504
|
+
logger37.error("LTI user insert returned no rows", { email, ltiTimebackId });
|
|
94275
94505
|
throw new InternalError("Failed to create user");
|
|
94276
94506
|
}
|
|
94277
94507
|
await tx.insert(accounts).values({
|
|
@@ -94286,7 +94516,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
94286
94516
|
createdAt: new Date,
|
|
94287
94517
|
updatedAt: new Date
|
|
94288
94518
|
});
|
|
94289
|
-
|
|
94519
|
+
logger37.info("Provisioned new user from LTI", {
|
|
94290
94520
|
userId: insertedUser.id,
|
|
94291
94521
|
ltiTimebackId
|
|
94292
94522
|
});
|
|
@@ -94294,7 +94524,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
94294
94524
|
});
|
|
94295
94525
|
return createdUser;
|
|
94296
94526
|
}
|
|
94297
|
-
var
|
|
94527
|
+
var logger37;
|
|
94298
94528
|
var init_lti_provisioning = __esm(() => {
|
|
94299
94529
|
init_drizzle_orm();
|
|
94300
94530
|
init_src();
|
|
@@ -94302,7 +94532,7 @@ var init_lti_provisioning = __esm(() => {
|
|
|
94302
94532
|
init_src2();
|
|
94303
94533
|
init_errors();
|
|
94304
94534
|
init_lti_util();
|
|
94305
|
-
|
|
94535
|
+
logger37 = log.scope("LtiProvisioning");
|
|
94306
94536
|
});
|
|
94307
94537
|
|
|
94308
94538
|
// ../api-core/src/utils/validation.util.ts
|
|
@@ -94350,21 +94580,21 @@ var init_utils11 = __esm(() => {
|
|
|
94350
94580
|
});
|
|
94351
94581
|
|
|
94352
94582
|
// ../api-core/src/controllers/achievement.controller.ts
|
|
94353
|
-
var
|
|
94583
|
+
var logger38, listCurrent, listHistory, postProgress, achievements3;
|
|
94354
94584
|
var init_achievement_controller = __esm(() => {
|
|
94355
94585
|
init_esm();
|
|
94356
94586
|
init_schemas_index();
|
|
94357
94587
|
init_src2();
|
|
94358
94588
|
init_errors();
|
|
94359
94589
|
init_utils11();
|
|
94360
|
-
|
|
94590
|
+
logger38 = log.scope("AchievementController");
|
|
94361
94591
|
listCurrent = requireNonAnonymous(async (ctx) => {
|
|
94362
|
-
|
|
94592
|
+
logger38.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
94363
94593
|
return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
|
|
94364
94594
|
});
|
|
94365
94595
|
listHistory = requireNonAnonymous(async (ctx) => {
|
|
94366
94596
|
const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
|
|
94367
|
-
|
|
94597
|
+
logger38.debug("Listing achievement history", { userId: ctx.user.id, limit });
|
|
94368
94598
|
return ctx.services.achievement.listHistory(ctx.user, limit);
|
|
94369
94599
|
});
|
|
94370
94600
|
postProgress = requireNonAnonymous(async (ctx) => {
|
|
@@ -94375,12 +94605,12 @@ var init_achievement_controller = __esm(() => {
|
|
|
94375
94605
|
} catch (error2) {
|
|
94376
94606
|
if (error2 instanceof exports_external.ZodError) {
|
|
94377
94607
|
const details = formatZodError(error2);
|
|
94378
|
-
|
|
94608
|
+
logger38.warn("Submit achievement progress validation failed", { details });
|
|
94379
94609
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
94380
94610
|
}
|
|
94381
94611
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94382
94612
|
}
|
|
94383
|
-
|
|
94613
|
+
logger38.debug("Submitting progress", {
|
|
94384
94614
|
userId: ctx.user.id,
|
|
94385
94615
|
achievementId: body2.achievementId
|
|
94386
94616
|
});
|
|
@@ -94394,14 +94624,14 @@ var init_achievement_controller = __esm(() => {
|
|
|
94394
94624
|
});
|
|
94395
94625
|
|
|
94396
94626
|
// ../api-core/src/controllers/admin.controller.ts
|
|
94397
|
-
var
|
|
94627
|
+
var logger39, getAllowedOrigins;
|
|
94398
94628
|
var init_admin_controller = __esm(() => {
|
|
94399
94629
|
init_src2();
|
|
94400
94630
|
init_utils11();
|
|
94401
|
-
|
|
94631
|
+
logger39 = log.scope("AdminController");
|
|
94402
94632
|
getAllowedOrigins = requireAdmin(async (ctx) => {
|
|
94403
94633
|
const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
|
|
94404
|
-
|
|
94634
|
+
logger39.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
|
|
94405
94635
|
if (shouldRefresh) {
|
|
94406
94636
|
await ctx.providers.cache.refreshGameOrigins();
|
|
94407
94637
|
}
|
|
@@ -94416,14 +94646,14 @@ var init_admin_controller = __esm(() => {
|
|
|
94416
94646
|
});
|
|
94417
94647
|
|
|
94418
94648
|
// ../api-core/src/controllers/bucket.controller.ts
|
|
94419
|
-
var
|
|
94649
|
+
var logger40, listFiles, getFile, putFile, deleteFile, initiateUpload;
|
|
94420
94650
|
var init_bucket_controller = __esm(() => {
|
|
94421
94651
|
init_esm();
|
|
94422
94652
|
init_schemas_index();
|
|
94423
94653
|
init_src2();
|
|
94424
94654
|
init_errors();
|
|
94425
94655
|
init_utils11();
|
|
94426
|
-
|
|
94656
|
+
logger40 = log.scope("BucketController");
|
|
94427
94657
|
listFiles = requireDeveloper(async (ctx) => {
|
|
94428
94658
|
const slug2 = ctx.params.slug;
|
|
94429
94659
|
if (!slug2) {
|
|
@@ -94431,7 +94661,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
94431
94661
|
}
|
|
94432
94662
|
const url = ctx.url;
|
|
94433
94663
|
const prefix2 = url.searchParams.get("prefix") || undefined;
|
|
94434
|
-
|
|
94664
|
+
logger40.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
94435
94665
|
const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
|
|
94436
94666
|
return { files };
|
|
94437
94667
|
});
|
|
@@ -94441,7 +94671,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
94441
94671
|
if (!slug2 || !key) {
|
|
94442
94672
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
94443
94673
|
}
|
|
94444
|
-
|
|
94674
|
+
logger40.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
|
|
94445
94675
|
const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
|
|
94446
94676
|
return new Response(Buffer.from(object.body), {
|
|
94447
94677
|
status: 200,
|
|
@@ -94460,7 +94690,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
94460
94690
|
const arrayBuffer = await ctx.request.arrayBuffer();
|
|
94461
94691
|
const body2 = new Uint8Array(arrayBuffer);
|
|
94462
94692
|
const contentType = ctx.request.headers.get("content-type") || undefined;
|
|
94463
|
-
|
|
94693
|
+
logger40.debug("Uploading file", {
|
|
94464
94694
|
userId: ctx.user.id,
|
|
94465
94695
|
slug: slug2,
|
|
94466
94696
|
key,
|
|
@@ -94476,7 +94706,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
94476
94706
|
if (!slug2 || !key) {
|
|
94477
94707
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
94478
94708
|
}
|
|
94479
|
-
|
|
94709
|
+
logger40.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
|
|
94480
94710
|
await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
|
|
94481
94711
|
return { success: true, key };
|
|
94482
94712
|
});
|
|
@@ -94488,12 +94718,12 @@ var init_bucket_controller = __esm(() => {
|
|
|
94488
94718
|
} catch (error2) {
|
|
94489
94719
|
if (error2 instanceof exports_external.ZodError) {
|
|
94490
94720
|
const details = formatZodError(error2);
|
|
94491
|
-
|
|
94721
|
+
logger40.warn("Initiate upload validation failed", { details });
|
|
94492
94722
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
94493
94723
|
}
|
|
94494
94724
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94495
94725
|
}
|
|
94496
|
-
|
|
94726
|
+
logger40.debug("Initiating multipart upload", {
|
|
94497
94727
|
userId: ctx.user.id,
|
|
94498
94728
|
gameId: body2.gameId,
|
|
94499
94729
|
fileName: body2.fileName
|
|
@@ -94510,19 +94740,19 @@ async function listComponents(ctx) {
|
|
|
94510
94740
|
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
94511
94741
|
level = Math.floor(Math.max(0, parsed));
|
|
94512
94742
|
}
|
|
94513
|
-
|
|
94743
|
+
logger41.debug("Listing components", { level });
|
|
94514
94744
|
return ctx.services.character.listAvailableComponents(level);
|
|
94515
94745
|
}
|
|
94516
|
-
var
|
|
94746
|
+
var logger41, get, getByUserId, create, update2, equipAccessory, removeAccessory, character2;
|
|
94517
94747
|
var init_character_controller = __esm(() => {
|
|
94518
94748
|
init_esm();
|
|
94519
94749
|
init_schemas_index();
|
|
94520
94750
|
init_src2();
|
|
94521
94751
|
init_errors();
|
|
94522
94752
|
init_utils11();
|
|
94523
|
-
|
|
94753
|
+
logger41 = log.scope("CharacterController");
|
|
94524
94754
|
get = requireNonAnonymous(async (ctx) => {
|
|
94525
|
-
|
|
94755
|
+
logger41.debug("Getting character", { userId: ctx.user.id });
|
|
94526
94756
|
return ctx.services.character.getByUser(ctx.user);
|
|
94527
94757
|
});
|
|
94528
94758
|
getByUserId = requireNonAnonymous(async (ctx) => {
|
|
@@ -94530,7 +94760,7 @@ var init_character_controller = __esm(() => {
|
|
|
94530
94760
|
if (!userId) {
|
|
94531
94761
|
throw ApiError.badRequest("User ID is required in the URL path");
|
|
94532
94762
|
}
|
|
94533
|
-
|
|
94763
|
+
logger41.debug("Getting character by user ID", { requestedUserId: userId });
|
|
94534
94764
|
return ctx.services.character.getByUserId(userId);
|
|
94535
94765
|
});
|
|
94536
94766
|
create = requireNonAnonymous(async (ctx) => {
|
|
@@ -94541,12 +94771,12 @@ var init_character_controller = __esm(() => {
|
|
|
94541
94771
|
} catch (error2) {
|
|
94542
94772
|
if (error2 instanceof exports_external.ZodError) {
|
|
94543
94773
|
const details = formatZodError(error2);
|
|
94544
|
-
|
|
94774
|
+
logger41.warn("Create character validation failed", { details });
|
|
94545
94775
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
94546
94776
|
}
|
|
94547
94777
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94548
94778
|
}
|
|
94549
|
-
|
|
94779
|
+
logger41.debug("Creating character", {
|
|
94550
94780
|
userId: ctx.user.id,
|
|
94551
94781
|
bodyComponentId: body2.bodyComponentId,
|
|
94552
94782
|
hairstyleComponentId: body2.hairstyleComponentId
|
|
@@ -94561,12 +94791,12 @@ var init_character_controller = __esm(() => {
|
|
|
94561
94791
|
} catch (error2) {
|
|
94562
94792
|
if (error2 instanceof exports_external.ZodError) {
|
|
94563
94793
|
const details = formatZodError(error2);
|
|
94564
|
-
|
|
94794
|
+
logger41.warn("Update character validation failed", { details });
|
|
94565
94795
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
94566
94796
|
}
|
|
94567
94797
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94568
94798
|
}
|
|
94569
|
-
|
|
94799
|
+
logger41.debug("Updating character", {
|
|
94570
94800
|
userId: ctx.user.id,
|
|
94571
94801
|
bodyComponentId: body2.bodyComponentId,
|
|
94572
94802
|
hairstyleComponentId: body2.hairstyleComponentId,
|
|
@@ -94582,12 +94812,12 @@ var init_character_controller = __esm(() => {
|
|
|
94582
94812
|
} catch (error2) {
|
|
94583
94813
|
if (error2 instanceof exports_external.ZodError) {
|
|
94584
94814
|
const details = formatZodError(error2);
|
|
94585
|
-
|
|
94815
|
+
logger41.warn("Equip accessory validation failed", { details });
|
|
94586
94816
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
94587
94817
|
}
|
|
94588
94818
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94589
94819
|
}
|
|
94590
|
-
|
|
94820
|
+
logger41.debug("Equipping accessory", {
|
|
94591
94821
|
userId: ctx.user.id,
|
|
94592
94822
|
slot: body2.slot,
|
|
94593
94823
|
accessoryComponentId: body2.accessoryComponentId
|
|
@@ -94599,7 +94829,7 @@ var init_character_controller = __esm(() => {
|
|
|
94599
94829
|
if (!slot) {
|
|
94600
94830
|
throw ApiError.badRequest("Slot is required in the URL path");
|
|
94601
94831
|
}
|
|
94602
|
-
|
|
94832
|
+
logger41.debug("Removing accessory", { userId: ctx.user.id, slot });
|
|
94603
94833
|
await ctx.services.character.removeAccessory(slot, ctx.user);
|
|
94604
94834
|
return { success: true };
|
|
94605
94835
|
});
|
|
@@ -94615,7 +94845,7 @@ var init_character_controller = __esm(() => {
|
|
|
94615
94845
|
});
|
|
94616
94846
|
|
|
94617
94847
|
// ../api-core/src/controllers/currency.controller.ts
|
|
94618
|
-
var
|
|
94848
|
+
var logger42, list, getById, create2, update3, remove, currencyController;
|
|
94619
94849
|
var init_currency_controller = __esm(() => {
|
|
94620
94850
|
init_esm();
|
|
94621
94851
|
init_schemas_index();
|
|
@@ -94623,9 +94853,9 @@ var init_currency_controller = __esm(() => {
|
|
|
94623
94853
|
init_src4();
|
|
94624
94854
|
init_errors();
|
|
94625
94855
|
init_utils11();
|
|
94626
|
-
|
|
94856
|
+
logger42 = log.scope("CurrencyController");
|
|
94627
94857
|
list = requireNonAnonymous(async (ctx) => {
|
|
94628
|
-
|
|
94858
|
+
logger42.debug("Listing currencies", { userId: ctx.user.id });
|
|
94629
94859
|
return ctx.services.currency.list();
|
|
94630
94860
|
});
|
|
94631
94861
|
getById = requireNonAnonymous(async (ctx) => {
|
|
@@ -94636,7 +94866,7 @@ var init_currency_controller = __esm(() => {
|
|
|
94636
94866
|
if (!isValidUUID(currencyId)) {
|
|
94637
94867
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
94638
94868
|
}
|
|
94639
|
-
|
|
94869
|
+
logger42.debug("Getting currency", { userId: ctx.user.id, currencyId });
|
|
94640
94870
|
return ctx.services.currency.getById(currencyId);
|
|
94641
94871
|
});
|
|
94642
94872
|
create2 = requireAdmin(async (ctx) => {
|
|
@@ -94647,12 +94877,12 @@ var init_currency_controller = __esm(() => {
|
|
|
94647
94877
|
} catch (error2) {
|
|
94648
94878
|
if (error2 instanceof exports_external.ZodError) {
|
|
94649
94879
|
const details = formatZodError(error2);
|
|
94650
|
-
|
|
94880
|
+
logger42.warn("Create currency validation failed", { details });
|
|
94651
94881
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
94652
94882
|
}
|
|
94653
94883
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94654
94884
|
}
|
|
94655
|
-
|
|
94885
|
+
logger42.debug("Creating currency", {
|
|
94656
94886
|
userId: ctx.user.id,
|
|
94657
94887
|
symbol: body2.symbol,
|
|
94658
94888
|
itemId: body2.itemId,
|
|
@@ -94675,12 +94905,12 @@ var init_currency_controller = __esm(() => {
|
|
|
94675
94905
|
} catch (error2) {
|
|
94676
94906
|
if (error2 instanceof exports_external.ZodError) {
|
|
94677
94907
|
const details = formatZodError(error2);
|
|
94678
|
-
|
|
94908
|
+
logger42.warn("Update currency validation failed", { details });
|
|
94679
94909
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
94680
94910
|
}
|
|
94681
94911
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94682
94912
|
}
|
|
94683
|
-
|
|
94913
|
+
logger42.debug("Updating currency", {
|
|
94684
94914
|
userId: ctx.user.id,
|
|
94685
94915
|
currencyId,
|
|
94686
94916
|
symbol: body2.symbol,
|
|
@@ -94697,7 +94927,7 @@ var init_currency_controller = __esm(() => {
|
|
|
94697
94927
|
if (!isValidUUID(currencyId)) {
|
|
94698
94928
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
94699
94929
|
}
|
|
94700
|
-
|
|
94930
|
+
logger42.debug("Deleting currency", { userId: ctx.user.id, currencyId });
|
|
94701
94931
|
await ctx.services.currency.delete(currencyId);
|
|
94702
94932
|
});
|
|
94703
94933
|
currencyController = {
|
|
@@ -94710,14 +94940,14 @@ var init_currency_controller = __esm(() => {
|
|
|
94710
94940
|
});
|
|
94711
94941
|
|
|
94712
94942
|
// ../api-core/src/controllers/database.controller.ts
|
|
94713
|
-
var
|
|
94943
|
+
var logger43, reset;
|
|
94714
94944
|
var init_database_controller = __esm(() => {
|
|
94715
94945
|
init_esm();
|
|
94716
94946
|
init_schemas_index();
|
|
94717
94947
|
init_src2();
|
|
94718
94948
|
init_errors();
|
|
94719
94949
|
init_utils11();
|
|
94720
|
-
|
|
94950
|
+
logger43 = log.scope("DatabaseController");
|
|
94721
94951
|
reset = requireDeveloper(async (ctx) => {
|
|
94722
94952
|
const slug2 = ctx.params.slug;
|
|
94723
94953
|
if (!slug2) {
|
|
@@ -94730,11 +94960,11 @@ var init_database_controller = __esm(() => {
|
|
|
94730
94960
|
} catch (error2) {
|
|
94731
94961
|
if (error2 instanceof exports_external.ZodError) {
|
|
94732
94962
|
const details = formatZodError(error2);
|
|
94733
|
-
|
|
94963
|
+
logger43.warn("Database reset validation failed", { details });
|
|
94734
94964
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
94735
94965
|
}
|
|
94736
94966
|
}
|
|
94737
|
-
|
|
94967
|
+
logger43.debug("Resetting database", {
|
|
94738
94968
|
userId: ctx.user.id,
|
|
94739
94969
|
slug: slug2,
|
|
94740
94970
|
hasSchema: Boolean(body2.schema)
|
|
@@ -94752,7 +94982,7 @@ async function createJob(ctx) {
|
|
|
94752
94982
|
let body2;
|
|
94753
94983
|
try {
|
|
94754
94984
|
const json4 = await ctx.request.json();
|
|
94755
|
-
|
|
94985
|
+
logger44.debug("Deploy request body", {
|
|
94756
94986
|
keys: Object.keys(json4 || {}),
|
|
94757
94987
|
hasUploadToken: Boolean(json4?.uploadToken),
|
|
94758
94988
|
hasCode: Boolean(json4?.code),
|
|
@@ -94762,7 +94992,7 @@ async function createJob(ctx) {
|
|
|
94762
94992
|
} catch (error2) {
|
|
94763
94993
|
if (error2 instanceof exports_external.ZodError) {
|
|
94764
94994
|
const details = formatZodError(error2);
|
|
94765
|
-
|
|
94995
|
+
logger44.warn("Deploy validation failed", { details });
|
|
94766
94996
|
throw ApiError.unprocessableEntity("Invalid deploy request", details);
|
|
94767
94997
|
}
|
|
94768
94998
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -94783,14 +95013,14 @@ async function getJob(ctx) {
|
|
|
94783
95013
|
}
|
|
94784
95014
|
return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
|
|
94785
95015
|
}
|
|
94786
|
-
var
|
|
95016
|
+
var logger44, deploy;
|
|
94787
95017
|
var init_deploy_controller = __esm(() => {
|
|
94788
95018
|
init_esm();
|
|
94789
95019
|
init_schemas_index();
|
|
94790
95020
|
init_src2();
|
|
94791
95021
|
init_errors();
|
|
94792
95022
|
init_utils11();
|
|
94793
|
-
|
|
95023
|
+
logger44 = log.scope("DeployController");
|
|
94794
95024
|
deploy = {
|
|
94795
95025
|
createJob: requireDeveloper(createJob),
|
|
94796
95026
|
getJob: requireDeveloper(getJob)
|
|
@@ -94798,17 +95028,17 @@ var init_deploy_controller = __esm(() => {
|
|
|
94798
95028
|
});
|
|
94799
95029
|
|
|
94800
95030
|
// ../api-core/src/controllers/developer.controller.ts
|
|
94801
|
-
var
|
|
95031
|
+
var logger45, apply, getStatus, developer;
|
|
94802
95032
|
var init_developer_controller = __esm(() => {
|
|
94803
95033
|
init_src2();
|
|
94804
95034
|
init_utils11();
|
|
94805
|
-
|
|
95035
|
+
logger45 = log.scope("DeveloperController");
|
|
94806
95036
|
apply = requireNonAnonymous(async (ctx) => {
|
|
94807
|
-
|
|
95037
|
+
logger45.debug("Applying for developer status", { userId: ctx.user.id });
|
|
94808
95038
|
await ctx.services.developer.apply(ctx.user);
|
|
94809
95039
|
});
|
|
94810
95040
|
getStatus = requireNonAnonymous(async (ctx) => {
|
|
94811
|
-
|
|
95041
|
+
logger45.debug("Getting developer status", { userId: ctx.user.id });
|
|
94812
95042
|
const status = await ctx.services.developer.getStatus(ctx.user.id);
|
|
94813
95043
|
return { status };
|
|
94814
95044
|
});
|
|
@@ -94819,7 +95049,7 @@ var init_developer_controller = __esm(() => {
|
|
|
94819
95049
|
});
|
|
94820
95050
|
|
|
94821
95051
|
// ../api-core/src/controllers/domain.controller.ts
|
|
94822
|
-
var
|
|
95052
|
+
var logger46, add, list2, getStatus2, remove2, domains2;
|
|
94823
95053
|
var init_domain_controller = __esm(() => {
|
|
94824
95054
|
init_esm();
|
|
94825
95055
|
init_schemas_index();
|
|
@@ -94827,7 +95057,7 @@ var init_domain_controller = __esm(() => {
|
|
|
94827
95057
|
init_config2();
|
|
94828
95058
|
init_errors();
|
|
94829
95059
|
init_utils11();
|
|
94830
|
-
|
|
95060
|
+
logger46 = log.scope("DomainController");
|
|
94831
95061
|
add = requireDeveloper(async (ctx) => {
|
|
94832
95062
|
const slug2 = ctx.params.slug;
|
|
94833
95063
|
if (!slug2) {
|
|
@@ -94840,13 +95070,13 @@ var init_domain_controller = __esm(() => {
|
|
|
94840
95070
|
} catch (error2) {
|
|
94841
95071
|
if (error2 instanceof exports_external.ZodError) {
|
|
94842
95072
|
const details = formatZodError(error2);
|
|
94843
|
-
|
|
95073
|
+
logger46.warn("Add domain validation failed", { details });
|
|
94844
95074
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
94845
95075
|
}
|
|
94846
95076
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94847
95077
|
}
|
|
94848
95078
|
const environment = getPlatformEnvironment(ctx.config);
|
|
94849
|
-
|
|
95079
|
+
logger46.debug("Adding domain", {
|
|
94850
95080
|
userId: ctx.user.id,
|
|
94851
95081
|
slug: slug2,
|
|
94852
95082
|
hostname: body2.hostname,
|
|
@@ -94860,7 +95090,7 @@ var init_domain_controller = __esm(() => {
|
|
|
94860
95090
|
throw ApiError.badRequest("Missing game slug");
|
|
94861
95091
|
}
|
|
94862
95092
|
const environment = getPlatformEnvironment(ctx.config);
|
|
94863
|
-
|
|
95093
|
+
logger46.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
|
|
94864
95094
|
const domains2 = await ctx.services.domain.list(slug2, environment, ctx.user);
|
|
94865
95095
|
return { domains: domains2 };
|
|
94866
95096
|
});
|
|
@@ -94875,7 +95105,7 @@ var init_domain_controller = __esm(() => {
|
|
|
94875
95105
|
}
|
|
94876
95106
|
const refresh = ctx.url.searchParams.get("refresh") === "true";
|
|
94877
95107
|
const environment = getPlatformEnvironment(ctx.config);
|
|
94878
|
-
|
|
95108
|
+
logger46.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
|
|
94879
95109
|
return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
|
|
94880
95110
|
});
|
|
94881
95111
|
remove2 = requireDeveloper(async (ctx) => {
|
|
@@ -94888,7 +95118,7 @@ var init_domain_controller = __esm(() => {
|
|
|
94888
95118
|
throw ApiError.badRequest("Missing hostname");
|
|
94889
95119
|
}
|
|
94890
95120
|
const environment = getPlatformEnvironment(ctx.config);
|
|
94891
|
-
|
|
95121
|
+
logger46.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
|
|
94892
95122
|
await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
|
|
94893
95123
|
});
|
|
94894
95124
|
domains2 = {
|
|
@@ -94900,7 +95130,7 @@ var init_domain_controller = __esm(() => {
|
|
|
94900
95130
|
});
|
|
94901
95131
|
|
|
94902
95132
|
// ../api-core/src/controllers/game.controller.ts
|
|
94903
|
-
var
|
|
95133
|
+
var logger47, list3, listManageable, getSubjects, getById2, getBySlug, getManifest, upsertBySlug, remove3, games2;
|
|
94904
95134
|
var init_game_controller = __esm(() => {
|
|
94905
95135
|
init_esm();
|
|
94906
95136
|
init_schemas_index();
|
|
@@ -94908,17 +95138,17 @@ var init_game_controller = __esm(() => {
|
|
|
94908
95138
|
init_src4();
|
|
94909
95139
|
init_errors();
|
|
94910
95140
|
init_utils11();
|
|
94911
|
-
|
|
95141
|
+
logger47 = log.scope("GameController");
|
|
94912
95142
|
list3 = requireNonAnonymous(async (ctx) => {
|
|
94913
|
-
|
|
95143
|
+
logger47.debug("Listing games", { userId: ctx.user.id });
|
|
94914
95144
|
return ctx.services.game.list(ctx.user);
|
|
94915
95145
|
});
|
|
94916
95146
|
listManageable = requireNonAnonymous(async (ctx) => {
|
|
94917
|
-
|
|
95147
|
+
logger47.debug("Listing manageable games", { userId: ctx.user.id });
|
|
94918
95148
|
return ctx.services.game.listManageable(ctx.user);
|
|
94919
95149
|
});
|
|
94920
95150
|
getSubjects = requireNonAnonymous(async (ctx) => {
|
|
94921
|
-
|
|
95151
|
+
logger47.debug("Getting game subjects", { userId: ctx.user.id });
|
|
94922
95152
|
return ctx.services.game.getSubjects();
|
|
94923
95153
|
});
|
|
94924
95154
|
getById2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -94929,7 +95159,7 @@ var init_game_controller = __esm(() => {
|
|
|
94929
95159
|
if (!isValidUUID(gameId)) {
|
|
94930
95160
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
94931
95161
|
}
|
|
94932
|
-
|
|
95162
|
+
logger47.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
|
|
94933
95163
|
return ctx.services.game.getById(gameId, ctx.user);
|
|
94934
95164
|
});
|
|
94935
95165
|
getBySlug = requireNonAnonymous(async (ctx) => {
|
|
@@ -94937,7 +95167,7 @@ var init_game_controller = __esm(() => {
|
|
|
94937
95167
|
if (!slug2) {
|
|
94938
95168
|
throw ApiError.badRequest("Missing game slug");
|
|
94939
95169
|
}
|
|
94940
|
-
|
|
95170
|
+
logger47.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
|
|
94941
95171
|
return ctx.services.game.getBySlug(slug2, ctx.user);
|
|
94942
95172
|
});
|
|
94943
95173
|
getManifest = requireNonAnonymous(async (ctx) => {
|
|
@@ -94948,7 +95178,7 @@ var init_game_controller = __esm(() => {
|
|
|
94948
95178
|
if (!isValidUUID(gameId)) {
|
|
94949
95179
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
94950
95180
|
}
|
|
94951
|
-
|
|
95181
|
+
logger47.debug("Getting game manifest by ID", {
|
|
94952
95182
|
userId: ctx.user.id,
|
|
94953
95183
|
gameId,
|
|
94954
95184
|
launchId: ctx.launchId
|
|
@@ -94967,12 +95197,12 @@ var init_game_controller = __esm(() => {
|
|
|
94967
95197
|
} catch (error2) {
|
|
94968
95198
|
if (error2 instanceof exports_external.ZodError) {
|
|
94969
95199
|
const details = formatZodError(error2);
|
|
94970
|
-
|
|
95200
|
+
logger47.warn("Upsert game validation failed", { details });
|
|
94971
95201
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
94972
95202
|
}
|
|
94973
95203
|
throw ApiError.badRequest("Invalid JSON body");
|
|
94974
95204
|
}
|
|
94975
|
-
|
|
95205
|
+
logger47.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
|
|
94976
95206
|
return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
|
|
94977
95207
|
});
|
|
94978
95208
|
remove3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -94983,7 +95213,7 @@ var init_game_controller = __esm(() => {
|
|
|
94983
95213
|
if (!isValidUUID(gameId)) {
|
|
94984
95214
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
94985
95215
|
}
|
|
94986
|
-
|
|
95216
|
+
logger47.debug("Deleting game", { userId: ctx.user.id, gameId });
|
|
94987
95217
|
await ctx.services.game.delete(gameId, ctx.user);
|
|
94988
95218
|
});
|
|
94989
95219
|
games2 = {
|
|
@@ -94999,16 +95229,16 @@ var init_game_controller = __esm(() => {
|
|
|
94999
95229
|
});
|
|
95000
95230
|
|
|
95001
95231
|
// ../api-core/src/controllers/inventory.controller.ts
|
|
95002
|
-
var
|
|
95232
|
+
var logger48, list4, addItem, removeItem, inventory;
|
|
95003
95233
|
var init_inventory_controller = __esm(() => {
|
|
95004
95234
|
init_esm();
|
|
95005
95235
|
init_schemas_index();
|
|
95006
95236
|
init_src2();
|
|
95007
95237
|
init_errors();
|
|
95008
95238
|
init_utils11();
|
|
95009
|
-
|
|
95239
|
+
logger48 = log.scope("InventoryController");
|
|
95010
95240
|
list4 = requireNonAnonymous(async (ctx) => {
|
|
95011
|
-
|
|
95241
|
+
logger48.debug("Listing inventory", { userId: ctx.user.id });
|
|
95012
95242
|
return ctx.services.inventory.list(ctx.user);
|
|
95013
95243
|
});
|
|
95014
95244
|
addItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -95019,12 +95249,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
95019
95249
|
} catch (error2) {
|
|
95020
95250
|
if (error2 instanceof exports_external.ZodError) {
|
|
95021
95251
|
const details = formatZodError(error2);
|
|
95022
|
-
|
|
95252
|
+
logger48.warn("Add inventory item validation failed", { details });
|
|
95023
95253
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
95024
95254
|
}
|
|
95025
95255
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95026
95256
|
}
|
|
95027
|
-
|
|
95257
|
+
logger48.debug("Adding item", {
|
|
95028
95258
|
userId: ctx.user.id,
|
|
95029
95259
|
itemId: body2.itemId,
|
|
95030
95260
|
qty: body2.qty
|
|
@@ -95039,12 +95269,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
95039
95269
|
} catch (error2) {
|
|
95040
95270
|
if (error2 instanceof exports_external.ZodError) {
|
|
95041
95271
|
const details = formatZodError(error2);
|
|
95042
|
-
|
|
95272
|
+
logger48.warn("Remove inventory item validation failed", { details });
|
|
95043
95273
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
95044
95274
|
}
|
|
95045
95275
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95046
95276
|
}
|
|
95047
|
-
|
|
95277
|
+
logger48.debug("Removing item", {
|
|
95048
95278
|
userId: ctx.user.id,
|
|
95049
95279
|
itemId: body2.itemId,
|
|
95050
95280
|
qty: body2.qty
|
|
@@ -95059,7 +95289,7 @@ var init_inventory_controller = __esm(() => {
|
|
|
95059
95289
|
});
|
|
95060
95290
|
|
|
95061
95291
|
// ../api-core/src/controllers/item.controller.ts
|
|
95062
|
-
var
|
|
95292
|
+
var logger49, list5, getById3, resolve2, create3, update4, remove4, listByGame, createForGame, updateForGame, deleteForGame, items2;
|
|
95063
95293
|
var init_item_controller = __esm(() => {
|
|
95064
95294
|
init_esm();
|
|
95065
95295
|
init_schemas_index();
|
|
@@ -95067,10 +95297,10 @@ var init_item_controller = __esm(() => {
|
|
|
95067
95297
|
init_src4();
|
|
95068
95298
|
init_errors();
|
|
95069
95299
|
init_utils11();
|
|
95070
|
-
|
|
95300
|
+
logger49 = log.scope("ItemController");
|
|
95071
95301
|
list5 = requireNonAnonymous(async (ctx) => {
|
|
95072
95302
|
const gameId = ctx.url.searchParams.get("gameId") || undefined;
|
|
95073
|
-
|
|
95303
|
+
logger49.debug("Listing items", { userId: ctx.user.id, gameId });
|
|
95074
95304
|
return ctx.services.item.list(gameId);
|
|
95075
95305
|
});
|
|
95076
95306
|
getById3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -95081,7 +95311,7 @@ var init_item_controller = __esm(() => {
|
|
|
95081
95311
|
if (!isValidUUID(itemId)) {
|
|
95082
95312
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
95083
95313
|
}
|
|
95084
|
-
|
|
95314
|
+
logger49.debug("Getting item", { userId: ctx.user.id, itemId });
|
|
95085
95315
|
return ctx.services.item.getById(itemId);
|
|
95086
95316
|
});
|
|
95087
95317
|
resolve2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -95093,7 +95323,7 @@ var init_item_controller = __esm(() => {
|
|
|
95093
95323
|
if (gameId && !isValidUUID(gameId)) {
|
|
95094
95324
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
95095
95325
|
}
|
|
95096
|
-
|
|
95326
|
+
logger49.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
|
|
95097
95327
|
return ctx.services.item.resolveBySlug(slug2, gameId);
|
|
95098
95328
|
});
|
|
95099
95329
|
create3 = requireRole(["admin"], async (ctx) => {
|
|
@@ -95104,12 +95334,12 @@ var init_item_controller = __esm(() => {
|
|
|
95104
95334
|
} catch (error2) {
|
|
95105
95335
|
if (error2 instanceof exports_external.ZodError) {
|
|
95106
95336
|
const details = formatZodError(error2);
|
|
95107
|
-
|
|
95337
|
+
logger49.warn("Create item validation failed", { details });
|
|
95108
95338
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95109
95339
|
}
|
|
95110
95340
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95111
95341
|
}
|
|
95112
|
-
|
|
95342
|
+
logger49.debug("Creating item", {
|
|
95113
95343
|
userId: ctx.user.id,
|
|
95114
95344
|
slug: body2.slug,
|
|
95115
95345
|
displayName: body2.displayName
|
|
@@ -95131,7 +95361,7 @@ var init_item_controller = __esm(() => {
|
|
|
95131
95361
|
} catch (error2) {
|
|
95132
95362
|
if (error2 instanceof exports_external.ZodError) {
|
|
95133
95363
|
const details = formatZodError(error2);
|
|
95134
|
-
|
|
95364
|
+
logger49.warn("Update item validation failed", { details });
|
|
95135
95365
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95136
95366
|
}
|
|
95137
95367
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -95139,7 +95369,7 @@ var init_item_controller = __esm(() => {
|
|
|
95139
95369
|
if (Object.keys(body2).length === 0) {
|
|
95140
95370
|
throw ApiError.badRequest("No update data provided");
|
|
95141
95371
|
}
|
|
95142
|
-
|
|
95372
|
+
logger49.debug("Updating item", {
|
|
95143
95373
|
userId: ctx.user.id,
|
|
95144
95374
|
itemId,
|
|
95145
95375
|
slug: body2.slug,
|
|
@@ -95156,7 +95386,7 @@ var init_item_controller = __esm(() => {
|
|
|
95156
95386
|
if (!isValidUUID(itemId)) {
|
|
95157
95387
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
95158
95388
|
}
|
|
95159
|
-
|
|
95389
|
+
logger49.debug("Deleting item", { userId: ctx.user.id, itemId });
|
|
95160
95390
|
await ctx.services.item.delete(itemId);
|
|
95161
95391
|
});
|
|
95162
95392
|
listByGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -95167,7 +95397,7 @@ var init_item_controller = __esm(() => {
|
|
|
95167
95397
|
if (!isValidUUID(gameId)) {
|
|
95168
95398
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
95169
95399
|
}
|
|
95170
|
-
|
|
95400
|
+
logger49.debug("Listing game items", { userId: ctx.user.id, gameId });
|
|
95171
95401
|
return ctx.services.item.listByGame(gameId);
|
|
95172
95402
|
});
|
|
95173
95403
|
createForGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -95185,12 +95415,12 @@ var init_item_controller = __esm(() => {
|
|
|
95185
95415
|
} catch (error2) {
|
|
95186
95416
|
if (error2 instanceof exports_external.ZodError) {
|
|
95187
95417
|
const details = formatZodError(error2);
|
|
95188
|
-
|
|
95418
|
+
logger49.warn("Create game item validation failed", { details });
|
|
95189
95419
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95190
95420
|
}
|
|
95191
95421
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95192
95422
|
}
|
|
95193
|
-
|
|
95423
|
+
logger49.debug("Creating game item", {
|
|
95194
95424
|
userId: ctx.user.id,
|
|
95195
95425
|
gameId,
|
|
95196
95426
|
slug: body2.slug,
|
|
@@ -95217,7 +95447,7 @@ var init_item_controller = __esm(() => {
|
|
|
95217
95447
|
} catch (error2) {
|
|
95218
95448
|
if (error2 instanceof exports_external.ZodError) {
|
|
95219
95449
|
const details = formatZodError(error2);
|
|
95220
|
-
|
|
95450
|
+
logger49.warn("Update game item validation failed", { details });
|
|
95221
95451
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95222
95452
|
}
|
|
95223
95453
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -95225,7 +95455,7 @@ var init_item_controller = __esm(() => {
|
|
|
95225
95455
|
if (Object.keys(body2).length === 0) {
|
|
95226
95456
|
throw ApiError.badRequest("No update data provided");
|
|
95227
95457
|
}
|
|
95228
|
-
|
|
95458
|
+
logger49.debug("Updating game item", {
|
|
95229
95459
|
userId: ctx.user.id,
|
|
95230
95460
|
gameId,
|
|
95231
95461
|
itemId,
|
|
@@ -95247,7 +95477,7 @@ var init_item_controller = __esm(() => {
|
|
|
95247
95477
|
if (!isValidUUID(itemId)) {
|
|
95248
95478
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
95249
95479
|
}
|
|
95250
|
-
|
|
95480
|
+
logger49.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
|
|
95251
95481
|
await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
|
|
95252
95482
|
});
|
|
95253
95483
|
items2 = {
|
|
@@ -95265,14 +95495,14 @@ var init_item_controller = __esm(() => {
|
|
|
95265
95495
|
});
|
|
95266
95496
|
|
|
95267
95497
|
// ../api-core/src/controllers/kv.controller.ts
|
|
95268
|
-
var
|
|
95498
|
+
var logger50, listKeys, getStats, seed, getValue2, setValue2, deleteValue, getMetadata, clear;
|
|
95269
95499
|
var init_kv_controller = __esm(() => {
|
|
95270
95500
|
init_esm();
|
|
95271
95501
|
init_schemas_index();
|
|
95272
95502
|
init_src2();
|
|
95273
95503
|
init_errors();
|
|
95274
95504
|
init_utils11();
|
|
95275
|
-
|
|
95505
|
+
logger50 = log.scope("KVController");
|
|
95276
95506
|
listKeys = requireDeveloper(async (ctx) => {
|
|
95277
95507
|
const slug2 = ctx.params.slug;
|
|
95278
95508
|
if (!slug2) {
|
|
@@ -95280,7 +95510,7 @@ var init_kv_controller = __esm(() => {
|
|
|
95280
95510
|
}
|
|
95281
95511
|
const url = ctx.url;
|
|
95282
95512
|
const prefix2 = url.searchParams.get("prefix") || undefined;
|
|
95283
|
-
|
|
95513
|
+
logger50.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
95284
95514
|
const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
|
|
95285
95515
|
return { keys };
|
|
95286
95516
|
});
|
|
@@ -95289,7 +95519,7 @@ var init_kv_controller = __esm(() => {
|
|
|
95289
95519
|
if (!slug2) {
|
|
95290
95520
|
throw ApiError.badRequest("Missing game slug");
|
|
95291
95521
|
}
|
|
95292
|
-
|
|
95522
|
+
logger50.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
|
|
95293
95523
|
return ctx.services.kv.getStats(slug2, ctx.user);
|
|
95294
95524
|
});
|
|
95295
95525
|
seed = requireDeveloper(async (ctx) => {
|
|
@@ -95304,12 +95534,12 @@ var init_kv_controller = __esm(() => {
|
|
|
95304
95534
|
} catch (error2) {
|
|
95305
95535
|
if (error2 instanceof exports_external.ZodError) {
|
|
95306
95536
|
const details = formatZodError(error2);
|
|
95307
|
-
|
|
95537
|
+
logger50.warn("Seed validation failed", { details });
|
|
95308
95538
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95309
95539
|
}
|
|
95310
95540
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95311
95541
|
}
|
|
95312
|
-
|
|
95542
|
+
logger50.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
|
|
95313
95543
|
await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
|
|
95314
95544
|
return { success: true, count: body2.entries.length };
|
|
95315
95545
|
});
|
|
@@ -95319,7 +95549,7 @@ var init_kv_controller = __esm(() => {
|
|
|
95319
95549
|
if (!slug2 || !key) {
|
|
95320
95550
|
throw ApiError.badRequest("Missing game slug or key");
|
|
95321
95551
|
}
|
|
95322
|
-
|
|
95552
|
+
logger50.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
|
|
95323
95553
|
const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
|
|
95324
95554
|
return { key, value };
|
|
95325
95555
|
});
|
|
@@ -95333,7 +95563,7 @@ var init_kv_controller = __esm(() => {
|
|
|
95333
95563
|
if (!value) {
|
|
95334
95564
|
throw ApiError.badRequest("Missing value in request body");
|
|
95335
95565
|
}
|
|
95336
|
-
|
|
95566
|
+
logger50.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
|
|
95337
95567
|
await ctx.services.kv.setValue(slug2, key, value, ctx.user);
|
|
95338
95568
|
return { success: true, key };
|
|
95339
95569
|
});
|
|
@@ -95343,7 +95573,7 @@ var init_kv_controller = __esm(() => {
|
|
|
95343
95573
|
if (!slug2 || !key) {
|
|
95344
95574
|
throw ApiError.badRequest("Missing game slug or key");
|
|
95345
95575
|
}
|
|
95346
|
-
|
|
95576
|
+
logger50.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
|
|
95347
95577
|
await ctx.services.kv.deleteValue(slug2, key, ctx.user);
|
|
95348
95578
|
return { success: true, key };
|
|
95349
95579
|
});
|
|
@@ -95353,7 +95583,7 @@ var init_kv_controller = __esm(() => {
|
|
|
95353
95583
|
if (!slug2 || !key) {
|
|
95354
95584
|
throw ApiError.badRequest("Missing game slug or key");
|
|
95355
95585
|
}
|
|
95356
|
-
|
|
95586
|
+
logger50.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
|
|
95357
95587
|
const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
|
|
95358
95588
|
return { key, metadata: metadata2 };
|
|
95359
95589
|
});
|
|
@@ -95362,21 +95592,21 @@ var init_kv_controller = __esm(() => {
|
|
|
95362
95592
|
if (!slug2) {
|
|
95363
95593
|
throw ApiError.badRequest("Missing game slug");
|
|
95364
95594
|
}
|
|
95365
|
-
|
|
95595
|
+
logger50.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
|
|
95366
95596
|
const deleted = await ctx.services.kv.clear(slug2, ctx.user);
|
|
95367
95597
|
return { success: true, deleted };
|
|
95368
95598
|
});
|
|
95369
95599
|
});
|
|
95370
95600
|
|
|
95371
95601
|
// ../api-core/src/controllers/leaderboard.controller.ts
|
|
95372
|
-
var
|
|
95602
|
+
var logger51, submitScore, getGlobalLeaderboard, getLeaderboard, getUserRank, getUserAllScores, getUserScores, leaderboard;
|
|
95373
95603
|
var init_leaderboard_controller = __esm(() => {
|
|
95374
95604
|
init_esm();
|
|
95375
95605
|
init_schemas_index();
|
|
95376
95606
|
init_src2();
|
|
95377
95607
|
init_errors();
|
|
95378
95608
|
init_utils11();
|
|
95379
|
-
|
|
95609
|
+
logger51 = log.scope("LeaderboardController");
|
|
95380
95610
|
submitScore = requireAuth(async (ctx) => {
|
|
95381
95611
|
const gameId = ctx.params.gameId;
|
|
95382
95612
|
if (!gameId) {
|
|
@@ -95389,12 +95619,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
95389
95619
|
} catch (error2) {
|
|
95390
95620
|
if (error2 instanceof exports_external.ZodError) {
|
|
95391
95621
|
const details = formatZodError(error2);
|
|
95392
|
-
|
|
95622
|
+
logger51.warn("Submit score validation failed", { details });
|
|
95393
95623
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95394
95624
|
}
|
|
95395
95625
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95396
95626
|
}
|
|
95397
|
-
|
|
95627
|
+
logger51.debug("Submitting score", {
|
|
95398
95628
|
userId: ctx.user.id,
|
|
95399
95629
|
gameId,
|
|
95400
95630
|
score: body2.score
|
|
@@ -95417,12 +95647,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
95417
95647
|
} catch (error2) {
|
|
95418
95648
|
if (error2 instanceof exports_external.ZodError) {
|
|
95419
95649
|
const details = formatZodError(error2);
|
|
95420
|
-
|
|
95650
|
+
logger51.warn("Get global leaderboard query validation failed", { details });
|
|
95421
95651
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
95422
95652
|
}
|
|
95423
95653
|
throw ApiError.badRequest("Invalid query parameters");
|
|
95424
95654
|
}
|
|
95425
|
-
|
|
95655
|
+
logger51.debug("Getting global leaderboard", {
|
|
95426
95656
|
userId: ctx.user.id,
|
|
95427
95657
|
gameId,
|
|
95428
95658
|
...query
|
|
@@ -95445,12 +95675,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
95445
95675
|
} catch (error2) {
|
|
95446
95676
|
if (error2 instanceof exports_external.ZodError) {
|
|
95447
95677
|
const details = formatZodError(error2);
|
|
95448
|
-
|
|
95678
|
+
logger51.warn("Get leaderboard query validation failed", { details });
|
|
95449
95679
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
95450
95680
|
}
|
|
95451
95681
|
throw ApiError.badRequest("Invalid query parameters");
|
|
95452
95682
|
}
|
|
95453
|
-
|
|
95683
|
+
logger51.debug("Getting leaderboard", {
|
|
95454
95684
|
userId: ctx.user.id,
|
|
95455
95685
|
gameId,
|
|
95456
95686
|
...query
|
|
@@ -95462,7 +95692,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
95462
95692
|
if (!gameId || !userId) {
|
|
95463
95693
|
throw ApiError.badRequest("Game ID and User ID are required");
|
|
95464
95694
|
}
|
|
95465
|
-
|
|
95695
|
+
logger51.debug("Getting user rank", {
|
|
95466
95696
|
requesterId: ctx.user.id,
|
|
95467
95697
|
gameId,
|
|
95468
95698
|
targetUserId: userId
|
|
@@ -95477,7 +95707,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
95477
95707
|
const url = ctx.url;
|
|
95478
95708
|
const limit = Math.min(Number(url.searchParams.get("limit") || "50"), 100);
|
|
95479
95709
|
const gameId = url.searchParams.get("gameId") || undefined;
|
|
95480
|
-
|
|
95710
|
+
logger51.debug("Getting user all scores", {
|
|
95481
95711
|
requesterId: ctx.user.id,
|
|
95482
95712
|
targetUserId: userId,
|
|
95483
95713
|
gameId,
|
|
@@ -95492,7 +95722,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
95492
95722
|
}
|
|
95493
95723
|
const url = ctx.url;
|
|
95494
95724
|
const limit = Math.min(Number(url.searchParams.get("limit") || "10"), 100);
|
|
95495
|
-
|
|
95725
|
+
logger51.debug("Getting user scores", {
|
|
95496
95726
|
requesterId: ctx.user.id,
|
|
95497
95727
|
gameId,
|
|
95498
95728
|
targetUserId: userId,
|
|
@@ -95512,7 +95742,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
95512
95742
|
|
|
95513
95743
|
// ../api-core/src/controllers/level.controller.ts
|
|
95514
95744
|
async function listConfigs(ctx) {
|
|
95515
|
-
|
|
95745
|
+
logger52.debug("Listing level configs");
|
|
95516
95746
|
return ctx.services.level.listConfigs();
|
|
95517
95747
|
}
|
|
95518
95748
|
async function getConfig(ctx) {
|
|
@@ -95524,21 +95754,21 @@ async function getConfig(ctx) {
|
|
|
95524
95754
|
if (isNaN(level) || level < 1) {
|
|
95525
95755
|
throw ApiError.badRequest("Level must be a positive integer");
|
|
95526
95756
|
}
|
|
95527
|
-
|
|
95757
|
+
logger52.debug("Getting level config", { level });
|
|
95528
95758
|
return ctx.services.level.getConfig(level);
|
|
95529
95759
|
}
|
|
95530
|
-
var
|
|
95760
|
+
var logger52, getByUser, getProgress, levels;
|
|
95531
95761
|
var init_level_controller = __esm(() => {
|
|
95532
95762
|
init_src2();
|
|
95533
95763
|
init_errors();
|
|
95534
95764
|
init_utils11();
|
|
95535
|
-
|
|
95765
|
+
logger52 = log.scope("LevelController");
|
|
95536
95766
|
getByUser = requireNonAnonymous(async (ctx) => {
|
|
95537
|
-
|
|
95767
|
+
logger52.debug("Getting user level", { userId: ctx.user.id });
|
|
95538
95768
|
return ctx.services.level.getByUser(ctx.user);
|
|
95539
95769
|
});
|
|
95540
95770
|
getProgress = requireNonAnonymous(async (ctx) => {
|
|
95541
|
-
|
|
95771
|
+
logger52.debug("Getting level progress", { userId: ctx.user.id });
|
|
95542
95772
|
return ctx.services.level.getProgress(ctx.user);
|
|
95543
95773
|
});
|
|
95544
95774
|
levels = {
|
|
@@ -95550,12 +95780,12 @@ var init_level_controller = __esm(() => {
|
|
|
95550
95780
|
});
|
|
95551
95781
|
|
|
95552
95782
|
// ../api-core/src/controllers/logs.controller.ts
|
|
95553
|
-
var
|
|
95783
|
+
var logger53, generateToken, logs;
|
|
95554
95784
|
var init_logs_controller = __esm(() => {
|
|
95555
95785
|
init_src2();
|
|
95556
95786
|
init_errors();
|
|
95557
95787
|
init_utils11();
|
|
95558
|
-
|
|
95788
|
+
logger53 = log.scope("LogsController");
|
|
95559
95789
|
generateToken = requireDeveloper(async (ctx) => {
|
|
95560
95790
|
const slug2 = ctx.params.slug;
|
|
95561
95791
|
if (!slug2) {
|
|
@@ -95574,7 +95804,7 @@ var init_logs_controller = __esm(() => {
|
|
|
95574
95804
|
}
|
|
95575
95805
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95576
95806
|
}
|
|
95577
|
-
|
|
95807
|
+
logger53.debug("Generating log stream token", {
|
|
95578
95808
|
userId: ctx.user.id,
|
|
95579
95809
|
slug: slug2,
|
|
95580
95810
|
environment: body2.environment
|
|
@@ -95587,13 +95817,13 @@ var init_logs_controller = __esm(() => {
|
|
|
95587
95817
|
});
|
|
95588
95818
|
|
|
95589
95819
|
// ../api-core/src/controllers/lti.controller.ts
|
|
95590
|
-
var
|
|
95820
|
+
var logger54, getStatus3, lti;
|
|
95591
95821
|
var init_lti_controller = __esm(() => {
|
|
95592
95822
|
init_src2();
|
|
95593
95823
|
init_utils11();
|
|
95594
|
-
|
|
95824
|
+
logger54 = log.scope("LtiController");
|
|
95595
95825
|
getStatus3 = requireNonAnonymous(async (ctx) => {
|
|
95596
|
-
|
|
95826
|
+
logger54.debug("Getting status", { userId: ctx.user.id });
|
|
95597
95827
|
return ctx.services.lti.getStatus(ctx.user);
|
|
95598
95828
|
});
|
|
95599
95829
|
lti = {
|
|
@@ -95602,7 +95832,7 @@ var init_lti_controller = __esm(() => {
|
|
|
95602
95832
|
});
|
|
95603
95833
|
|
|
95604
95834
|
// ../api-core/src/controllers/map.controller.ts
|
|
95605
|
-
var
|
|
95835
|
+
var logger55, getByIdentifier, getElements, getObjects, createObject, deleteObject, maps2;
|
|
95606
95836
|
var init_map_controller = __esm(() => {
|
|
95607
95837
|
init_esm();
|
|
95608
95838
|
init_schemas_index();
|
|
@@ -95610,13 +95840,13 @@ var init_map_controller = __esm(() => {
|
|
|
95610
95840
|
init_src4();
|
|
95611
95841
|
init_errors();
|
|
95612
95842
|
init_utils11();
|
|
95613
|
-
|
|
95843
|
+
logger55 = log.scope("MapController");
|
|
95614
95844
|
getByIdentifier = requireNonAnonymous(async (ctx) => {
|
|
95615
95845
|
const identifier = ctx.params.identifier;
|
|
95616
95846
|
if (!identifier) {
|
|
95617
95847
|
throw ApiError.badRequest("Missing map identifier");
|
|
95618
95848
|
}
|
|
95619
|
-
|
|
95849
|
+
logger55.debug("Getting map", { userId: ctx.user.id, identifier });
|
|
95620
95850
|
return ctx.services.map.getByIdentifier(identifier);
|
|
95621
95851
|
});
|
|
95622
95852
|
getElements = requireNonAnonymous(async (ctx) => {
|
|
@@ -95627,7 +95857,7 @@ var init_map_controller = __esm(() => {
|
|
|
95627
95857
|
if (!isValidUUID(mapId)) {
|
|
95628
95858
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
95629
95859
|
}
|
|
95630
|
-
|
|
95860
|
+
logger55.debug("Getting map elements", { userId: ctx.user.id, mapId });
|
|
95631
95861
|
return ctx.services.map.getElements(mapId);
|
|
95632
95862
|
});
|
|
95633
95863
|
getObjects = requireNonAnonymous(async (ctx) => {
|
|
@@ -95638,7 +95868,7 @@ var init_map_controller = __esm(() => {
|
|
|
95638
95868
|
if (!isValidUUID(mapId)) {
|
|
95639
95869
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
95640
95870
|
}
|
|
95641
|
-
|
|
95871
|
+
logger55.debug("Getting map objects", { userId: ctx.user.id, mapId });
|
|
95642
95872
|
return ctx.services.map.getObjects(mapId, ctx.user.id);
|
|
95643
95873
|
});
|
|
95644
95874
|
createObject = requireNonAnonymous(async (ctx) => {
|
|
@@ -95660,12 +95890,12 @@ var init_map_controller = __esm(() => {
|
|
|
95660
95890
|
} catch (error2) {
|
|
95661
95891
|
if (error2 instanceof exports_external.ZodError) {
|
|
95662
95892
|
const details = formatZodError(error2);
|
|
95663
|
-
|
|
95893
|
+
logger55.warn("Create map object validation failed", { details });
|
|
95664
95894
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95665
95895
|
}
|
|
95666
95896
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95667
95897
|
}
|
|
95668
|
-
|
|
95898
|
+
logger55.debug("Creating map object", {
|
|
95669
95899
|
userId: ctx.user.id,
|
|
95670
95900
|
mapId,
|
|
95671
95901
|
itemId: body2.itemId,
|
|
@@ -95689,7 +95919,7 @@ var init_map_controller = __esm(() => {
|
|
|
95689
95919
|
if (!isValidUUID(objectId)) {
|
|
95690
95920
|
throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
|
|
95691
95921
|
}
|
|
95692
|
-
|
|
95922
|
+
logger55.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
|
|
95693
95923
|
await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
|
|
95694
95924
|
});
|
|
95695
95925
|
maps2 = {
|
|
@@ -95702,14 +95932,14 @@ var init_map_controller = __esm(() => {
|
|
|
95702
95932
|
});
|
|
95703
95933
|
|
|
95704
95934
|
// ../api-core/src/controllers/notification.controller.ts
|
|
95705
|
-
var
|
|
95935
|
+
var logger56, list6, updateStatus, getStats2, create4, deliver, notifications2;
|
|
95706
95936
|
var init_notification_controller = __esm(() => {
|
|
95707
95937
|
init_esm();
|
|
95708
95938
|
init_schemas_index();
|
|
95709
95939
|
init_src2();
|
|
95710
95940
|
init_errors();
|
|
95711
95941
|
init_utils11();
|
|
95712
|
-
|
|
95942
|
+
logger56 = log.scope("NotificationController");
|
|
95713
95943
|
list6 = requireNonAnonymous(async (ctx) => {
|
|
95714
95944
|
const query = {
|
|
95715
95945
|
status: ctx.url.searchParams.get("status") || undefined,
|
|
@@ -95720,10 +95950,10 @@ var init_notification_controller = __esm(() => {
|
|
|
95720
95950
|
const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
|
|
95721
95951
|
if (!result.success) {
|
|
95722
95952
|
const details = formatZodError(result.error);
|
|
95723
|
-
|
|
95953
|
+
logger56.warn("List notifications query validation failed", { details });
|
|
95724
95954
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
95725
95955
|
}
|
|
95726
|
-
|
|
95956
|
+
logger56.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
|
|
95727
95957
|
return ctx.services.notification.list(ctx.user, result.data);
|
|
95728
95958
|
});
|
|
95729
95959
|
updateStatus = requireNonAnonymous(async (ctx) => {
|
|
@@ -95738,12 +95968,12 @@ var init_notification_controller = __esm(() => {
|
|
|
95738
95968
|
} catch (error2) {
|
|
95739
95969
|
if (error2 instanceof exports_external.ZodError) {
|
|
95740
95970
|
const details = formatZodError(error2);
|
|
95741
|
-
|
|
95971
|
+
logger56.warn("Update notification status validation failed", { details });
|
|
95742
95972
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
95743
95973
|
}
|
|
95744
95974
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95745
95975
|
}
|
|
95746
|
-
|
|
95976
|
+
logger56.debug("Updating status", {
|
|
95747
95977
|
userId: ctx.user.id,
|
|
95748
95978
|
notificationId,
|
|
95749
95979
|
status: body2.status
|
|
@@ -95753,7 +95983,7 @@ var init_notification_controller = __esm(() => {
|
|
|
95753
95983
|
getStats2 = requireNonAnonymous(async (ctx) => {
|
|
95754
95984
|
const startDate = ctx.url.searchParams.get("startDate");
|
|
95755
95985
|
const endDate = ctx.url.searchParams.get("endDate");
|
|
95756
|
-
|
|
95986
|
+
logger56.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
|
|
95757
95987
|
return ctx.services.notification.getStats(ctx.user, {
|
|
95758
95988
|
startDate: startDate ? new Date(startDate) : undefined,
|
|
95759
95989
|
endDate: endDate ? new Date(endDate) : undefined
|
|
@@ -95767,12 +95997,12 @@ var init_notification_controller = __esm(() => {
|
|
|
95767
95997
|
} catch (error2) {
|
|
95768
95998
|
if (error2 instanceof exports_external.ZodError) {
|
|
95769
95999
|
const details = formatZodError(error2);
|
|
95770
|
-
|
|
96000
|
+
logger56.warn("Create notification validation failed", { details });
|
|
95771
96001
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
95772
96002
|
}
|
|
95773
96003
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95774
96004
|
}
|
|
95775
|
-
|
|
96005
|
+
logger56.debug("Creating notification", {
|
|
95776
96006
|
userId: ctx.user.id,
|
|
95777
96007
|
targetUserId: body2.userId,
|
|
95778
96008
|
type: body2.type
|
|
@@ -95790,12 +96020,12 @@ var init_notification_controller = __esm(() => {
|
|
|
95790
96020
|
});
|
|
95791
96021
|
});
|
|
95792
96022
|
deliver = requireNonAnonymous(async (ctx) => {
|
|
95793
|
-
|
|
96023
|
+
logger56.debug("Delivering notifications", { userId: ctx.user.id });
|
|
95794
96024
|
try {
|
|
95795
96025
|
await ctx.services.notification.deliverPending(ctx.user.id);
|
|
95796
96026
|
return { success: true };
|
|
95797
96027
|
} catch (error2) {
|
|
95798
|
-
|
|
96028
|
+
logger56.error("Failed to deliver notifications", { error: error2 });
|
|
95799
96029
|
throw ApiError.internal("Failed to deliver notifications");
|
|
95800
96030
|
}
|
|
95801
96031
|
});
|
|
@@ -95809,14 +96039,14 @@ var init_notification_controller = __esm(() => {
|
|
|
95809
96039
|
});
|
|
95810
96040
|
|
|
95811
96041
|
// ../api-core/src/controllers/realtime.controller.ts
|
|
95812
|
-
var
|
|
96042
|
+
var logger57, generateToken2, realtime;
|
|
95813
96043
|
var init_realtime_controller = __esm(() => {
|
|
95814
96044
|
init_src2();
|
|
95815
96045
|
init_utils11();
|
|
95816
|
-
|
|
96046
|
+
logger57 = log.scope("RealtimeController");
|
|
95817
96047
|
generateToken2 = requireNonAnonymous(async (ctx) => {
|
|
95818
96048
|
const gameIdOrSlug = ctx.params.gameId;
|
|
95819
|
-
|
|
96049
|
+
logger57.debug("Generating token", {
|
|
95820
96050
|
userId: ctx.user.id,
|
|
95821
96051
|
gameId: gameIdOrSlug || "global",
|
|
95822
96052
|
launchId: ctx.launchId
|
|
@@ -95829,20 +96059,20 @@ var init_realtime_controller = __esm(() => {
|
|
|
95829
96059
|
});
|
|
95830
96060
|
|
|
95831
96061
|
// ../api-core/src/controllers/secrets.controller.ts
|
|
95832
|
-
var
|
|
96062
|
+
var logger58, listKeys2, setSecrets, deleteSecret, secrets;
|
|
95833
96063
|
var init_secrets_controller = __esm(() => {
|
|
95834
96064
|
init_esm();
|
|
95835
96065
|
init_schemas_index();
|
|
95836
96066
|
init_src2();
|
|
95837
96067
|
init_errors();
|
|
95838
96068
|
init_utils11();
|
|
95839
|
-
|
|
96069
|
+
logger58 = log.scope("SecretsController");
|
|
95840
96070
|
listKeys2 = requireDeveloper(async (ctx) => {
|
|
95841
96071
|
const slug2 = ctx.params.slug;
|
|
95842
96072
|
if (!slug2) {
|
|
95843
96073
|
throw ApiError.badRequest("Missing game slug");
|
|
95844
96074
|
}
|
|
95845
|
-
|
|
96075
|
+
logger58.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
|
|
95846
96076
|
const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
|
|
95847
96077
|
return { keys };
|
|
95848
96078
|
});
|
|
@@ -95858,12 +96088,12 @@ var init_secrets_controller = __esm(() => {
|
|
|
95858
96088
|
} catch (error2) {
|
|
95859
96089
|
if (error2 instanceof exports_external.ZodError) {
|
|
95860
96090
|
const details = formatZodError(error2);
|
|
95861
|
-
|
|
96091
|
+
logger58.warn("Set secrets validation failed", { details });
|
|
95862
96092
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95863
96093
|
}
|
|
95864
96094
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95865
96095
|
}
|
|
95866
|
-
|
|
96096
|
+
logger58.debug("Setting secrets", {
|
|
95867
96097
|
userId: ctx.user.id,
|
|
95868
96098
|
slug: slug2,
|
|
95869
96099
|
keyCount: Object.keys(body2).length
|
|
@@ -95880,7 +96110,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
95880
96110
|
if (!key) {
|
|
95881
96111
|
throw ApiError.badRequest("Missing secret key");
|
|
95882
96112
|
}
|
|
95883
|
-
|
|
96113
|
+
logger58.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
|
|
95884
96114
|
await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
|
|
95885
96115
|
return { success: true };
|
|
95886
96116
|
});
|
|
@@ -95892,14 +96122,14 @@ var init_secrets_controller = __esm(() => {
|
|
|
95892
96122
|
});
|
|
95893
96123
|
|
|
95894
96124
|
// ../api-core/src/controllers/seed.controller.ts
|
|
95895
|
-
var
|
|
96125
|
+
var logger59, seed2;
|
|
95896
96126
|
var init_seed_controller = __esm(() => {
|
|
95897
96127
|
init_esm();
|
|
95898
96128
|
init_schemas_index();
|
|
95899
96129
|
init_src2();
|
|
95900
96130
|
init_errors();
|
|
95901
96131
|
init_utils11();
|
|
95902
|
-
|
|
96132
|
+
logger59 = log.scope("SeedController");
|
|
95903
96133
|
seed2 = requireDeveloper(async (ctx) => {
|
|
95904
96134
|
const slug2 = ctx.params.slug;
|
|
95905
96135
|
if (!slug2) {
|
|
@@ -95912,12 +96142,12 @@ var init_seed_controller = __esm(() => {
|
|
|
95912
96142
|
} catch (error2) {
|
|
95913
96143
|
if (error2 instanceof exports_external.ZodError) {
|
|
95914
96144
|
const details = formatZodError(error2);
|
|
95915
|
-
|
|
96145
|
+
logger59.warn("Seed database validation failed", { details });
|
|
95916
96146
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
95917
96147
|
}
|
|
95918
96148
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95919
96149
|
}
|
|
95920
|
-
|
|
96150
|
+
logger59.debug("Seeding database", {
|
|
95921
96151
|
userId: ctx.user.id,
|
|
95922
96152
|
slug: slug2,
|
|
95923
96153
|
codeLength: body2.code.length,
|
|
@@ -95928,18 +96158,18 @@ var init_seed_controller = __esm(() => {
|
|
|
95928
96158
|
});
|
|
95929
96159
|
|
|
95930
96160
|
// ../api-core/src/controllers/session.controller.ts
|
|
95931
|
-
var
|
|
96161
|
+
var logger60, start2, end, mintToken, sessions2;
|
|
95932
96162
|
var init_session_controller = __esm(() => {
|
|
95933
96163
|
init_src2();
|
|
95934
96164
|
init_errors();
|
|
95935
96165
|
init_utils11();
|
|
95936
|
-
|
|
96166
|
+
logger60 = log.scope("SessionController");
|
|
95937
96167
|
start2 = requireAuth(async (ctx) => {
|
|
95938
96168
|
const gameIdOrSlug = ctx.params.gameId;
|
|
95939
96169
|
if (!gameIdOrSlug) {
|
|
95940
96170
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
95941
96171
|
}
|
|
95942
|
-
|
|
96172
|
+
logger60.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
95943
96173
|
return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
|
|
95944
96174
|
});
|
|
95945
96175
|
end = requireAuth(async (ctx) => {
|
|
@@ -95951,7 +96181,7 @@ var init_session_controller = __esm(() => {
|
|
|
95951
96181
|
if (!sessionId) {
|
|
95952
96182
|
throw ApiError.badRequest("Missing session ID");
|
|
95953
96183
|
}
|
|
95954
|
-
|
|
96184
|
+
logger60.debug("Ending session", {
|
|
95955
96185
|
userId: ctx.user.id,
|
|
95956
96186
|
gameIdOrSlug,
|
|
95957
96187
|
sessionId,
|
|
@@ -95964,7 +96194,7 @@ var init_session_controller = __esm(() => {
|
|
|
95964
96194
|
if (!gameIdOrSlug) {
|
|
95965
96195
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
95966
96196
|
}
|
|
95967
|
-
|
|
96197
|
+
logger60.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
95968
96198
|
return ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
|
|
95969
96199
|
});
|
|
95970
96200
|
sessions2 = {
|
|
@@ -95975,13 +96205,13 @@ var init_session_controller = __esm(() => {
|
|
|
95975
96205
|
});
|
|
95976
96206
|
|
|
95977
96207
|
// ../api-core/src/controllers/shop.controller.ts
|
|
95978
|
-
var
|
|
96208
|
+
var logger61, getShopView, shop;
|
|
95979
96209
|
var init_shop_controller = __esm(() => {
|
|
95980
96210
|
init_src2();
|
|
95981
96211
|
init_utils11();
|
|
95982
|
-
|
|
96212
|
+
logger61 = log.scope("ShopController");
|
|
95983
96213
|
getShopView = requireNonAnonymous(async (ctx) => {
|
|
95984
|
-
|
|
96214
|
+
logger61.debug("Getting shop view", { userId: ctx.user.id });
|
|
95985
96215
|
return ctx.services.shop.getShopView(ctx.user);
|
|
95986
96216
|
});
|
|
95987
96217
|
shop = {
|
|
@@ -95990,7 +96220,7 @@ var init_shop_controller = __esm(() => {
|
|
|
95990
96220
|
});
|
|
95991
96221
|
|
|
95992
96222
|
// ../api-core/src/controllers/shop-listing.controller.ts
|
|
95993
|
-
var
|
|
96223
|
+
var logger62, list7, getById4, create5, update5, remove5, listByGame2, getByGameItem, createForGameItem, updateForGameItem, deleteForGameItem, shopListings2;
|
|
95994
96224
|
var init_shop_listing_controller = __esm(() => {
|
|
95995
96225
|
init_esm();
|
|
95996
96226
|
init_schemas_index();
|
|
@@ -95998,9 +96228,9 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
95998
96228
|
init_src4();
|
|
95999
96229
|
init_errors();
|
|
96000
96230
|
init_utils11();
|
|
96001
|
-
|
|
96231
|
+
logger62 = log.scope("ShopListingController");
|
|
96002
96232
|
list7 = requireAdmin(async (ctx) => {
|
|
96003
|
-
|
|
96233
|
+
logger62.debug("Listing shop listings", { userId: ctx.user.id });
|
|
96004
96234
|
return ctx.services.shopListing.list();
|
|
96005
96235
|
});
|
|
96006
96236
|
getById4 = requireAdmin(async (ctx) => {
|
|
@@ -96011,7 +96241,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96011
96241
|
if (!isValidUUID(listingId)) {
|
|
96012
96242
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
96013
96243
|
}
|
|
96014
|
-
|
|
96244
|
+
logger62.debug("Getting listing", { userId: ctx.user.id, listingId });
|
|
96015
96245
|
return ctx.services.shopListing.getById(listingId);
|
|
96016
96246
|
});
|
|
96017
96247
|
create5 = requireAdmin(async (ctx) => {
|
|
@@ -96022,12 +96252,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96022
96252
|
} catch (error2) {
|
|
96023
96253
|
if (error2 instanceof exports_external.ZodError) {
|
|
96024
96254
|
const details = formatZodError(error2);
|
|
96025
|
-
|
|
96255
|
+
logger62.warn("Create shop listing validation failed", { details });
|
|
96026
96256
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96027
96257
|
}
|
|
96028
96258
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96029
96259
|
}
|
|
96030
|
-
|
|
96260
|
+
logger62.debug("Creating listing", {
|
|
96031
96261
|
userId: ctx.user.id,
|
|
96032
96262
|
itemId: body2.itemId,
|
|
96033
96263
|
currencyId: body2.currencyId,
|
|
@@ -96050,12 +96280,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96050
96280
|
} catch (error2) {
|
|
96051
96281
|
if (error2 instanceof exports_external.ZodError) {
|
|
96052
96282
|
const details = formatZodError(error2);
|
|
96053
|
-
|
|
96283
|
+
logger62.warn("Update shop listing validation failed", { details });
|
|
96054
96284
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96055
96285
|
}
|
|
96056
96286
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96057
96287
|
}
|
|
96058
|
-
|
|
96288
|
+
logger62.debug("Updating listing", {
|
|
96059
96289
|
userId: ctx.user.id,
|
|
96060
96290
|
listingId,
|
|
96061
96291
|
price: body2.price,
|
|
@@ -96072,7 +96302,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96072
96302
|
if (!isValidUUID(listingId)) {
|
|
96073
96303
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
96074
96304
|
}
|
|
96075
|
-
|
|
96305
|
+
logger62.debug("Deleting listing", { userId: ctx.user.id, listingId });
|
|
96076
96306
|
await ctx.services.shopListing.delete(listingId);
|
|
96077
96307
|
});
|
|
96078
96308
|
listByGame2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96083,7 +96313,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96083
96313
|
if (!isValidUUID(gameId)) {
|
|
96084
96314
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96085
96315
|
}
|
|
96086
|
-
|
|
96316
|
+
logger62.debug("Listing game listings", { userId: ctx.user.id, gameId });
|
|
96087
96317
|
return ctx.services.shopListing.listByGame(gameId, ctx.user);
|
|
96088
96318
|
});
|
|
96089
96319
|
getByGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -96098,7 +96328,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96098
96328
|
if (!isValidUUID(itemId)) {
|
|
96099
96329
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96100
96330
|
}
|
|
96101
|
-
|
|
96331
|
+
logger62.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
|
|
96102
96332
|
return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
|
|
96103
96333
|
});
|
|
96104
96334
|
createForGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -96120,12 +96350,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96120
96350
|
} catch (error2) {
|
|
96121
96351
|
if (error2 instanceof exports_external.ZodError) {
|
|
96122
96352
|
const details = formatZodError(error2);
|
|
96123
|
-
|
|
96353
|
+
logger62.warn("Create game item listing validation failed", { details });
|
|
96124
96354
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96125
96355
|
}
|
|
96126
96356
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96127
96357
|
}
|
|
96128
|
-
|
|
96358
|
+
logger62.debug("Creating game item listing", {
|
|
96129
96359
|
userId: ctx.user.id,
|
|
96130
96360
|
gameId,
|
|
96131
96361
|
itemId,
|
|
@@ -96153,12 +96383,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96153
96383
|
} catch (error2) {
|
|
96154
96384
|
if (error2 instanceof exports_external.ZodError) {
|
|
96155
96385
|
const details = formatZodError(error2);
|
|
96156
|
-
|
|
96386
|
+
logger62.warn("Update game item listing validation failed", { details });
|
|
96157
96387
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96158
96388
|
}
|
|
96159
96389
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96160
96390
|
}
|
|
96161
|
-
|
|
96391
|
+
logger62.debug("Updating game item listing", {
|
|
96162
96392
|
userId: ctx.user.id,
|
|
96163
96393
|
gameId,
|
|
96164
96394
|
itemId,
|
|
@@ -96180,7 +96410,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
96180
96410
|
if (!isValidUUID(itemId)) {
|
|
96181
96411
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96182
96412
|
}
|
|
96183
|
-
|
|
96413
|
+
logger62.debug("Deleting game item listing", {
|
|
96184
96414
|
userId: ctx.user.id,
|
|
96185
96415
|
gameId,
|
|
96186
96416
|
itemId
|
|
@@ -96207,21 +96437,21 @@ async function getBySlug2(ctx) {
|
|
|
96207
96437
|
if (!slug2) {
|
|
96208
96438
|
throw ApiError.badRequest("Template slug is required");
|
|
96209
96439
|
}
|
|
96210
|
-
|
|
96440
|
+
logger63.debug("Getting sprite by slug", { slug: slug2 });
|
|
96211
96441
|
return ctx.services.sprite.getBySlug(slug2);
|
|
96212
96442
|
}
|
|
96213
|
-
var
|
|
96443
|
+
var logger63, sprites;
|
|
96214
96444
|
var init_sprite_controller = __esm(() => {
|
|
96215
96445
|
init_src2();
|
|
96216
96446
|
init_errors();
|
|
96217
|
-
|
|
96447
|
+
logger63 = log.scope("SpriteController");
|
|
96218
96448
|
sprites = {
|
|
96219
96449
|
getBySlug: getBySlug2
|
|
96220
96450
|
};
|
|
96221
96451
|
});
|
|
96222
96452
|
|
|
96223
96453
|
// ../api-core/src/controllers/timeback.controller.ts
|
|
96224
|
-
var
|
|
96454
|
+
var logger64, getTodayXp, getTotalXp, updateTodayXp, getXpHistory, populateStudent, getUser, getUserById, setupIntegration, getIntegrations, verifyIntegration, getConfig2, deleteIntegrations, endActivity, heartbeat, advanceCourse, getStudentXp, getRoster, getStudentOverview, getStudentActivity, grantXp, adjustTime, adjustMastery, toggleCompletion, searchStudents, enrollStudent, unenrollStudent, timeback2;
|
|
96225
96455
|
var init_timeback_controller = __esm(() => {
|
|
96226
96456
|
init_esm();
|
|
96227
96457
|
init_schemas_index();
|
|
@@ -96229,15 +96459,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
96229
96459
|
init_src4();
|
|
96230
96460
|
init_errors();
|
|
96231
96461
|
init_utils11();
|
|
96232
|
-
|
|
96462
|
+
logger64 = log.scope("TimebackController");
|
|
96233
96463
|
getTodayXp = requireNonAnonymous(async (ctx) => {
|
|
96234
96464
|
const date4 = ctx.url.searchParams.get("date") || undefined;
|
|
96235
96465
|
const tz = ctx.url.searchParams.get("tz") || undefined;
|
|
96236
|
-
|
|
96466
|
+
logger64.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
|
|
96237
96467
|
return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
|
|
96238
96468
|
});
|
|
96239
96469
|
getTotalXp = requireNonAnonymous(async (ctx) => {
|
|
96240
|
-
|
|
96470
|
+
logger64.debug("Getting total XP", { userId: ctx.user.id });
|
|
96241
96471
|
return ctx.services.timeback.getTotalXp(ctx.user.id);
|
|
96242
96472
|
});
|
|
96243
96473
|
updateTodayXp = requireNonAnonymous(async (ctx) => {
|
|
@@ -96248,18 +96478,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
96248
96478
|
} catch (error2) {
|
|
96249
96479
|
if (error2 instanceof exports_external.ZodError) {
|
|
96250
96480
|
const details = formatZodError(error2);
|
|
96251
|
-
|
|
96481
|
+
logger64.warn("Update today XP validation failed", { details });
|
|
96252
96482
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96253
96483
|
}
|
|
96254
96484
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96255
96485
|
}
|
|
96256
|
-
|
|
96486
|
+
logger64.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
|
|
96257
96487
|
return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
|
|
96258
96488
|
});
|
|
96259
96489
|
getXpHistory = requireNonAnonymous(async (ctx) => {
|
|
96260
96490
|
const startDate = ctx.url.searchParams.get("startDate") || undefined;
|
|
96261
96491
|
const endDate = ctx.url.searchParams.get("endDate") || undefined;
|
|
96262
|
-
|
|
96492
|
+
logger64.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
|
|
96263
96493
|
return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
|
|
96264
96494
|
});
|
|
96265
96495
|
populateStudent = requireNonAnonymous(async (ctx) => {
|
|
@@ -96270,18 +96500,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
96270
96500
|
} catch (error2) {
|
|
96271
96501
|
if (error2 instanceof exports_external.ZodError) {
|
|
96272
96502
|
const details = formatZodError(error2);
|
|
96273
|
-
|
|
96503
|
+
logger64.warn("Populate student validation failed", { details });
|
|
96274
96504
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96275
96505
|
}
|
|
96276
96506
|
}
|
|
96277
|
-
|
|
96507
|
+
logger64.debug("Populating student", {
|
|
96278
96508
|
userId: ctx.user.id,
|
|
96279
96509
|
hasProvidedNames: Boolean(providedNames)
|
|
96280
96510
|
});
|
|
96281
96511
|
return ctx.services.timeback.populateStudent(ctx.user, providedNames);
|
|
96282
96512
|
});
|
|
96283
96513
|
getUser = requireNonAnonymous(async (ctx) => {
|
|
96284
|
-
|
|
96514
|
+
logger64.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
96285
96515
|
return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
|
|
96286
96516
|
});
|
|
96287
96517
|
getUserById = requireNonAnonymous(async (ctx) => {
|
|
@@ -96289,7 +96519,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96289
96519
|
if (!timebackId) {
|
|
96290
96520
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
96291
96521
|
}
|
|
96292
|
-
|
|
96522
|
+
logger64.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
|
|
96293
96523
|
return ctx.services.timeback.getUserDataByTimebackId(timebackId);
|
|
96294
96524
|
});
|
|
96295
96525
|
setupIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -96300,12 +96530,12 @@ var init_timeback_controller = __esm(() => {
|
|
|
96300
96530
|
} catch (error2) {
|
|
96301
96531
|
if (error2 instanceof exports_external.ZodError) {
|
|
96302
96532
|
const details = formatZodError(error2);
|
|
96303
|
-
|
|
96533
|
+
logger64.warn("Setup integration validation failed", { details });
|
|
96304
96534
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96305
96535
|
}
|
|
96306
96536
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96307
96537
|
}
|
|
96308
|
-
|
|
96538
|
+
logger64.debug("Setting up integration", {
|
|
96309
96539
|
userId: ctx.user.id,
|
|
96310
96540
|
gameId: body2.gameId
|
|
96311
96541
|
});
|
|
@@ -96319,7 +96549,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96319
96549
|
if (!isValidUUID(gameId)) {
|
|
96320
96550
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
96321
96551
|
}
|
|
96322
|
-
|
|
96552
|
+
logger64.debug("Getting integrations", { userId: ctx.user.id, gameId });
|
|
96323
96553
|
return ctx.services.timeback.getIntegrations(gameId, ctx.user);
|
|
96324
96554
|
});
|
|
96325
96555
|
verifyIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -96330,7 +96560,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96330
96560
|
if (!isValidUUID(gameId)) {
|
|
96331
96561
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
96332
96562
|
}
|
|
96333
|
-
|
|
96563
|
+
logger64.debug("Verifying integration", { userId: ctx.user.id, gameId });
|
|
96334
96564
|
return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
|
|
96335
96565
|
});
|
|
96336
96566
|
getConfig2 = requireDeveloper(async (ctx) => {
|
|
@@ -96341,7 +96571,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96341
96571
|
if (!isValidUUID(gameId)) {
|
|
96342
96572
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
96343
96573
|
}
|
|
96344
|
-
|
|
96574
|
+
logger64.debug("Getting config", { userId: ctx.user.id, gameId });
|
|
96345
96575
|
return ctx.services.timeback.getConfig(gameId, ctx.user);
|
|
96346
96576
|
});
|
|
96347
96577
|
deleteIntegrations = requireDeveloper(async (ctx) => {
|
|
@@ -96352,7 +96582,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96352
96582
|
if (!isValidUUID(gameId)) {
|
|
96353
96583
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
96354
96584
|
}
|
|
96355
|
-
|
|
96585
|
+
logger64.debug("Deleting integrations", { userId: ctx.user.id, gameId });
|
|
96356
96586
|
await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
|
|
96357
96587
|
});
|
|
96358
96588
|
endActivity = requireDeveloper(async (ctx) => {
|
|
@@ -96363,7 +96593,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96363
96593
|
} catch (error2) {
|
|
96364
96594
|
if (error2 instanceof exports_external.ZodError) {
|
|
96365
96595
|
const details = formatZodError(error2);
|
|
96366
|
-
|
|
96596
|
+
logger64.warn("End activity validation failed", { details });
|
|
96367
96597
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96368
96598
|
}
|
|
96369
96599
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96381,7 +96611,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96381
96611
|
masteredUnits,
|
|
96382
96612
|
extensions
|
|
96383
96613
|
} = body2;
|
|
96384
|
-
|
|
96614
|
+
logger64.debug("Ending activity", { userId: ctx.user.id, gameId });
|
|
96385
96615
|
return ctx.services.timeback.endActivity({
|
|
96386
96616
|
gameId,
|
|
96387
96617
|
studentId,
|
|
@@ -96405,7 +96635,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96405
96635
|
} catch (error2) {
|
|
96406
96636
|
if (error2 instanceof exports_external.ZodError) {
|
|
96407
96637
|
const details = formatZodError(error2);
|
|
96408
|
-
|
|
96638
|
+
logger64.warn("Heartbeat validation failed", { details });
|
|
96409
96639
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96410
96640
|
}
|
|
96411
96641
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96421,7 +96651,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96421
96651
|
windowSequence,
|
|
96422
96652
|
isFinal
|
|
96423
96653
|
} = body2;
|
|
96424
|
-
|
|
96654
|
+
logger64.debug("Recording heartbeat", {
|
|
96425
96655
|
userId: ctx.user.id,
|
|
96426
96656
|
gameId,
|
|
96427
96657
|
runId,
|
|
@@ -96444,6 +96674,19 @@ var init_timeback_controller = __esm(() => {
|
|
|
96444
96674
|
user: ctx.user
|
|
96445
96675
|
});
|
|
96446
96676
|
});
|
|
96677
|
+
advanceCourse = requireDeveloper(async (ctx) => {
|
|
96678
|
+
const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
|
|
96679
|
+
logger64.debug("Advancing student manually", {
|
|
96680
|
+
userId: ctx.user.id,
|
|
96681
|
+
gameId: body2.gameId,
|
|
96682
|
+
studentId: body2.studentId,
|
|
96683
|
+
subject: body2.subject
|
|
96684
|
+
});
|
|
96685
|
+
return ctx.services.timeback.advanceCourse({
|
|
96686
|
+
...body2,
|
|
96687
|
+
user: ctx.user
|
|
96688
|
+
});
|
|
96689
|
+
});
|
|
96447
96690
|
getStudentXp = requireDeveloper(async (ctx) => {
|
|
96448
96691
|
const timebackId = ctx.params.timebackId;
|
|
96449
96692
|
if (!timebackId) {
|
|
@@ -96474,7 +96717,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96474
96717
|
perCourse: includeOptions.includes("percourse"),
|
|
96475
96718
|
today: includeOptions.includes("today")
|
|
96476
96719
|
};
|
|
96477
|
-
|
|
96720
|
+
logger64.debug("Getting student XP", {
|
|
96478
96721
|
requesterId: ctx.user.id,
|
|
96479
96722
|
timebackId,
|
|
96480
96723
|
gameId,
|
|
@@ -96495,7 +96738,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96495
96738
|
if (!gameId || !courseId) {
|
|
96496
96739
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
96497
96740
|
}
|
|
96498
|
-
|
|
96741
|
+
logger64.debug("Getting course roster", {
|
|
96499
96742
|
requesterId: ctx.user.id,
|
|
96500
96743
|
gameId,
|
|
96501
96744
|
courseId
|
|
@@ -96509,7 +96752,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96509
96752
|
if (!timebackId || !gameId) {
|
|
96510
96753
|
throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
|
|
96511
96754
|
}
|
|
96512
|
-
|
|
96755
|
+
logger64.debug("Getting student overview", {
|
|
96513
96756
|
requesterId: ctx.user.id,
|
|
96514
96757
|
timebackId,
|
|
96515
96758
|
gameId,
|
|
@@ -96528,7 +96771,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96528
96771
|
if (!timebackId || !courseId || !gameId) {
|
|
96529
96772
|
throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
|
|
96530
96773
|
}
|
|
96531
|
-
|
|
96774
|
+
logger64.debug("Getting student activity", {
|
|
96532
96775
|
requesterId: ctx.user.id,
|
|
96533
96776
|
timebackId,
|
|
96534
96777
|
courseId,
|
|
@@ -96546,7 +96789,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96546
96789
|
});
|
|
96547
96790
|
grantXp = requireDeveloper(async (ctx) => {
|
|
96548
96791
|
const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
|
|
96549
|
-
|
|
96792
|
+
logger64.debug("Granting manual XP", {
|
|
96550
96793
|
requesterId: ctx.user.id,
|
|
96551
96794
|
gameId: body2.gameId,
|
|
96552
96795
|
courseId: body2.courseId,
|
|
@@ -96558,7 +96801,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96558
96801
|
});
|
|
96559
96802
|
adjustTime = requireDeveloper(async (ctx) => {
|
|
96560
96803
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
|
|
96561
|
-
|
|
96804
|
+
logger64.debug("Adjusting time spent", {
|
|
96562
96805
|
requesterId: ctx.user.id,
|
|
96563
96806
|
gameId: body2.gameId,
|
|
96564
96807
|
courseId: body2.courseId,
|
|
@@ -96570,7 +96813,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96570
96813
|
});
|
|
96571
96814
|
adjustMastery = requireDeveloper(async (ctx) => {
|
|
96572
96815
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
|
|
96573
|
-
|
|
96816
|
+
logger64.debug("Adjusting mastered units", {
|
|
96574
96817
|
requesterId: ctx.user.id,
|
|
96575
96818
|
gameId: body2.gameId,
|
|
96576
96819
|
courseId: body2.courseId,
|
|
@@ -96582,7 +96825,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96582
96825
|
});
|
|
96583
96826
|
toggleCompletion = requireGameManagementAccess(async (ctx) => {
|
|
96584
96827
|
const body2 = await parseRequestBody(ctx.request, ToggleCourseCompletionRequestSchema);
|
|
96585
|
-
|
|
96828
|
+
logger64.debug("Toggling course completion", {
|
|
96586
96829
|
requesterId: ctx.user.id,
|
|
96587
96830
|
gameId: body2.gameId,
|
|
96588
96831
|
courseId: body2.courseId,
|
|
@@ -96598,7 +96841,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96598
96841
|
if (!gameId || !courseId) {
|
|
96599
96842
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
96600
96843
|
}
|
|
96601
|
-
|
|
96844
|
+
logger64.debug("Searching students for enrollment", {
|
|
96602
96845
|
requesterId: ctx.user.id,
|
|
96603
96846
|
gameId,
|
|
96604
96847
|
courseId,
|
|
@@ -96608,7 +96851,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96608
96851
|
});
|
|
96609
96852
|
enrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
96610
96853
|
const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
|
|
96611
|
-
|
|
96854
|
+
logger64.debug("Enrolling student", {
|
|
96612
96855
|
requesterId: ctx.user.id,
|
|
96613
96856
|
gameId: body2.gameId,
|
|
96614
96857
|
courseId: body2.courseId,
|
|
@@ -96618,7 +96861,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96618
96861
|
});
|
|
96619
96862
|
unenrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
96620
96863
|
const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
|
|
96621
|
-
|
|
96864
|
+
logger64.debug("Unenrolling student", {
|
|
96622
96865
|
requesterId: ctx.user.id,
|
|
96623
96866
|
gameId: body2.gameId,
|
|
96624
96867
|
courseId: body2.courseId,
|
|
@@ -96641,6 +96884,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
96641
96884
|
deleteIntegrations,
|
|
96642
96885
|
endActivity,
|
|
96643
96886
|
heartbeat,
|
|
96887
|
+
advanceCourse,
|
|
96644
96888
|
getStudentXp,
|
|
96645
96889
|
getRoster,
|
|
96646
96890
|
getStudentOverview,
|
|
@@ -96656,14 +96900,14 @@ var init_timeback_controller = __esm(() => {
|
|
|
96656
96900
|
});
|
|
96657
96901
|
|
|
96658
96902
|
// ../api-core/src/controllers/upload.controller.ts
|
|
96659
|
-
var
|
|
96903
|
+
var logger65, initiate;
|
|
96660
96904
|
var init_upload_controller = __esm(() => {
|
|
96661
96905
|
init_esm();
|
|
96662
96906
|
init_schemas_index();
|
|
96663
96907
|
init_src2();
|
|
96664
96908
|
init_errors();
|
|
96665
96909
|
init_utils11();
|
|
96666
|
-
|
|
96910
|
+
logger65 = log.scope("UploadController");
|
|
96667
96911
|
initiate = requireDeveloper(async (ctx) => {
|
|
96668
96912
|
let body2;
|
|
96669
96913
|
try {
|
|
@@ -96672,34 +96916,34 @@ var init_upload_controller = __esm(() => {
|
|
|
96672
96916
|
} catch (error2) {
|
|
96673
96917
|
if (error2 instanceof exports_external.ZodError) {
|
|
96674
96918
|
const details = formatZodError(error2);
|
|
96675
|
-
|
|
96919
|
+
logger65.warn("Initiate upload validation failed", { details });
|
|
96676
96920
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96677
96921
|
}
|
|
96678
96922
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96679
96923
|
}
|
|
96680
|
-
|
|
96924
|
+
logger65.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
|
|
96681
96925
|
return ctx.services.upload.initiate(body2, ctx.user);
|
|
96682
96926
|
});
|
|
96683
96927
|
});
|
|
96684
96928
|
|
|
96685
96929
|
// ../api-core/src/controllers/user.controller.ts
|
|
96686
|
-
var
|
|
96930
|
+
var logger66, getMe, getDemoProfile, updateDemoProfile, users2;
|
|
96687
96931
|
var init_user_controller = __esm(() => {
|
|
96688
96932
|
init_schemas_index();
|
|
96689
96933
|
init_src2();
|
|
96690
96934
|
init_utils11();
|
|
96691
|
-
|
|
96935
|
+
logger66 = log.scope("UserController");
|
|
96692
96936
|
getMe = requireNonAnonymous(async (ctx) => {
|
|
96693
|
-
|
|
96937
|
+
logger66.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
96694
96938
|
return ctx.services.user.getMe(ctx.user, ctx.gameId);
|
|
96695
96939
|
});
|
|
96696
96940
|
getDemoProfile = requireAnonymous(async (ctx) => {
|
|
96697
|
-
|
|
96941
|
+
logger66.debug("Getting demo profile", { userId: ctx.user.id });
|
|
96698
96942
|
return ctx.services.user.getDemoProfile(ctx.user.id);
|
|
96699
96943
|
});
|
|
96700
96944
|
updateDemoProfile = requireAnonymous(async (ctx) => {
|
|
96701
96945
|
const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
|
|
96702
|
-
|
|
96946
|
+
logger66.debug("Updating demo profile", {
|
|
96703
96947
|
userId: ctx.user.id,
|
|
96704
96948
|
displayName: body2.displayName
|
|
96705
96949
|
});
|
|
@@ -96713,13 +96957,13 @@ var init_user_controller = __esm(() => {
|
|
|
96713
96957
|
});
|
|
96714
96958
|
|
|
96715
96959
|
// ../api-core/src/controllers/verify.controller.ts
|
|
96716
|
-
var
|
|
96960
|
+
var logger67;
|
|
96717
96961
|
var init_verify_controller = __esm(() => {
|
|
96718
96962
|
init_schemas_index();
|
|
96719
96963
|
init_src2();
|
|
96720
96964
|
init_errors();
|
|
96721
96965
|
init_utils11();
|
|
96722
|
-
|
|
96966
|
+
logger67 = log.scope("VerifyController");
|
|
96723
96967
|
});
|
|
96724
96968
|
|
|
96725
96969
|
// ../api-core/src/controllers/index.ts
|
|
@@ -97032,7 +97276,7 @@ var init_uploads = __esm(() => {
|
|
|
97032
97276
|
});
|
|
97033
97277
|
|
|
97034
97278
|
// src/routes/platform/games/deploy.ts
|
|
97035
|
-
var
|
|
97279
|
+
var logger68, gameDeployRouter;
|
|
97036
97280
|
var init_deploy = __esm(() => {
|
|
97037
97281
|
init_drizzle_orm();
|
|
97038
97282
|
init_dist4();
|
|
@@ -97042,7 +97286,7 @@ var init_deploy = __esm(() => {
|
|
|
97042
97286
|
init_src2();
|
|
97043
97287
|
init_api();
|
|
97044
97288
|
init_uploads();
|
|
97045
|
-
|
|
97289
|
+
logger68 = log.scope("SandboxDeploy");
|
|
97046
97290
|
gameDeployRouter = new Hono2;
|
|
97047
97291
|
gameDeployRouter.post("/:slug/deploy", async (c2) => {
|
|
97048
97292
|
const user = c2.get("user");
|
|
@@ -97159,7 +97403,7 @@ var init_deploy = __esm(() => {
|
|
|
97159
97403
|
completedAt: now2
|
|
97160
97404
|
};
|
|
97161
97405
|
const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
|
|
97162
|
-
|
|
97406
|
+
logger68.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
|
|
97163
97407
|
return c2.json({
|
|
97164
97408
|
id: insertedJob.id,
|
|
97165
97409
|
status: "succeeded",
|
|
@@ -97712,6 +97956,7 @@ var init_timeback6 = __esm(() => {
|
|
|
97712
97956
|
timebackRouter.delete("/integrations/:gameId", handle2(timeback2.deleteIntegrations, { status: 204 }));
|
|
97713
97957
|
timebackRouter.post("/end-activity", handle2(timeback2.endActivity));
|
|
97714
97958
|
timebackRouter.post("/heartbeat", handle2(timeback2.heartbeat));
|
|
97959
|
+
timebackRouter.post("/advance-course", handle2(timeback2.advanceCourse));
|
|
97715
97960
|
timebackRouter.get("/user", async (c2) => {
|
|
97716
97961
|
const user = c2.get("user");
|
|
97717
97962
|
const gameId = c2.get("gameId");
|
|
@@ -97799,7 +98044,7 @@ function verifyMockToken(idToken) {
|
|
|
97799
98044
|
throw new Error("Invalid LTI token format");
|
|
97800
98045
|
}
|
|
97801
98046
|
}
|
|
97802
|
-
var
|
|
98047
|
+
var logger69, ltiRouter;
|
|
97803
98048
|
var init_lti = __esm(() => {
|
|
97804
98049
|
init_drizzle_orm();
|
|
97805
98050
|
init_dist4();
|
|
@@ -97809,7 +98054,7 @@ var init_lti = __esm(() => {
|
|
|
97809
98054
|
init_src2();
|
|
97810
98055
|
init_constants();
|
|
97811
98056
|
init_api();
|
|
97812
|
-
|
|
98057
|
+
logger69 = log.scope("SandboxLti");
|
|
97813
98058
|
ltiRouter = new Hono2;
|
|
97814
98059
|
ltiRouter.post("/launch", async (c2) => {
|
|
97815
98060
|
const db2 = c2.get("db");
|
|
@@ -97827,7 +98072,7 @@ var init_lti = __esm(() => {
|
|
|
97827
98072
|
claims = verifyMockToken(idToken);
|
|
97828
98073
|
} catch (error2) {
|
|
97829
98074
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
97830
|
-
|
|
98075
|
+
logger69.error("LTI token verification failed", { error: errorMessage });
|
|
97831
98076
|
return c2.json({
|
|
97832
98077
|
error: "invalid_token",
|
|
97833
98078
|
message: errorMessage
|
|
@@ -97835,7 +98080,7 @@ var init_lti = __esm(() => {
|
|
|
97835
98080
|
}
|
|
97836
98081
|
const validationError = validateLtiClaims(claims);
|
|
97837
98082
|
if (validationError) {
|
|
97838
|
-
|
|
98083
|
+
logger69.warn("LTI claims validation failed", {
|
|
97839
98084
|
error: validationError,
|
|
97840
98085
|
sub: claims.sub
|
|
97841
98086
|
});
|
|
@@ -97855,7 +98100,7 @@ var init_lti = __esm(() => {
|
|
|
97855
98100
|
createdAt: new Date,
|
|
97856
98101
|
updatedAt: new Date
|
|
97857
98102
|
});
|
|
97858
|
-
|
|
98103
|
+
logger69.info("LTI launch successful", { userId: user.id });
|
|
97859
98104
|
const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
|
|
97860
98105
|
const currentHost = new URL(c2.req.url).hostname;
|
|
97861
98106
|
const redirectPath = extractRedirectPath(targetUri, currentHost);
|
|
@@ -97863,7 +98108,7 @@ var init_lti = __esm(() => {
|
|
|
97863
98108
|
return c2.redirect(redirectPath);
|
|
97864
98109
|
} catch (error2) {
|
|
97865
98110
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
97866
|
-
|
|
98111
|
+
logger69.error("Unexpected error during LTI launch", { error: errorMessage });
|
|
97867
98112
|
return c2.json({
|
|
97868
98113
|
error: "unexpected_error",
|
|
97869
98114
|
message: "An unexpected error occurred during LTI launch"
|