@playcademy/vite-plugin 0.2.26-beta.3 → 0.2.26-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +655 -409
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24423,7 +24423,8 @@ var init_timeback2 = __esm(() => {
|
|
|
24423
24423
|
TIMEBACK_ROUTES = {
|
|
24424
24424
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
24425
24425
|
GET_XP: "/integrations/timeback/xp",
|
|
24426
|
-
HEARTBEAT: "/integrations/timeback/heartbeat"
|
|
24426
|
+
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
24427
|
+
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
24427
24428
|
};
|
|
24428
24429
|
TIMEBACK_COURSE_DEFAULTS = {
|
|
24429
24430
|
gradingScheme: "STANDARD",
|
|
@@ -25369,7 +25370,7 @@ var package_default;
|
|
|
25369
25370
|
var init_package = __esm(() => {
|
|
25370
25371
|
package_default = {
|
|
25371
25372
|
name: "@playcademy/sandbox",
|
|
25372
|
-
version: "0.3.17-beta.
|
|
25373
|
+
version: "0.3.17-beta.19",
|
|
25373
25374
|
description: "Local development server for Playcademy game development",
|
|
25374
25375
|
type: "module",
|
|
25375
25376
|
exports: {
|
|
@@ -52738,7 +52739,8 @@ var init_constants3 = __esm(() => {
|
|
|
52738
52739
|
TIMEBACK: {
|
|
52739
52740
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
52740
52741
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
52741
|
-
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}
|
|
52742
|
+
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
52743
|
+
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`
|
|
52742
52744
|
}
|
|
52743
52745
|
};
|
|
52744
52746
|
});
|
|
@@ -55131,6 +55133,7 @@ class TimebackAdminService {
|
|
|
55131
55133
|
await client.edubridge.enrollments.enroll(data.studentId, data.courseId, {
|
|
55132
55134
|
role: "student"
|
|
55133
55135
|
});
|
|
55136
|
+
client.invalidateEnrollments(data.studentId);
|
|
55134
55137
|
return { status: "ok" };
|
|
55135
55138
|
}
|
|
55136
55139
|
async unenrollStudent(data, user) {
|
|
@@ -55143,6 +55146,7 @@ class TimebackAdminService {
|
|
|
55143
55146
|
throw new NotFoundError("Timeback integration", `${data.gameId}:${data.courseId}`);
|
|
55144
55147
|
}
|
|
55145
55148
|
await client.edubridge.enrollments.unenroll(data.studentId, data.courseId);
|
|
55149
|
+
client.invalidateEnrollments(data.studentId);
|
|
55146
55150
|
return { status: "ok" };
|
|
55147
55151
|
}
|
|
55148
55152
|
async getCompletionStatus(client, courseId, studentId) {
|
|
@@ -55198,7 +55202,103 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
55198
55202
|
init_timeback_util();
|
|
55199
55203
|
logger16 = log.scope("TimebackAdminService");
|
|
55200
55204
|
});
|
|
55205
|
+
async function promoteCompletedCourse({
|
|
55206
|
+
db: db2,
|
|
55207
|
+
client,
|
|
55208
|
+
currentIntegration,
|
|
55209
|
+
studentId,
|
|
55210
|
+
enrollments: prefetchedEnrollments
|
|
55211
|
+
}) {
|
|
55212
|
+
const subjectIntegrations = await db2.query.gameTimebackIntegrations.findMany({
|
|
55213
|
+
where: and(eq(gameTimebackIntegrations.gameId, currentIntegration.gameId), eq(gameTimebackIntegrations.subject, currentIntegration.subject))
|
|
55214
|
+
});
|
|
55215
|
+
const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
|
|
55216
|
+
if (!nextIntegration) {
|
|
55217
|
+
logger17.debug("Skipping promotion because no next course is configured", {
|
|
55218
|
+
gameId: currentIntegration.gameId,
|
|
55219
|
+
studentId,
|
|
55220
|
+
grade: currentIntegration.grade,
|
|
55221
|
+
subject: currentIntegration.subject,
|
|
55222
|
+
currentCourseId: currentIntegration.courseId
|
|
55223
|
+
});
|
|
55224
|
+
return {
|
|
55225
|
+
status: "no-next-course",
|
|
55226
|
+
currentCourseId: currentIntegration.courseId
|
|
55227
|
+
};
|
|
55228
|
+
}
|
|
55229
|
+
const enrollments = prefetchedEnrollments ?? await client.edubridge.enrollments.listByUser(studentId);
|
|
55230
|
+
const currentEnrollment = enrollments.find((enrollment) => enrollment.course.id === currentIntegration.courseId);
|
|
55231
|
+
const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
|
|
55232
|
+
if (!currentEnrollment) {
|
|
55233
|
+
if (nextEnrollment) {
|
|
55234
|
+
logger17.debug("Skipping promotion because student is already on the next course", {
|
|
55235
|
+
gameId: currentIntegration.gameId,
|
|
55236
|
+
studentId,
|
|
55237
|
+
grade: currentIntegration.grade,
|
|
55238
|
+
subject: currentIntegration.subject,
|
|
55239
|
+
currentCourseId: currentIntegration.courseId,
|
|
55240
|
+
nextCourseId: nextIntegration.courseId
|
|
55241
|
+
});
|
|
55242
|
+
return {
|
|
55243
|
+
status: "already-promoted",
|
|
55244
|
+
currentCourseId: currentIntegration.courseId,
|
|
55245
|
+
nextCourseId: nextIntegration.courseId
|
|
55246
|
+
};
|
|
55247
|
+
}
|
|
55248
|
+
logger17.debug("Skipping promotion because student is not enrolled in the current course", {
|
|
55249
|
+
gameId: currentIntegration.gameId,
|
|
55250
|
+
studentId,
|
|
55251
|
+
grade: currentIntegration.grade,
|
|
55252
|
+
subject: currentIntegration.subject,
|
|
55253
|
+
currentCourseId: currentIntegration.courseId,
|
|
55254
|
+
nextCourseId: nextIntegration.courseId
|
|
55255
|
+
});
|
|
55256
|
+
return {
|
|
55257
|
+
status: "not-enrolled",
|
|
55258
|
+
currentCourseId: currentIntegration.courseId,
|
|
55259
|
+
nextCourseId: nextIntegration.courseId
|
|
55260
|
+
};
|
|
55261
|
+
}
|
|
55262
|
+
const schoolId = currentEnrollment.school.id;
|
|
55263
|
+
let mutatedEnrollments = false;
|
|
55264
|
+
try {
|
|
55265
|
+
if (!nextEnrollment) {
|
|
55266
|
+
await client.edubridge.enrollments.enroll(studentId, nextIntegration.courseId, {
|
|
55267
|
+
role: "student",
|
|
55268
|
+
...schoolId ? { schoolId } : {}
|
|
55269
|
+
});
|
|
55270
|
+
mutatedEnrollments = true;
|
|
55271
|
+
}
|
|
55272
|
+
await client.edubridge.enrollments.unenroll(studentId, currentIntegration.courseId, schoolId ? { schoolId } : {});
|
|
55273
|
+
mutatedEnrollments = true;
|
|
55274
|
+
} finally {
|
|
55275
|
+
if (mutatedEnrollments) {
|
|
55276
|
+
client.invalidateEnrollments(studentId);
|
|
55277
|
+
}
|
|
55278
|
+
}
|
|
55279
|
+
logger17.info("Promoted student to next course", {
|
|
55280
|
+
gameId: currentIntegration.gameId,
|
|
55281
|
+
studentId,
|
|
55282
|
+
subject: currentIntegration.subject,
|
|
55283
|
+
fromGrade: currentIntegration.grade,
|
|
55284
|
+
toGrade: nextIntegration.grade,
|
|
55285
|
+
currentCourseId: currentIntegration.courseId,
|
|
55286
|
+
nextCourseId: nextIntegration.courseId
|
|
55287
|
+
});
|
|
55288
|
+
return {
|
|
55289
|
+
status: "promoted",
|
|
55290
|
+
currentCourseId: currentIntegration.courseId,
|
|
55291
|
+
nextCourseId: nextIntegration.courseId
|
|
55292
|
+
};
|
|
55293
|
+
}
|
|
55201
55294
|
var logger17;
|
|
55295
|
+
var init_timeback_promotion_util = __esm(() => {
|
|
55296
|
+
init_drizzle_orm();
|
|
55297
|
+
init_tables_index();
|
|
55298
|
+
init_src2();
|
|
55299
|
+
logger17 = log.scope("TimebackPromotion");
|
|
55300
|
+
});
|
|
55301
|
+
var logger18;
|
|
55202
55302
|
var TimebackService;
|
|
55203
55303
|
var init_timeback_service = __esm(() => {
|
|
55204
55304
|
init_drizzle_orm();
|
|
@@ -55208,8 +55308,9 @@ var init_timeback_service = __esm(() => {
|
|
|
55208
55308
|
init_types4();
|
|
55209
55309
|
init_src4();
|
|
55210
55310
|
init_errors();
|
|
55311
|
+
init_timeback_promotion_util();
|
|
55211
55312
|
init_timeback_util();
|
|
55212
|
-
|
|
55313
|
+
logger18 = log.scope("TimebackService");
|
|
55213
55314
|
TimebackService = class TimebackService2 {
|
|
55214
55315
|
static HEARTBEAT_DEDUPE_TTL_MS = 300000;
|
|
55215
55316
|
static processedHeartbeatWindows = new Map;
|
|
@@ -55255,7 +55356,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55255
55356
|
}
|
|
55256
55357
|
requireClient() {
|
|
55257
55358
|
if (!this.deps.timeback) {
|
|
55258
|
-
|
|
55359
|
+
logger18.error("Timeback client not available in context");
|
|
55259
55360
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
55260
55361
|
}
|
|
55261
55362
|
return this.deps.timeback;
|
|
@@ -55308,7 +55409,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55308
55409
|
set: { xp: sql`excluded.xp`, updatedAt: new Date }
|
|
55309
55410
|
}).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
|
|
55310
55411
|
if (!result) {
|
|
55311
|
-
|
|
55412
|
+
logger18.error("Daily XP upsert returned no rows", { userId, date: targetDate });
|
|
55312
55413
|
throw new InternalError("Failed to update daily XP record");
|
|
55313
55414
|
}
|
|
55314
55415
|
return { xp: result.xp, date: result.date.toISOString() };
|
|
@@ -55339,7 +55440,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55339
55440
|
columns: { id: true, timebackId: true }
|
|
55340
55441
|
});
|
|
55341
55442
|
if (dbUser?.timebackId) {
|
|
55342
|
-
|
|
55443
|
+
logger18.info("Student already onboarded", { userId: user.id });
|
|
55343
55444
|
return { status: "already_populated" };
|
|
55344
55445
|
}
|
|
55345
55446
|
let timebackId;
|
|
@@ -55348,7 +55449,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55348
55449
|
const existingUser = await client.oneroster.users.findByEmail(user.email);
|
|
55349
55450
|
timebackId = existingUser.sourcedId;
|
|
55350
55451
|
name3 = `${existingUser.givenName} ${existingUser.familyName}`;
|
|
55351
|
-
|
|
55452
|
+
logger18.info("Found existing student in OneRoster", {
|
|
55352
55453
|
userId: user.id,
|
|
55353
55454
|
timebackId
|
|
55354
55455
|
});
|
|
@@ -55377,7 +55478,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55377
55478
|
}
|
|
55378
55479
|
timebackId = response.sourcedIdPairs.allocatedSourcedId;
|
|
55379
55480
|
name3 = `${providedNames.firstName} ${providedNames.lastName}`;
|
|
55380
|
-
|
|
55481
|
+
logger18.info("Created student in OneRoster", { userId: user.id, timebackId });
|
|
55381
55482
|
}
|
|
55382
55483
|
const assessments = await this.fetchAssessments(timebackId);
|
|
55383
55484
|
await db2.transaction(async (tx) => {
|
|
@@ -55411,7 +55512,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55411
55512
|
}
|
|
55412
55513
|
const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
|
|
55413
55514
|
if (!updated) {
|
|
55414
|
-
|
|
55515
|
+
logger18.error("User Timeback ID update returned no rows", {
|
|
55415
55516
|
userId: user.id,
|
|
55416
55517
|
timebackId
|
|
55417
55518
|
});
|
|
@@ -55435,13 +55536,13 @@ var init_timeback_service = __esm(() => {
|
|
|
55435
55536
|
}
|
|
55436
55537
|
offset += limit;
|
|
55437
55538
|
}
|
|
55438
|
-
|
|
55539
|
+
logger18.debug("Fetched assessments", {
|
|
55439
55540
|
studentSourcedId,
|
|
55440
55541
|
totalCount: allAssessments.length
|
|
55441
55542
|
});
|
|
55442
55543
|
return allAssessments;
|
|
55443
55544
|
} catch (error) {
|
|
55444
|
-
|
|
55545
|
+
logger18.warn("Failed to fetch assessments", { studentSourcedId, error });
|
|
55445
55546
|
return [];
|
|
55446
55547
|
}
|
|
55447
55548
|
}
|
|
@@ -55554,7 +55655,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55554
55655
|
masterableUnits: derivedMasterableUnits
|
|
55555
55656
|
} = courseConfig;
|
|
55556
55657
|
if (!isTimebackSubject(subjectInput)) {
|
|
55557
|
-
|
|
55658
|
+
logger18.warn("Invalid Timeback subject in course config", {
|
|
55558
55659
|
subject: subjectInput,
|
|
55559
55660
|
courseCode,
|
|
55560
55661
|
title
|
|
@@ -55562,7 +55663,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55562
55663
|
throw new ValidationError(`Invalid subject "${subjectInput}"`);
|
|
55563
55664
|
}
|
|
55564
55665
|
if (!isTimebackGrade(grade)) {
|
|
55565
|
-
|
|
55666
|
+
logger18.warn("Invalid Timeback grade in course config", {
|
|
55566
55667
|
grade,
|
|
55567
55668
|
courseCode,
|
|
55568
55669
|
title
|
|
@@ -55574,7 +55675,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55574
55675
|
const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
|
|
55575
55676
|
const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
|
|
55576
55677
|
if (typeof totalXp !== "number") {
|
|
55577
|
-
|
|
55678
|
+
logger18.warn("Course missing totalXp in Timeback config", {
|
|
55578
55679
|
courseCode,
|
|
55579
55680
|
title
|
|
55580
55681
|
});
|
|
@@ -55775,7 +55876,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55775
55876
|
...runId ? { runId } : {}
|
|
55776
55877
|
});
|
|
55777
55878
|
}
|
|
55778
|
-
|
|
55879
|
+
logger18.info("Recorded activity completion", {
|
|
55779
55880
|
gameId,
|
|
55780
55881
|
courseId: integration.courseId,
|
|
55781
55882
|
studentId,
|
|
@@ -55792,6 +55893,72 @@ var init_timeback_service = __esm(() => {
|
|
|
55792
55893
|
inProgress: result.inProgress
|
|
55793
55894
|
};
|
|
55794
55895
|
}
|
|
55896
|
+
async advanceCourse({
|
|
55897
|
+
gameId,
|
|
55898
|
+
studentId,
|
|
55899
|
+
subject,
|
|
55900
|
+
user
|
|
55901
|
+
}) {
|
|
55902
|
+
const client = this.requireClient();
|
|
55903
|
+
const db2 = this.deps.db;
|
|
55904
|
+
await this.deps.validateDeveloperAccess(user, gameId);
|
|
55905
|
+
const integrations = await db2.query.gameTimebackIntegrations.findMany({
|
|
55906
|
+
where: subject ? and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.subject, subject)) : eq(gameTimebackIntegrations.gameId, gameId)
|
|
55907
|
+
});
|
|
55908
|
+
if (integrations.length === 0) {
|
|
55909
|
+
throw new NotFoundError(subject ? `Timeback integrations for game (subject ${subject})` : "Timeback integrations for game");
|
|
55910
|
+
}
|
|
55911
|
+
const enrollments = await client.edubridge.enrollments.listByUser(studentId);
|
|
55912
|
+
const enrolledCourseIds = new Set(enrollments.map((e) => e.course.id));
|
|
55913
|
+
const enrolledIntegrations = integrations.filter((integration) => enrolledCourseIds.has(integration.courseId));
|
|
55914
|
+
if (enrolledIntegrations.length === 0) {
|
|
55915
|
+
throw new NotFoundError(subject ? `Active enrollment for game ladder (subject ${subject})` : "Active enrollment for game ladder");
|
|
55916
|
+
}
|
|
55917
|
+
const subjectsInPlay = new Set(enrolledIntegrations.map((i2) => i2.subject));
|
|
55918
|
+
if (subjectsInPlay.size > 1) {
|
|
55919
|
+
throw new ValidationError(`Ambiguous Timeback advance: student is enrolled in ${subjectsInPlay.size} parallel ladders (${[...subjectsInPlay].join(", ")}); pass { subject } to disambiguate`);
|
|
55920
|
+
}
|
|
55921
|
+
const currentIntegration = enrolledIntegrations.toSorted((left, right) => left.grade - right.grade)[0];
|
|
55922
|
+
const masteryStatus = await client.getMasteryStatus(currentIntegration.courseId, studentId);
|
|
55923
|
+
if (!masteryStatus) {
|
|
55924
|
+
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().`);
|
|
55925
|
+
}
|
|
55926
|
+
if (!masteryStatus.isComplete) {
|
|
55927
|
+
const promotion2 = {
|
|
55928
|
+
status: "not-mastered",
|
|
55929
|
+
currentCourseId: currentIntegration.courseId,
|
|
55930
|
+
masteredUnits: masteryStatus.masteredUnits,
|
|
55931
|
+
masterableUnits: masteryStatus.masterableUnits
|
|
55932
|
+
};
|
|
55933
|
+
logger18.debug("Skipping course advancement because mastery is incomplete", {
|
|
55934
|
+
gameId,
|
|
55935
|
+
studentId,
|
|
55936
|
+
subject: currentIntegration.subject,
|
|
55937
|
+
grade: currentIntegration.grade,
|
|
55938
|
+
currentCourseId: currentIntegration.courseId,
|
|
55939
|
+
masteredUnits: masteryStatus.masteredUnits,
|
|
55940
|
+
masterableUnits: masteryStatus.masterableUnits
|
|
55941
|
+
});
|
|
55942
|
+
return { status: "ok", promotion: promotion2 };
|
|
55943
|
+
}
|
|
55944
|
+
const promotion = await promoteCompletedCourse({
|
|
55945
|
+
db: db2,
|
|
55946
|
+
client,
|
|
55947
|
+
currentIntegration,
|
|
55948
|
+
studentId,
|
|
55949
|
+
enrollments
|
|
55950
|
+
});
|
|
55951
|
+
logger18.info("Manually advanced student", {
|
|
55952
|
+
gameId,
|
|
55953
|
+
studentId,
|
|
55954
|
+
subject: currentIntegration.subject,
|
|
55955
|
+
grade: currentIntegration.grade,
|
|
55956
|
+
promotionStatus: promotion.status,
|
|
55957
|
+
currentCourseId: promotion.currentCourseId,
|
|
55958
|
+
nextCourseId: promotion.nextCourseId
|
|
55959
|
+
});
|
|
55960
|
+
return { status: "ok", promotion };
|
|
55961
|
+
}
|
|
55795
55962
|
async recordHeartbeat({
|
|
55796
55963
|
gameId,
|
|
55797
55964
|
studentId,
|
|
@@ -55814,7 +55981,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55814
55981
|
const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
|
|
55815
55982
|
const effectiveResumeId = resumeId ?? runId;
|
|
55816
55983
|
if (TimebackService2.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
|
|
55817
|
-
|
|
55984
|
+
logger18.debug("Skipping duplicate heartbeat window", {
|
|
55818
55985
|
gameId,
|
|
55819
55986
|
studentId,
|
|
55820
55987
|
runId,
|
|
@@ -55827,7 +55994,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55827
55994
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
55828
55995
|
const inFlightHeartbeat = TimebackService2.getInFlightHeartbeatWindow(heartbeatWindowKey);
|
|
55829
55996
|
if (inFlightHeartbeat) {
|
|
55830
|
-
|
|
55997
|
+
logger18.debug("Joining in-flight heartbeat window", {
|
|
55831
55998
|
gameId,
|
|
55832
55999
|
studentId,
|
|
55833
56000
|
runId,
|
|
@@ -55864,7 +56031,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55864
56031
|
});
|
|
55865
56032
|
}
|
|
55866
56033
|
TimebackService2.markHeartbeatWindowProcessed(heartbeatWindowKey);
|
|
55867
|
-
|
|
56034
|
+
logger18.debug("Recorded heartbeat", {
|
|
55868
56035
|
gameId,
|
|
55869
56036
|
courseId: integration.courseId,
|
|
55870
56037
|
studentId,
|
|
@@ -55899,7 +56066,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55899
56066
|
});
|
|
55900
56067
|
courseIds = integrations.map((i2) => i2.courseId);
|
|
55901
56068
|
if (courseIds.length === 0) {
|
|
55902
|
-
|
|
56069
|
+
logger18.debug("No integrations found for game, returning 0 XP", {
|
|
55903
56070
|
timebackId,
|
|
55904
56071
|
gameId: options.gameId,
|
|
55905
56072
|
grade: options.grade,
|
|
@@ -55916,7 +56083,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55916
56083
|
courseIds: courseIds.length > 0 ? courseIds : undefined,
|
|
55917
56084
|
include: options?.include
|
|
55918
56085
|
});
|
|
55919
|
-
|
|
56086
|
+
logger18.debug("Retrieved student XP", {
|
|
55920
56087
|
timebackId,
|
|
55921
56088
|
gameId: options?.gameId,
|
|
55922
56089
|
grade: options?.grade,
|
|
@@ -55944,15 +56111,15 @@ class UploadService {
|
|
|
55944
56111
|
const { fileName, gameId } = request;
|
|
55945
56112
|
const bucketName = this.deps.uploadBucket;
|
|
55946
56113
|
if (!bucketName) {
|
|
55947
|
-
|
|
56114
|
+
logger19.error("Upload bucket not configured in environment");
|
|
55948
56115
|
throw new ValidationError("Upload bucket not configured");
|
|
55949
56116
|
}
|
|
55950
56117
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
55951
56118
|
const version2 = ulid();
|
|
55952
56119
|
const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
|
|
55953
|
-
|
|
56120
|
+
logger19.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
|
|
55954
56121
|
const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
|
|
55955
|
-
|
|
56122
|
+
logger19.info("Presigned URL generated", {
|
|
55956
56123
|
userId: user.id,
|
|
55957
56124
|
gameId,
|
|
55958
56125
|
version: version2
|
|
@@ -55965,12 +56132,12 @@ class UploadService {
|
|
|
55965
56132
|
};
|
|
55966
56133
|
}
|
|
55967
56134
|
}
|
|
55968
|
-
var
|
|
56135
|
+
var logger19;
|
|
55969
56136
|
var init_upload_service = __esm(() => {
|
|
55970
56137
|
init_node();
|
|
55971
56138
|
init_src2();
|
|
55972
56139
|
init_errors();
|
|
55973
|
-
|
|
56140
|
+
logger19 = log.scope("UploadService");
|
|
55974
56141
|
});
|
|
55975
56142
|
function createPlatformServices(deps) {
|
|
55976
56143
|
const {
|
|
@@ -56262,7 +56429,7 @@ class AchievementService {
|
|
|
56262
56429
|
results.push(result);
|
|
56263
56430
|
}
|
|
56264
56431
|
}
|
|
56265
|
-
|
|
56432
|
+
logger20.debug("Listed current achievements", { userId: user.id, count: results.length });
|
|
56266
56433
|
return results;
|
|
56267
56434
|
}
|
|
56268
56435
|
async listHistory(user, limit) {
|
|
@@ -56280,14 +56447,14 @@ class AchievementService {
|
|
|
56280
56447
|
createdAt: c.createdAt,
|
|
56281
56448
|
scopeKey: c.scopeKey
|
|
56282
56449
|
}));
|
|
56283
|
-
|
|
56450
|
+
logger20.debug("Listed achievement history", { userId: user.id, count: results.length });
|
|
56284
56451
|
return results;
|
|
56285
56452
|
}
|
|
56286
56453
|
async submitProgress(achievementId, user) {
|
|
56287
56454
|
const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
|
|
56288
56455
|
broadcast: false
|
|
56289
56456
|
});
|
|
56290
|
-
|
|
56457
|
+
logger20.debug("Submitted progress", {
|
|
56291
56458
|
userId: user.id,
|
|
56292
56459
|
achievementId,
|
|
56293
56460
|
wasNewClaim
|
|
@@ -56319,7 +56486,7 @@ class AchievementService {
|
|
|
56319
56486
|
rewardCredits
|
|
56320
56487
|
}).returning();
|
|
56321
56488
|
if (!newClaim) {
|
|
56322
|
-
|
|
56489
|
+
logger20.error("Achievement claim insert returned no rows", {
|
|
56323
56490
|
userId,
|
|
56324
56491
|
achievementId,
|
|
56325
56492
|
scopeKey
|
|
@@ -56328,7 +56495,7 @@ class AchievementService {
|
|
|
56328
56495
|
}
|
|
56329
56496
|
await this.deps.addCredits(userId, rewardCredits);
|
|
56330
56497
|
await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
|
|
56331
|
-
|
|
56498
|
+
logger20.info("Awarded achievement", {
|
|
56332
56499
|
userId,
|
|
56333
56500
|
achievementId,
|
|
56334
56501
|
scopeKey,
|
|
@@ -56365,7 +56532,7 @@ class AchievementService {
|
|
|
56365
56532
|
return { title, body: body2 };
|
|
56366
56533
|
}
|
|
56367
56534
|
}
|
|
56368
|
-
var
|
|
56535
|
+
var logger20;
|
|
56369
56536
|
var init_achievement_service = __esm(() => {
|
|
56370
56537
|
init_drizzle_orm();
|
|
56371
56538
|
init_tables_index();
|
|
@@ -56374,7 +56541,7 @@ var init_achievement_service = __esm(() => {
|
|
|
56374
56541
|
init_errors();
|
|
56375
56542
|
init_leaderboard_util();
|
|
56376
56543
|
init_scope_util();
|
|
56377
|
-
|
|
56544
|
+
logger20 = log.scope("AchievementService");
|
|
56378
56545
|
});
|
|
56379
56546
|
|
|
56380
56547
|
class InventoryService {
|
|
@@ -56401,7 +56568,7 @@ class InventoryService {
|
|
|
56401
56568
|
},
|
|
56402
56569
|
updatedAt: inventoryItems.updatedAt
|
|
56403
56570
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
56404
|
-
|
|
56571
|
+
logger21.debug("Listed inventory", { userId: user.id, count: inventory.length });
|
|
56405
56572
|
return inventory;
|
|
56406
56573
|
}
|
|
56407
56574
|
async addItem(itemId, quantity, user) {
|
|
@@ -56418,7 +56585,7 @@ class InventoryService {
|
|
|
56418
56585
|
const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
|
|
56419
56586
|
return inserted?.quantity ?? 0;
|
|
56420
56587
|
});
|
|
56421
|
-
|
|
56588
|
+
logger21.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
|
|
56422
56589
|
return { newTotal };
|
|
56423
56590
|
}
|
|
56424
56591
|
async removeItem(itemId, quantity, user) {
|
|
@@ -56429,7 +56596,7 @@ class InventoryService {
|
|
|
56429
56596
|
}
|
|
56430
56597
|
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);
|
|
56431
56598
|
if (!currentItem) {
|
|
56432
|
-
|
|
56599
|
+
logger21.warn("Insufficient inventory for removal", {
|
|
56433
56600
|
userId: user.id,
|
|
56434
56601
|
itemId,
|
|
56435
56602
|
requestedQuantity: quantity
|
|
@@ -56439,13 +56606,13 @@ class InventoryService {
|
|
|
56439
56606
|
const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
|
|
56440
56607
|
return updated?.quantity ?? 0;
|
|
56441
56608
|
});
|
|
56442
|
-
|
|
56609
|
+
logger21.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
|
|
56443
56610
|
return { newTotal };
|
|
56444
56611
|
}
|
|
56445
56612
|
async addCredits(userId, amount) {
|
|
56446
56613
|
const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
56447
56614
|
if (!creditsItem) {
|
|
56448
|
-
|
|
56615
|
+
logger21.error("Primary currency not found", {
|
|
56449
56616
|
userId,
|
|
56450
56617
|
amount
|
|
56451
56618
|
});
|
|
@@ -56458,17 +56625,17 @@ class InventoryService {
|
|
|
56458
56625
|
updatedAt: new Date
|
|
56459
56626
|
}
|
|
56460
56627
|
});
|
|
56461
|
-
|
|
56628
|
+
logger21.debug("Added credits", { userId, amount });
|
|
56462
56629
|
}
|
|
56463
56630
|
}
|
|
56464
|
-
var
|
|
56631
|
+
var logger21;
|
|
56465
56632
|
var init_inventory_service = __esm(() => {
|
|
56466
56633
|
init_drizzle_orm();
|
|
56467
56634
|
init_src();
|
|
56468
56635
|
init_tables_index();
|
|
56469
56636
|
init_src2();
|
|
56470
56637
|
init_errors();
|
|
56471
|
-
|
|
56638
|
+
logger21 = log.scope("InventoryService");
|
|
56472
56639
|
});
|
|
56473
56640
|
var NotificationType;
|
|
56474
56641
|
var NotificationStatus;
|
|
@@ -56522,7 +56689,7 @@ class LeaderboardService {
|
|
|
56522
56689
|
sessionId
|
|
56523
56690
|
}).returning();
|
|
56524
56691
|
if (!newScore) {
|
|
56525
|
-
|
|
56692
|
+
logger22.error("Score insert returned no rows", { userId, gameId, score: input.score });
|
|
56526
56693
|
throw new InternalError("Failed to insert score");
|
|
56527
56694
|
}
|
|
56528
56695
|
const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
|
|
@@ -56550,7 +56717,7 @@ class LeaderboardService {
|
|
|
56550
56717
|
movedUpWithinTop3
|
|
56551
56718
|
});
|
|
56552
56719
|
}
|
|
56553
|
-
|
|
56720
|
+
logger22.info("Score submitted", {
|
|
56554
56721
|
gameId,
|
|
56555
56722
|
userId,
|
|
56556
56723
|
isAnonymousUser,
|
|
@@ -56627,7 +56794,7 @@ class LeaderboardService {
|
|
|
56627
56794
|
});
|
|
56628
56795
|
}
|
|
56629
56796
|
} catch (error) {
|
|
56630
|
-
|
|
56797
|
+
logger22.warn("Failed to publish notification", { error });
|
|
56631
56798
|
}
|
|
56632
56799
|
}
|
|
56633
56800
|
async getLeaderboard(gameId, query, isAnonymousUser) {
|
|
@@ -56746,7 +56913,7 @@ class LeaderboardService {
|
|
|
56746
56913
|
return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
|
|
56747
56914
|
}
|
|
56748
56915
|
}
|
|
56749
|
-
var
|
|
56916
|
+
var logger22;
|
|
56750
56917
|
var init_leaderboard_service = __esm(() => {
|
|
56751
56918
|
init_drizzle_orm();
|
|
56752
56919
|
init_src();
|
|
@@ -56756,7 +56923,7 @@ var init_leaderboard_service = __esm(() => {
|
|
|
56756
56923
|
init_notification();
|
|
56757
56924
|
init_errors();
|
|
56758
56925
|
init_leaderboard_util();
|
|
56759
|
-
|
|
56926
|
+
logger22 = log.scope("LeaderboardService");
|
|
56760
56927
|
});
|
|
56761
56928
|
|
|
56762
56929
|
class LevelService {
|
|
@@ -56771,9 +56938,9 @@ class LevelService {
|
|
|
56771
56938
|
for (const config2 of configs) {
|
|
56772
56939
|
levelConfigCache.set(config2.level, config2);
|
|
56773
56940
|
}
|
|
56774
|
-
|
|
56941
|
+
logger23.info("Cache pre-warmed", { count: configs.length });
|
|
56775
56942
|
} catch (error) {
|
|
56776
|
-
|
|
56943
|
+
logger23.error("Cache pre-warm failed", { error });
|
|
56777
56944
|
}
|
|
56778
56945
|
}
|
|
56779
56946
|
async getConfig(level) {
|
|
@@ -56807,7 +56974,7 @@ class LevelService {
|
|
|
56807
56974
|
totalXP
|
|
56808
56975
|
}).returning();
|
|
56809
56976
|
if (!newUserLevel) {
|
|
56810
|
-
|
|
56977
|
+
logger23.error("User level insert returned no rows", { userId: user.id });
|
|
56811
56978
|
throw new InternalError("Failed to create user level cache record");
|
|
56812
56979
|
}
|
|
56813
56980
|
userLevel = newUserLevel;
|
|
@@ -56822,7 +56989,7 @@ class LevelService {
|
|
|
56822
56989
|
userLevel = updatedUserLevel;
|
|
56823
56990
|
}
|
|
56824
56991
|
}
|
|
56825
|
-
|
|
56992
|
+
logger23.debug("Retrieved user level", {
|
|
56826
56993
|
userId: user.id,
|
|
56827
56994
|
totalXP,
|
|
56828
56995
|
currentLevel,
|
|
@@ -56833,7 +57000,7 @@ class LevelService {
|
|
|
56833
57000
|
async getProgress(user) {
|
|
56834
57001
|
const userLevel = await this.getByUser(user);
|
|
56835
57002
|
const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
|
|
56836
|
-
|
|
57003
|
+
logger23.debug("Retrieved progress", { userId: user.id });
|
|
56837
57004
|
return {
|
|
56838
57005
|
level: userLevel.currentLevel,
|
|
56839
57006
|
currentXp: userLevel.currentXp,
|
|
@@ -56867,7 +57034,7 @@ class LevelService {
|
|
|
56867
57034
|
if (leveledUp && previousUserLevel) {
|
|
56868
57035
|
await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
|
|
56869
57036
|
}
|
|
56870
|
-
|
|
57037
|
+
logger23.info("Synced from Timeback", {
|
|
56871
57038
|
userId,
|
|
56872
57039
|
totalXP,
|
|
56873
57040
|
currentLevel,
|
|
@@ -56908,7 +57075,7 @@ class LevelService {
|
|
|
56908
57075
|
}
|
|
56909
57076
|
if (totalCredits > 0) {
|
|
56910
57077
|
await this.deps.addCredits(userId, totalCredits);
|
|
56911
|
-
|
|
57078
|
+
logger23.info("Awarded level-up credits", {
|
|
56912
57079
|
userId,
|
|
56913
57080
|
fromLevel,
|
|
56914
57081
|
toLevel,
|
|
@@ -56946,7 +57113,7 @@ class LevelService {
|
|
|
56946
57113
|
};
|
|
56947
57114
|
}
|
|
56948
57115
|
}
|
|
56949
|
-
var
|
|
57116
|
+
var logger23;
|
|
56950
57117
|
var levelConfigCache = null;
|
|
56951
57118
|
var init_level_service = __esm(() => {
|
|
56952
57119
|
init_drizzle_orm();
|
|
@@ -56954,7 +57121,7 @@ var init_level_service = __esm(() => {
|
|
|
56954
57121
|
init_tables_index();
|
|
56955
57122
|
init_src2();
|
|
56956
57123
|
init_errors();
|
|
56957
|
-
|
|
57124
|
+
logger23 = log.scope("LevelService");
|
|
56958
57125
|
});
|
|
56959
57126
|
var init_events = () => {};
|
|
56960
57127
|
function convertWebSocketUrlToHttp(wsUrl) {
|
|
@@ -56971,13 +57138,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
|
|
|
56971
57138
|
});
|
|
56972
57139
|
if (!res.ok) {
|
|
56973
57140
|
const text3 = await res.text().catch(() => "");
|
|
56974
|
-
|
|
57141
|
+
logger24.warn("Failed to publish to user", {
|
|
56975
57142
|
status: res.status,
|
|
56976
57143
|
body: text3
|
|
56977
57144
|
});
|
|
56978
57145
|
}
|
|
56979
57146
|
} catch (error) {
|
|
56980
|
-
|
|
57147
|
+
logger24.error("Publish to user error", { error });
|
|
56981
57148
|
}
|
|
56982
57149
|
}
|
|
56983
57150
|
|
|
@@ -56999,7 +57166,7 @@ class NotificationService {
|
|
|
56999
57166
|
conditions2.push(eq(notifications.type, type));
|
|
57000
57167
|
}
|
|
57001
57168
|
const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
|
|
57002
|
-
|
|
57169
|
+
logger24.debug("Listed notifications", { userId: user.id, count: results.length });
|
|
57003
57170
|
return results;
|
|
57004
57171
|
}
|
|
57005
57172
|
async updateStatus(notificationId, status, method) {
|
|
@@ -57018,7 +57185,7 @@ class NotificationService {
|
|
|
57018
57185
|
if (!updated) {
|
|
57019
57186
|
throw new NotFoundError("Notification", notificationId);
|
|
57020
57187
|
}
|
|
57021
|
-
|
|
57188
|
+
logger24.debug("Updated status", { notificationId, status });
|
|
57022
57189
|
return updated;
|
|
57023
57190
|
}
|
|
57024
57191
|
async getStats(user, options) {
|
|
@@ -57044,7 +57211,7 @@ class NotificationService {
|
|
|
57044
57211
|
const clicked = statsMap.clicked || 0;
|
|
57045
57212
|
const dismissed = statsMap.dismissed || 0;
|
|
57046
57213
|
const expired = statsMap.expired || 0;
|
|
57047
|
-
|
|
57214
|
+
logger24.debug("Retrieved stats", { userId: user.id, total });
|
|
57048
57215
|
return {
|
|
57049
57216
|
total,
|
|
57050
57217
|
delivered,
|
|
@@ -57093,7 +57260,7 @@ class NotificationService {
|
|
|
57093
57260
|
options: { data, clickUrl, metadata: metadata2 }
|
|
57094
57261
|
});
|
|
57095
57262
|
}
|
|
57096
|
-
|
|
57263
|
+
logger24.debug("Created notification", {
|
|
57097
57264
|
userId,
|
|
57098
57265
|
type,
|
|
57099
57266
|
id: notificationId,
|
|
@@ -57101,7 +57268,7 @@ class NotificationService {
|
|
|
57101
57268
|
});
|
|
57102
57269
|
return notificationId;
|
|
57103
57270
|
} catch (error) {
|
|
57104
|
-
|
|
57271
|
+
logger24.error("Failed to create notification", { userId, type, error });
|
|
57105
57272
|
return null;
|
|
57106
57273
|
}
|
|
57107
57274
|
}
|
|
@@ -57115,7 +57282,7 @@ class NotificationService {
|
|
|
57115
57282
|
}) {
|
|
57116
57283
|
const realtimeConfig = this.deps.realtime;
|
|
57117
57284
|
if (!realtimeConfig) {
|
|
57118
|
-
|
|
57285
|
+
logger24.warn("No realtime config for publish");
|
|
57119
57286
|
return;
|
|
57120
57287
|
}
|
|
57121
57288
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -57157,13 +57324,13 @@ class NotificationService {
|
|
|
57157
57324
|
metadata: data.metadata || {}
|
|
57158
57325
|
}).returning();
|
|
57159
57326
|
if (!notification) {
|
|
57160
|
-
|
|
57327
|
+
logger24.error("Notification insert returned no rows", {
|
|
57161
57328
|
userId: data.userId,
|
|
57162
57329
|
type: data.type
|
|
57163
57330
|
});
|
|
57164
57331
|
throw new InternalError("Failed to create notification");
|
|
57165
57332
|
}
|
|
57166
|
-
|
|
57333
|
+
logger24.info("Inserted notification", {
|
|
57167
57334
|
notificationId: notification.id,
|
|
57168
57335
|
userId: notification.userId,
|
|
57169
57336
|
type: notification.type
|
|
@@ -57173,7 +57340,7 @@ class NotificationService {
|
|
|
57173
57340
|
async deliverPending(userId) {
|
|
57174
57341
|
const realtimeConfig = this.deps.realtime;
|
|
57175
57342
|
if (!realtimeConfig) {
|
|
57176
|
-
|
|
57343
|
+
logger24.warn("No realtime config for delivery");
|
|
57177
57344
|
return;
|
|
57178
57345
|
}
|
|
57179
57346
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -57200,13 +57367,13 @@ class NotificationService {
|
|
|
57200
57367
|
metadata: notification.metadata,
|
|
57201
57368
|
clickUrl: notification.clickUrl
|
|
57202
57369
|
});
|
|
57203
|
-
|
|
57370
|
+
logger24.info("Delivered notification", {
|
|
57204
57371
|
notificationId: notification.id,
|
|
57205
57372
|
userId,
|
|
57206
57373
|
type: notification.type
|
|
57207
57374
|
});
|
|
57208
57375
|
} catch (error) {
|
|
57209
|
-
|
|
57376
|
+
logger24.warn("Failed to deliver", {
|
|
57210
57377
|
notificationId: notification.id,
|
|
57211
57378
|
error
|
|
57212
57379
|
});
|
|
@@ -57214,7 +57381,7 @@ class NotificationService {
|
|
|
57214
57381
|
}
|
|
57215
57382
|
}
|
|
57216
57383
|
}
|
|
57217
|
-
var
|
|
57384
|
+
var logger24;
|
|
57218
57385
|
var init_notification_service = __esm(() => {
|
|
57219
57386
|
init_drizzle_orm();
|
|
57220
57387
|
init_src();
|
|
@@ -57223,7 +57390,7 @@ var init_notification_service = __esm(() => {
|
|
|
57223
57390
|
init_events();
|
|
57224
57391
|
init_notification();
|
|
57225
57392
|
init_errors();
|
|
57226
|
-
|
|
57393
|
+
logger24 = log.scope("NotificationService");
|
|
57227
57394
|
});
|
|
57228
57395
|
function createPlayerServices(deps) {
|
|
57229
57396
|
const { db: db2, realtime } = deps;
|
|
@@ -57342,7 +57509,7 @@ class CharacterService {
|
|
|
57342
57509
|
createdAt: characterComponents.createdAt,
|
|
57343
57510
|
updatedAt: characterComponents.updatedAt
|
|
57344
57511
|
}).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
|
|
57345
|
-
|
|
57512
|
+
logger25.debug("Listed available components", {
|
|
57346
57513
|
level,
|
|
57347
57514
|
count: components.length
|
|
57348
57515
|
});
|
|
@@ -57360,7 +57527,7 @@ class CharacterService {
|
|
|
57360
57527
|
}
|
|
57361
57528
|
}
|
|
57362
57529
|
});
|
|
57363
|
-
|
|
57530
|
+
logger25.debug("Retrieved character", { userId: user.id, found: Boolean(pc3) });
|
|
57364
57531
|
return pc3 ?? null;
|
|
57365
57532
|
}
|
|
57366
57533
|
async getByUserId(userId) {
|
|
@@ -57375,7 +57542,7 @@ class CharacterService {
|
|
|
57375
57542
|
}
|
|
57376
57543
|
}
|
|
57377
57544
|
});
|
|
57378
|
-
|
|
57545
|
+
logger25.debug("Retrieved character by ID", { userId, found: Boolean(pc3) });
|
|
57379
57546
|
return pc3 ?? null;
|
|
57380
57547
|
}
|
|
57381
57548
|
async create(input, user) {
|
|
@@ -57390,13 +57557,13 @@ class CharacterService {
|
|
|
57390
57557
|
}
|
|
57391
57558
|
const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
|
|
57392
57559
|
if (!characterRow) {
|
|
57393
|
-
|
|
57560
|
+
logger25.error("Character insert returned no rows", { userId: user.id });
|
|
57394
57561
|
throw new InternalError("Failed to create character in database");
|
|
57395
57562
|
}
|
|
57396
57563
|
await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
|
|
57397
57564
|
return characterRow;
|
|
57398
57565
|
});
|
|
57399
|
-
|
|
57566
|
+
logger25.info("Created character", { userId: user.id, characterId: result.id });
|
|
57400
57567
|
return result;
|
|
57401
57568
|
}
|
|
57402
57569
|
async update(input, user) {
|
|
@@ -57408,7 +57575,7 @@ class CharacterService {
|
|
|
57408
57575
|
if (!row) {
|
|
57409
57576
|
throw new NotFoundError("Player character");
|
|
57410
57577
|
}
|
|
57411
|
-
|
|
57578
|
+
logger25.info("Updated character", {
|
|
57412
57579
|
userId: user.id,
|
|
57413
57580
|
characterId: row.id,
|
|
57414
57581
|
updatedFields: Object.keys(input)
|
|
@@ -57430,7 +57597,7 @@ class CharacterService {
|
|
|
57430
57597
|
const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
|
|
57431
57598
|
const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
|
|
57432
57599
|
if (!validation.isValid) {
|
|
57433
|
-
|
|
57600
|
+
logger25.warn("Accessory validation failed", {
|
|
57434
57601
|
userId: user.id,
|
|
57435
57602
|
slot,
|
|
57436
57603
|
accessoryComponentId,
|
|
@@ -57446,14 +57613,14 @@ class CharacterService {
|
|
|
57446
57613
|
slot
|
|
57447
57614
|
}).returning();
|
|
57448
57615
|
if (!result) {
|
|
57449
|
-
|
|
57616
|
+
logger25.error("Accessory insert returned no rows", {
|
|
57450
57617
|
userId: user.id,
|
|
57451
57618
|
slot,
|
|
57452
57619
|
accessoryComponentId
|
|
57453
57620
|
});
|
|
57454
57621
|
throw new InternalError("Failed to equip accessory");
|
|
57455
57622
|
}
|
|
57456
|
-
|
|
57623
|
+
logger25.info("Equipped accessory", {
|
|
57457
57624
|
userId: user.id,
|
|
57458
57625
|
slot,
|
|
57459
57626
|
accessoryComponentId
|
|
@@ -57474,7 +57641,7 @@ class CharacterService {
|
|
|
57474
57641
|
const playerLevel = userLevel?.currentLevel ?? 1;
|
|
57475
57642
|
const validation = validateAccessoryRemoval(slot, playerLevel);
|
|
57476
57643
|
if (!validation.isValid) {
|
|
57477
|
-
|
|
57644
|
+
logger25.warn("Accessory removal validation failed", {
|
|
57478
57645
|
userId: user.id,
|
|
57479
57646
|
slot,
|
|
57480
57647
|
playerLevel,
|
|
@@ -57483,17 +57650,17 @@ class CharacterService {
|
|
|
57483
57650
|
throw new ValidationError(validation.error ?? "Invalid accessory removal");
|
|
57484
57651
|
}
|
|
57485
57652
|
await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
|
|
57486
|
-
|
|
57653
|
+
logger25.info("Removed accessory", { userId: user.id, slot });
|
|
57487
57654
|
}
|
|
57488
57655
|
}
|
|
57489
|
-
var
|
|
57656
|
+
var logger25;
|
|
57490
57657
|
var init_character_service = __esm(() => {
|
|
57491
57658
|
init_drizzle_orm();
|
|
57492
57659
|
init_tables_index();
|
|
57493
57660
|
init_src2();
|
|
57494
57661
|
init_errors();
|
|
57495
57662
|
init_accessory_util();
|
|
57496
|
-
|
|
57663
|
+
logger25 = log.scope("CharacterService");
|
|
57497
57664
|
});
|
|
57498
57665
|
|
|
57499
57666
|
class CurrencyService {
|
|
@@ -57504,7 +57671,7 @@ class CurrencyService {
|
|
|
57504
57671
|
async list() {
|
|
57505
57672
|
const db2 = this.deps.db;
|
|
57506
57673
|
const allCurrencies = await db2.query.currencies.findMany();
|
|
57507
|
-
|
|
57674
|
+
logger26.debug("Listed currencies", { count: allCurrencies.length });
|
|
57508
57675
|
return allCurrencies;
|
|
57509
57676
|
}
|
|
57510
57677
|
async getById(currencyId) {
|
|
@@ -57515,7 +57682,7 @@ class CurrencyService {
|
|
|
57515
57682
|
if (!currency) {
|
|
57516
57683
|
throw new NotFoundError("Currency", currencyId);
|
|
57517
57684
|
}
|
|
57518
|
-
|
|
57685
|
+
logger26.debug("Retrieved currency", { currencyId });
|
|
57519
57686
|
return currency;
|
|
57520
57687
|
}
|
|
57521
57688
|
async create(data) {
|
|
@@ -57523,13 +57690,13 @@ class CurrencyService {
|
|
|
57523
57690
|
try {
|
|
57524
57691
|
const [newCurrency] = await db2.insert(currencies).values(data).returning();
|
|
57525
57692
|
if (!newCurrency) {
|
|
57526
|
-
|
|
57693
|
+
logger26.error("Currency insert returned no rows", {
|
|
57527
57694
|
itemId: data.itemId,
|
|
57528
57695
|
symbol: data.symbol
|
|
57529
57696
|
});
|
|
57530
57697
|
throw new InternalError("Failed to create currency");
|
|
57531
57698
|
}
|
|
57532
|
-
|
|
57699
|
+
logger26.info("Created currency", {
|
|
57533
57700
|
currencyId: newCurrency.id,
|
|
57534
57701
|
itemId: newCurrency.itemId,
|
|
57535
57702
|
symbol: newCurrency.symbol,
|
|
@@ -57558,7 +57725,7 @@ class CurrencyService {
|
|
|
57558
57725
|
if (!updatedCurrency) {
|
|
57559
57726
|
throw new NotFoundError("Currency", currencyId);
|
|
57560
57727
|
}
|
|
57561
|
-
|
|
57728
|
+
logger26.info("Updated currency", {
|
|
57562
57729
|
currencyId: updatedCurrency.id,
|
|
57563
57730
|
updatedFields: Object.keys(data)
|
|
57564
57731
|
});
|
|
@@ -57584,16 +57751,16 @@ class CurrencyService {
|
|
|
57584
57751
|
if (result.length === 0) {
|
|
57585
57752
|
throw new NotFoundError("Currency", currencyId);
|
|
57586
57753
|
}
|
|
57587
|
-
|
|
57754
|
+
logger26.info("Deleted currency", { currencyId });
|
|
57588
57755
|
}
|
|
57589
57756
|
}
|
|
57590
|
-
var
|
|
57757
|
+
var logger26;
|
|
57591
57758
|
var init_currency_service = __esm(() => {
|
|
57592
57759
|
init_drizzle_orm();
|
|
57593
57760
|
init_tables_index();
|
|
57594
57761
|
init_src2();
|
|
57595
57762
|
init_errors();
|
|
57596
|
-
|
|
57763
|
+
logger26 = log.scope("CurrencyService");
|
|
57597
57764
|
});
|
|
57598
57765
|
|
|
57599
57766
|
class LogsService {
|
|
@@ -57611,11 +57778,11 @@ class LogsService {
|
|
|
57611
57778
|
if (!game) {
|
|
57612
57779
|
throw new NotFoundError("Game", slug2);
|
|
57613
57780
|
}
|
|
57614
|
-
|
|
57781
|
+
logger27.info("Admin accessing game logs", { adminId: user.id, slug: slug2, environment });
|
|
57615
57782
|
} else {
|
|
57616
57783
|
const isApprovedDev = user.developerStatus === "approved";
|
|
57617
57784
|
if (!isApprovedDev) {
|
|
57618
|
-
|
|
57785
|
+
logger27.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
|
|
57619
57786
|
throw new AccessDeniedError("Must be an approved developer");
|
|
57620
57787
|
}
|
|
57621
57788
|
const game = await db2.query.games.findFirst({
|
|
@@ -57623,7 +57790,7 @@ class LogsService {
|
|
|
57623
57790
|
columns: { id: true }
|
|
57624
57791
|
});
|
|
57625
57792
|
if (!game) {
|
|
57626
|
-
|
|
57793
|
+
logger27.warn("Developer attempted access to unowned game logs", {
|
|
57627
57794
|
userId: user.id,
|
|
57628
57795
|
slug: slug2
|
|
57629
57796
|
});
|
|
@@ -57633,7 +57800,7 @@ class LogsService {
|
|
|
57633
57800
|
const isProduction3 = environment === "production";
|
|
57634
57801
|
const workerId = getDeploymentId(slug2, isProduction3);
|
|
57635
57802
|
const token = await this.deps.mintLogStreamToken(user.id, workerId);
|
|
57636
|
-
|
|
57803
|
+
logger27.debug("Generated log stream token", {
|
|
57637
57804
|
userId: user.id,
|
|
57638
57805
|
slug: slug2,
|
|
57639
57806
|
workerId
|
|
@@ -57641,14 +57808,14 @@ class LogsService {
|
|
|
57641
57808
|
return { token, workerId };
|
|
57642
57809
|
}
|
|
57643
57810
|
}
|
|
57644
|
-
var
|
|
57811
|
+
var logger27;
|
|
57645
57812
|
var init_logs_service = __esm(() => {
|
|
57646
57813
|
init_drizzle_orm();
|
|
57647
57814
|
init_tables_index();
|
|
57648
57815
|
init_src2();
|
|
57649
57816
|
init_errors();
|
|
57650
57817
|
init_deployment_util();
|
|
57651
|
-
|
|
57818
|
+
logger27 = log.scope("LogsService");
|
|
57652
57819
|
});
|
|
57653
57820
|
|
|
57654
57821
|
class LtiService {
|
|
@@ -57699,7 +57866,7 @@ class MapService {
|
|
|
57699
57866
|
if (!mapDetails) {
|
|
57700
57867
|
throw new NotFoundError("Map", identifier);
|
|
57701
57868
|
}
|
|
57702
|
-
|
|
57869
|
+
logger28.debug("Retrieved map", { identifier });
|
|
57703
57870
|
return mapDetails;
|
|
57704
57871
|
}
|
|
57705
57872
|
async getElements(mapId) {
|
|
@@ -57715,7 +57882,7 @@ class MapService {
|
|
|
57715
57882
|
}
|
|
57716
57883
|
}
|
|
57717
57884
|
});
|
|
57718
|
-
|
|
57885
|
+
logger28.debug("Retrieved elements", { mapId, count: elements.length });
|
|
57719
57886
|
return elements;
|
|
57720
57887
|
}
|
|
57721
57888
|
async getObjects(mapId, userId) {
|
|
@@ -57736,7 +57903,7 @@ class MapService {
|
|
|
57736
57903
|
}
|
|
57737
57904
|
}
|
|
57738
57905
|
});
|
|
57739
|
-
|
|
57906
|
+
logger28.debug("Retrieved objects", { mapId, userId, count: objects.length });
|
|
57740
57907
|
return objects.map((object) => this.formatMapObjectWithItem(object));
|
|
57741
57908
|
}
|
|
57742
57909
|
async createObject(mapId, data, user) {
|
|
@@ -57763,7 +57930,7 @@ class MapService {
|
|
|
57763
57930
|
throw new NotFoundError("Item", data.itemId);
|
|
57764
57931
|
}
|
|
57765
57932
|
if (!item.isPlaceable) {
|
|
57766
|
-
|
|
57933
|
+
logger28.warn("Attempted to place non-placeable item", {
|
|
57767
57934
|
userId: user.id,
|
|
57768
57935
|
itemId: data.itemId,
|
|
57769
57936
|
mapId
|
|
@@ -57777,7 +57944,7 @@ class MapService {
|
|
|
57777
57944
|
};
|
|
57778
57945
|
const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
|
|
57779
57946
|
if (!createdObject) {
|
|
57780
|
-
|
|
57947
|
+
logger28.error("Map object insert returned no rows", {
|
|
57781
57948
|
userId: user.id,
|
|
57782
57949
|
mapId,
|
|
57783
57950
|
itemId: data.itemId
|
|
@@ -57801,12 +57968,12 @@ class MapService {
|
|
|
57801
57968
|
}
|
|
57802
57969
|
});
|
|
57803
57970
|
if (!objectWithItem) {
|
|
57804
|
-
|
|
57971
|
+
logger28.error("Map object query after insert returned no rows", {
|
|
57805
57972
|
objectId: createdObject.id
|
|
57806
57973
|
});
|
|
57807
57974
|
throw new InternalError("Failed to retrieve created object");
|
|
57808
57975
|
}
|
|
57809
|
-
|
|
57976
|
+
logger28.info("Created object", {
|
|
57810
57977
|
userId: user.id,
|
|
57811
57978
|
mapId,
|
|
57812
57979
|
objectId: createdObject.id,
|
|
@@ -57830,7 +57997,7 @@ class MapService {
|
|
|
57830
57997
|
if (result.length === 0) {
|
|
57831
57998
|
throw new NotFoundError("MapObject", objectId);
|
|
57832
57999
|
}
|
|
57833
|
-
|
|
58000
|
+
logger28.info("Deleted object", {
|
|
57834
58001
|
userId: user.id,
|
|
57835
58002
|
mapId,
|
|
57836
58003
|
objectId
|
|
@@ -57859,13 +58026,13 @@ class MapService {
|
|
|
57859
58026
|
};
|
|
57860
58027
|
}
|
|
57861
58028
|
}
|
|
57862
|
-
var
|
|
58029
|
+
var logger28;
|
|
57863
58030
|
var init_map_service = __esm(() => {
|
|
57864
58031
|
init_drizzle_orm();
|
|
57865
58032
|
init_tables_index();
|
|
57866
58033
|
init_src2();
|
|
57867
58034
|
init_errors();
|
|
57868
|
-
|
|
58035
|
+
logger28 = log.scope("MapService");
|
|
57869
58036
|
});
|
|
57870
58037
|
|
|
57871
58038
|
class RealtimeService {
|
|
@@ -57899,20 +58066,20 @@ class RealtimeService {
|
|
|
57899
58066
|
}
|
|
57900
58067
|
const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
|
|
57901
58068
|
const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
|
|
57902
|
-
|
|
58069
|
+
logger29.info("Generated token", {
|
|
57903
58070
|
userId: user.id,
|
|
57904
58071
|
gameId: resolvedGameId || "global"
|
|
57905
58072
|
});
|
|
57906
58073
|
return { token };
|
|
57907
58074
|
}
|
|
57908
58075
|
}
|
|
57909
|
-
var
|
|
58076
|
+
var logger29;
|
|
57910
58077
|
var init_realtime_service = __esm(() => {
|
|
57911
58078
|
init_drizzle_orm();
|
|
57912
58079
|
init_tables_index();
|
|
57913
58080
|
init_src2();
|
|
57914
58081
|
init_errors();
|
|
57915
|
-
|
|
58082
|
+
logger29 = log.scope("RealtimeService");
|
|
57916
58083
|
});
|
|
57917
58084
|
|
|
57918
58085
|
class SessionService {
|
|
@@ -57946,10 +58113,10 @@ class SessionService {
|
|
|
57946
58113
|
};
|
|
57947
58114
|
const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
|
|
57948
58115
|
if (!newSession?.sessionId) {
|
|
57949
|
-
|
|
58116
|
+
logger30.error("Game session insert returned no rows", { userId, gameId });
|
|
57950
58117
|
throw new InternalError("Failed to create game session");
|
|
57951
58118
|
}
|
|
57952
|
-
|
|
58119
|
+
logger30.info("Started new session", {
|
|
57953
58120
|
sessionId: newSession.sessionId,
|
|
57954
58121
|
gameId,
|
|
57955
58122
|
userId
|
|
@@ -57970,23 +58137,23 @@ class SessionService {
|
|
|
57970
58137
|
return { success: true, message: "Session already ended" };
|
|
57971
58138
|
}
|
|
57972
58139
|
await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
|
|
57973
|
-
|
|
58140
|
+
logger30.info("Ended session", { sessionId, gameId, userId });
|
|
57974
58141
|
return { success: true };
|
|
57975
58142
|
}
|
|
57976
58143
|
async mintToken(gameIdOrSlug, userId) {
|
|
57977
58144
|
const gameId = await this.resolveGameId(gameIdOrSlug);
|
|
57978
58145
|
const result = await this.deps.mintGameToken(gameId, userId);
|
|
57979
|
-
|
|
58146
|
+
logger30.debug("Minted game token", { gameId, userId });
|
|
57980
58147
|
return result;
|
|
57981
58148
|
}
|
|
57982
58149
|
}
|
|
57983
|
-
var
|
|
58150
|
+
var logger30;
|
|
57984
58151
|
var init_session_service = __esm(() => {
|
|
57985
58152
|
init_drizzle_orm();
|
|
57986
58153
|
init_tables_index();
|
|
57987
58154
|
init_src2();
|
|
57988
58155
|
init_errors();
|
|
57989
|
-
|
|
58156
|
+
logger30 = log.scope("SessionService");
|
|
57990
58157
|
});
|
|
57991
58158
|
|
|
57992
58159
|
class ShopService {
|
|
@@ -58031,7 +58198,7 @@ class ShopService {
|
|
|
58031
58198
|
const shopItems = [];
|
|
58032
58199
|
for (const listing of listingsWithRelations) {
|
|
58033
58200
|
if (!listing.item || !listing.currency) {
|
|
58034
|
-
|
|
58201
|
+
logger31.warn("Listing missing item or currency, skipping", {
|
|
58035
58202
|
listingId: listing.id
|
|
58036
58203
|
});
|
|
58037
58204
|
} else {
|
|
@@ -58048,7 +58215,7 @@ class ShopService {
|
|
|
58048
58215
|
});
|
|
58049
58216
|
}
|
|
58050
58217
|
}
|
|
58051
|
-
|
|
58218
|
+
logger31.debug("Retrieved shop view", {
|
|
58052
58219
|
userId: user.id,
|
|
58053
58220
|
itemCount: shopItems.length,
|
|
58054
58221
|
currencyCount: shopCurrencies.length
|
|
@@ -58059,12 +58226,12 @@ class ShopService {
|
|
|
58059
58226
|
};
|
|
58060
58227
|
}
|
|
58061
58228
|
}
|
|
58062
|
-
var
|
|
58229
|
+
var logger31;
|
|
58063
58230
|
var init_shop_service = __esm(() => {
|
|
58064
58231
|
init_drizzle_orm();
|
|
58065
58232
|
init_tables_index();
|
|
58066
58233
|
init_src2();
|
|
58067
|
-
|
|
58234
|
+
logger31 = log.scope("ShopService");
|
|
58068
58235
|
});
|
|
58069
58236
|
|
|
58070
58237
|
class SpriteService {
|
|
@@ -58080,17 +58247,17 @@ class SpriteService {
|
|
|
58080
58247
|
if (!template) {
|
|
58081
58248
|
throw new NotFoundError("SpriteTemplate", slug2);
|
|
58082
58249
|
}
|
|
58083
|
-
|
|
58250
|
+
logger32.debug("Retrieved sprite", { slug: slug2 });
|
|
58084
58251
|
return template;
|
|
58085
58252
|
}
|
|
58086
58253
|
}
|
|
58087
|
-
var
|
|
58254
|
+
var logger32;
|
|
58088
58255
|
var init_sprite_service = __esm(() => {
|
|
58089
58256
|
init_drizzle_orm();
|
|
58090
58257
|
init_tables_index();
|
|
58091
58258
|
init_src2();
|
|
58092
58259
|
init_errors();
|
|
58093
|
-
|
|
58260
|
+
logger32 = log.scope("SpriteService");
|
|
58094
58261
|
});
|
|
58095
58262
|
|
|
58096
58263
|
class UserService {
|
|
@@ -58104,12 +58271,12 @@ class UserService {
|
|
|
58104
58271
|
where: eq(users.id, user.id)
|
|
58105
58272
|
});
|
|
58106
58273
|
if (!userData) {
|
|
58107
|
-
|
|
58274
|
+
logger33.error("User not found", { userId: user.id });
|
|
58108
58275
|
throw new NotFoundError("User", user.id);
|
|
58109
58276
|
}
|
|
58110
58277
|
const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
|
|
58111
58278
|
if (gameId) {
|
|
58112
|
-
|
|
58279
|
+
logger33.debug("Fetched user profile (game context)", { userId: user.id, gameId });
|
|
58113
58280
|
return {
|
|
58114
58281
|
id: userData.id,
|
|
58115
58282
|
name: userData.name,
|
|
@@ -58122,7 +58289,7 @@ class UserService {
|
|
|
58122
58289
|
const timebackAccount = await db2.query.accounts.findFirst({
|
|
58123
58290
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
58124
58291
|
});
|
|
58125
|
-
|
|
58292
|
+
logger33.debug("Fetched user profile (platform context)", { userId: user.id });
|
|
58126
58293
|
return {
|
|
58127
58294
|
id: userData.id,
|
|
58128
58295
|
name: userData.name,
|
|
@@ -58145,7 +58312,7 @@ class UserService {
|
|
|
58145
58312
|
columns: { name: true }
|
|
58146
58313
|
});
|
|
58147
58314
|
if (!userData) {
|
|
58148
|
-
|
|
58315
|
+
logger33.error("Demo user not found", { userId });
|
|
58149
58316
|
throw new NotFoundError("User", userId);
|
|
58150
58317
|
}
|
|
58151
58318
|
return {
|
|
@@ -58159,10 +58326,10 @@ class UserService {
|
|
|
58159
58326
|
updatedAt: new Date
|
|
58160
58327
|
}).where(eq(users.id, userId)).returning({ name: users.name });
|
|
58161
58328
|
if (!updatedUser) {
|
|
58162
|
-
|
|
58329
|
+
logger33.error("Demo user not found for profile update", { userId });
|
|
58163
58330
|
throw new NotFoundError("User", userId);
|
|
58164
58331
|
}
|
|
58165
|
-
|
|
58332
|
+
logger33.debug("Updated demo profile", { userId, displayName });
|
|
58166
58333
|
return {
|
|
58167
58334
|
displayName: updatedUser.name,
|
|
58168
58335
|
isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
|
|
@@ -58175,7 +58342,7 @@ class UserService {
|
|
|
58175
58342
|
]);
|
|
58176
58343
|
const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
58177
58344
|
const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
58178
|
-
|
|
58345
|
+
logger33.debug("Fetched Timeback data", {
|
|
58179
58346
|
timebackId,
|
|
58180
58347
|
role,
|
|
58181
58348
|
enrollmentCount: enrollments.length,
|
|
@@ -58184,9 +58351,9 @@ class UserService {
|
|
|
58184
58351
|
return { id: timebackId, role, enrollments, organizations };
|
|
58185
58352
|
}
|
|
58186
58353
|
async fetchStudentProfile(timebackId) {
|
|
58187
|
-
|
|
58354
|
+
logger33.debug("Fetching student profile", { timebackId });
|
|
58188
58355
|
if (!this.deps.timeback) {
|
|
58189
|
-
|
|
58356
|
+
logger33.warn("Timeback client not available");
|
|
58190
58357
|
return { role: "student", organizations: [] };
|
|
58191
58358
|
}
|
|
58192
58359
|
try {
|
|
@@ -58214,14 +58381,14 @@ class UserService {
|
|
|
58214
58381
|
}
|
|
58215
58382
|
return { role, organizations: [...orgMap.values()] };
|
|
58216
58383
|
} catch (error) {
|
|
58217
|
-
|
|
58384
|
+
logger33.warn("Failed to fetch student profile", { error, timebackId });
|
|
58218
58385
|
return { role: "student", organizations: [] };
|
|
58219
58386
|
}
|
|
58220
58387
|
}
|
|
58221
58388
|
async fetchEnrollments(timebackId) {
|
|
58222
|
-
|
|
58389
|
+
logger33.debug("Fetching enrollments", { timebackId });
|
|
58223
58390
|
if (!this.deps.timeback) {
|
|
58224
|
-
|
|
58391
|
+
logger33.warn("Timeback client not available");
|
|
58225
58392
|
return [];
|
|
58226
58393
|
}
|
|
58227
58394
|
try {
|
|
@@ -58242,7 +58409,7 @@ class UserService {
|
|
|
58242
58409
|
orgId: courseToSchool.get(i2.courseId)
|
|
58243
58410
|
}));
|
|
58244
58411
|
} catch (error) {
|
|
58245
|
-
|
|
58412
|
+
logger33.warn("Failed to fetch enrollments", { error, timebackId });
|
|
58246
58413
|
return [];
|
|
58247
58414
|
}
|
|
58248
58415
|
}
|
|
@@ -58257,14 +58424,14 @@ class UserService {
|
|
|
58257
58424
|
return organizations.filter((o) => enrollmentOrgIds.has(o.id));
|
|
58258
58425
|
}
|
|
58259
58426
|
}
|
|
58260
|
-
var
|
|
58427
|
+
var logger33;
|
|
58261
58428
|
var init_user_service = __esm(() => {
|
|
58262
58429
|
init_drizzle_orm();
|
|
58263
58430
|
init_src();
|
|
58264
58431
|
init_tables_index();
|
|
58265
58432
|
init_src2();
|
|
58266
58433
|
init_errors();
|
|
58267
|
-
|
|
58434
|
+
logger33 = log.scope("UserService");
|
|
58268
58435
|
});
|
|
58269
58436
|
|
|
58270
58437
|
class VerifyService {
|
|
@@ -58273,16 +58440,16 @@ class VerifyService {
|
|
|
58273
58440
|
this.deps = deps;
|
|
58274
58441
|
}
|
|
58275
58442
|
async verifyGameToken(token) {
|
|
58276
|
-
|
|
58443
|
+
logger34.debug("Verifying game token");
|
|
58277
58444
|
const payload = await this.deps.validateGameToken(token);
|
|
58278
58445
|
if (!payload) {
|
|
58279
|
-
|
|
58446
|
+
logger34.warn("Invalid or expired game token presented");
|
|
58280
58447
|
throw new ValidationError("Invalid or expired token");
|
|
58281
58448
|
}
|
|
58282
58449
|
const gameId = payload.sub;
|
|
58283
58450
|
const userId = payload.uid;
|
|
58284
58451
|
if (typeof gameId !== "string" || typeof userId !== "string") {
|
|
58285
|
-
|
|
58452
|
+
logger34.warn("Game token missing required claims", {
|
|
58286
58453
|
hasGameId: typeof gameId === "string",
|
|
58287
58454
|
hasUserId: typeof userId === "string"
|
|
58288
58455
|
});
|
|
@@ -58293,7 +58460,7 @@ class VerifyService {
|
|
|
58293
58460
|
where: eq(users.id, userId)
|
|
58294
58461
|
});
|
|
58295
58462
|
if (!userData) {
|
|
58296
|
-
|
|
58463
|
+
logger34.error("User not found for valid token", {
|
|
58297
58464
|
userId
|
|
58298
58465
|
});
|
|
58299
58466
|
throw new NotFoundError("User", userId);
|
|
@@ -58307,7 +58474,7 @@ class VerifyService {
|
|
|
58307
58474
|
family_name: undefined,
|
|
58308
58475
|
timeback_id: userData.timebackId || undefined
|
|
58309
58476
|
};
|
|
58310
|
-
|
|
58477
|
+
logger34.info("Token verified", { gameId, userId });
|
|
58311
58478
|
return {
|
|
58312
58479
|
claims: payload,
|
|
58313
58480
|
gameId,
|
|
@@ -58315,13 +58482,13 @@ class VerifyService {
|
|
|
58315
58482
|
};
|
|
58316
58483
|
}
|
|
58317
58484
|
}
|
|
58318
|
-
var
|
|
58485
|
+
var logger34;
|
|
58319
58486
|
var init_verify_service = __esm(() => {
|
|
58320
58487
|
init_drizzle_orm();
|
|
58321
58488
|
init_tables_index();
|
|
58322
58489
|
init_src2();
|
|
58323
58490
|
init_errors();
|
|
58324
|
-
|
|
58491
|
+
logger34 = log.scope("VerifyService");
|
|
58325
58492
|
});
|
|
58326
58493
|
function createStandaloneServices(deps) {
|
|
58327
58494
|
const { db: db2, auth: auth2, timeback: timeback2 } = deps;
|
|
@@ -59901,6 +60068,9 @@ class TimebackCacheManager {
|
|
|
59901
60068
|
setEnrollments(studentId, enrollments) {
|
|
59902
60069
|
this.enrollmentCache.set(studentId, enrollments);
|
|
59903
60070
|
}
|
|
60071
|
+
clearEnrollments(studentId) {
|
|
60072
|
+
return this.enrollmentCache.delete(studentId);
|
|
60073
|
+
}
|
|
59904
60074
|
clearAll() {
|
|
59905
60075
|
this.studentCache.clear();
|
|
59906
60076
|
this.assessmentLineItemCache.clear();
|
|
@@ -59939,6 +60109,41 @@ class MasteryTracker {
|
|
|
59939
60109
|
if (typeof masteredUnits !== "number" || masteredUnits <= 0) {
|
|
59940
60110
|
return;
|
|
59941
60111
|
}
|
|
60112
|
+
const status = await this.calculateStatus({
|
|
60113
|
+
studentId,
|
|
60114
|
+
courseId,
|
|
60115
|
+
resourceId,
|
|
60116
|
+
additionalMasteredUnits: masteredUnits
|
|
60117
|
+
});
|
|
60118
|
+
if (!status) {
|
|
60119
|
+
return;
|
|
60120
|
+
}
|
|
60121
|
+
return {
|
|
60122
|
+
pctCompleteApp: status.pctCompleteApp,
|
|
60123
|
+
masteryAchieved: status.historicalMasteredUnits < status.masterableUnits && status.isComplete
|
|
60124
|
+
};
|
|
60125
|
+
}
|
|
60126
|
+
async getStatus(input) {
|
|
60127
|
+
const status = await this.calculateStatus({
|
|
60128
|
+
...input,
|
|
60129
|
+
additionalMasteredUnits: 0
|
|
60130
|
+
});
|
|
60131
|
+
if (!status) {
|
|
60132
|
+
return;
|
|
60133
|
+
}
|
|
60134
|
+
return {
|
|
60135
|
+
masteredUnits: status.masteredUnits,
|
|
60136
|
+
masterableUnits: status.masterableUnits,
|
|
60137
|
+
pctCompleteApp: status.pctCompleteApp,
|
|
60138
|
+
isComplete: status.isComplete
|
|
60139
|
+
};
|
|
60140
|
+
}
|
|
60141
|
+
async calculateStatus({
|
|
60142
|
+
studentId,
|
|
60143
|
+
courseId,
|
|
60144
|
+
resourceId,
|
|
60145
|
+
additionalMasteredUnits
|
|
60146
|
+
}) {
|
|
59942
60147
|
const masterableUnits = await this.resolveMasterableUnits(resourceId);
|
|
59943
60148
|
if (!masterableUnits || masterableUnits <= 0) {
|
|
59944
60149
|
log.warn("[MasteryTracker] No masterableUnits configured for course", {
|
|
@@ -59956,11 +60161,16 @@ class MasteryTracker {
|
|
|
59956
60161
|
return;
|
|
59957
60162
|
}
|
|
59958
60163
|
const historicalMasteredUnits = this.sumAnalyticsMetric(facts, "masteredUnits");
|
|
59959
|
-
const totalMastered = historicalMasteredUnits +
|
|
60164
|
+
const totalMastered = historicalMasteredUnits + additionalMasteredUnits;
|
|
59960
60165
|
const rawPct = totalMastered / masterableUnits * 100;
|
|
59961
60166
|
const pctCompleteApp = Math.min(100, Math.max(0, Math.round(rawPct)));
|
|
59962
|
-
|
|
59963
|
-
|
|
60167
|
+
return {
|
|
60168
|
+
masteredUnits: totalMastered,
|
|
60169
|
+
masterableUnits,
|
|
60170
|
+
pctCompleteApp,
|
|
60171
|
+
isComplete: totalMastered >= masterableUnits,
|
|
60172
|
+
historicalMasteredUnits
|
|
60173
|
+
};
|
|
59964
60174
|
}
|
|
59965
60175
|
async createCompletionEntry(studentId, courseId, classId, appName) {
|
|
59966
60176
|
const ids = deriveSourcedIds2(courseId);
|
|
@@ -60556,6 +60766,7 @@ class TimebackClient {
|
|
|
60556
60766
|
progressRecorder;
|
|
60557
60767
|
sessionRecorder;
|
|
60558
60768
|
adminEventRecorder;
|
|
60769
|
+
masteryTracker;
|
|
60559
60770
|
constructor(config2) {
|
|
60560
60771
|
this.baseUrl = TimebackClient.resolveBaseUrl(config2?.baseUrl);
|
|
60561
60772
|
this.environment = process.env[ENV_VARS4.environment] === "staging" ? "staging" : "production";
|
|
@@ -60573,8 +60784,8 @@ class TimebackClient {
|
|
|
60573
60784
|
this.edubridge = createEduBridgeNamespace(this);
|
|
60574
60785
|
this.cacheManager = new TimebackCacheManager;
|
|
60575
60786
|
this.studentResolver = new StudentResolver(this.cacheManager, this.oneroster);
|
|
60576
|
-
|
|
60577
|
-
this.progressRecorder = new ProgressRecorder(this.studentResolver, this.cacheManager, this.oneroster, this.caliper, masteryTracker);
|
|
60787
|
+
this.masteryTracker = new MasteryTracker(this.cacheManager, this.oneroster, this.edubridge);
|
|
60788
|
+
this.progressRecorder = new ProgressRecorder(this.studentResolver, this.cacheManager, this.oneroster, this.caliper, this.masteryTracker);
|
|
60578
60789
|
this.sessionRecorder = new SessionRecorder(this.studentResolver, this.caliper);
|
|
60579
60790
|
this.adminEventRecorder = new AdminEventRecorder(this.studentResolver, this.oneroster, this.caliper, this.environment);
|
|
60580
60791
|
if (this.credentials) {
|
|
@@ -60732,6 +60943,18 @@ class TimebackClient {
|
|
|
60732
60943
|
this.cacheManager.setEnrollments(studentId, enrollments);
|
|
60733
60944
|
return enrollments;
|
|
60734
60945
|
}
|
|
60946
|
+
invalidateEnrollments(studentId) {
|
|
60947
|
+
this.cacheManager.clearEnrollments(studentId);
|
|
60948
|
+
}
|
|
60949
|
+
async getMasteryStatus(courseId, studentId) {
|
|
60950
|
+
await this._ensureAuthenticated();
|
|
60951
|
+
const ids = deriveSourcedIds2(courseId);
|
|
60952
|
+
return this.masteryTracker.getStatus({
|
|
60953
|
+
studentId,
|
|
60954
|
+
courseId,
|
|
60955
|
+
resourceId: ids.resource
|
|
60956
|
+
});
|
|
60957
|
+
}
|
|
60735
60958
|
async getStudentXp(studentId, options) {
|
|
60736
60959
|
await this._ensureAuthenticated();
|
|
60737
60960
|
const enrollments = await this.edubridge.enrollments.listByUser(studentId);
|
|
@@ -63277,7 +63500,7 @@ var colorStatus = async (status) => {
|
|
|
63277
63500
|
}
|
|
63278
63501
|
return `${status}`;
|
|
63279
63502
|
};
|
|
63280
|
-
var
|
|
63503
|
+
var logger35 = (fn = console.log) => {
|
|
63281
63504
|
return async function logger2(c, next) {
|
|
63282
63505
|
const { method, url } = c.req;
|
|
63283
63506
|
const path2 = url.slice(url.indexOf("/", 8));
|
|
@@ -63454,7 +63677,7 @@ function createApp(db2, options) {
|
|
|
63454
63677
|
const app = new Hono2;
|
|
63455
63678
|
app.use("*", cors({ origin: "*", credentials: true }));
|
|
63456
63679
|
if (options.verbose && !options.quiet) {
|
|
63457
|
-
app.use("*",
|
|
63680
|
+
app.use("*", logger35());
|
|
63458
63681
|
}
|
|
63459
63682
|
app.use("/api/*", async (c, next) => {
|
|
63460
63683
|
c.set("db", db2);
|
|
@@ -70156,12 +70379,12 @@ var init_session2 = __esm(() => {
|
|
|
70156
70379
|
init_utils();
|
|
70157
70380
|
init_dist5();
|
|
70158
70381
|
PglitePreparedQuery = class PglitePreparedQuery2 extends PgPreparedQuery {
|
|
70159
|
-
constructor(client, queryString, params,
|
|
70382
|
+
constructor(client, queryString, params, logger36, fields, name3, _isResponseInArrayMode, customResultMapper) {
|
|
70160
70383
|
super({ sql: queryString, params });
|
|
70161
70384
|
this.client = client;
|
|
70162
70385
|
this.queryString = queryString;
|
|
70163
70386
|
this.params = params;
|
|
70164
|
-
this.logger =
|
|
70387
|
+
this.logger = logger36;
|
|
70165
70388
|
this.fields = fields;
|
|
70166
70389
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
70167
70390
|
this.customResultMapper = customResultMapper;
|
|
@@ -70263,11 +70486,11 @@ var init_session2 = __esm(() => {
|
|
|
70263
70486
|
});
|
|
70264
70487
|
function construct(client, config2 = {}) {
|
|
70265
70488
|
const dialect2 = new PgDialect({ casing: config2.casing });
|
|
70266
|
-
let
|
|
70489
|
+
let logger36;
|
|
70267
70490
|
if (config2.logger === true) {
|
|
70268
|
-
|
|
70491
|
+
logger36 = new DefaultLogger;
|
|
70269
70492
|
} else if (config2.logger !== false) {
|
|
70270
|
-
|
|
70493
|
+
logger36 = config2.logger;
|
|
70271
70494
|
}
|
|
70272
70495
|
let schema2;
|
|
70273
70496
|
if (config2.schema) {
|
|
@@ -70278,7 +70501,7 @@ function construct(client, config2 = {}) {
|
|
|
70278
70501
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
70279
70502
|
};
|
|
70280
70503
|
}
|
|
70281
|
-
const driver = new PgliteDriver(client, dialect2, { logger:
|
|
70504
|
+
const driver = new PgliteDriver(client, dialect2, { logger: logger36 });
|
|
70282
70505
|
const session2 = driver.createSession(schema2);
|
|
70283
70506
|
const db2 = new PgliteDatabase(dialect2, session2, schema2);
|
|
70284
70507
|
db2.$client = client;
|
|
@@ -118923,8 +119146,8 @@ var init_currencies = __esm(() => {
|
|
|
118923
119146
|
init_tables_index();
|
|
118924
119147
|
init_constants();
|
|
118925
119148
|
});
|
|
118926
|
-
function setLogger(
|
|
118927
|
-
customLogger =
|
|
119149
|
+
function setLogger(logger36) {
|
|
119150
|
+
customLogger = logger36;
|
|
118928
119151
|
}
|
|
118929
119152
|
function getLogger() {
|
|
118930
119153
|
if (customLogger) {
|
|
@@ -118937,10 +119160,10 @@ function getLogger() {
|
|
|
118937
119160
|
};
|
|
118938
119161
|
}
|
|
118939
119162
|
var customLogger;
|
|
118940
|
-
var
|
|
119163
|
+
var logger36;
|
|
118941
119164
|
var init_adapter = __esm(() => {
|
|
118942
119165
|
init_config();
|
|
118943
|
-
|
|
119166
|
+
logger36 = {
|
|
118944
119167
|
info: (msg) => {
|
|
118945
119168
|
if (customLogger || !config.embedded) {
|
|
118946
119169
|
getLogger().info(msg);
|
|
@@ -119020,7 +119243,7 @@ async function seedCoreGames(db2) {
|
|
|
119020
119243
|
try {
|
|
119021
119244
|
await db2.insert(games).values(gameData).onConflictDoNothing();
|
|
119022
119245
|
} catch (error2) {
|
|
119023
|
-
|
|
119246
|
+
logger36.error(`Error seeding core game '${gameData.slug}': ${error2}`);
|
|
119024
119247
|
}
|
|
119025
119248
|
}
|
|
119026
119249
|
}
|
|
@@ -119066,7 +119289,7 @@ async function seedCurrentProjectGame(db2, project) {
|
|
|
119066
119289
|
}
|
|
119067
119290
|
return newGame;
|
|
119068
119291
|
} catch (error2) {
|
|
119069
|
-
|
|
119292
|
+
logger36.error(`❌ Error seeding project game: ${error2}`);
|
|
119070
119293
|
throw error2;
|
|
119071
119294
|
}
|
|
119072
119295
|
}
|
|
@@ -120427,6 +120650,7 @@ var TimebackSubjectSchema;
|
|
|
120427
120650
|
var UpdateTimebackXpRequestSchema;
|
|
120428
120651
|
var TimebackActivityDataSchema;
|
|
120429
120652
|
var EndActivityRequestSchema;
|
|
120653
|
+
var AdvanceCourseRequestSchema;
|
|
120430
120654
|
var HeartbeatRequestSchema;
|
|
120431
120655
|
var PopulateStudentRequestSchema;
|
|
120432
120656
|
var DerivedPlatformCourseConfigSchema;
|
|
@@ -120494,6 +120718,11 @@ var init_schemas11 = __esm(() => {
|
|
|
120494
120718
|
masteredUnits: exports_external.number().nonnegative().optional(),
|
|
120495
120719
|
extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
120496
120720
|
});
|
|
120721
|
+
AdvanceCourseRequestSchema = exports_external.object({
|
|
120722
|
+
gameId: exports_external.string().uuid(),
|
|
120723
|
+
studentId: exports_external.string().min(1),
|
|
120724
|
+
subject: TimebackSubjectSchema.optional()
|
|
120725
|
+
});
|
|
120497
120726
|
HeartbeatRequestSchema = exports_external.object({
|
|
120498
120727
|
gameId: exports_external.string().uuid(),
|
|
120499
120728
|
studentId: exports_external.string().min(1),
|
|
@@ -120763,7 +120992,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120763
120992
|
where: eq(users.id, existingAccount.userId)
|
|
120764
120993
|
});
|
|
120765
120994
|
if (user) {
|
|
120766
|
-
|
|
120995
|
+
logger37.info("Found user by LTI account", {
|
|
120767
120996
|
userId: user.id,
|
|
120768
120997
|
ltiTimebackId
|
|
120769
120998
|
});
|
|
@@ -120792,13 +121021,13 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120792
121021
|
updatedAt: new Date
|
|
120793
121022
|
}).returning({ id: accounts.id });
|
|
120794
121023
|
if (!account) {
|
|
120795
|
-
|
|
121024
|
+
logger37.error("LTI account link insert returned no rows", {
|
|
120796
121025
|
userId: existingUser.id,
|
|
120797
121026
|
ltiTimebackId
|
|
120798
121027
|
});
|
|
120799
121028
|
throw new InternalError("Failed to link LTI account");
|
|
120800
121029
|
}
|
|
120801
|
-
|
|
121030
|
+
logger37.info("Linked LTI account to existing user", {
|
|
120802
121031
|
userId: existingUser.id,
|
|
120803
121032
|
ltiTimebackId
|
|
120804
121033
|
});
|
|
@@ -120818,7 +121047,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120818
121047
|
updatedAt: new Date
|
|
120819
121048
|
}).returning();
|
|
120820
121049
|
if (!insertedUser) {
|
|
120821
|
-
|
|
121050
|
+
logger37.error("LTI user insert returned no rows", { email, ltiTimebackId });
|
|
120822
121051
|
throw new InternalError("Failed to create user");
|
|
120823
121052
|
}
|
|
120824
121053
|
await tx.insert(accounts).values({
|
|
@@ -120833,7 +121062,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120833
121062
|
createdAt: new Date,
|
|
120834
121063
|
updatedAt: new Date
|
|
120835
121064
|
});
|
|
120836
|
-
|
|
121065
|
+
logger37.info("Provisioned new user from LTI", {
|
|
120837
121066
|
userId: insertedUser.id,
|
|
120838
121067
|
ltiTimebackId
|
|
120839
121068
|
});
|
|
@@ -120841,7 +121070,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120841
121070
|
});
|
|
120842
121071
|
return createdUser;
|
|
120843
121072
|
}
|
|
120844
|
-
var
|
|
121073
|
+
var logger37;
|
|
120845
121074
|
var init_lti_provisioning = __esm(() => {
|
|
120846
121075
|
init_drizzle_orm();
|
|
120847
121076
|
init_src();
|
|
@@ -120849,7 +121078,7 @@ var init_lti_provisioning = __esm(() => {
|
|
|
120849
121078
|
init_src2();
|
|
120850
121079
|
init_errors();
|
|
120851
121080
|
init_lti_util();
|
|
120852
|
-
|
|
121081
|
+
logger37 = log.scope("LtiProvisioning");
|
|
120853
121082
|
});
|
|
120854
121083
|
function formatZodError(error2) {
|
|
120855
121084
|
const flat = error2.flatten();
|
|
@@ -120892,7 +121121,7 @@ var init_utils11 = __esm(() => {
|
|
|
120892
121121
|
init_timeback_util();
|
|
120893
121122
|
init_validation_util();
|
|
120894
121123
|
});
|
|
120895
|
-
var
|
|
121124
|
+
var logger38;
|
|
120896
121125
|
var listCurrent;
|
|
120897
121126
|
var listHistory;
|
|
120898
121127
|
var postProgress;
|
|
@@ -120903,14 +121132,14 @@ var init_achievement_controller = __esm(() => {
|
|
|
120903
121132
|
init_src2();
|
|
120904
121133
|
init_errors();
|
|
120905
121134
|
init_utils11();
|
|
120906
|
-
|
|
121135
|
+
logger38 = log.scope("AchievementController");
|
|
120907
121136
|
listCurrent = requireNonAnonymous(async (ctx) => {
|
|
120908
|
-
|
|
121137
|
+
logger38.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
120909
121138
|
return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
|
|
120910
121139
|
});
|
|
120911
121140
|
listHistory = requireNonAnonymous(async (ctx) => {
|
|
120912
121141
|
const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
|
|
120913
|
-
|
|
121142
|
+
logger38.debug("Listing achievement history", { userId: ctx.user.id, limit });
|
|
120914
121143
|
return ctx.services.achievement.listHistory(ctx.user, limit);
|
|
120915
121144
|
});
|
|
120916
121145
|
postProgress = requireNonAnonymous(async (ctx) => {
|
|
@@ -120921,12 +121150,12 @@ var init_achievement_controller = __esm(() => {
|
|
|
120921
121150
|
} catch (error2) {
|
|
120922
121151
|
if (error2 instanceof exports_external.ZodError) {
|
|
120923
121152
|
const details = formatZodError(error2);
|
|
120924
|
-
|
|
121153
|
+
logger38.warn("Submit achievement progress validation failed", { details });
|
|
120925
121154
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
120926
121155
|
}
|
|
120927
121156
|
throw ApiError.badRequest("Invalid JSON body");
|
|
120928
121157
|
}
|
|
120929
|
-
|
|
121158
|
+
logger38.debug("Submitting progress", {
|
|
120930
121159
|
userId: ctx.user.id,
|
|
120931
121160
|
achievementId: body2.achievementId
|
|
120932
121161
|
});
|
|
@@ -120938,15 +121167,15 @@ var init_achievement_controller = __esm(() => {
|
|
|
120938
121167
|
postProgress
|
|
120939
121168
|
};
|
|
120940
121169
|
});
|
|
120941
|
-
var
|
|
121170
|
+
var logger39;
|
|
120942
121171
|
var getAllowedOrigins;
|
|
120943
121172
|
var init_admin_controller = __esm(() => {
|
|
120944
121173
|
init_src2();
|
|
120945
121174
|
init_utils11();
|
|
120946
|
-
|
|
121175
|
+
logger39 = log.scope("AdminController");
|
|
120947
121176
|
getAllowedOrigins = requireAdmin(async (ctx) => {
|
|
120948
121177
|
const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
|
|
120949
|
-
|
|
121178
|
+
logger39.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
|
|
120950
121179
|
if (shouldRefresh) {
|
|
120951
121180
|
await ctx.providers.cache.refreshGameOrigins();
|
|
120952
121181
|
}
|
|
@@ -120959,7 +121188,7 @@ var init_admin_controller = __esm(() => {
|
|
|
120959
121188
|
};
|
|
120960
121189
|
});
|
|
120961
121190
|
});
|
|
120962
|
-
var
|
|
121191
|
+
var logger40;
|
|
120963
121192
|
var listFiles;
|
|
120964
121193
|
var getFile;
|
|
120965
121194
|
var putFile;
|
|
@@ -120971,7 +121200,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
120971
121200
|
init_src2();
|
|
120972
121201
|
init_errors();
|
|
120973
121202
|
init_utils11();
|
|
120974
|
-
|
|
121203
|
+
logger40 = log.scope("BucketController");
|
|
120975
121204
|
listFiles = requireDeveloper(async (ctx) => {
|
|
120976
121205
|
const slug2 = ctx.params.slug;
|
|
120977
121206
|
if (!slug2) {
|
|
@@ -120979,7 +121208,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
120979
121208
|
}
|
|
120980
121209
|
const url = ctx.url;
|
|
120981
121210
|
const prefix2 = url.searchParams.get("prefix") || undefined;
|
|
120982
|
-
|
|
121211
|
+
logger40.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
120983
121212
|
const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
|
|
120984
121213
|
return { files };
|
|
120985
121214
|
});
|
|
@@ -120989,7 +121218,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
120989
121218
|
if (!slug2 || !key) {
|
|
120990
121219
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
120991
121220
|
}
|
|
120992
|
-
|
|
121221
|
+
logger40.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
|
|
120993
121222
|
const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
|
|
120994
121223
|
return new Response(Buffer.from(object.body), {
|
|
120995
121224
|
status: 200,
|
|
@@ -121008,7 +121237,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
121008
121237
|
const arrayBuffer = await ctx.request.arrayBuffer();
|
|
121009
121238
|
const body2 = new Uint8Array(arrayBuffer);
|
|
121010
121239
|
const contentType = ctx.request.headers.get("content-type") || undefined;
|
|
121011
|
-
|
|
121240
|
+
logger40.debug("Uploading file", {
|
|
121012
121241
|
userId: ctx.user.id,
|
|
121013
121242
|
slug: slug2,
|
|
121014
121243
|
key,
|
|
@@ -121024,7 +121253,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
121024
121253
|
if (!slug2 || !key) {
|
|
121025
121254
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
121026
121255
|
}
|
|
121027
|
-
|
|
121256
|
+
logger40.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
|
|
121028
121257
|
await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
|
|
121029
121258
|
return { success: true, key };
|
|
121030
121259
|
});
|
|
@@ -121036,12 +121265,12 @@ var init_bucket_controller = __esm(() => {
|
|
|
121036
121265
|
} catch (error2) {
|
|
121037
121266
|
if (error2 instanceof exports_external.ZodError) {
|
|
121038
121267
|
const details = formatZodError(error2);
|
|
121039
|
-
|
|
121268
|
+
logger40.warn("Initiate upload validation failed", { details });
|
|
121040
121269
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121041
121270
|
}
|
|
121042
121271
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121043
121272
|
}
|
|
121044
|
-
|
|
121273
|
+
logger40.debug("Initiating multipart upload", {
|
|
121045
121274
|
userId: ctx.user.id,
|
|
121046
121275
|
gameId: body2.gameId,
|
|
121047
121276
|
fileName: body2.fileName
|
|
@@ -121056,10 +121285,10 @@ async function listComponents(ctx) {
|
|
|
121056
121285
|
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
121057
121286
|
level = Math.floor(Math.max(0, parsed));
|
|
121058
121287
|
}
|
|
121059
|
-
|
|
121288
|
+
logger41.debug("Listing components", { level });
|
|
121060
121289
|
return ctx.services.character.listAvailableComponents(level);
|
|
121061
121290
|
}
|
|
121062
|
-
var
|
|
121291
|
+
var logger41;
|
|
121063
121292
|
var get;
|
|
121064
121293
|
var getByUserId;
|
|
121065
121294
|
var create;
|
|
@@ -121073,9 +121302,9 @@ var init_character_controller = __esm(() => {
|
|
|
121073
121302
|
init_src2();
|
|
121074
121303
|
init_errors();
|
|
121075
121304
|
init_utils11();
|
|
121076
|
-
|
|
121305
|
+
logger41 = log.scope("CharacterController");
|
|
121077
121306
|
get = requireNonAnonymous(async (ctx) => {
|
|
121078
|
-
|
|
121307
|
+
logger41.debug("Getting character", { userId: ctx.user.id });
|
|
121079
121308
|
return ctx.services.character.getByUser(ctx.user);
|
|
121080
121309
|
});
|
|
121081
121310
|
getByUserId = requireNonAnonymous(async (ctx) => {
|
|
@@ -121083,7 +121312,7 @@ var init_character_controller = __esm(() => {
|
|
|
121083
121312
|
if (!userId) {
|
|
121084
121313
|
throw ApiError.badRequest("User ID is required in the URL path");
|
|
121085
121314
|
}
|
|
121086
|
-
|
|
121315
|
+
logger41.debug("Getting character by user ID", { requestedUserId: userId });
|
|
121087
121316
|
return ctx.services.character.getByUserId(userId);
|
|
121088
121317
|
});
|
|
121089
121318
|
create = requireNonAnonymous(async (ctx) => {
|
|
@@ -121094,12 +121323,12 @@ var init_character_controller = __esm(() => {
|
|
|
121094
121323
|
} catch (error2) {
|
|
121095
121324
|
if (error2 instanceof exports_external.ZodError) {
|
|
121096
121325
|
const details = formatZodError(error2);
|
|
121097
|
-
|
|
121326
|
+
logger41.warn("Create character validation failed", { details });
|
|
121098
121327
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121099
121328
|
}
|
|
121100
121329
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121101
121330
|
}
|
|
121102
|
-
|
|
121331
|
+
logger41.debug("Creating character", {
|
|
121103
121332
|
userId: ctx.user.id,
|
|
121104
121333
|
bodyComponentId: body2.bodyComponentId,
|
|
121105
121334
|
hairstyleComponentId: body2.hairstyleComponentId
|
|
@@ -121114,12 +121343,12 @@ var init_character_controller = __esm(() => {
|
|
|
121114
121343
|
} catch (error2) {
|
|
121115
121344
|
if (error2 instanceof exports_external.ZodError) {
|
|
121116
121345
|
const details = formatZodError(error2);
|
|
121117
|
-
|
|
121346
|
+
logger41.warn("Update character validation failed", { details });
|
|
121118
121347
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121119
121348
|
}
|
|
121120
121349
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121121
121350
|
}
|
|
121122
|
-
|
|
121351
|
+
logger41.debug("Updating character", {
|
|
121123
121352
|
userId: ctx.user.id,
|
|
121124
121353
|
bodyComponentId: body2.bodyComponentId,
|
|
121125
121354
|
hairstyleComponentId: body2.hairstyleComponentId,
|
|
@@ -121135,12 +121364,12 @@ var init_character_controller = __esm(() => {
|
|
|
121135
121364
|
} catch (error2) {
|
|
121136
121365
|
if (error2 instanceof exports_external.ZodError) {
|
|
121137
121366
|
const details = formatZodError(error2);
|
|
121138
|
-
|
|
121367
|
+
logger41.warn("Equip accessory validation failed", { details });
|
|
121139
121368
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121140
121369
|
}
|
|
121141
121370
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121142
121371
|
}
|
|
121143
|
-
|
|
121372
|
+
logger41.debug("Equipping accessory", {
|
|
121144
121373
|
userId: ctx.user.id,
|
|
121145
121374
|
slot: body2.slot,
|
|
121146
121375
|
accessoryComponentId: body2.accessoryComponentId
|
|
@@ -121152,7 +121381,7 @@ var init_character_controller = __esm(() => {
|
|
|
121152
121381
|
if (!slot) {
|
|
121153
121382
|
throw ApiError.badRequest("Slot is required in the URL path");
|
|
121154
121383
|
}
|
|
121155
|
-
|
|
121384
|
+
logger41.debug("Removing accessory", { userId: ctx.user.id, slot });
|
|
121156
121385
|
await ctx.services.character.removeAccessory(slot, ctx.user);
|
|
121157
121386
|
return { success: true };
|
|
121158
121387
|
});
|
|
@@ -121166,7 +121395,7 @@ var init_character_controller = __esm(() => {
|
|
|
121166
121395
|
removeAccessory
|
|
121167
121396
|
};
|
|
121168
121397
|
});
|
|
121169
|
-
var
|
|
121398
|
+
var logger42;
|
|
121170
121399
|
var list;
|
|
121171
121400
|
var getById;
|
|
121172
121401
|
var create2;
|
|
@@ -121180,9 +121409,9 @@ var init_currency_controller = __esm(() => {
|
|
|
121180
121409
|
init_src4();
|
|
121181
121410
|
init_errors();
|
|
121182
121411
|
init_utils11();
|
|
121183
|
-
|
|
121412
|
+
logger42 = log.scope("CurrencyController");
|
|
121184
121413
|
list = requireNonAnonymous(async (ctx) => {
|
|
121185
|
-
|
|
121414
|
+
logger42.debug("Listing currencies", { userId: ctx.user.id });
|
|
121186
121415
|
return ctx.services.currency.list();
|
|
121187
121416
|
});
|
|
121188
121417
|
getById = requireNonAnonymous(async (ctx) => {
|
|
@@ -121193,7 +121422,7 @@ var init_currency_controller = __esm(() => {
|
|
|
121193
121422
|
if (!isValidUUID(currencyId)) {
|
|
121194
121423
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
121195
121424
|
}
|
|
121196
|
-
|
|
121425
|
+
logger42.debug("Getting currency", { userId: ctx.user.id, currencyId });
|
|
121197
121426
|
return ctx.services.currency.getById(currencyId);
|
|
121198
121427
|
});
|
|
121199
121428
|
create2 = requireAdmin(async (ctx) => {
|
|
@@ -121204,12 +121433,12 @@ var init_currency_controller = __esm(() => {
|
|
|
121204
121433
|
} catch (error2) {
|
|
121205
121434
|
if (error2 instanceof exports_external.ZodError) {
|
|
121206
121435
|
const details = formatZodError(error2);
|
|
121207
|
-
|
|
121436
|
+
logger42.warn("Create currency validation failed", { details });
|
|
121208
121437
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121209
121438
|
}
|
|
121210
121439
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121211
121440
|
}
|
|
121212
|
-
|
|
121441
|
+
logger42.debug("Creating currency", {
|
|
121213
121442
|
userId: ctx.user.id,
|
|
121214
121443
|
symbol: body2.symbol,
|
|
121215
121444
|
itemId: body2.itemId,
|
|
@@ -121232,12 +121461,12 @@ var init_currency_controller = __esm(() => {
|
|
|
121232
121461
|
} catch (error2) {
|
|
121233
121462
|
if (error2 instanceof exports_external.ZodError) {
|
|
121234
121463
|
const details = formatZodError(error2);
|
|
121235
|
-
|
|
121464
|
+
logger42.warn("Update currency validation failed", { details });
|
|
121236
121465
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121237
121466
|
}
|
|
121238
121467
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121239
121468
|
}
|
|
121240
|
-
|
|
121469
|
+
logger42.debug("Updating currency", {
|
|
121241
121470
|
userId: ctx.user.id,
|
|
121242
121471
|
currencyId,
|
|
121243
121472
|
symbol: body2.symbol,
|
|
@@ -121254,7 +121483,7 @@ var init_currency_controller = __esm(() => {
|
|
|
121254
121483
|
if (!isValidUUID(currencyId)) {
|
|
121255
121484
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
121256
121485
|
}
|
|
121257
|
-
|
|
121486
|
+
logger42.debug("Deleting currency", { userId: ctx.user.id, currencyId });
|
|
121258
121487
|
await ctx.services.currency.delete(currencyId);
|
|
121259
121488
|
});
|
|
121260
121489
|
currencyController = {
|
|
@@ -121265,7 +121494,7 @@ var init_currency_controller = __esm(() => {
|
|
|
121265
121494
|
remove
|
|
121266
121495
|
};
|
|
121267
121496
|
});
|
|
121268
|
-
var
|
|
121497
|
+
var logger43;
|
|
121269
121498
|
var reset;
|
|
121270
121499
|
var init_database_controller = __esm(() => {
|
|
121271
121500
|
init_esm();
|
|
@@ -121273,7 +121502,7 @@ var init_database_controller = __esm(() => {
|
|
|
121273
121502
|
init_src2();
|
|
121274
121503
|
init_errors();
|
|
121275
121504
|
init_utils11();
|
|
121276
|
-
|
|
121505
|
+
logger43 = log.scope("DatabaseController");
|
|
121277
121506
|
reset = requireDeveloper(async (ctx) => {
|
|
121278
121507
|
const slug2 = ctx.params.slug;
|
|
121279
121508
|
if (!slug2) {
|
|
@@ -121286,11 +121515,11 @@ var init_database_controller = __esm(() => {
|
|
|
121286
121515
|
} catch (error2) {
|
|
121287
121516
|
if (error2 instanceof exports_external.ZodError) {
|
|
121288
121517
|
const details = formatZodError(error2);
|
|
121289
|
-
|
|
121518
|
+
logger43.warn("Database reset validation failed", { details });
|
|
121290
121519
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121291
121520
|
}
|
|
121292
121521
|
}
|
|
121293
|
-
|
|
121522
|
+
logger43.debug("Resetting database", {
|
|
121294
121523
|
userId: ctx.user.id,
|
|
121295
121524
|
slug: slug2,
|
|
121296
121525
|
hasSchema: Boolean(body2.schema)
|
|
@@ -121306,7 +121535,7 @@ async function createJob(ctx) {
|
|
|
121306
121535
|
let body2;
|
|
121307
121536
|
try {
|
|
121308
121537
|
const json4 = await ctx.request.json();
|
|
121309
|
-
|
|
121538
|
+
logger44.debug("Deploy request body", {
|
|
121310
121539
|
keys: Object.keys(json4 || {}),
|
|
121311
121540
|
hasUploadToken: Boolean(json4?.uploadToken),
|
|
121312
121541
|
hasCode: Boolean(json4?.code),
|
|
@@ -121316,7 +121545,7 @@ async function createJob(ctx) {
|
|
|
121316
121545
|
} catch (error2) {
|
|
121317
121546
|
if (error2 instanceof exports_external.ZodError) {
|
|
121318
121547
|
const details = formatZodError(error2);
|
|
121319
|
-
|
|
121548
|
+
logger44.warn("Deploy validation failed", { details });
|
|
121320
121549
|
throw ApiError.unprocessableEntity("Invalid deploy request", details);
|
|
121321
121550
|
}
|
|
121322
121551
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -121337,7 +121566,7 @@ async function getJob(ctx) {
|
|
|
121337
121566
|
}
|
|
121338
121567
|
return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
|
|
121339
121568
|
}
|
|
121340
|
-
var
|
|
121569
|
+
var logger44;
|
|
121341
121570
|
var deploy;
|
|
121342
121571
|
var init_deploy_controller = __esm(() => {
|
|
121343
121572
|
init_esm();
|
|
@@ -121345,26 +121574,26 @@ var init_deploy_controller = __esm(() => {
|
|
|
121345
121574
|
init_src2();
|
|
121346
121575
|
init_errors();
|
|
121347
121576
|
init_utils11();
|
|
121348
|
-
|
|
121577
|
+
logger44 = log.scope("DeployController");
|
|
121349
121578
|
deploy = {
|
|
121350
121579
|
createJob: requireDeveloper(createJob),
|
|
121351
121580
|
getJob: requireDeveloper(getJob)
|
|
121352
121581
|
};
|
|
121353
121582
|
});
|
|
121354
|
-
var
|
|
121583
|
+
var logger45;
|
|
121355
121584
|
var apply;
|
|
121356
121585
|
var getStatus;
|
|
121357
121586
|
var developer;
|
|
121358
121587
|
var init_developer_controller = __esm(() => {
|
|
121359
121588
|
init_src2();
|
|
121360
121589
|
init_utils11();
|
|
121361
|
-
|
|
121590
|
+
logger45 = log.scope("DeveloperController");
|
|
121362
121591
|
apply = requireNonAnonymous(async (ctx) => {
|
|
121363
|
-
|
|
121592
|
+
logger45.debug("Applying for developer status", { userId: ctx.user.id });
|
|
121364
121593
|
await ctx.services.developer.apply(ctx.user);
|
|
121365
121594
|
});
|
|
121366
121595
|
getStatus = requireNonAnonymous(async (ctx) => {
|
|
121367
|
-
|
|
121596
|
+
logger45.debug("Getting developer status", { userId: ctx.user.id });
|
|
121368
121597
|
const status = await ctx.services.developer.getStatus(ctx.user.id);
|
|
121369
121598
|
return { status };
|
|
121370
121599
|
});
|
|
@@ -121373,7 +121602,7 @@ var init_developer_controller = __esm(() => {
|
|
|
121373
121602
|
getStatus
|
|
121374
121603
|
};
|
|
121375
121604
|
});
|
|
121376
|
-
var
|
|
121605
|
+
var logger46;
|
|
121377
121606
|
var add;
|
|
121378
121607
|
var list2;
|
|
121379
121608
|
var getStatus2;
|
|
@@ -121386,7 +121615,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121386
121615
|
init_config2();
|
|
121387
121616
|
init_errors();
|
|
121388
121617
|
init_utils11();
|
|
121389
|
-
|
|
121618
|
+
logger46 = log.scope("DomainController");
|
|
121390
121619
|
add = requireDeveloper(async (ctx) => {
|
|
121391
121620
|
const slug2 = ctx.params.slug;
|
|
121392
121621
|
if (!slug2) {
|
|
@@ -121399,13 +121628,13 @@ var init_domain_controller = __esm(() => {
|
|
|
121399
121628
|
} catch (error2) {
|
|
121400
121629
|
if (error2 instanceof exports_external.ZodError) {
|
|
121401
121630
|
const details = formatZodError(error2);
|
|
121402
|
-
|
|
121631
|
+
logger46.warn("Add domain validation failed", { details });
|
|
121403
121632
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121404
121633
|
}
|
|
121405
121634
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121406
121635
|
}
|
|
121407
121636
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121408
|
-
|
|
121637
|
+
logger46.debug("Adding domain", {
|
|
121409
121638
|
userId: ctx.user.id,
|
|
121410
121639
|
slug: slug2,
|
|
121411
121640
|
hostname: body2.hostname,
|
|
@@ -121419,7 +121648,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121419
121648
|
throw ApiError.badRequest("Missing game slug");
|
|
121420
121649
|
}
|
|
121421
121650
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121422
|
-
|
|
121651
|
+
logger46.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
|
|
121423
121652
|
const domains22 = await ctx.services.domain.list(slug2, environment, ctx.user);
|
|
121424
121653
|
return { domains: domains22 };
|
|
121425
121654
|
});
|
|
@@ -121434,7 +121663,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121434
121663
|
}
|
|
121435
121664
|
const refresh = ctx.url.searchParams.get("refresh") === "true";
|
|
121436
121665
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121437
|
-
|
|
121666
|
+
logger46.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
|
|
121438
121667
|
return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
|
|
121439
121668
|
});
|
|
121440
121669
|
remove2 = requireDeveloper(async (ctx) => {
|
|
@@ -121447,7 +121676,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121447
121676
|
throw ApiError.badRequest("Missing hostname");
|
|
121448
121677
|
}
|
|
121449
121678
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121450
|
-
|
|
121679
|
+
logger46.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
|
|
121451
121680
|
await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
|
|
121452
121681
|
});
|
|
121453
121682
|
domains2 = {
|
|
@@ -121457,7 +121686,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121457
121686
|
remove: remove2
|
|
121458
121687
|
};
|
|
121459
121688
|
});
|
|
121460
|
-
var
|
|
121689
|
+
var logger47;
|
|
121461
121690
|
var list3;
|
|
121462
121691
|
var listManageable;
|
|
121463
121692
|
var getSubjects;
|
|
@@ -121474,17 +121703,17 @@ var init_game_controller = __esm(() => {
|
|
|
121474
121703
|
init_src4();
|
|
121475
121704
|
init_errors();
|
|
121476
121705
|
init_utils11();
|
|
121477
|
-
|
|
121706
|
+
logger47 = log.scope("GameController");
|
|
121478
121707
|
list3 = requireNonAnonymous(async (ctx) => {
|
|
121479
|
-
|
|
121708
|
+
logger47.debug("Listing games", { userId: ctx.user.id });
|
|
121480
121709
|
return ctx.services.game.list(ctx.user);
|
|
121481
121710
|
});
|
|
121482
121711
|
listManageable = requireNonAnonymous(async (ctx) => {
|
|
121483
|
-
|
|
121712
|
+
logger47.debug("Listing manageable games", { userId: ctx.user.id });
|
|
121484
121713
|
return ctx.services.game.listManageable(ctx.user);
|
|
121485
121714
|
});
|
|
121486
121715
|
getSubjects = requireNonAnonymous(async (ctx) => {
|
|
121487
|
-
|
|
121716
|
+
logger47.debug("Getting game subjects", { userId: ctx.user.id });
|
|
121488
121717
|
return ctx.services.game.getSubjects();
|
|
121489
121718
|
});
|
|
121490
121719
|
getById2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121495,7 +121724,7 @@ var init_game_controller = __esm(() => {
|
|
|
121495
121724
|
if (!isValidUUID(gameId)) {
|
|
121496
121725
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121497
121726
|
}
|
|
121498
|
-
|
|
121727
|
+
logger47.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
|
|
121499
121728
|
return ctx.services.game.getById(gameId, ctx.user);
|
|
121500
121729
|
});
|
|
121501
121730
|
getBySlug = requireNonAnonymous(async (ctx) => {
|
|
@@ -121503,7 +121732,7 @@ var init_game_controller = __esm(() => {
|
|
|
121503
121732
|
if (!slug2) {
|
|
121504
121733
|
throw ApiError.badRequest("Missing game slug");
|
|
121505
121734
|
}
|
|
121506
|
-
|
|
121735
|
+
logger47.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
|
|
121507
121736
|
return ctx.services.game.getBySlug(slug2, ctx.user);
|
|
121508
121737
|
});
|
|
121509
121738
|
getManifest = requireNonAnonymous(async (ctx) => {
|
|
@@ -121514,7 +121743,7 @@ var init_game_controller = __esm(() => {
|
|
|
121514
121743
|
if (!isValidUUID(gameId)) {
|
|
121515
121744
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121516
121745
|
}
|
|
121517
|
-
|
|
121746
|
+
logger47.debug("Getting game manifest by ID", {
|
|
121518
121747
|
userId: ctx.user.id,
|
|
121519
121748
|
gameId,
|
|
121520
121749
|
launchId: ctx.launchId
|
|
@@ -121533,12 +121762,12 @@ var init_game_controller = __esm(() => {
|
|
|
121533
121762
|
} catch (error2) {
|
|
121534
121763
|
if (error2 instanceof exports_external.ZodError) {
|
|
121535
121764
|
const details = formatZodError(error2);
|
|
121536
|
-
|
|
121765
|
+
logger47.warn("Upsert game validation failed", { details });
|
|
121537
121766
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121538
121767
|
}
|
|
121539
121768
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121540
121769
|
}
|
|
121541
|
-
|
|
121770
|
+
logger47.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
|
|
121542
121771
|
return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
|
|
121543
121772
|
});
|
|
121544
121773
|
remove3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121549,7 +121778,7 @@ var init_game_controller = __esm(() => {
|
|
|
121549
121778
|
if (!isValidUUID(gameId)) {
|
|
121550
121779
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121551
121780
|
}
|
|
121552
|
-
|
|
121781
|
+
logger47.debug("Deleting game", { userId: ctx.user.id, gameId });
|
|
121553
121782
|
await ctx.services.game.delete(gameId, ctx.user);
|
|
121554
121783
|
});
|
|
121555
121784
|
games2 = {
|
|
@@ -121563,7 +121792,7 @@ var init_game_controller = __esm(() => {
|
|
|
121563
121792
|
remove: remove3
|
|
121564
121793
|
};
|
|
121565
121794
|
});
|
|
121566
|
-
var
|
|
121795
|
+
var logger48;
|
|
121567
121796
|
var list4;
|
|
121568
121797
|
var addItem;
|
|
121569
121798
|
var removeItem;
|
|
@@ -121574,9 +121803,9 @@ var init_inventory_controller = __esm(() => {
|
|
|
121574
121803
|
init_src2();
|
|
121575
121804
|
init_errors();
|
|
121576
121805
|
init_utils11();
|
|
121577
|
-
|
|
121806
|
+
logger48 = log.scope("InventoryController");
|
|
121578
121807
|
list4 = requireNonAnonymous(async (ctx) => {
|
|
121579
|
-
|
|
121808
|
+
logger48.debug("Listing inventory", { userId: ctx.user.id });
|
|
121580
121809
|
return ctx.services.inventory.list(ctx.user);
|
|
121581
121810
|
});
|
|
121582
121811
|
addItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -121587,12 +121816,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
121587
121816
|
} catch (error2) {
|
|
121588
121817
|
if (error2 instanceof exports_external.ZodError) {
|
|
121589
121818
|
const details = formatZodError(error2);
|
|
121590
|
-
|
|
121819
|
+
logger48.warn("Add inventory item validation failed", { details });
|
|
121591
121820
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121592
121821
|
}
|
|
121593
121822
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121594
121823
|
}
|
|
121595
|
-
|
|
121824
|
+
logger48.debug("Adding item", {
|
|
121596
121825
|
userId: ctx.user.id,
|
|
121597
121826
|
itemId: body2.itemId,
|
|
121598
121827
|
qty: body2.qty
|
|
@@ -121607,12 +121836,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
121607
121836
|
} catch (error2) {
|
|
121608
121837
|
if (error2 instanceof exports_external.ZodError) {
|
|
121609
121838
|
const details = formatZodError(error2);
|
|
121610
|
-
|
|
121839
|
+
logger48.warn("Remove inventory item validation failed", { details });
|
|
121611
121840
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121612
121841
|
}
|
|
121613
121842
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121614
121843
|
}
|
|
121615
|
-
|
|
121844
|
+
logger48.debug("Removing item", {
|
|
121616
121845
|
userId: ctx.user.id,
|
|
121617
121846
|
itemId: body2.itemId,
|
|
121618
121847
|
qty: body2.qty
|
|
@@ -121625,7 +121854,7 @@ var init_inventory_controller = __esm(() => {
|
|
|
121625
121854
|
removeItem
|
|
121626
121855
|
};
|
|
121627
121856
|
});
|
|
121628
|
-
var
|
|
121857
|
+
var logger49;
|
|
121629
121858
|
var list5;
|
|
121630
121859
|
var getById3;
|
|
121631
121860
|
var resolve2;
|
|
@@ -121644,10 +121873,10 @@ var init_item_controller = __esm(() => {
|
|
|
121644
121873
|
init_src4();
|
|
121645
121874
|
init_errors();
|
|
121646
121875
|
init_utils11();
|
|
121647
|
-
|
|
121876
|
+
logger49 = log.scope("ItemController");
|
|
121648
121877
|
list5 = requireNonAnonymous(async (ctx) => {
|
|
121649
121878
|
const gameId = ctx.url.searchParams.get("gameId") || undefined;
|
|
121650
|
-
|
|
121879
|
+
logger49.debug("Listing items", { userId: ctx.user.id, gameId });
|
|
121651
121880
|
return ctx.services.item.list(gameId);
|
|
121652
121881
|
});
|
|
121653
121882
|
getById3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121658,7 +121887,7 @@ var init_item_controller = __esm(() => {
|
|
|
121658
121887
|
if (!isValidUUID(itemId)) {
|
|
121659
121888
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
121660
121889
|
}
|
|
121661
|
-
|
|
121890
|
+
logger49.debug("Getting item", { userId: ctx.user.id, itemId });
|
|
121662
121891
|
return ctx.services.item.getById(itemId);
|
|
121663
121892
|
});
|
|
121664
121893
|
resolve2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121670,7 +121899,7 @@ var init_item_controller = __esm(() => {
|
|
|
121670
121899
|
if (gameId && !isValidUUID(gameId)) {
|
|
121671
121900
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121672
121901
|
}
|
|
121673
|
-
|
|
121902
|
+
logger49.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
|
|
121674
121903
|
return ctx.services.item.resolveBySlug(slug2, gameId);
|
|
121675
121904
|
});
|
|
121676
121905
|
create3 = requireRole(["admin"], async (ctx) => {
|
|
@@ -121681,12 +121910,12 @@ var init_item_controller = __esm(() => {
|
|
|
121681
121910
|
} catch (error2) {
|
|
121682
121911
|
if (error2 instanceof exports_external.ZodError) {
|
|
121683
121912
|
const details = formatZodError(error2);
|
|
121684
|
-
|
|
121913
|
+
logger49.warn("Create item validation failed", { details });
|
|
121685
121914
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121686
121915
|
}
|
|
121687
121916
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121688
121917
|
}
|
|
121689
|
-
|
|
121918
|
+
logger49.debug("Creating item", {
|
|
121690
121919
|
userId: ctx.user.id,
|
|
121691
121920
|
slug: body2.slug,
|
|
121692
121921
|
displayName: body2.displayName
|
|
@@ -121708,7 +121937,7 @@ var init_item_controller = __esm(() => {
|
|
|
121708
121937
|
} catch (error2) {
|
|
121709
121938
|
if (error2 instanceof exports_external.ZodError) {
|
|
121710
121939
|
const details = formatZodError(error2);
|
|
121711
|
-
|
|
121940
|
+
logger49.warn("Update item validation failed", { details });
|
|
121712
121941
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121713
121942
|
}
|
|
121714
121943
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -121716,7 +121945,7 @@ var init_item_controller = __esm(() => {
|
|
|
121716
121945
|
if (Object.keys(body2).length === 0) {
|
|
121717
121946
|
throw ApiError.badRequest("No update data provided");
|
|
121718
121947
|
}
|
|
121719
|
-
|
|
121948
|
+
logger49.debug("Updating item", {
|
|
121720
121949
|
userId: ctx.user.id,
|
|
121721
121950
|
itemId,
|
|
121722
121951
|
slug: body2.slug,
|
|
@@ -121733,7 +121962,7 @@ var init_item_controller = __esm(() => {
|
|
|
121733
121962
|
if (!isValidUUID(itemId)) {
|
|
121734
121963
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
121735
121964
|
}
|
|
121736
|
-
|
|
121965
|
+
logger49.debug("Deleting item", { userId: ctx.user.id, itemId });
|
|
121737
121966
|
await ctx.services.item.delete(itemId);
|
|
121738
121967
|
});
|
|
121739
121968
|
listByGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -121744,7 +121973,7 @@ var init_item_controller = __esm(() => {
|
|
|
121744
121973
|
if (!isValidUUID(gameId)) {
|
|
121745
121974
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121746
121975
|
}
|
|
121747
|
-
|
|
121976
|
+
logger49.debug("Listing game items", { userId: ctx.user.id, gameId });
|
|
121748
121977
|
return ctx.services.item.listByGame(gameId);
|
|
121749
121978
|
});
|
|
121750
121979
|
createForGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -121762,12 +121991,12 @@ var init_item_controller = __esm(() => {
|
|
|
121762
121991
|
} catch (error2) {
|
|
121763
121992
|
if (error2 instanceof exports_external.ZodError) {
|
|
121764
121993
|
const details = formatZodError(error2);
|
|
121765
|
-
|
|
121994
|
+
logger49.warn("Create game item validation failed", { details });
|
|
121766
121995
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121767
121996
|
}
|
|
121768
121997
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121769
121998
|
}
|
|
121770
|
-
|
|
121999
|
+
logger49.debug("Creating game item", {
|
|
121771
122000
|
userId: ctx.user.id,
|
|
121772
122001
|
gameId,
|
|
121773
122002
|
slug: body2.slug,
|
|
@@ -121794,7 +122023,7 @@ var init_item_controller = __esm(() => {
|
|
|
121794
122023
|
} catch (error2) {
|
|
121795
122024
|
if (error2 instanceof exports_external.ZodError) {
|
|
121796
122025
|
const details = formatZodError(error2);
|
|
121797
|
-
|
|
122026
|
+
logger49.warn("Update game item validation failed", { details });
|
|
121798
122027
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121799
122028
|
}
|
|
121800
122029
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -121802,7 +122031,7 @@ var init_item_controller = __esm(() => {
|
|
|
121802
122031
|
if (Object.keys(body2).length === 0) {
|
|
121803
122032
|
throw ApiError.badRequest("No update data provided");
|
|
121804
122033
|
}
|
|
121805
|
-
|
|
122034
|
+
logger49.debug("Updating game item", {
|
|
121806
122035
|
userId: ctx.user.id,
|
|
121807
122036
|
gameId,
|
|
121808
122037
|
itemId,
|
|
@@ -121824,7 +122053,7 @@ var init_item_controller = __esm(() => {
|
|
|
121824
122053
|
if (!isValidUUID(itemId)) {
|
|
121825
122054
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
121826
122055
|
}
|
|
121827
|
-
|
|
122056
|
+
logger49.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
|
|
121828
122057
|
await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
|
|
121829
122058
|
});
|
|
121830
122059
|
items2 = {
|
|
@@ -121840,7 +122069,7 @@ var init_item_controller = __esm(() => {
|
|
|
121840
122069
|
deleteForGame
|
|
121841
122070
|
};
|
|
121842
122071
|
});
|
|
121843
|
-
var
|
|
122072
|
+
var logger50;
|
|
121844
122073
|
var listKeys;
|
|
121845
122074
|
var getStats;
|
|
121846
122075
|
var seed;
|
|
@@ -121855,7 +122084,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121855
122084
|
init_src2();
|
|
121856
122085
|
init_errors();
|
|
121857
122086
|
init_utils11();
|
|
121858
|
-
|
|
122087
|
+
logger50 = log.scope("KVController");
|
|
121859
122088
|
listKeys = requireDeveloper(async (ctx) => {
|
|
121860
122089
|
const slug2 = ctx.params.slug;
|
|
121861
122090
|
if (!slug2) {
|
|
@@ -121863,7 +122092,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121863
122092
|
}
|
|
121864
122093
|
const url = ctx.url;
|
|
121865
122094
|
const prefix2 = url.searchParams.get("prefix") || undefined;
|
|
121866
|
-
|
|
122095
|
+
logger50.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
121867
122096
|
const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
|
|
121868
122097
|
return { keys };
|
|
121869
122098
|
});
|
|
@@ -121872,7 +122101,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121872
122101
|
if (!slug2) {
|
|
121873
122102
|
throw ApiError.badRequest("Missing game slug");
|
|
121874
122103
|
}
|
|
121875
|
-
|
|
122104
|
+
logger50.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
|
|
121876
122105
|
return ctx.services.kv.getStats(slug2, ctx.user);
|
|
121877
122106
|
});
|
|
121878
122107
|
seed = requireDeveloper(async (ctx) => {
|
|
@@ -121887,12 +122116,12 @@ var init_kv_controller = __esm(() => {
|
|
|
121887
122116
|
} catch (error2) {
|
|
121888
122117
|
if (error2 instanceof exports_external.ZodError) {
|
|
121889
122118
|
const details = formatZodError(error2);
|
|
121890
|
-
|
|
122119
|
+
logger50.warn("Seed validation failed", { details });
|
|
121891
122120
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121892
122121
|
}
|
|
121893
122122
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121894
122123
|
}
|
|
121895
|
-
|
|
122124
|
+
logger50.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
|
|
121896
122125
|
await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
|
|
121897
122126
|
return { success: true, count: body2.entries.length };
|
|
121898
122127
|
});
|
|
@@ -121902,7 +122131,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121902
122131
|
if (!slug2 || !key) {
|
|
121903
122132
|
throw ApiError.badRequest("Missing game slug or key");
|
|
121904
122133
|
}
|
|
121905
|
-
|
|
122134
|
+
logger50.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
|
|
121906
122135
|
const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
|
|
121907
122136
|
return { key, value };
|
|
121908
122137
|
});
|
|
@@ -121916,7 +122145,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121916
122145
|
if (!value) {
|
|
121917
122146
|
throw ApiError.badRequest("Missing value in request body");
|
|
121918
122147
|
}
|
|
121919
|
-
|
|
122148
|
+
logger50.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
|
|
121920
122149
|
await ctx.services.kv.setValue(slug2, key, value, ctx.user);
|
|
121921
122150
|
return { success: true, key };
|
|
121922
122151
|
});
|
|
@@ -121926,7 +122155,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121926
122155
|
if (!slug2 || !key) {
|
|
121927
122156
|
throw ApiError.badRequest("Missing game slug or key");
|
|
121928
122157
|
}
|
|
121929
|
-
|
|
122158
|
+
logger50.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
|
|
121930
122159
|
await ctx.services.kv.deleteValue(slug2, key, ctx.user);
|
|
121931
122160
|
return { success: true, key };
|
|
121932
122161
|
});
|
|
@@ -121936,7 +122165,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121936
122165
|
if (!slug2 || !key) {
|
|
121937
122166
|
throw ApiError.badRequest("Missing game slug or key");
|
|
121938
122167
|
}
|
|
121939
|
-
|
|
122168
|
+
logger50.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
|
|
121940
122169
|
const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
|
|
121941
122170
|
return { key, metadata: metadata2 };
|
|
121942
122171
|
});
|
|
@@ -121945,12 +122174,12 @@ var init_kv_controller = __esm(() => {
|
|
|
121945
122174
|
if (!slug2) {
|
|
121946
122175
|
throw ApiError.badRequest("Missing game slug");
|
|
121947
122176
|
}
|
|
121948
|
-
|
|
122177
|
+
logger50.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
|
|
121949
122178
|
const deleted = await ctx.services.kv.clear(slug2, ctx.user);
|
|
121950
122179
|
return { success: true, deleted };
|
|
121951
122180
|
});
|
|
121952
122181
|
});
|
|
121953
|
-
var
|
|
122182
|
+
var logger51;
|
|
121954
122183
|
var submitScore;
|
|
121955
122184
|
var getGlobalLeaderboard;
|
|
121956
122185
|
var getLeaderboard;
|
|
@@ -121964,7 +122193,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
121964
122193
|
init_src2();
|
|
121965
122194
|
init_errors();
|
|
121966
122195
|
init_utils11();
|
|
121967
|
-
|
|
122196
|
+
logger51 = log.scope("LeaderboardController");
|
|
121968
122197
|
submitScore = requireAuth(async (ctx) => {
|
|
121969
122198
|
const gameId = ctx.params.gameId;
|
|
121970
122199
|
if (!gameId) {
|
|
@@ -121977,12 +122206,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
121977
122206
|
} catch (error2) {
|
|
121978
122207
|
if (error2 instanceof exports_external.ZodError) {
|
|
121979
122208
|
const details = formatZodError(error2);
|
|
121980
|
-
|
|
122209
|
+
logger51.warn("Submit score validation failed", { details });
|
|
121981
122210
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121982
122211
|
}
|
|
121983
122212
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121984
122213
|
}
|
|
121985
|
-
|
|
122214
|
+
logger51.debug("Submitting score", {
|
|
121986
122215
|
userId: ctx.user.id,
|
|
121987
122216
|
gameId,
|
|
121988
122217
|
score: body2.score
|
|
@@ -122005,12 +122234,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122005
122234
|
} catch (error2) {
|
|
122006
122235
|
if (error2 instanceof exports_external.ZodError) {
|
|
122007
122236
|
const details = formatZodError(error2);
|
|
122008
|
-
|
|
122237
|
+
logger51.warn("Get global leaderboard query validation failed", { details });
|
|
122009
122238
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
122010
122239
|
}
|
|
122011
122240
|
throw ApiError.badRequest("Invalid query parameters");
|
|
122012
122241
|
}
|
|
122013
|
-
|
|
122242
|
+
logger51.debug("Getting global leaderboard", {
|
|
122014
122243
|
userId: ctx.user.id,
|
|
122015
122244
|
gameId,
|
|
122016
122245
|
...query
|
|
@@ -122033,12 +122262,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122033
122262
|
} catch (error2) {
|
|
122034
122263
|
if (error2 instanceof exports_external.ZodError) {
|
|
122035
122264
|
const details = formatZodError(error2);
|
|
122036
|
-
|
|
122265
|
+
logger51.warn("Get leaderboard query validation failed", { details });
|
|
122037
122266
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
122038
122267
|
}
|
|
122039
122268
|
throw ApiError.badRequest("Invalid query parameters");
|
|
122040
122269
|
}
|
|
122041
|
-
|
|
122270
|
+
logger51.debug("Getting leaderboard", {
|
|
122042
122271
|
userId: ctx.user.id,
|
|
122043
122272
|
gameId,
|
|
122044
122273
|
...query
|
|
@@ -122050,7 +122279,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122050
122279
|
if (!gameId || !userId) {
|
|
122051
122280
|
throw ApiError.badRequest("Game ID and User ID are required");
|
|
122052
122281
|
}
|
|
122053
|
-
|
|
122282
|
+
logger51.debug("Getting user rank", {
|
|
122054
122283
|
requesterId: ctx.user.id,
|
|
122055
122284
|
gameId,
|
|
122056
122285
|
targetUserId: userId
|
|
@@ -122065,7 +122294,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122065
122294
|
const url = ctx.url;
|
|
122066
122295
|
const limit = Math.min(Number(url.searchParams.get("limit") || "50"), 100);
|
|
122067
122296
|
const gameId = url.searchParams.get("gameId") || undefined;
|
|
122068
|
-
|
|
122297
|
+
logger51.debug("Getting user all scores", {
|
|
122069
122298
|
requesterId: ctx.user.id,
|
|
122070
122299
|
targetUserId: userId,
|
|
122071
122300
|
gameId,
|
|
@@ -122080,7 +122309,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122080
122309
|
}
|
|
122081
122310
|
const url = ctx.url;
|
|
122082
122311
|
const limit = Math.min(Number(url.searchParams.get("limit") || "10"), 100);
|
|
122083
|
-
|
|
122312
|
+
logger51.debug("Getting user scores", {
|
|
122084
122313
|
requesterId: ctx.user.id,
|
|
122085
122314
|
gameId,
|
|
122086
122315
|
targetUserId: userId,
|
|
@@ -122098,7 +122327,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122098
122327
|
};
|
|
122099
122328
|
});
|
|
122100
122329
|
async function listConfigs(ctx) {
|
|
122101
|
-
|
|
122330
|
+
logger52.debug("Listing level configs");
|
|
122102
122331
|
return ctx.services.level.listConfigs();
|
|
122103
122332
|
}
|
|
122104
122333
|
async function getConfig(ctx) {
|
|
@@ -122110,10 +122339,10 @@ async function getConfig(ctx) {
|
|
|
122110
122339
|
if (isNaN(level) || level < 1) {
|
|
122111
122340
|
throw ApiError.badRequest("Level must be a positive integer");
|
|
122112
122341
|
}
|
|
122113
|
-
|
|
122342
|
+
logger52.debug("Getting level config", { level });
|
|
122114
122343
|
return ctx.services.level.getConfig(level);
|
|
122115
122344
|
}
|
|
122116
|
-
var
|
|
122345
|
+
var logger52;
|
|
122117
122346
|
var getByUser;
|
|
122118
122347
|
var getProgress;
|
|
122119
122348
|
var levels;
|
|
@@ -122121,13 +122350,13 @@ var init_level_controller = __esm(() => {
|
|
|
122121
122350
|
init_src2();
|
|
122122
122351
|
init_errors();
|
|
122123
122352
|
init_utils11();
|
|
122124
|
-
|
|
122353
|
+
logger52 = log.scope("LevelController");
|
|
122125
122354
|
getByUser = requireNonAnonymous(async (ctx) => {
|
|
122126
|
-
|
|
122355
|
+
logger52.debug("Getting user level", { userId: ctx.user.id });
|
|
122127
122356
|
return ctx.services.level.getByUser(ctx.user);
|
|
122128
122357
|
});
|
|
122129
122358
|
getProgress = requireNonAnonymous(async (ctx) => {
|
|
122130
|
-
|
|
122359
|
+
logger52.debug("Getting level progress", { userId: ctx.user.id });
|
|
122131
122360
|
return ctx.services.level.getProgress(ctx.user);
|
|
122132
122361
|
});
|
|
122133
122362
|
levels = {
|
|
@@ -122137,14 +122366,14 @@ var init_level_controller = __esm(() => {
|
|
|
122137
122366
|
getProgress
|
|
122138
122367
|
};
|
|
122139
122368
|
});
|
|
122140
|
-
var
|
|
122369
|
+
var logger53;
|
|
122141
122370
|
var generateToken;
|
|
122142
122371
|
var logs;
|
|
122143
122372
|
var init_logs_controller = __esm(() => {
|
|
122144
122373
|
init_src2();
|
|
122145
122374
|
init_errors();
|
|
122146
122375
|
init_utils11();
|
|
122147
|
-
|
|
122376
|
+
logger53 = log.scope("LogsController");
|
|
122148
122377
|
generateToken = requireDeveloper(async (ctx) => {
|
|
122149
122378
|
const slug2 = ctx.params.slug;
|
|
122150
122379
|
if (!slug2) {
|
|
@@ -122163,7 +122392,7 @@ var init_logs_controller = __esm(() => {
|
|
|
122163
122392
|
}
|
|
122164
122393
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122165
122394
|
}
|
|
122166
|
-
|
|
122395
|
+
logger53.debug("Generating log stream token", {
|
|
122167
122396
|
userId: ctx.user.id,
|
|
122168
122397
|
slug: slug2,
|
|
122169
122398
|
environment: body2.environment
|
|
@@ -122174,22 +122403,22 @@ var init_logs_controller = __esm(() => {
|
|
|
122174
122403
|
generateToken
|
|
122175
122404
|
};
|
|
122176
122405
|
});
|
|
122177
|
-
var
|
|
122406
|
+
var logger54;
|
|
122178
122407
|
var getStatus3;
|
|
122179
122408
|
var lti;
|
|
122180
122409
|
var init_lti_controller = __esm(() => {
|
|
122181
122410
|
init_src2();
|
|
122182
122411
|
init_utils11();
|
|
122183
|
-
|
|
122412
|
+
logger54 = log.scope("LtiController");
|
|
122184
122413
|
getStatus3 = requireNonAnonymous(async (ctx) => {
|
|
122185
|
-
|
|
122414
|
+
logger54.debug("Getting status", { userId: ctx.user.id });
|
|
122186
122415
|
return ctx.services.lti.getStatus(ctx.user);
|
|
122187
122416
|
});
|
|
122188
122417
|
lti = {
|
|
122189
122418
|
getStatus: getStatus3
|
|
122190
122419
|
};
|
|
122191
122420
|
});
|
|
122192
|
-
var
|
|
122421
|
+
var logger55;
|
|
122193
122422
|
var getByIdentifier;
|
|
122194
122423
|
var getElements;
|
|
122195
122424
|
var getObjects;
|
|
@@ -122203,13 +122432,13 @@ var init_map_controller = __esm(() => {
|
|
|
122203
122432
|
init_src4();
|
|
122204
122433
|
init_errors();
|
|
122205
122434
|
init_utils11();
|
|
122206
|
-
|
|
122435
|
+
logger55 = log.scope("MapController");
|
|
122207
122436
|
getByIdentifier = requireNonAnonymous(async (ctx) => {
|
|
122208
122437
|
const identifier = ctx.params.identifier;
|
|
122209
122438
|
if (!identifier) {
|
|
122210
122439
|
throw ApiError.badRequest("Missing map identifier");
|
|
122211
122440
|
}
|
|
122212
|
-
|
|
122441
|
+
logger55.debug("Getting map", { userId: ctx.user.id, identifier });
|
|
122213
122442
|
return ctx.services.map.getByIdentifier(identifier);
|
|
122214
122443
|
});
|
|
122215
122444
|
getElements = requireNonAnonymous(async (ctx) => {
|
|
@@ -122220,7 +122449,7 @@ var init_map_controller = __esm(() => {
|
|
|
122220
122449
|
if (!isValidUUID(mapId)) {
|
|
122221
122450
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
122222
122451
|
}
|
|
122223
|
-
|
|
122452
|
+
logger55.debug("Getting map elements", { userId: ctx.user.id, mapId });
|
|
122224
122453
|
return ctx.services.map.getElements(mapId);
|
|
122225
122454
|
});
|
|
122226
122455
|
getObjects = requireNonAnonymous(async (ctx) => {
|
|
@@ -122231,7 +122460,7 @@ var init_map_controller = __esm(() => {
|
|
|
122231
122460
|
if (!isValidUUID(mapId)) {
|
|
122232
122461
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
122233
122462
|
}
|
|
122234
|
-
|
|
122463
|
+
logger55.debug("Getting map objects", { userId: ctx.user.id, mapId });
|
|
122235
122464
|
return ctx.services.map.getObjects(mapId, ctx.user.id);
|
|
122236
122465
|
});
|
|
122237
122466
|
createObject = requireNonAnonymous(async (ctx) => {
|
|
@@ -122253,12 +122482,12 @@ var init_map_controller = __esm(() => {
|
|
|
122253
122482
|
} catch (error2) {
|
|
122254
122483
|
if (error2 instanceof exports_external.ZodError) {
|
|
122255
122484
|
const details = formatZodError(error2);
|
|
122256
|
-
|
|
122485
|
+
logger55.warn("Create map object validation failed", { details });
|
|
122257
122486
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122258
122487
|
}
|
|
122259
122488
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122260
122489
|
}
|
|
122261
|
-
|
|
122490
|
+
logger55.debug("Creating map object", {
|
|
122262
122491
|
userId: ctx.user.id,
|
|
122263
122492
|
mapId,
|
|
122264
122493
|
itemId: body2.itemId,
|
|
@@ -122282,7 +122511,7 @@ var init_map_controller = __esm(() => {
|
|
|
122282
122511
|
if (!isValidUUID(objectId)) {
|
|
122283
122512
|
throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
|
|
122284
122513
|
}
|
|
122285
|
-
|
|
122514
|
+
logger55.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
|
|
122286
122515
|
await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
|
|
122287
122516
|
});
|
|
122288
122517
|
maps2 = {
|
|
@@ -122293,7 +122522,7 @@ var init_map_controller = __esm(() => {
|
|
|
122293
122522
|
deleteObject
|
|
122294
122523
|
};
|
|
122295
122524
|
});
|
|
122296
|
-
var
|
|
122525
|
+
var logger56;
|
|
122297
122526
|
var list6;
|
|
122298
122527
|
var updateStatus;
|
|
122299
122528
|
var getStats2;
|
|
@@ -122306,7 +122535,7 @@ var init_notification_controller = __esm(() => {
|
|
|
122306
122535
|
init_src2();
|
|
122307
122536
|
init_errors();
|
|
122308
122537
|
init_utils11();
|
|
122309
|
-
|
|
122538
|
+
logger56 = log.scope("NotificationController");
|
|
122310
122539
|
list6 = requireNonAnonymous(async (ctx) => {
|
|
122311
122540
|
const query = {
|
|
122312
122541
|
status: ctx.url.searchParams.get("status") || undefined,
|
|
@@ -122317,10 +122546,10 @@ var init_notification_controller = __esm(() => {
|
|
|
122317
122546
|
const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
|
|
122318
122547
|
if (!result.success) {
|
|
122319
122548
|
const details = formatZodError(result.error);
|
|
122320
|
-
|
|
122549
|
+
logger56.warn("List notifications query validation failed", { details });
|
|
122321
122550
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
122322
122551
|
}
|
|
122323
|
-
|
|
122552
|
+
logger56.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
|
|
122324
122553
|
return ctx.services.notification.list(ctx.user, result.data);
|
|
122325
122554
|
});
|
|
122326
122555
|
updateStatus = requireNonAnonymous(async (ctx) => {
|
|
@@ -122335,12 +122564,12 @@ var init_notification_controller = __esm(() => {
|
|
|
122335
122564
|
} catch (error2) {
|
|
122336
122565
|
if (error2 instanceof exports_external.ZodError) {
|
|
122337
122566
|
const details = formatZodError(error2);
|
|
122338
|
-
|
|
122567
|
+
logger56.warn("Update notification status validation failed", { details });
|
|
122339
122568
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122340
122569
|
}
|
|
122341
122570
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122342
122571
|
}
|
|
122343
|
-
|
|
122572
|
+
logger56.debug("Updating status", {
|
|
122344
122573
|
userId: ctx.user.id,
|
|
122345
122574
|
notificationId,
|
|
122346
122575
|
status: body2.status
|
|
@@ -122350,7 +122579,7 @@ var init_notification_controller = __esm(() => {
|
|
|
122350
122579
|
getStats2 = requireNonAnonymous(async (ctx) => {
|
|
122351
122580
|
const startDate = ctx.url.searchParams.get("startDate");
|
|
122352
122581
|
const endDate = ctx.url.searchParams.get("endDate");
|
|
122353
|
-
|
|
122582
|
+
logger56.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
|
|
122354
122583
|
return ctx.services.notification.getStats(ctx.user, {
|
|
122355
122584
|
startDate: startDate ? new Date(startDate) : undefined,
|
|
122356
122585
|
endDate: endDate ? new Date(endDate) : undefined
|
|
@@ -122364,12 +122593,12 @@ var init_notification_controller = __esm(() => {
|
|
|
122364
122593
|
} catch (error2) {
|
|
122365
122594
|
if (error2 instanceof exports_external.ZodError) {
|
|
122366
122595
|
const details = formatZodError(error2);
|
|
122367
|
-
|
|
122596
|
+
logger56.warn("Create notification validation failed", { details });
|
|
122368
122597
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122369
122598
|
}
|
|
122370
122599
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122371
122600
|
}
|
|
122372
|
-
|
|
122601
|
+
logger56.debug("Creating notification", {
|
|
122373
122602
|
userId: ctx.user.id,
|
|
122374
122603
|
targetUserId: body2.userId,
|
|
122375
122604
|
type: body2.type
|
|
@@ -122387,12 +122616,12 @@ var init_notification_controller = __esm(() => {
|
|
|
122387
122616
|
});
|
|
122388
122617
|
});
|
|
122389
122618
|
deliver = requireNonAnonymous(async (ctx) => {
|
|
122390
|
-
|
|
122619
|
+
logger56.debug("Delivering notifications", { userId: ctx.user.id });
|
|
122391
122620
|
try {
|
|
122392
122621
|
await ctx.services.notification.deliverPending(ctx.user.id);
|
|
122393
122622
|
return { success: true };
|
|
122394
122623
|
} catch (error2) {
|
|
122395
|
-
|
|
122624
|
+
logger56.error("Failed to deliver notifications", { error: error2 });
|
|
122396
122625
|
throw ApiError.internal("Failed to deliver notifications");
|
|
122397
122626
|
}
|
|
122398
122627
|
});
|
|
@@ -122404,16 +122633,16 @@ var init_notification_controller = __esm(() => {
|
|
|
122404
122633
|
deliver
|
|
122405
122634
|
};
|
|
122406
122635
|
});
|
|
122407
|
-
var
|
|
122636
|
+
var logger57;
|
|
122408
122637
|
var generateToken2;
|
|
122409
122638
|
var realtime;
|
|
122410
122639
|
var init_realtime_controller = __esm(() => {
|
|
122411
122640
|
init_src2();
|
|
122412
122641
|
init_utils11();
|
|
122413
|
-
|
|
122642
|
+
logger57 = log.scope("RealtimeController");
|
|
122414
122643
|
generateToken2 = requireNonAnonymous(async (ctx) => {
|
|
122415
122644
|
const gameIdOrSlug = ctx.params.gameId;
|
|
122416
|
-
|
|
122645
|
+
logger57.debug("Generating token", {
|
|
122417
122646
|
userId: ctx.user.id,
|
|
122418
122647
|
gameId: gameIdOrSlug || "global",
|
|
122419
122648
|
launchId: ctx.launchId
|
|
@@ -122424,7 +122653,7 @@ var init_realtime_controller = __esm(() => {
|
|
|
122424
122653
|
generateToken: generateToken2
|
|
122425
122654
|
};
|
|
122426
122655
|
});
|
|
122427
|
-
var
|
|
122656
|
+
var logger58;
|
|
122428
122657
|
var listKeys2;
|
|
122429
122658
|
var setSecrets;
|
|
122430
122659
|
var deleteSecret;
|
|
@@ -122435,13 +122664,13 @@ var init_secrets_controller = __esm(() => {
|
|
|
122435
122664
|
init_src2();
|
|
122436
122665
|
init_errors();
|
|
122437
122666
|
init_utils11();
|
|
122438
|
-
|
|
122667
|
+
logger58 = log.scope("SecretsController");
|
|
122439
122668
|
listKeys2 = requireDeveloper(async (ctx) => {
|
|
122440
122669
|
const slug2 = ctx.params.slug;
|
|
122441
122670
|
if (!slug2) {
|
|
122442
122671
|
throw ApiError.badRequest("Missing game slug");
|
|
122443
122672
|
}
|
|
122444
|
-
|
|
122673
|
+
logger58.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
|
|
122445
122674
|
const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
|
|
122446
122675
|
return { keys };
|
|
122447
122676
|
});
|
|
@@ -122457,12 +122686,12 @@ var init_secrets_controller = __esm(() => {
|
|
|
122457
122686
|
} catch (error2) {
|
|
122458
122687
|
if (error2 instanceof exports_external.ZodError) {
|
|
122459
122688
|
const details = formatZodError(error2);
|
|
122460
|
-
|
|
122689
|
+
logger58.warn("Set secrets validation failed", { details });
|
|
122461
122690
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122462
122691
|
}
|
|
122463
122692
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122464
122693
|
}
|
|
122465
|
-
|
|
122694
|
+
logger58.debug("Setting secrets", {
|
|
122466
122695
|
userId: ctx.user.id,
|
|
122467
122696
|
slug: slug2,
|
|
122468
122697
|
keyCount: Object.keys(body2).length
|
|
@@ -122479,7 +122708,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
122479
122708
|
if (!key) {
|
|
122480
122709
|
throw ApiError.badRequest("Missing secret key");
|
|
122481
122710
|
}
|
|
122482
|
-
|
|
122711
|
+
logger58.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
|
|
122483
122712
|
await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
|
|
122484
122713
|
return { success: true };
|
|
122485
122714
|
});
|
|
@@ -122489,7 +122718,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
122489
122718
|
deleteSecret
|
|
122490
122719
|
};
|
|
122491
122720
|
});
|
|
122492
|
-
var
|
|
122721
|
+
var logger59;
|
|
122493
122722
|
var seed2;
|
|
122494
122723
|
var init_seed_controller = __esm(() => {
|
|
122495
122724
|
init_esm();
|
|
@@ -122497,7 +122726,7 @@ var init_seed_controller = __esm(() => {
|
|
|
122497
122726
|
init_src2();
|
|
122498
122727
|
init_errors();
|
|
122499
122728
|
init_utils11();
|
|
122500
|
-
|
|
122729
|
+
logger59 = log.scope("SeedController");
|
|
122501
122730
|
seed2 = requireDeveloper(async (ctx) => {
|
|
122502
122731
|
const slug2 = ctx.params.slug;
|
|
122503
122732
|
if (!slug2) {
|
|
@@ -122510,12 +122739,12 @@ var init_seed_controller = __esm(() => {
|
|
|
122510
122739
|
} catch (error2) {
|
|
122511
122740
|
if (error2 instanceof exports_external.ZodError) {
|
|
122512
122741
|
const details = formatZodError(error2);
|
|
122513
|
-
|
|
122742
|
+
logger59.warn("Seed database validation failed", { details });
|
|
122514
122743
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122515
122744
|
}
|
|
122516
122745
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122517
122746
|
}
|
|
122518
|
-
|
|
122747
|
+
logger59.debug("Seeding database", {
|
|
122519
122748
|
userId: ctx.user.id,
|
|
122520
122749
|
slug: slug2,
|
|
122521
122750
|
codeLength: body2.code.length,
|
|
@@ -122524,7 +122753,7 @@ var init_seed_controller = __esm(() => {
|
|
|
122524
122753
|
return ctx.services.seed.seed(slug2, body2.code, ctx.user, body2.secrets);
|
|
122525
122754
|
});
|
|
122526
122755
|
});
|
|
122527
|
-
var
|
|
122756
|
+
var logger60;
|
|
122528
122757
|
var start2;
|
|
122529
122758
|
var end;
|
|
122530
122759
|
var mintToken;
|
|
@@ -122533,13 +122762,13 @@ var init_session_controller = __esm(() => {
|
|
|
122533
122762
|
init_src2();
|
|
122534
122763
|
init_errors();
|
|
122535
122764
|
init_utils11();
|
|
122536
|
-
|
|
122765
|
+
logger60 = log.scope("SessionController");
|
|
122537
122766
|
start2 = requireAuth(async (ctx) => {
|
|
122538
122767
|
const gameIdOrSlug = ctx.params.gameId;
|
|
122539
122768
|
if (!gameIdOrSlug) {
|
|
122540
122769
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
122541
122770
|
}
|
|
122542
|
-
|
|
122771
|
+
logger60.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
122543
122772
|
return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
|
|
122544
122773
|
});
|
|
122545
122774
|
end = requireAuth(async (ctx) => {
|
|
@@ -122551,7 +122780,7 @@ var init_session_controller = __esm(() => {
|
|
|
122551
122780
|
if (!sessionId) {
|
|
122552
122781
|
throw ApiError.badRequest("Missing session ID");
|
|
122553
122782
|
}
|
|
122554
|
-
|
|
122783
|
+
logger60.debug("Ending session", {
|
|
122555
122784
|
userId: ctx.user.id,
|
|
122556
122785
|
gameIdOrSlug,
|
|
122557
122786
|
sessionId,
|
|
@@ -122564,7 +122793,7 @@ var init_session_controller = __esm(() => {
|
|
|
122564
122793
|
if (!gameIdOrSlug) {
|
|
122565
122794
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
122566
122795
|
}
|
|
122567
|
-
|
|
122796
|
+
logger60.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
122568
122797
|
return ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
|
|
122569
122798
|
});
|
|
122570
122799
|
sessions2 = {
|
|
@@ -122573,22 +122802,22 @@ var init_session_controller = __esm(() => {
|
|
|
122573
122802
|
mintToken
|
|
122574
122803
|
};
|
|
122575
122804
|
});
|
|
122576
|
-
var
|
|
122805
|
+
var logger61;
|
|
122577
122806
|
var getShopView;
|
|
122578
122807
|
var shop;
|
|
122579
122808
|
var init_shop_controller = __esm(() => {
|
|
122580
122809
|
init_src2();
|
|
122581
122810
|
init_utils11();
|
|
122582
|
-
|
|
122811
|
+
logger61 = log.scope("ShopController");
|
|
122583
122812
|
getShopView = requireNonAnonymous(async (ctx) => {
|
|
122584
|
-
|
|
122813
|
+
logger61.debug("Getting shop view", { userId: ctx.user.id });
|
|
122585
122814
|
return ctx.services.shop.getShopView(ctx.user);
|
|
122586
122815
|
});
|
|
122587
122816
|
shop = {
|
|
122588
122817
|
getShopView
|
|
122589
122818
|
};
|
|
122590
122819
|
});
|
|
122591
|
-
var
|
|
122820
|
+
var logger62;
|
|
122592
122821
|
var list7;
|
|
122593
122822
|
var getById4;
|
|
122594
122823
|
var create5;
|
|
@@ -122607,9 +122836,9 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122607
122836
|
init_src4();
|
|
122608
122837
|
init_errors();
|
|
122609
122838
|
init_utils11();
|
|
122610
|
-
|
|
122839
|
+
logger62 = log.scope("ShopListingController");
|
|
122611
122840
|
list7 = requireAdmin(async (ctx) => {
|
|
122612
|
-
|
|
122841
|
+
logger62.debug("Listing shop listings", { userId: ctx.user.id });
|
|
122613
122842
|
return ctx.services.shopListing.list();
|
|
122614
122843
|
});
|
|
122615
122844
|
getById4 = requireAdmin(async (ctx) => {
|
|
@@ -122620,7 +122849,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122620
122849
|
if (!isValidUUID(listingId)) {
|
|
122621
122850
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
122622
122851
|
}
|
|
122623
|
-
|
|
122852
|
+
logger62.debug("Getting listing", { userId: ctx.user.id, listingId });
|
|
122624
122853
|
return ctx.services.shopListing.getById(listingId);
|
|
122625
122854
|
});
|
|
122626
122855
|
create5 = requireAdmin(async (ctx) => {
|
|
@@ -122631,12 +122860,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122631
122860
|
} catch (error2) {
|
|
122632
122861
|
if (error2 instanceof exports_external.ZodError) {
|
|
122633
122862
|
const details = formatZodError(error2);
|
|
122634
|
-
|
|
122863
|
+
logger62.warn("Create shop listing validation failed", { details });
|
|
122635
122864
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122636
122865
|
}
|
|
122637
122866
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122638
122867
|
}
|
|
122639
|
-
|
|
122868
|
+
logger62.debug("Creating listing", {
|
|
122640
122869
|
userId: ctx.user.id,
|
|
122641
122870
|
itemId: body2.itemId,
|
|
122642
122871
|
currencyId: body2.currencyId,
|
|
@@ -122659,12 +122888,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122659
122888
|
} catch (error2) {
|
|
122660
122889
|
if (error2 instanceof exports_external.ZodError) {
|
|
122661
122890
|
const details = formatZodError(error2);
|
|
122662
|
-
|
|
122891
|
+
logger62.warn("Update shop listing validation failed", { details });
|
|
122663
122892
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122664
122893
|
}
|
|
122665
122894
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122666
122895
|
}
|
|
122667
|
-
|
|
122896
|
+
logger62.debug("Updating listing", {
|
|
122668
122897
|
userId: ctx.user.id,
|
|
122669
122898
|
listingId,
|
|
122670
122899
|
price: body2.price,
|
|
@@ -122681,7 +122910,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122681
122910
|
if (!isValidUUID(listingId)) {
|
|
122682
122911
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
122683
122912
|
}
|
|
122684
|
-
|
|
122913
|
+
logger62.debug("Deleting listing", { userId: ctx.user.id, listingId });
|
|
122685
122914
|
await ctx.services.shopListing.delete(listingId);
|
|
122686
122915
|
});
|
|
122687
122916
|
listByGame2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -122692,7 +122921,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122692
122921
|
if (!isValidUUID(gameId)) {
|
|
122693
122922
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
122694
122923
|
}
|
|
122695
|
-
|
|
122924
|
+
logger62.debug("Listing game listings", { userId: ctx.user.id, gameId });
|
|
122696
122925
|
return ctx.services.shopListing.listByGame(gameId, ctx.user);
|
|
122697
122926
|
});
|
|
122698
122927
|
getByGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -122707,7 +122936,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122707
122936
|
if (!isValidUUID(itemId)) {
|
|
122708
122937
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
122709
122938
|
}
|
|
122710
|
-
|
|
122939
|
+
logger62.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
|
|
122711
122940
|
return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
|
|
122712
122941
|
});
|
|
122713
122942
|
createForGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -122729,12 +122958,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122729
122958
|
} catch (error2) {
|
|
122730
122959
|
if (error2 instanceof exports_external.ZodError) {
|
|
122731
122960
|
const details = formatZodError(error2);
|
|
122732
|
-
|
|
122961
|
+
logger62.warn("Create game item listing validation failed", { details });
|
|
122733
122962
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122734
122963
|
}
|
|
122735
122964
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122736
122965
|
}
|
|
122737
|
-
|
|
122966
|
+
logger62.debug("Creating game item listing", {
|
|
122738
122967
|
userId: ctx.user.id,
|
|
122739
122968
|
gameId,
|
|
122740
122969
|
itemId,
|
|
@@ -122762,12 +122991,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122762
122991
|
} catch (error2) {
|
|
122763
122992
|
if (error2 instanceof exports_external.ZodError) {
|
|
122764
122993
|
const details = formatZodError(error2);
|
|
122765
|
-
|
|
122994
|
+
logger62.warn("Update game item listing validation failed", { details });
|
|
122766
122995
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122767
122996
|
}
|
|
122768
122997
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122769
122998
|
}
|
|
122770
|
-
|
|
122999
|
+
logger62.debug("Updating game item listing", {
|
|
122771
123000
|
userId: ctx.user.id,
|
|
122772
123001
|
gameId,
|
|
122773
123002
|
itemId,
|
|
@@ -122789,7 +123018,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122789
123018
|
if (!isValidUUID(itemId)) {
|
|
122790
123019
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
122791
123020
|
}
|
|
122792
|
-
|
|
123021
|
+
logger62.debug("Deleting game item listing", {
|
|
122793
123022
|
userId: ctx.user.id,
|
|
122794
123023
|
gameId,
|
|
122795
123024
|
itemId
|
|
@@ -122814,20 +123043,20 @@ async function getBySlug2(ctx) {
|
|
|
122814
123043
|
if (!slug2) {
|
|
122815
123044
|
throw ApiError.badRequest("Template slug is required");
|
|
122816
123045
|
}
|
|
122817
|
-
|
|
123046
|
+
logger63.debug("Getting sprite by slug", { slug: slug2 });
|
|
122818
123047
|
return ctx.services.sprite.getBySlug(slug2);
|
|
122819
123048
|
}
|
|
122820
|
-
var
|
|
123049
|
+
var logger63;
|
|
122821
123050
|
var sprites;
|
|
122822
123051
|
var init_sprite_controller = __esm(() => {
|
|
122823
123052
|
init_src2();
|
|
122824
123053
|
init_errors();
|
|
122825
|
-
|
|
123054
|
+
logger63 = log.scope("SpriteController");
|
|
122826
123055
|
sprites = {
|
|
122827
123056
|
getBySlug: getBySlug2
|
|
122828
123057
|
};
|
|
122829
123058
|
});
|
|
122830
|
-
var
|
|
123059
|
+
var logger64;
|
|
122831
123060
|
var getTodayXp;
|
|
122832
123061
|
var getTotalXp;
|
|
122833
123062
|
var updateTodayXp;
|
|
@@ -122842,6 +123071,7 @@ var getConfig2;
|
|
|
122842
123071
|
var deleteIntegrations;
|
|
122843
123072
|
var endActivity;
|
|
122844
123073
|
var heartbeat;
|
|
123074
|
+
var advanceCourse;
|
|
122845
123075
|
var getStudentXp;
|
|
122846
123076
|
var getRoster;
|
|
122847
123077
|
var getStudentOverview;
|
|
@@ -122861,15 +123091,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
122861
123091
|
init_src4();
|
|
122862
123092
|
init_errors();
|
|
122863
123093
|
init_utils11();
|
|
122864
|
-
|
|
123094
|
+
logger64 = log.scope("TimebackController");
|
|
122865
123095
|
getTodayXp = requireNonAnonymous(async (ctx) => {
|
|
122866
123096
|
const date4 = ctx.url.searchParams.get("date") || undefined;
|
|
122867
123097
|
const tz = ctx.url.searchParams.get("tz") || undefined;
|
|
122868
|
-
|
|
123098
|
+
logger64.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
|
|
122869
123099
|
return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
|
|
122870
123100
|
});
|
|
122871
123101
|
getTotalXp = requireNonAnonymous(async (ctx) => {
|
|
122872
|
-
|
|
123102
|
+
logger64.debug("Getting total XP", { userId: ctx.user.id });
|
|
122873
123103
|
return ctx.services.timeback.getTotalXp(ctx.user.id);
|
|
122874
123104
|
});
|
|
122875
123105
|
updateTodayXp = requireNonAnonymous(async (ctx) => {
|
|
@@ -122880,18 +123110,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
122880
123110
|
} catch (error2) {
|
|
122881
123111
|
if (error2 instanceof exports_external.ZodError) {
|
|
122882
123112
|
const details = formatZodError(error2);
|
|
122883
|
-
|
|
123113
|
+
logger64.warn("Update today XP validation failed", { details });
|
|
122884
123114
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122885
123115
|
}
|
|
122886
123116
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122887
123117
|
}
|
|
122888
|
-
|
|
123118
|
+
logger64.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
|
|
122889
123119
|
return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
|
|
122890
123120
|
});
|
|
122891
123121
|
getXpHistory = requireNonAnonymous(async (ctx) => {
|
|
122892
123122
|
const startDate = ctx.url.searchParams.get("startDate") || undefined;
|
|
122893
123123
|
const endDate = ctx.url.searchParams.get("endDate") || undefined;
|
|
122894
|
-
|
|
123124
|
+
logger64.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
|
|
122895
123125
|
return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
|
|
122896
123126
|
});
|
|
122897
123127
|
populateStudent = requireNonAnonymous(async (ctx) => {
|
|
@@ -122902,18 +123132,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
122902
123132
|
} catch (error2) {
|
|
122903
123133
|
if (error2 instanceof exports_external.ZodError) {
|
|
122904
123134
|
const details = formatZodError(error2);
|
|
122905
|
-
|
|
123135
|
+
logger64.warn("Populate student validation failed", { details });
|
|
122906
123136
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122907
123137
|
}
|
|
122908
123138
|
}
|
|
122909
|
-
|
|
123139
|
+
logger64.debug("Populating student", {
|
|
122910
123140
|
userId: ctx.user.id,
|
|
122911
123141
|
hasProvidedNames: Boolean(providedNames)
|
|
122912
123142
|
});
|
|
122913
123143
|
return ctx.services.timeback.populateStudent(ctx.user, providedNames);
|
|
122914
123144
|
});
|
|
122915
123145
|
getUser = requireNonAnonymous(async (ctx) => {
|
|
122916
|
-
|
|
123146
|
+
logger64.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
122917
123147
|
return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
|
|
122918
123148
|
});
|
|
122919
123149
|
getUserById = requireNonAnonymous(async (ctx) => {
|
|
@@ -122921,7 +123151,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122921
123151
|
if (!timebackId) {
|
|
122922
123152
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
122923
123153
|
}
|
|
122924
|
-
|
|
123154
|
+
logger64.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
|
|
122925
123155
|
return ctx.services.timeback.getUserDataByTimebackId(timebackId);
|
|
122926
123156
|
});
|
|
122927
123157
|
setupIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -122932,12 +123162,12 @@ var init_timeback_controller = __esm(() => {
|
|
|
122932
123162
|
} catch (error2) {
|
|
122933
123163
|
if (error2 instanceof exports_external.ZodError) {
|
|
122934
123164
|
const details = formatZodError(error2);
|
|
122935
|
-
|
|
123165
|
+
logger64.warn("Setup integration validation failed", { details });
|
|
122936
123166
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122937
123167
|
}
|
|
122938
123168
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122939
123169
|
}
|
|
122940
|
-
|
|
123170
|
+
logger64.debug("Setting up integration", {
|
|
122941
123171
|
userId: ctx.user.id,
|
|
122942
123172
|
gameId: body2.gameId
|
|
122943
123173
|
});
|
|
@@ -122951,7 +123181,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122951
123181
|
if (!isValidUUID(gameId)) {
|
|
122952
123182
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122953
123183
|
}
|
|
122954
|
-
|
|
123184
|
+
logger64.debug("Getting integrations", { userId: ctx.user.id, gameId });
|
|
122955
123185
|
return ctx.services.timeback.getIntegrations(gameId, ctx.user);
|
|
122956
123186
|
});
|
|
122957
123187
|
verifyIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -122962,7 +123192,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122962
123192
|
if (!isValidUUID(gameId)) {
|
|
122963
123193
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122964
123194
|
}
|
|
122965
|
-
|
|
123195
|
+
logger64.debug("Verifying integration", { userId: ctx.user.id, gameId });
|
|
122966
123196
|
return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
|
|
122967
123197
|
});
|
|
122968
123198
|
getConfig2 = requireDeveloper(async (ctx) => {
|
|
@@ -122973,7 +123203,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122973
123203
|
if (!isValidUUID(gameId)) {
|
|
122974
123204
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122975
123205
|
}
|
|
122976
|
-
|
|
123206
|
+
logger64.debug("Getting config", { userId: ctx.user.id, gameId });
|
|
122977
123207
|
return ctx.services.timeback.getConfig(gameId, ctx.user);
|
|
122978
123208
|
});
|
|
122979
123209
|
deleteIntegrations = requireDeveloper(async (ctx) => {
|
|
@@ -122984,7 +123214,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122984
123214
|
if (!isValidUUID(gameId)) {
|
|
122985
123215
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122986
123216
|
}
|
|
122987
|
-
|
|
123217
|
+
logger64.debug("Deleting integrations", { userId: ctx.user.id, gameId });
|
|
122988
123218
|
await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
|
|
122989
123219
|
});
|
|
122990
123220
|
endActivity = requireDeveloper(async (ctx) => {
|
|
@@ -122995,7 +123225,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122995
123225
|
} catch (error2) {
|
|
122996
123226
|
if (error2 instanceof exports_external.ZodError) {
|
|
122997
123227
|
const details = formatZodError(error2);
|
|
122998
|
-
|
|
123228
|
+
logger64.warn("End activity validation failed", { details });
|
|
122999
123229
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123000
123230
|
}
|
|
123001
123231
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -123013,7 +123243,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123013
123243
|
masteredUnits,
|
|
123014
123244
|
extensions
|
|
123015
123245
|
} = body2;
|
|
123016
|
-
|
|
123246
|
+
logger64.debug("Ending activity", { userId: ctx.user.id, gameId });
|
|
123017
123247
|
return ctx.services.timeback.endActivity({
|
|
123018
123248
|
gameId,
|
|
123019
123249
|
studentId,
|
|
@@ -123037,7 +123267,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123037
123267
|
} catch (error2) {
|
|
123038
123268
|
if (error2 instanceof exports_external.ZodError) {
|
|
123039
123269
|
const details = formatZodError(error2);
|
|
123040
|
-
|
|
123270
|
+
logger64.warn("Heartbeat validation failed", { details });
|
|
123041
123271
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123042
123272
|
}
|
|
123043
123273
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -123053,7 +123283,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123053
123283
|
windowSequence,
|
|
123054
123284
|
isFinal
|
|
123055
123285
|
} = body2;
|
|
123056
|
-
|
|
123286
|
+
logger64.debug("Recording heartbeat", {
|
|
123057
123287
|
userId: ctx.user.id,
|
|
123058
123288
|
gameId,
|
|
123059
123289
|
runId,
|
|
@@ -123076,6 +123306,19 @@ var init_timeback_controller = __esm(() => {
|
|
|
123076
123306
|
user: ctx.user
|
|
123077
123307
|
});
|
|
123078
123308
|
});
|
|
123309
|
+
advanceCourse = requireDeveloper(async (ctx) => {
|
|
123310
|
+
const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
|
|
123311
|
+
logger64.debug("Advancing student manually", {
|
|
123312
|
+
userId: ctx.user.id,
|
|
123313
|
+
gameId: body2.gameId,
|
|
123314
|
+
studentId: body2.studentId,
|
|
123315
|
+
subject: body2.subject
|
|
123316
|
+
});
|
|
123317
|
+
return ctx.services.timeback.advanceCourse({
|
|
123318
|
+
...body2,
|
|
123319
|
+
user: ctx.user
|
|
123320
|
+
});
|
|
123321
|
+
});
|
|
123079
123322
|
getStudentXp = requireDeveloper(async (ctx) => {
|
|
123080
123323
|
const timebackId = ctx.params.timebackId;
|
|
123081
123324
|
if (!timebackId) {
|
|
@@ -123106,7 +123349,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123106
123349
|
perCourse: includeOptions.includes("percourse"),
|
|
123107
123350
|
today: includeOptions.includes("today")
|
|
123108
123351
|
};
|
|
123109
|
-
|
|
123352
|
+
logger64.debug("Getting student XP", {
|
|
123110
123353
|
requesterId: ctx.user.id,
|
|
123111
123354
|
timebackId,
|
|
123112
123355
|
gameId,
|
|
@@ -123127,7 +123370,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123127
123370
|
if (!gameId || !courseId) {
|
|
123128
123371
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
123129
123372
|
}
|
|
123130
|
-
|
|
123373
|
+
logger64.debug("Getting course roster", {
|
|
123131
123374
|
requesterId: ctx.user.id,
|
|
123132
123375
|
gameId,
|
|
123133
123376
|
courseId
|
|
@@ -123141,7 +123384,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123141
123384
|
if (!timebackId || !gameId) {
|
|
123142
123385
|
throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
|
|
123143
123386
|
}
|
|
123144
|
-
|
|
123387
|
+
logger64.debug("Getting student overview", {
|
|
123145
123388
|
requesterId: ctx.user.id,
|
|
123146
123389
|
timebackId,
|
|
123147
123390
|
gameId,
|
|
@@ -123160,7 +123403,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123160
123403
|
if (!timebackId || !courseId || !gameId) {
|
|
123161
123404
|
throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
|
|
123162
123405
|
}
|
|
123163
|
-
|
|
123406
|
+
logger64.debug("Getting student activity", {
|
|
123164
123407
|
requesterId: ctx.user.id,
|
|
123165
123408
|
timebackId,
|
|
123166
123409
|
courseId,
|
|
@@ -123178,7 +123421,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123178
123421
|
});
|
|
123179
123422
|
grantXp = requireDeveloper(async (ctx) => {
|
|
123180
123423
|
const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
|
|
123181
|
-
|
|
123424
|
+
logger64.debug("Granting manual XP", {
|
|
123182
123425
|
requesterId: ctx.user.id,
|
|
123183
123426
|
gameId: body2.gameId,
|
|
123184
123427
|
courseId: body2.courseId,
|
|
@@ -123190,7 +123433,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123190
123433
|
});
|
|
123191
123434
|
adjustTime = requireDeveloper(async (ctx) => {
|
|
123192
123435
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
|
|
123193
|
-
|
|
123436
|
+
logger64.debug("Adjusting time spent", {
|
|
123194
123437
|
requesterId: ctx.user.id,
|
|
123195
123438
|
gameId: body2.gameId,
|
|
123196
123439
|
courseId: body2.courseId,
|
|
@@ -123202,7 +123445,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123202
123445
|
});
|
|
123203
123446
|
adjustMastery = requireDeveloper(async (ctx) => {
|
|
123204
123447
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
|
|
123205
|
-
|
|
123448
|
+
logger64.debug("Adjusting mastered units", {
|
|
123206
123449
|
requesterId: ctx.user.id,
|
|
123207
123450
|
gameId: body2.gameId,
|
|
123208
123451
|
courseId: body2.courseId,
|
|
@@ -123214,7 +123457,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123214
123457
|
});
|
|
123215
123458
|
toggleCompletion = requireGameManagementAccess(async (ctx) => {
|
|
123216
123459
|
const body2 = await parseRequestBody(ctx.request, ToggleCourseCompletionRequestSchema);
|
|
123217
|
-
|
|
123460
|
+
logger64.debug("Toggling course completion", {
|
|
123218
123461
|
requesterId: ctx.user.id,
|
|
123219
123462
|
gameId: body2.gameId,
|
|
123220
123463
|
courseId: body2.courseId,
|
|
@@ -123230,7 +123473,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123230
123473
|
if (!gameId || !courseId) {
|
|
123231
123474
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
123232
123475
|
}
|
|
123233
|
-
|
|
123476
|
+
logger64.debug("Searching students for enrollment", {
|
|
123234
123477
|
requesterId: ctx.user.id,
|
|
123235
123478
|
gameId,
|
|
123236
123479
|
courseId,
|
|
@@ -123240,7 +123483,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123240
123483
|
});
|
|
123241
123484
|
enrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
123242
123485
|
const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
|
|
123243
|
-
|
|
123486
|
+
logger64.debug("Enrolling student", {
|
|
123244
123487
|
requesterId: ctx.user.id,
|
|
123245
123488
|
gameId: body2.gameId,
|
|
123246
123489
|
courseId: body2.courseId,
|
|
@@ -123250,7 +123493,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123250
123493
|
});
|
|
123251
123494
|
unenrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
123252
123495
|
const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
|
|
123253
|
-
|
|
123496
|
+
logger64.debug("Unenrolling student", {
|
|
123254
123497
|
requesterId: ctx.user.id,
|
|
123255
123498
|
gameId: body2.gameId,
|
|
123256
123499
|
courseId: body2.courseId,
|
|
@@ -123273,6 +123516,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123273
123516
|
deleteIntegrations,
|
|
123274
123517
|
endActivity,
|
|
123275
123518
|
heartbeat,
|
|
123519
|
+
advanceCourse,
|
|
123276
123520
|
getStudentXp,
|
|
123277
123521
|
getRoster,
|
|
123278
123522
|
getStudentOverview,
|
|
@@ -123286,7 +123530,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123286
123530
|
unenrollStudent
|
|
123287
123531
|
};
|
|
123288
123532
|
});
|
|
123289
|
-
var
|
|
123533
|
+
var logger65;
|
|
123290
123534
|
var initiate;
|
|
123291
123535
|
var init_upload_controller = __esm(() => {
|
|
123292
123536
|
init_esm();
|
|
@@ -123294,7 +123538,7 @@ var init_upload_controller = __esm(() => {
|
|
|
123294
123538
|
init_src2();
|
|
123295
123539
|
init_errors();
|
|
123296
123540
|
init_utils11();
|
|
123297
|
-
|
|
123541
|
+
logger65 = log.scope("UploadController");
|
|
123298
123542
|
initiate = requireDeveloper(async (ctx) => {
|
|
123299
123543
|
let body2;
|
|
123300
123544
|
try {
|
|
@@ -123303,16 +123547,16 @@ var init_upload_controller = __esm(() => {
|
|
|
123303
123547
|
} catch (error2) {
|
|
123304
123548
|
if (error2 instanceof exports_external.ZodError) {
|
|
123305
123549
|
const details = formatZodError(error2);
|
|
123306
|
-
|
|
123550
|
+
logger65.warn("Initiate upload validation failed", { details });
|
|
123307
123551
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123308
123552
|
}
|
|
123309
123553
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123310
123554
|
}
|
|
123311
|
-
|
|
123555
|
+
logger65.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
|
|
123312
123556
|
return ctx.services.upload.initiate(body2, ctx.user);
|
|
123313
123557
|
});
|
|
123314
123558
|
});
|
|
123315
|
-
var
|
|
123559
|
+
var logger66;
|
|
123316
123560
|
var getMe;
|
|
123317
123561
|
var getDemoProfile;
|
|
123318
123562
|
var updateDemoProfile;
|
|
@@ -123321,18 +123565,18 @@ var init_user_controller = __esm(() => {
|
|
|
123321
123565
|
init_schemas_index();
|
|
123322
123566
|
init_src2();
|
|
123323
123567
|
init_utils11();
|
|
123324
|
-
|
|
123568
|
+
logger66 = log.scope("UserController");
|
|
123325
123569
|
getMe = requireNonAnonymous(async (ctx) => {
|
|
123326
|
-
|
|
123570
|
+
logger66.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
123327
123571
|
return ctx.services.user.getMe(ctx.user, ctx.gameId);
|
|
123328
123572
|
});
|
|
123329
123573
|
getDemoProfile = requireAnonymous(async (ctx) => {
|
|
123330
|
-
|
|
123574
|
+
logger66.debug("Getting demo profile", { userId: ctx.user.id });
|
|
123331
123575
|
return ctx.services.user.getDemoProfile(ctx.user.id);
|
|
123332
123576
|
});
|
|
123333
123577
|
updateDemoProfile = requireAnonymous(async (ctx) => {
|
|
123334
123578
|
const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
|
|
123335
|
-
|
|
123579
|
+
logger66.debug("Updating demo profile", {
|
|
123336
123580
|
userId: ctx.user.id,
|
|
123337
123581
|
displayName: body2.displayName
|
|
123338
123582
|
});
|
|
@@ -123344,13 +123588,13 @@ var init_user_controller = __esm(() => {
|
|
|
123344
123588
|
updateDemoProfile
|
|
123345
123589
|
};
|
|
123346
123590
|
});
|
|
123347
|
-
var
|
|
123591
|
+
var logger67;
|
|
123348
123592
|
var init_verify_controller = __esm(() => {
|
|
123349
123593
|
init_schemas_index();
|
|
123350
123594
|
init_src2();
|
|
123351
123595
|
init_errors();
|
|
123352
123596
|
init_utils11();
|
|
123353
|
-
|
|
123597
|
+
logger67 = log.scope("VerifyController");
|
|
123354
123598
|
});
|
|
123355
123599
|
var init_controllers = __esm(() => {
|
|
123356
123600
|
init_achievement_controller();
|
|
@@ -123647,7 +123891,7 @@ var init_uploads = __esm(() => {
|
|
|
123647
123891
|
gameUploadsRouter.post("/uploads/finalize", finalizeHandler);
|
|
123648
123892
|
gameUploadsRouter.post("/uploads/finalize/", finalizeHandler);
|
|
123649
123893
|
});
|
|
123650
|
-
var
|
|
123894
|
+
var logger68;
|
|
123651
123895
|
var gameDeployRouter;
|
|
123652
123896
|
var init_deploy = __esm(() => {
|
|
123653
123897
|
init_drizzle_orm();
|
|
@@ -123658,7 +123902,7 @@ var init_deploy = __esm(() => {
|
|
|
123658
123902
|
init_src2();
|
|
123659
123903
|
init_api();
|
|
123660
123904
|
init_uploads();
|
|
123661
|
-
|
|
123905
|
+
logger68 = log.scope("SandboxDeploy");
|
|
123662
123906
|
gameDeployRouter = new Hono2;
|
|
123663
123907
|
gameDeployRouter.post("/:slug/deploy", async (c2) => {
|
|
123664
123908
|
const user = c2.get("user");
|
|
@@ -123775,7 +124019,7 @@ var init_deploy = __esm(() => {
|
|
|
123775
124019
|
completedAt: now2
|
|
123776
124020
|
};
|
|
123777
124021
|
const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
|
|
123778
|
-
|
|
124022
|
+
logger68.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
|
|
123779
124023
|
return c2.json({
|
|
123780
124024
|
id: insertedJob.id,
|
|
123781
124025
|
status: "succeeded",
|
|
@@ -124281,6 +124525,7 @@ var init_timeback6 = __esm(() => {
|
|
|
124281
124525
|
timebackRouter.delete("/integrations/:gameId", handle2(timeback2.deleteIntegrations, { status: 204 }));
|
|
124282
124526
|
timebackRouter.post("/end-activity", handle2(timeback2.endActivity));
|
|
124283
124527
|
timebackRouter.post("/heartbeat", handle2(timeback2.heartbeat));
|
|
124528
|
+
timebackRouter.post("/advance-course", handle2(timeback2.advanceCourse));
|
|
124284
124529
|
timebackRouter.get("/user", async (c2) => {
|
|
124285
124530
|
const user = c2.get("user");
|
|
124286
124531
|
const gameId = c2.get("gameId");
|
|
@@ -124366,7 +124611,7 @@ function verifyMockToken(idToken) {
|
|
|
124366
124611
|
throw new Error("Invalid LTI token format");
|
|
124367
124612
|
}
|
|
124368
124613
|
}
|
|
124369
|
-
var
|
|
124614
|
+
var logger69;
|
|
124370
124615
|
var ltiRouter;
|
|
124371
124616
|
var init_lti = __esm(() => {
|
|
124372
124617
|
init_drizzle_orm();
|
|
@@ -124377,7 +124622,7 @@ var init_lti = __esm(() => {
|
|
|
124377
124622
|
init_src2();
|
|
124378
124623
|
init_constants();
|
|
124379
124624
|
init_api();
|
|
124380
|
-
|
|
124625
|
+
logger69 = log.scope("SandboxLti");
|
|
124381
124626
|
ltiRouter = new Hono2;
|
|
124382
124627
|
ltiRouter.post("/launch", async (c2) => {
|
|
124383
124628
|
const db2 = c2.get("db");
|
|
@@ -124395,7 +124640,7 @@ var init_lti = __esm(() => {
|
|
|
124395
124640
|
claims = verifyMockToken(idToken);
|
|
124396
124641
|
} catch (error2) {
|
|
124397
124642
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
124398
|
-
|
|
124643
|
+
logger69.error("LTI token verification failed", { error: errorMessage });
|
|
124399
124644
|
return c2.json({
|
|
124400
124645
|
error: "invalid_token",
|
|
124401
124646
|
message: errorMessage
|
|
@@ -124403,7 +124648,7 @@ var init_lti = __esm(() => {
|
|
|
124403
124648
|
}
|
|
124404
124649
|
const validationError = validateLtiClaims(claims);
|
|
124405
124650
|
if (validationError) {
|
|
124406
|
-
|
|
124651
|
+
logger69.warn("LTI claims validation failed", {
|
|
124407
124652
|
error: validationError,
|
|
124408
124653
|
sub: claims.sub
|
|
124409
124654
|
});
|
|
@@ -124423,7 +124668,7 @@ var init_lti = __esm(() => {
|
|
|
124423
124668
|
createdAt: new Date,
|
|
124424
124669
|
updatedAt: new Date
|
|
124425
124670
|
});
|
|
124426
|
-
|
|
124671
|
+
logger69.info("LTI launch successful", { userId: user.id });
|
|
124427
124672
|
const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
|
|
124428
124673
|
const currentHost = new URL(c2.req.url).hostname;
|
|
124429
124674
|
const redirectPath = extractRedirectPath(targetUri, currentHost);
|
|
@@ -124431,7 +124676,7 @@ var init_lti = __esm(() => {
|
|
|
124431
124676
|
return c2.redirect(redirectPath);
|
|
124432
124677
|
} catch (error2) {
|
|
124433
124678
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
124434
|
-
|
|
124679
|
+
logger69.error("Unexpected error during LTI launch", { error: errorMessage });
|
|
124435
124680
|
return c2.json({
|
|
124436
124681
|
error: "unexpected_error",
|
|
124437
124682
|
message: "An unexpected error occurred during LTI launch"
|
|
@@ -125419,7 +125664,8 @@ var init_timeback7 = __esm7(() => {
|
|
|
125419
125664
|
TIMEBACK_ROUTES2 = {
|
|
125420
125665
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
125421
125666
|
GET_XP: "/integrations/timeback/xp",
|
|
125422
|
-
HEARTBEAT: "/integrations/timeback/heartbeat"
|
|
125667
|
+
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
125668
|
+
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
125423
125669
|
};
|
|
125424
125670
|
TIMEBACK_COURSE_DEFAULTS2 = {
|
|
125425
125671
|
gradingScheme: "STANDARD",
|
|
@@ -126096,7 +126342,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
|
126096
126342
|
// package.json
|
|
126097
126343
|
var package_default2 = {
|
|
126098
126344
|
name: "@playcademy/vite-plugin",
|
|
126099
|
-
version: "0.2.26-beta.
|
|
126345
|
+
version: "0.2.26-beta.4",
|
|
126100
126346
|
type: "module",
|
|
126101
126347
|
exports: {
|
|
126102
126348
|
".": {
|