@playcademy/vite-plugin 0.2.26-beta.3 → 0.2.26-beta.5
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 +695 -422
- package/dist/lib/backend/hot-reload.d.ts +1 -1
- package/dist/server/state.d.ts +2 -2
- package/dist/types/internal.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24333,10 +24333,10 @@ var init_typescript = __esm(() => {
|
|
|
24333
24333
|
TypeScriptPackages = {
|
|
24334
24334
|
tsc: "tsc",
|
|
24335
24335
|
nativePreview: "@typescript/native-preview",
|
|
24336
|
-
|
|
24336
|
+
nativePreviewBeta: "@typescript/native-preview@beta"
|
|
24337
24337
|
};
|
|
24338
24338
|
TYPESCRIPT_RUNNER = {
|
|
24339
|
-
package: TypeScriptPackages.
|
|
24339
|
+
package: TypeScriptPackages.nativePreviewBeta,
|
|
24340
24340
|
bin: "tsgo"
|
|
24341
24341
|
};
|
|
24342
24342
|
});
|
|
@@ -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.20",
|
|
25373
25374
|
description: "Local development server for Playcademy game development",
|
|
25374
25375
|
type: "module",
|
|
25375
25376
|
exports: {
|
|
@@ -25706,7 +25707,7 @@ function formatJSONSingleLine(level, message, context, scope) {
|
|
|
25706
25707
|
...context && Object.keys(context).length > 0 && { context }
|
|
25707
25708
|
};
|
|
25708
25709
|
const consoleMethod = getConsoleMethod(level);
|
|
25709
|
-
consoleMethod(
|
|
25710
|
+
consoleMethod(safeJSONStringify(logEntry));
|
|
25710
25711
|
}
|
|
25711
25712
|
function formatJSONPretty(level, message, context, scope) {
|
|
25712
25713
|
const timestamp = new Date().toISOString();
|
|
@@ -25718,7 +25719,30 @@ function formatJSONPretty(level, message, context, scope) {
|
|
|
25718
25719
|
...context && Object.keys(context).length > 0 && { context }
|
|
25719
25720
|
};
|
|
25720
25721
|
const consoleMethod = getConsoleMethod(level);
|
|
25721
|
-
consoleMethod(
|
|
25722
|
+
consoleMethod(safeJSONStringify(logEntry, 2));
|
|
25723
|
+
}
|
|
25724
|
+
function safeJSONStringify(value, space) {
|
|
25725
|
+
const seen = new WeakSet;
|
|
25726
|
+
try {
|
|
25727
|
+
return JSON.stringify(value, (_key, currentValue) => {
|
|
25728
|
+
if (typeof currentValue === "bigint") {
|
|
25729
|
+
return currentValue.toString();
|
|
25730
|
+
}
|
|
25731
|
+
if (typeof currentValue === "object" && currentValue !== null) {
|
|
25732
|
+
if (seen.has(currentValue)) {
|
|
25733
|
+
return "[Circular]";
|
|
25734
|
+
}
|
|
25735
|
+
seen.add(currentValue);
|
|
25736
|
+
}
|
|
25737
|
+
return currentValue;
|
|
25738
|
+
}, space);
|
|
25739
|
+
} catch {
|
|
25740
|
+
return JSON.stringify({
|
|
25741
|
+
timestamp: new Date().toISOString(),
|
|
25742
|
+
level: "ERROR",
|
|
25743
|
+
message: "[Logger] Failed to serialize log entry"
|
|
25744
|
+
});
|
|
25745
|
+
}
|
|
25722
25746
|
}
|
|
25723
25747
|
function getConsoleMethod(level) {
|
|
25724
25748
|
switch (level) {
|
|
@@ -52738,7 +52762,8 @@ var init_constants3 = __esm(() => {
|
|
|
52738
52762
|
TIMEBACK: {
|
|
52739
52763
|
END_ACTIVITY: `/api${TIMEBACK_ROUTES.END_ACTIVITY}`,
|
|
52740
52764
|
GET_XP: `/api${TIMEBACK_ROUTES.GET_XP}`,
|
|
52741
|
-
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}
|
|
52765
|
+
HEARTBEAT: `/api${TIMEBACK_ROUTES.HEARTBEAT}`,
|
|
52766
|
+
ADVANCE_COURSE: `/api${TIMEBACK_ROUTES.ADVANCE_COURSE}`
|
|
52742
52767
|
}
|
|
52743
52768
|
};
|
|
52744
52769
|
});
|
|
@@ -55131,6 +55156,7 @@ class TimebackAdminService {
|
|
|
55131
55156
|
await client.edubridge.enrollments.enroll(data.studentId, data.courseId, {
|
|
55132
55157
|
role: "student"
|
|
55133
55158
|
});
|
|
55159
|
+
client.invalidateEnrollments(data.studentId);
|
|
55134
55160
|
return { status: "ok" };
|
|
55135
55161
|
}
|
|
55136
55162
|
async unenrollStudent(data, user) {
|
|
@@ -55143,6 +55169,7 @@ class TimebackAdminService {
|
|
|
55143
55169
|
throw new NotFoundError("Timeback integration", `${data.gameId}:${data.courseId}`);
|
|
55144
55170
|
}
|
|
55145
55171
|
await client.edubridge.enrollments.unenroll(data.studentId, data.courseId);
|
|
55172
|
+
client.invalidateEnrollments(data.studentId);
|
|
55146
55173
|
return { status: "ok" };
|
|
55147
55174
|
}
|
|
55148
55175
|
async getCompletionStatus(client, courseId, studentId) {
|
|
@@ -55198,7 +55225,103 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
55198
55225
|
init_timeback_util();
|
|
55199
55226
|
logger16 = log.scope("TimebackAdminService");
|
|
55200
55227
|
});
|
|
55228
|
+
async function promoteCompletedCourse({
|
|
55229
|
+
db: db2,
|
|
55230
|
+
client,
|
|
55231
|
+
currentIntegration,
|
|
55232
|
+
studentId,
|
|
55233
|
+
enrollments: prefetchedEnrollments
|
|
55234
|
+
}) {
|
|
55235
|
+
const subjectIntegrations = await db2.query.gameTimebackIntegrations.findMany({
|
|
55236
|
+
where: and(eq(gameTimebackIntegrations.gameId, currentIntegration.gameId), eq(gameTimebackIntegrations.subject, currentIntegration.subject))
|
|
55237
|
+
});
|
|
55238
|
+
const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
|
|
55239
|
+
if (!nextIntegration) {
|
|
55240
|
+
logger17.debug("Skipping promotion because no next course is configured", {
|
|
55241
|
+
gameId: currentIntegration.gameId,
|
|
55242
|
+
studentId,
|
|
55243
|
+
grade: currentIntegration.grade,
|
|
55244
|
+
subject: currentIntegration.subject,
|
|
55245
|
+
currentCourseId: currentIntegration.courseId
|
|
55246
|
+
});
|
|
55247
|
+
return {
|
|
55248
|
+
status: "no-next-course",
|
|
55249
|
+
currentCourseId: currentIntegration.courseId
|
|
55250
|
+
};
|
|
55251
|
+
}
|
|
55252
|
+
const enrollments = prefetchedEnrollments ?? await client.edubridge.enrollments.listByUser(studentId);
|
|
55253
|
+
const currentEnrollment = enrollments.find((enrollment) => enrollment.course.id === currentIntegration.courseId);
|
|
55254
|
+
const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
|
|
55255
|
+
if (!currentEnrollment) {
|
|
55256
|
+
if (nextEnrollment) {
|
|
55257
|
+
logger17.debug("Skipping promotion because student is already on the next course", {
|
|
55258
|
+
gameId: currentIntegration.gameId,
|
|
55259
|
+
studentId,
|
|
55260
|
+
grade: currentIntegration.grade,
|
|
55261
|
+
subject: currentIntegration.subject,
|
|
55262
|
+
currentCourseId: currentIntegration.courseId,
|
|
55263
|
+
nextCourseId: nextIntegration.courseId
|
|
55264
|
+
});
|
|
55265
|
+
return {
|
|
55266
|
+
status: "already-promoted",
|
|
55267
|
+
currentCourseId: currentIntegration.courseId,
|
|
55268
|
+
nextCourseId: nextIntegration.courseId
|
|
55269
|
+
};
|
|
55270
|
+
}
|
|
55271
|
+
logger17.debug("Skipping promotion because student is not enrolled in the current course", {
|
|
55272
|
+
gameId: currentIntegration.gameId,
|
|
55273
|
+
studentId,
|
|
55274
|
+
grade: currentIntegration.grade,
|
|
55275
|
+
subject: currentIntegration.subject,
|
|
55276
|
+
currentCourseId: currentIntegration.courseId,
|
|
55277
|
+
nextCourseId: nextIntegration.courseId
|
|
55278
|
+
});
|
|
55279
|
+
return {
|
|
55280
|
+
status: "not-enrolled",
|
|
55281
|
+
currentCourseId: currentIntegration.courseId,
|
|
55282
|
+
nextCourseId: nextIntegration.courseId
|
|
55283
|
+
};
|
|
55284
|
+
}
|
|
55285
|
+
const schoolId = currentEnrollment.school.id;
|
|
55286
|
+
let mutatedEnrollments = false;
|
|
55287
|
+
try {
|
|
55288
|
+
if (!nextEnrollment) {
|
|
55289
|
+
await client.edubridge.enrollments.enroll(studentId, nextIntegration.courseId, {
|
|
55290
|
+
role: "student",
|
|
55291
|
+
...schoolId ? { schoolId } : {}
|
|
55292
|
+
});
|
|
55293
|
+
mutatedEnrollments = true;
|
|
55294
|
+
}
|
|
55295
|
+
await client.edubridge.enrollments.unenroll(studentId, currentIntegration.courseId, schoolId ? { schoolId } : {});
|
|
55296
|
+
mutatedEnrollments = true;
|
|
55297
|
+
} finally {
|
|
55298
|
+
if (mutatedEnrollments) {
|
|
55299
|
+
client.invalidateEnrollments(studentId);
|
|
55300
|
+
}
|
|
55301
|
+
}
|
|
55302
|
+
logger17.info("Promoted student to next course", {
|
|
55303
|
+
gameId: currentIntegration.gameId,
|
|
55304
|
+
studentId,
|
|
55305
|
+
subject: currentIntegration.subject,
|
|
55306
|
+
fromGrade: currentIntegration.grade,
|
|
55307
|
+
toGrade: nextIntegration.grade,
|
|
55308
|
+
currentCourseId: currentIntegration.courseId,
|
|
55309
|
+
nextCourseId: nextIntegration.courseId
|
|
55310
|
+
});
|
|
55311
|
+
return {
|
|
55312
|
+
status: "promoted",
|
|
55313
|
+
currentCourseId: currentIntegration.courseId,
|
|
55314
|
+
nextCourseId: nextIntegration.courseId
|
|
55315
|
+
};
|
|
55316
|
+
}
|
|
55201
55317
|
var logger17;
|
|
55318
|
+
var init_timeback_promotion_util = __esm(() => {
|
|
55319
|
+
init_drizzle_orm();
|
|
55320
|
+
init_tables_index();
|
|
55321
|
+
init_src2();
|
|
55322
|
+
logger17 = log.scope("TimebackPromotion");
|
|
55323
|
+
});
|
|
55324
|
+
var logger18;
|
|
55202
55325
|
var TimebackService;
|
|
55203
55326
|
var init_timeback_service = __esm(() => {
|
|
55204
55327
|
init_drizzle_orm();
|
|
@@ -55208,8 +55331,9 @@ var init_timeback_service = __esm(() => {
|
|
|
55208
55331
|
init_types4();
|
|
55209
55332
|
init_src4();
|
|
55210
55333
|
init_errors();
|
|
55334
|
+
init_timeback_promotion_util();
|
|
55211
55335
|
init_timeback_util();
|
|
55212
|
-
|
|
55336
|
+
logger18 = log.scope("TimebackService");
|
|
55213
55337
|
TimebackService = class TimebackService2 {
|
|
55214
55338
|
static HEARTBEAT_DEDUPE_TTL_MS = 300000;
|
|
55215
55339
|
static processedHeartbeatWindows = new Map;
|
|
@@ -55255,7 +55379,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55255
55379
|
}
|
|
55256
55380
|
requireClient() {
|
|
55257
55381
|
if (!this.deps.timeback) {
|
|
55258
|
-
|
|
55382
|
+
logger18.error("Timeback client not available in context");
|
|
55259
55383
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
55260
55384
|
}
|
|
55261
55385
|
return this.deps.timeback;
|
|
@@ -55308,7 +55432,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55308
55432
|
set: { xp: sql`excluded.xp`, updatedAt: new Date }
|
|
55309
55433
|
}).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
|
|
55310
55434
|
if (!result) {
|
|
55311
|
-
|
|
55435
|
+
logger18.error("Daily XP upsert returned no rows", { userId, date: targetDate });
|
|
55312
55436
|
throw new InternalError("Failed to update daily XP record");
|
|
55313
55437
|
}
|
|
55314
55438
|
return { xp: result.xp, date: result.date.toISOString() };
|
|
@@ -55339,7 +55463,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55339
55463
|
columns: { id: true, timebackId: true }
|
|
55340
55464
|
});
|
|
55341
55465
|
if (dbUser?.timebackId) {
|
|
55342
|
-
|
|
55466
|
+
logger18.info("Student already onboarded", { userId: user.id });
|
|
55343
55467
|
return { status: "already_populated" };
|
|
55344
55468
|
}
|
|
55345
55469
|
let timebackId;
|
|
@@ -55348,7 +55472,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55348
55472
|
const existingUser = await client.oneroster.users.findByEmail(user.email);
|
|
55349
55473
|
timebackId = existingUser.sourcedId;
|
|
55350
55474
|
name3 = `${existingUser.givenName} ${existingUser.familyName}`;
|
|
55351
|
-
|
|
55475
|
+
logger18.info("Found existing student in OneRoster", {
|
|
55352
55476
|
userId: user.id,
|
|
55353
55477
|
timebackId
|
|
55354
55478
|
});
|
|
@@ -55377,7 +55501,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55377
55501
|
}
|
|
55378
55502
|
timebackId = response.sourcedIdPairs.allocatedSourcedId;
|
|
55379
55503
|
name3 = `${providedNames.firstName} ${providedNames.lastName}`;
|
|
55380
|
-
|
|
55504
|
+
logger18.info("Created student in OneRoster", { userId: user.id, timebackId });
|
|
55381
55505
|
}
|
|
55382
55506
|
const assessments = await this.fetchAssessments(timebackId);
|
|
55383
55507
|
await db2.transaction(async (tx) => {
|
|
@@ -55411,7 +55535,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55411
55535
|
}
|
|
55412
55536
|
const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
|
|
55413
55537
|
if (!updated) {
|
|
55414
|
-
|
|
55538
|
+
logger18.error("User Timeback ID update returned no rows", {
|
|
55415
55539
|
userId: user.id,
|
|
55416
55540
|
timebackId
|
|
55417
55541
|
});
|
|
@@ -55435,13 +55559,13 @@ var init_timeback_service = __esm(() => {
|
|
|
55435
55559
|
}
|
|
55436
55560
|
offset += limit;
|
|
55437
55561
|
}
|
|
55438
|
-
|
|
55562
|
+
logger18.debug("Fetched assessments", {
|
|
55439
55563
|
studentSourcedId,
|
|
55440
55564
|
totalCount: allAssessments.length
|
|
55441
55565
|
});
|
|
55442
55566
|
return allAssessments;
|
|
55443
55567
|
} catch (error) {
|
|
55444
|
-
|
|
55568
|
+
logger18.warn("Failed to fetch assessments", { studentSourcedId, error });
|
|
55445
55569
|
return [];
|
|
55446
55570
|
}
|
|
55447
55571
|
}
|
|
@@ -55554,7 +55678,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55554
55678
|
masterableUnits: derivedMasterableUnits
|
|
55555
55679
|
} = courseConfig;
|
|
55556
55680
|
if (!isTimebackSubject(subjectInput)) {
|
|
55557
|
-
|
|
55681
|
+
logger18.warn("Invalid Timeback subject in course config", {
|
|
55558
55682
|
subject: subjectInput,
|
|
55559
55683
|
courseCode,
|
|
55560
55684
|
title
|
|
@@ -55562,7 +55686,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55562
55686
|
throw new ValidationError(`Invalid subject "${subjectInput}"`);
|
|
55563
55687
|
}
|
|
55564
55688
|
if (!isTimebackGrade(grade)) {
|
|
55565
|
-
|
|
55689
|
+
logger18.warn("Invalid Timeback grade in course config", {
|
|
55566
55690
|
grade,
|
|
55567
55691
|
courseCode,
|
|
55568
55692
|
title
|
|
@@ -55574,7 +55698,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55574
55698
|
const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
|
|
55575
55699
|
const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
|
|
55576
55700
|
if (typeof totalXp !== "number") {
|
|
55577
|
-
|
|
55701
|
+
logger18.warn("Course missing totalXp in Timeback config", {
|
|
55578
55702
|
courseCode,
|
|
55579
55703
|
title
|
|
55580
55704
|
});
|
|
@@ -55775,7 +55899,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55775
55899
|
...runId ? { runId } : {}
|
|
55776
55900
|
});
|
|
55777
55901
|
}
|
|
55778
|
-
|
|
55902
|
+
logger18.info("Recorded activity completion", {
|
|
55779
55903
|
gameId,
|
|
55780
55904
|
courseId: integration.courseId,
|
|
55781
55905
|
studentId,
|
|
@@ -55792,6 +55916,72 @@ var init_timeback_service = __esm(() => {
|
|
|
55792
55916
|
inProgress: result.inProgress
|
|
55793
55917
|
};
|
|
55794
55918
|
}
|
|
55919
|
+
async advanceCourse({
|
|
55920
|
+
gameId,
|
|
55921
|
+
studentId,
|
|
55922
|
+
subject,
|
|
55923
|
+
user
|
|
55924
|
+
}) {
|
|
55925
|
+
const client = this.requireClient();
|
|
55926
|
+
const db2 = this.deps.db;
|
|
55927
|
+
await this.deps.validateDeveloperAccess(user, gameId);
|
|
55928
|
+
const integrations = await db2.query.gameTimebackIntegrations.findMany({
|
|
55929
|
+
where: subject ? and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.subject, subject)) : eq(gameTimebackIntegrations.gameId, gameId)
|
|
55930
|
+
});
|
|
55931
|
+
if (integrations.length === 0) {
|
|
55932
|
+
throw new NotFoundError(subject ? `Timeback integrations for game (subject ${subject})` : "Timeback integrations for game");
|
|
55933
|
+
}
|
|
55934
|
+
const enrollments = await client.edubridge.enrollments.listByUser(studentId);
|
|
55935
|
+
const enrolledCourseIds = new Set(enrollments.map((e) => e.course.id));
|
|
55936
|
+
const enrolledIntegrations = integrations.filter((integration) => enrolledCourseIds.has(integration.courseId));
|
|
55937
|
+
if (enrolledIntegrations.length === 0) {
|
|
55938
|
+
throw new NotFoundError(subject ? `Active enrollment for game ladder (subject ${subject})` : "Active enrollment for game ladder");
|
|
55939
|
+
}
|
|
55940
|
+
const subjectsInPlay = new Set(enrolledIntegrations.map((i2) => i2.subject));
|
|
55941
|
+
if (subjectsInPlay.size > 1) {
|
|
55942
|
+
throw new ValidationError(`Ambiguous Timeback advance: student is enrolled in ${subjectsInPlay.size} parallel ladders (${[...subjectsInPlay].join(", ")}); pass { subject } to disambiguate`);
|
|
55943
|
+
}
|
|
55944
|
+
const currentIntegration = enrolledIntegrations.toSorted((left, right) => left.grade - right.grade)[0];
|
|
55945
|
+
const masteryStatus = await client.getMasteryStatus(currentIntegration.courseId, studentId);
|
|
55946
|
+
if (!masteryStatus) {
|
|
55947
|
+
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().`);
|
|
55948
|
+
}
|
|
55949
|
+
if (!masteryStatus.isComplete) {
|
|
55950
|
+
const promotion2 = {
|
|
55951
|
+
status: "not-mastered",
|
|
55952
|
+
currentCourseId: currentIntegration.courseId,
|
|
55953
|
+
masteredUnits: masteryStatus.masteredUnits,
|
|
55954
|
+
masterableUnits: masteryStatus.masterableUnits
|
|
55955
|
+
};
|
|
55956
|
+
logger18.debug("Skipping course advancement because mastery is incomplete", {
|
|
55957
|
+
gameId,
|
|
55958
|
+
studentId,
|
|
55959
|
+
subject: currentIntegration.subject,
|
|
55960
|
+
grade: currentIntegration.grade,
|
|
55961
|
+
currentCourseId: currentIntegration.courseId,
|
|
55962
|
+
masteredUnits: masteryStatus.masteredUnits,
|
|
55963
|
+
masterableUnits: masteryStatus.masterableUnits
|
|
55964
|
+
});
|
|
55965
|
+
return { status: "ok", promotion: promotion2 };
|
|
55966
|
+
}
|
|
55967
|
+
const promotion = await promoteCompletedCourse({
|
|
55968
|
+
db: db2,
|
|
55969
|
+
client,
|
|
55970
|
+
currentIntegration,
|
|
55971
|
+
studentId,
|
|
55972
|
+
enrollments
|
|
55973
|
+
});
|
|
55974
|
+
logger18.info("Manually advanced student", {
|
|
55975
|
+
gameId,
|
|
55976
|
+
studentId,
|
|
55977
|
+
subject: currentIntegration.subject,
|
|
55978
|
+
grade: currentIntegration.grade,
|
|
55979
|
+
promotionStatus: promotion.status,
|
|
55980
|
+
currentCourseId: promotion.currentCourseId,
|
|
55981
|
+
nextCourseId: promotion.nextCourseId
|
|
55982
|
+
});
|
|
55983
|
+
return { status: "ok", promotion };
|
|
55984
|
+
}
|
|
55795
55985
|
async recordHeartbeat({
|
|
55796
55986
|
gameId,
|
|
55797
55987
|
studentId,
|
|
@@ -55814,7 +56004,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55814
56004
|
const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
|
|
55815
56005
|
const effectiveResumeId = resumeId ?? runId;
|
|
55816
56006
|
if (TimebackService2.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
|
|
55817
|
-
|
|
56007
|
+
logger18.debug("Skipping duplicate heartbeat window", {
|
|
55818
56008
|
gameId,
|
|
55819
56009
|
studentId,
|
|
55820
56010
|
runId,
|
|
@@ -55827,7 +56017,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55827
56017
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
55828
56018
|
const inFlightHeartbeat = TimebackService2.getInFlightHeartbeatWindow(heartbeatWindowKey);
|
|
55829
56019
|
if (inFlightHeartbeat) {
|
|
55830
|
-
|
|
56020
|
+
logger18.debug("Joining in-flight heartbeat window", {
|
|
55831
56021
|
gameId,
|
|
55832
56022
|
studentId,
|
|
55833
56023
|
runId,
|
|
@@ -55864,7 +56054,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55864
56054
|
});
|
|
55865
56055
|
}
|
|
55866
56056
|
TimebackService2.markHeartbeatWindowProcessed(heartbeatWindowKey);
|
|
55867
|
-
|
|
56057
|
+
logger18.debug("Recorded heartbeat", {
|
|
55868
56058
|
gameId,
|
|
55869
56059
|
courseId: integration.courseId,
|
|
55870
56060
|
studentId,
|
|
@@ -55899,7 +56089,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55899
56089
|
});
|
|
55900
56090
|
courseIds = integrations.map((i2) => i2.courseId);
|
|
55901
56091
|
if (courseIds.length === 0) {
|
|
55902
|
-
|
|
56092
|
+
logger18.debug("No integrations found for game, returning 0 XP", {
|
|
55903
56093
|
timebackId,
|
|
55904
56094
|
gameId: options.gameId,
|
|
55905
56095
|
grade: options.grade,
|
|
@@ -55916,7 +56106,7 @@ var init_timeback_service = __esm(() => {
|
|
|
55916
56106
|
courseIds: courseIds.length > 0 ? courseIds : undefined,
|
|
55917
56107
|
include: options?.include
|
|
55918
56108
|
});
|
|
55919
|
-
|
|
56109
|
+
logger18.debug("Retrieved student XP", {
|
|
55920
56110
|
timebackId,
|
|
55921
56111
|
gameId: options?.gameId,
|
|
55922
56112
|
grade: options?.grade,
|
|
@@ -55944,15 +56134,15 @@ class UploadService {
|
|
|
55944
56134
|
const { fileName, gameId } = request;
|
|
55945
56135
|
const bucketName = this.deps.uploadBucket;
|
|
55946
56136
|
if (!bucketName) {
|
|
55947
|
-
|
|
56137
|
+
logger19.error("Upload bucket not configured in environment");
|
|
55948
56138
|
throw new ValidationError("Upload bucket not configured");
|
|
55949
56139
|
}
|
|
55950
56140
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
55951
56141
|
const version2 = ulid();
|
|
55952
56142
|
const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
|
|
55953
|
-
|
|
56143
|
+
logger19.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
|
|
55954
56144
|
const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
|
|
55955
|
-
|
|
56145
|
+
logger19.info("Presigned URL generated", {
|
|
55956
56146
|
userId: user.id,
|
|
55957
56147
|
gameId,
|
|
55958
56148
|
version: version2
|
|
@@ -55965,12 +56155,12 @@ class UploadService {
|
|
|
55965
56155
|
};
|
|
55966
56156
|
}
|
|
55967
56157
|
}
|
|
55968
|
-
var
|
|
56158
|
+
var logger19;
|
|
55969
56159
|
var init_upload_service = __esm(() => {
|
|
55970
56160
|
init_node();
|
|
55971
56161
|
init_src2();
|
|
55972
56162
|
init_errors();
|
|
55973
|
-
|
|
56163
|
+
logger19 = log.scope("UploadService");
|
|
55974
56164
|
});
|
|
55975
56165
|
function createPlatformServices(deps) {
|
|
55976
56166
|
const {
|
|
@@ -56262,7 +56452,7 @@ class AchievementService {
|
|
|
56262
56452
|
results.push(result);
|
|
56263
56453
|
}
|
|
56264
56454
|
}
|
|
56265
|
-
|
|
56455
|
+
logger20.debug("Listed current achievements", { userId: user.id, count: results.length });
|
|
56266
56456
|
return results;
|
|
56267
56457
|
}
|
|
56268
56458
|
async listHistory(user, limit) {
|
|
@@ -56280,14 +56470,14 @@ class AchievementService {
|
|
|
56280
56470
|
createdAt: c.createdAt,
|
|
56281
56471
|
scopeKey: c.scopeKey
|
|
56282
56472
|
}));
|
|
56283
|
-
|
|
56473
|
+
logger20.debug("Listed achievement history", { userId: user.id, count: results.length });
|
|
56284
56474
|
return results;
|
|
56285
56475
|
}
|
|
56286
56476
|
async submitProgress(achievementId, user) {
|
|
56287
56477
|
const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
|
|
56288
56478
|
broadcast: false
|
|
56289
56479
|
});
|
|
56290
|
-
|
|
56480
|
+
logger20.debug("Submitted progress", {
|
|
56291
56481
|
userId: user.id,
|
|
56292
56482
|
achievementId,
|
|
56293
56483
|
wasNewClaim
|
|
@@ -56319,7 +56509,7 @@ class AchievementService {
|
|
|
56319
56509
|
rewardCredits
|
|
56320
56510
|
}).returning();
|
|
56321
56511
|
if (!newClaim) {
|
|
56322
|
-
|
|
56512
|
+
logger20.error("Achievement claim insert returned no rows", {
|
|
56323
56513
|
userId,
|
|
56324
56514
|
achievementId,
|
|
56325
56515
|
scopeKey
|
|
@@ -56328,7 +56518,7 @@ class AchievementService {
|
|
|
56328
56518
|
}
|
|
56329
56519
|
await this.deps.addCredits(userId, rewardCredits);
|
|
56330
56520
|
await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
|
|
56331
|
-
|
|
56521
|
+
logger20.info("Awarded achievement", {
|
|
56332
56522
|
userId,
|
|
56333
56523
|
achievementId,
|
|
56334
56524
|
scopeKey,
|
|
@@ -56365,7 +56555,7 @@ class AchievementService {
|
|
|
56365
56555
|
return { title, body: body2 };
|
|
56366
56556
|
}
|
|
56367
56557
|
}
|
|
56368
|
-
var
|
|
56558
|
+
var logger20;
|
|
56369
56559
|
var init_achievement_service = __esm(() => {
|
|
56370
56560
|
init_drizzle_orm();
|
|
56371
56561
|
init_tables_index();
|
|
@@ -56374,7 +56564,7 @@ var init_achievement_service = __esm(() => {
|
|
|
56374
56564
|
init_errors();
|
|
56375
56565
|
init_leaderboard_util();
|
|
56376
56566
|
init_scope_util();
|
|
56377
|
-
|
|
56567
|
+
logger20 = log.scope("AchievementService");
|
|
56378
56568
|
});
|
|
56379
56569
|
|
|
56380
56570
|
class InventoryService {
|
|
@@ -56401,7 +56591,7 @@ class InventoryService {
|
|
|
56401
56591
|
},
|
|
56402
56592
|
updatedAt: inventoryItems.updatedAt
|
|
56403
56593
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
56404
|
-
|
|
56594
|
+
logger21.debug("Listed inventory", { userId: user.id, count: inventory.length });
|
|
56405
56595
|
return inventory;
|
|
56406
56596
|
}
|
|
56407
56597
|
async addItem(itemId, quantity, user) {
|
|
@@ -56418,7 +56608,7 @@ class InventoryService {
|
|
|
56418
56608
|
const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
|
|
56419
56609
|
return inserted?.quantity ?? 0;
|
|
56420
56610
|
});
|
|
56421
|
-
|
|
56611
|
+
logger21.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
|
|
56422
56612
|
return { newTotal };
|
|
56423
56613
|
}
|
|
56424
56614
|
async removeItem(itemId, quantity, user) {
|
|
@@ -56429,7 +56619,7 @@ class InventoryService {
|
|
|
56429
56619
|
}
|
|
56430
56620
|
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
56621
|
if (!currentItem) {
|
|
56432
|
-
|
|
56622
|
+
logger21.warn("Insufficient inventory for removal", {
|
|
56433
56623
|
userId: user.id,
|
|
56434
56624
|
itemId,
|
|
56435
56625
|
requestedQuantity: quantity
|
|
@@ -56439,13 +56629,13 @@ class InventoryService {
|
|
|
56439
56629
|
const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
|
|
56440
56630
|
return updated?.quantity ?? 0;
|
|
56441
56631
|
});
|
|
56442
|
-
|
|
56632
|
+
logger21.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
|
|
56443
56633
|
return { newTotal };
|
|
56444
56634
|
}
|
|
56445
56635
|
async addCredits(userId, amount) {
|
|
56446
56636
|
const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
56447
56637
|
if (!creditsItem) {
|
|
56448
|
-
|
|
56638
|
+
logger21.error("Primary currency not found", {
|
|
56449
56639
|
userId,
|
|
56450
56640
|
amount
|
|
56451
56641
|
});
|
|
@@ -56458,17 +56648,17 @@ class InventoryService {
|
|
|
56458
56648
|
updatedAt: new Date
|
|
56459
56649
|
}
|
|
56460
56650
|
});
|
|
56461
|
-
|
|
56651
|
+
logger21.debug("Added credits", { userId, amount });
|
|
56462
56652
|
}
|
|
56463
56653
|
}
|
|
56464
|
-
var
|
|
56654
|
+
var logger21;
|
|
56465
56655
|
var init_inventory_service = __esm(() => {
|
|
56466
56656
|
init_drizzle_orm();
|
|
56467
56657
|
init_src();
|
|
56468
56658
|
init_tables_index();
|
|
56469
56659
|
init_src2();
|
|
56470
56660
|
init_errors();
|
|
56471
|
-
|
|
56661
|
+
logger21 = log.scope("InventoryService");
|
|
56472
56662
|
});
|
|
56473
56663
|
var NotificationType;
|
|
56474
56664
|
var NotificationStatus;
|
|
@@ -56522,7 +56712,7 @@ class LeaderboardService {
|
|
|
56522
56712
|
sessionId
|
|
56523
56713
|
}).returning();
|
|
56524
56714
|
if (!newScore) {
|
|
56525
|
-
|
|
56715
|
+
logger22.error("Score insert returned no rows", { userId, gameId, score: input.score });
|
|
56526
56716
|
throw new InternalError("Failed to insert score");
|
|
56527
56717
|
}
|
|
56528
56718
|
const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
|
|
@@ -56550,7 +56740,7 @@ class LeaderboardService {
|
|
|
56550
56740
|
movedUpWithinTop3
|
|
56551
56741
|
});
|
|
56552
56742
|
}
|
|
56553
|
-
|
|
56743
|
+
logger22.info("Score submitted", {
|
|
56554
56744
|
gameId,
|
|
56555
56745
|
userId,
|
|
56556
56746
|
isAnonymousUser,
|
|
@@ -56627,7 +56817,7 @@ class LeaderboardService {
|
|
|
56627
56817
|
});
|
|
56628
56818
|
}
|
|
56629
56819
|
} catch (error) {
|
|
56630
|
-
|
|
56820
|
+
logger22.warn("Failed to publish notification", { error });
|
|
56631
56821
|
}
|
|
56632
56822
|
}
|
|
56633
56823
|
async getLeaderboard(gameId, query, isAnonymousUser) {
|
|
@@ -56746,7 +56936,7 @@ class LeaderboardService {
|
|
|
56746
56936
|
return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
|
|
56747
56937
|
}
|
|
56748
56938
|
}
|
|
56749
|
-
var
|
|
56939
|
+
var logger22;
|
|
56750
56940
|
var init_leaderboard_service = __esm(() => {
|
|
56751
56941
|
init_drizzle_orm();
|
|
56752
56942
|
init_src();
|
|
@@ -56756,7 +56946,7 @@ var init_leaderboard_service = __esm(() => {
|
|
|
56756
56946
|
init_notification();
|
|
56757
56947
|
init_errors();
|
|
56758
56948
|
init_leaderboard_util();
|
|
56759
|
-
|
|
56949
|
+
logger22 = log.scope("LeaderboardService");
|
|
56760
56950
|
});
|
|
56761
56951
|
|
|
56762
56952
|
class LevelService {
|
|
@@ -56771,9 +56961,9 @@ class LevelService {
|
|
|
56771
56961
|
for (const config2 of configs) {
|
|
56772
56962
|
levelConfigCache.set(config2.level, config2);
|
|
56773
56963
|
}
|
|
56774
|
-
|
|
56964
|
+
logger23.info("Cache pre-warmed", { count: configs.length });
|
|
56775
56965
|
} catch (error) {
|
|
56776
|
-
|
|
56966
|
+
logger23.error("Cache pre-warm failed", { error });
|
|
56777
56967
|
}
|
|
56778
56968
|
}
|
|
56779
56969
|
async getConfig(level) {
|
|
@@ -56807,7 +56997,7 @@ class LevelService {
|
|
|
56807
56997
|
totalXP
|
|
56808
56998
|
}).returning();
|
|
56809
56999
|
if (!newUserLevel) {
|
|
56810
|
-
|
|
57000
|
+
logger23.error("User level insert returned no rows", { userId: user.id });
|
|
56811
57001
|
throw new InternalError("Failed to create user level cache record");
|
|
56812
57002
|
}
|
|
56813
57003
|
userLevel = newUserLevel;
|
|
@@ -56822,7 +57012,7 @@ class LevelService {
|
|
|
56822
57012
|
userLevel = updatedUserLevel;
|
|
56823
57013
|
}
|
|
56824
57014
|
}
|
|
56825
|
-
|
|
57015
|
+
logger23.debug("Retrieved user level", {
|
|
56826
57016
|
userId: user.id,
|
|
56827
57017
|
totalXP,
|
|
56828
57018
|
currentLevel,
|
|
@@ -56833,7 +57023,7 @@ class LevelService {
|
|
|
56833
57023
|
async getProgress(user) {
|
|
56834
57024
|
const userLevel = await this.getByUser(user);
|
|
56835
57025
|
const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
|
|
56836
|
-
|
|
57026
|
+
logger23.debug("Retrieved progress", { userId: user.id });
|
|
56837
57027
|
return {
|
|
56838
57028
|
level: userLevel.currentLevel,
|
|
56839
57029
|
currentXp: userLevel.currentXp,
|
|
@@ -56867,7 +57057,7 @@ class LevelService {
|
|
|
56867
57057
|
if (leveledUp && previousUserLevel) {
|
|
56868
57058
|
await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
|
|
56869
57059
|
}
|
|
56870
|
-
|
|
57060
|
+
logger23.info("Synced from Timeback", {
|
|
56871
57061
|
userId,
|
|
56872
57062
|
totalXP,
|
|
56873
57063
|
currentLevel,
|
|
@@ -56908,7 +57098,7 @@ class LevelService {
|
|
|
56908
57098
|
}
|
|
56909
57099
|
if (totalCredits > 0) {
|
|
56910
57100
|
await this.deps.addCredits(userId, totalCredits);
|
|
56911
|
-
|
|
57101
|
+
logger23.info("Awarded level-up credits", {
|
|
56912
57102
|
userId,
|
|
56913
57103
|
fromLevel,
|
|
56914
57104
|
toLevel,
|
|
@@ -56946,7 +57136,7 @@ class LevelService {
|
|
|
56946
57136
|
};
|
|
56947
57137
|
}
|
|
56948
57138
|
}
|
|
56949
|
-
var
|
|
57139
|
+
var logger23;
|
|
56950
57140
|
var levelConfigCache = null;
|
|
56951
57141
|
var init_level_service = __esm(() => {
|
|
56952
57142
|
init_drizzle_orm();
|
|
@@ -56954,7 +57144,7 @@ var init_level_service = __esm(() => {
|
|
|
56954
57144
|
init_tables_index();
|
|
56955
57145
|
init_src2();
|
|
56956
57146
|
init_errors();
|
|
56957
|
-
|
|
57147
|
+
logger23 = log.scope("LevelService");
|
|
56958
57148
|
});
|
|
56959
57149
|
var init_events = () => {};
|
|
56960
57150
|
function convertWebSocketUrlToHttp(wsUrl) {
|
|
@@ -56971,13 +57161,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
|
|
|
56971
57161
|
});
|
|
56972
57162
|
if (!res.ok) {
|
|
56973
57163
|
const text3 = await res.text().catch(() => "");
|
|
56974
|
-
|
|
57164
|
+
logger24.warn("Failed to publish to user", {
|
|
56975
57165
|
status: res.status,
|
|
56976
57166
|
body: text3
|
|
56977
57167
|
});
|
|
56978
57168
|
}
|
|
56979
57169
|
} catch (error) {
|
|
56980
|
-
|
|
57170
|
+
logger24.error("Publish to user error", { error });
|
|
56981
57171
|
}
|
|
56982
57172
|
}
|
|
56983
57173
|
|
|
@@ -56999,7 +57189,7 @@ class NotificationService {
|
|
|
56999
57189
|
conditions2.push(eq(notifications.type, type));
|
|
57000
57190
|
}
|
|
57001
57191
|
const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
|
|
57002
|
-
|
|
57192
|
+
logger24.debug("Listed notifications", { userId: user.id, count: results.length });
|
|
57003
57193
|
return results;
|
|
57004
57194
|
}
|
|
57005
57195
|
async updateStatus(notificationId, status, method) {
|
|
@@ -57018,7 +57208,7 @@ class NotificationService {
|
|
|
57018
57208
|
if (!updated) {
|
|
57019
57209
|
throw new NotFoundError("Notification", notificationId);
|
|
57020
57210
|
}
|
|
57021
|
-
|
|
57211
|
+
logger24.debug("Updated status", { notificationId, status });
|
|
57022
57212
|
return updated;
|
|
57023
57213
|
}
|
|
57024
57214
|
async getStats(user, options) {
|
|
@@ -57044,7 +57234,7 @@ class NotificationService {
|
|
|
57044
57234
|
const clicked = statsMap.clicked || 0;
|
|
57045
57235
|
const dismissed = statsMap.dismissed || 0;
|
|
57046
57236
|
const expired = statsMap.expired || 0;
|
|
57047
|
-
|
|
57237
|
+
logger24.debug("Retrieved stats", { userId: user.id, total });
|
|
57048
57238
|
return {
|
|
57049
57239
|
total,
|
|
57050
57240
|
delivered,
|
|
@@ -57093,7 +57283,7 @@ class NotificationService {
|
|
|
57093
57283
|
options: { data, clickUrl, metadata: metadata2 }
|
|
57094
57284
|
});
|
|
57095
57285
|
}
|
|
57096
|
-
|
|
57286
|
+
logger24.debug("Created notification", {
|
|
57097
57287
|
userId,
|
|
57098
57288
|
type,
|
|
57099
57289
|
id: notificationId,
|
|
@@ -57101,7 +57291,7 @@ class NotificationService {
|
|
|
57101
57291
|
});
|
|
57102
57292
|
return notificationId;
|
|
57103
57293
|
} catch (error) {
|
|
57104
|
-
|
|
57294
|
+
logger24.error("Failed to create notification", { userId, type, error });
|
|
57105
57295
|
return null;
|
|
57106
57296
|
}
|
|
57107
57297
|
}
|
|
@@ -57115,7 +57305,7 @@ class NotificationService {
|
|
|
57115
57305
|
}) {
|
|
57116
57306
|
const realtimeConfig = this.deps.realtime;
|
|
57117
57307
|
if (!realtimeConfig) {
|
|
57118
|
-
|
|
57308
|
+
logger24.warn("No realtime config for publish");
|
|
57119
57309
|
return;
|
|
57120
57310
|
}
|
|
57121
57311
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -57157,13 +57347,13 @@ class NotificationService {
|
|
|
57157
57347
|
metadata: data.metadata || {}
|
|
57158
57348
|
}).returning();
|
|
57159
57349
|
if (!notification) {
|
|
57160
|
-
|
|
57350
|
+
logger24.error("Notification insert returned no rows", {
|
|
57161
57351
|
userId: data.userId,
|
|
57162
57352
|
type: data.type
|
|
57163
57353
|
});
|
|
57164
57354
|
throw new InternalError("Failed to create notification");
|
|
57165
57355
|
}
|
|
57166
|
-
|
|
57356
|
+
logger24.info("Inserted notification", {
|
|
57167
57357
|
notificationId: notification.id,
|
|
57168
57358
|
userId: notification.userId,
|
|
57169
57359
|
type: notification.type
|
|
@@ -57173,7 +57363,7 @@ class NotificationService {
|
|
|
57173
57363
|
async deliverPending(userId) {
|
|
57174
57364
|
const realtimeConfig = this.deps.realtime;
|
|
57175
57365
|
if (!realtimeConfig) {
|
|
57176
|
-
|
|
57366
|
+
logger24.warn("No realtime config for delivery");
|
|
57177
57367
|
return;
|
|
57178
57368
|
}
|
|
57179
57369
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -57200,13 +57390,13 @@ class NotificationService {
|
|
|
57200
57390
|
metadata: notification.metadata,
|
|
57201
57391
|
clickUrl: notification.clickUrl
|
|
57202
57392
|
});
|
|
57203
|
-
|
|
57393
|
+
logger24.info("Delivered notification", {
|
|
57204
57394
|
notificationId: notification.id,
|
|
57205
57395
|
userId,
|
|
57206
57396
|
type: notification.type
|
|
57207
57397
|
});
|
|
57208
57398
|
} catch (error) {
|
|
57209
|
-
|
|
57399
|
+
logger24.warn("Failed to deliver", {
|
|
57210
57400
|
notificationId: notification.id,
|
|
57211
57401
|
error
|
|
57212
57402
|
});
|
|
@@ -57214,7 +57404,7 @@ class NotificationService {
|
|
|
57214
57404
|
}
|
|
57215
57405
|
}
|
|
57216
57406
|
}
|
|
57217
|
-
var
|
|
57407
|
+
var logger24;
|
|
57218
57408
|
var init_notification_service = __esm(() => {
|
|
57219
57409
|
init_drizzle_orm();
|
|
57220
57410
|
init_src();
|
|
@@ -57223,7 +57413,7 @@ var init_notification_service = __esm(() => {
|
|
|
57223
57413
|
init_events();
|
|
57224
57414
|
init_notification();
|
|
57225
57415
|
init_errors();
|
|
57226
|
-
|
|
57416
|
+
logger24 = log.scope("NotificationService");
|
|
57227
57417
|
});
|
|
57228
57418
|
function createPlayerServices(deps) {
|
|
57229
57419
|
const { db: db2, realtime } = deps;
|
|
@@ -57342,7 +57532,7 @@ class CharacterService {
|
|
|
57342
57532
|
createdAt: characterComponents.createdAt,
|
|
57343
57533
|
updatedAt: characterComponents.updatedAt
|
|
57344
57534
|
}).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
|
|
57345
|
-
|
|
57535
|
+
logger25.debug("Listed available components", {
|
|
57346
57536
|
level,
|
|
57347
57537
|
count: components.length
|
|
57348
57538
|
});
|
|
@@ -57360,7 +57550,7 @@ class CharacterService {
|
|
|
57360
57550
|
}
|
|
57361
57551
|
}
|
|
57362
57552
|
});
|
|
57363
|
-
|
|
57553
|
+
logger25.debug("Retrieved character", { userId: user.id, found: Boolean(pc3) });
|
|
57364
57554
|
return pc3 ?? null;
|
|
57365
57555
|
}
|
|
57366
57556
|
async getByUserId(userId) {
|
|
@@ -57375,7 +57565,7 @@ class CharacterService {
|
|
|
57375
57565
|
}
|
|
57376
57566
|
}
|
|
57377
57567
|
});
|
|
57378
|
-
|
|
57568
|
+
logger25.debug("Retrieved character by ID", { userId, found: Boolean(pc3) });
|
|
57379
57569
|
return pc3 ?? null;
|
|
57380
57570
|
}
|
|
57381
57571
|
async create(input, user) {
|
|
@@ -57390,13 +57580,13 @@ class CharacterService {
|
|
|
57390
57580
|
}
|
|
57391
57581
|
const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
|
|
57392
57582
|
if (!characterRow) {
|
|
57393
|
-
|
|
57583
|
+
logger25.error("Character insert returned no rows", { userId: user.id });
|
|
57394
57584
|
throw new InternalError("Failed to create character in database");
|
|
57395
57585
|
}
|
|
57396
57586
|
await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
|
|
57397
57587
|
return characterRow;
|
|
57398
57588
|
});
|
|
57399
|
-
|
|
57589
|
+
logger25.info("Created character", { userId: user.id, characterId: result.id });
|
|
57400
57590
|
return result;
|
|
57401
57591
|
}
|
|
57402
57592
|
async update(input, user) {
|
|
@@ -57408,7 +57598,7 @@ class CharacterService {
|
|
|
57408
57598
|
if (!row) {
|
|
57409
57599
|
throw new NotFoundError("Player character");
|
|
57410
57600
|
}
|
|
57411
|
-
|
|
57601
|
+
logger25.info("Updated character", {
|
|
57412
57602
|
userId: user.id,
|
|
57413
57603
|
characterId: row.id,
|
|
57414
57604
|
updatedFields: Object.keys(input)
|
|
@@ -57430,7 +57620,7 @@ class CharacterService {
|
|
|
57430
57620
|
const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
|
|
57431
57621
|
const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
|
|
57432
57622
|
if (!validation.isValid) {
|
|
57433
|
-
|
|
57623
|
+
logger25.warn("Accessory validation failed", {
|
|
57434
57624
|
userId: user.id,
|
|
57435
57625
|
slot,
|
|
57436
57626
|
accessoryComponentId,
|
|
@@ -57446,14 +57636,14 @@ class CharacterService {
|
|
|
57446
57636
|
slot
|
|
57447
57637
|
}).returning();
|
|
57448
57638
|
if (!result) {
|
|
57449
|
-
|
|
57639
|
+
logger25.error("Accessory insert returned no rows", {
|
|
57450
57640
|
userId: user.id,
|
|
57451
57641
|
slot,
|
|
57452
57642
|
accessoryComponentId
|
|
57453
57643
|
});
|
|
57454
57644
|
throw new InternalError("Failed to equip accessory");
|
|
57455
57645
|
}
|
|
57456
|
-
|
|
57646
|
+
logger25.info("Equipped accessory", {
|
|
57457
57647
|
userId: user.id,
|
|
57458
57648
|
slot,
|
|
57459
57649
|
accessoryComponentId
|
|
@@ -57474,7 +57664,7 @@ class CharacterService {
|
|
|
57474
57664
|
const playerLevel = userLevel?.currentLevel ?? 1;
|
|
57475
57665
|
const validation = validateAccessoryRemoval(slot, playerLevel);
|
|
57476
57666
|
if (!validation.isValid) {
|
|
57477
|
-
|
|
57667
|
+
logger25.warn("Accessory removal validation failed", {
|
|
57478
57668
|
userId: user.id,
|
|
57479
57669
|
slot,
|
|
57480
57670
|
playerLevel,
|
|
@@ -57483,17 +57673,17 @@ class CharacterService {
|
|
|
57483
57673
|
throw new ValidationError(validation.error ?? "Invalid accessory removal");
|
|
57484
57674
|
}
|
|
57485
57675
|
await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
|
|
57486
|
-
|
|
57676
|
+
logger25.info("Removed accessory", { userId: user.id, slot });
|
|
57487
57677
|
}
|
|
57488
57678
|
}
|
|
57489
|
-
var
|
|
57679
|
+
var logger25;
|
|
57490
57680
|
var init_character_service = __esm(() => {
|
|
57491
57681
|
init_drizzle_orm();
|
|
57492
57682
|
init_tables_index();
|
|
57493
57683
|
init_src2();
|
|
57494
57684
|
init_errors();
|
|
57495
57685
|
init_accessory_util();
|
|
57496
|
-
|
|
57686
|
+
logger25 = log.scope("CharacterService");
|
|
57497
57687
|
});
|
|
57498
57688
|
|
|
57499
57689
|
class CurrencyService {
|
|
@@ -57504,7 +57694,7 @@ class CurrencyService {
|
|
|
57504
57694
|
async list() {
|
|
57505
57695
|
const db2 = this.deps.db;
|
|
57506
57696
|
const allCurrencies = await db2.query.currencies.findMany();
|
|
57507
|
-
|
|
57697
|
+
logger26.debug("Listed currencies", { count: allCurrencies.length });
|
|
57508
57698
|
return allCurrencies;
|
|
57509
57699
|
}
|
|
57510
57700
|
async getById(currencyId) {
|
|
@@ -57515,7 +57705,7 @@ class CurrencyService {
|
|
|
57515
57705
|
if (!currency) {
|
|
57516
57706
|
throw new NotFoundError("Currency", currencyId);
|
|
57517
57707
|
}
|
|
57518
|
-
|
|
57708
|
+
logger26.debug("Retrieved currency", { currencyId });
|
|
57519
57709
|
return currency;
|
|
57520
57710
|
}
|
|
57521
57711
|
async create(data) {
|
|
@@ -57523,13 +57713,13 @@ class CurrencyService {
|
|
|
57523
57713
|
try {
|
|
57524
57714
|
const [newCurrency] = await db2.insert(currencies).values(data).returning();
|
|
57525
57715
|
if (!newCurrency) {
|
|
57526
|
-
|
|
57716
|
+
logger26.error("Currency insert returned no rows", {
|
|
57527
57717
|
itemId: data.itemId,
|
|
57528
57718
|
symbol: data.symbol
|
|
57529
57719
|
});
|
|
57530
57720
|
throw new InternalError("Failed to create currency");
|
|
57531
57721
|
}
|
|
57532
|
-
|
|
57722
|
+
logger26.info("Created currency", {
|
|
57533
57723
|
currencyId: newCurrency.id,
|
|
57534
57724
|
itemId: newCurrency.itemId,
|
|
57535
57725
|
symbol: newCurrency.symbol,
|
|
@@ -57558,7 +57748,7 @@ class CurrencyService {
|
|
|
57558
57748
|
if (!updatedCurrency) {
|
|
57559
57749
|
throw new NotFoundError("Currency", currencyId);
|
|
57560
57750
|
}
|
|
57561
|
-
|
|
57751
|
+
logger26.info("Updated currency", {
|
|
57562
57752
|
currencyId: updatedCurrency.id,
|
|
57563
57753
|
updatedFields: Object.keys(data)
|
|
57564
57754
|
});
|
|
@@ -57584,16 +57774,16 @@ class CurrencyService {
|
|
|
57584
57774
|
if (result.length === 0) {
|
|
57585
57775
|
throw new NotFoundError("Currency", currencyId);
|
|
57586
57776
|
}
|
|
57587
|
-
|
|
57777
|
+
logger26.info("Deleted currency", { currencyId });
|
|
57588
57778
|
}
|
|
57589
57779
|
}
|
|
57590
|
-
var
|
|
57780
|
+
var logger26;
|
|
57591
57781
|
var init_currency_service = __esm(() => {
|
|
57592
57782
|
init_drizzle_orm();
|
|
57593
57783
|
init_tables_index();
|
|
57594
57784
|
init_src2();
|
|
57595
57785
|
init_errors();
|
|
57596
|
-
|
|
57786
|
+
logger26 = log.scope("CurrencyService");
|
|
57597
57787
|
});
|
|
57598
57788
|
|
|
57599
57789
|
class LogsService {
|
|
@@ -57611,11 +57801,11 @@ class LogsService {
|
|
|
57611
57801
|
if (!game) {
|
|
57612
57802
|
throw new NotFoundError("Game", slug2);
|
|
57613
57803
|
}
|
|
57614
|
-
|
|
57804
|
+
logger27.info("Admin accessing game logs", { adminId: user.id, slug: slug2, environment });
|
|
57615
57805
|
} else {
|
|
57616
57806
|
const isApprovedDev = user.developerStatus === "approved";
|
|
57617
57807
|
if (!isApprovedDev) {
|
|
57618
|
-
|
|
57808
|
+
logger27.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
|
|
57619
57809
|
throw new AccessDeniedError("Must be an approved developer");
|
|
57620
57810
|
}
|
|
57621
57811
|
const game = await db2.query.games.findFirst({
|
|
@@ -57623,7 +57813,7 @@ class LogsService {
|
|
|
57623
57813
|
columns: { id: true }
|
|
57624
57814
|
});
|
|
57625
57815
|
if (!game) {
|
|
57626
|
-
|
|
57816
|
+
logger27.warn("Developer attempted access to unowned game logs", {
|
|
57627
57817
|
userId: user.id,
|
|
57628
57818
|
slug: slug2
|
|
57629
57819
|
});
|
|
@@ -57633,7 +57823,7 @@ class LogsService {
|
|
|
57633
57823
|
const isProduction3 = environment === "production";
|
|
57634
57824
|
const workerId = getDeploymentId(slug2, isProduction3);
|
|
57635
57825
|
const token = await this.deps.mintLogStreamToken(user.id, workerId);
|
|
57636
|
-
|
|
57826
|
+
logger27.debug("Generated log stream token", {
|
|
57637
57827
|
userId: user.id,
|
|
57638
57828
|
slug: slug2,
|
|
57639
57829
|
workerId
|
|
@@ -57641,14 +57831,14 @@ class LogsService {
|
|
|
57641
57831
|
return { token, workerId };
|
|
57642
57832
|
}
|
|
57643
57833
|
}
|
|
57644
|
-
var
|
|
57834
|
+
var logger27;
|
|
57645
57835
|
var init_logs_service = __esm(() => {
|
|
57646
57836
|
init_drizzle_orm();
|
|
57647
57837
|
init_tables_index();
|
|
57648
57838
|
init_src2();
|
|
57649
57839
|
init_errors();
|
|
57650
57840
|
init_deployment_util();
|
|
57651
|
-
|
|
57841
|
+
logger27 = log.scope("LogsService");
|
|
57652
57842
|
});
|
|
57653
57843
|
|
|
57654
57844
|
class LtiService {
|
|
@@ -57699,7 +57889,7 @@ class MapService {
|
|
|
57699
57889
|
if (!mapDetails) {
|
|
57700
57890
|
throw new NotFoundError("Map", identifier);
|
|
57701
57891
|
}
|
|
57702
|
-
|
|
57892
|
+
logger28.debug("Retrieved map", { identifier });
|
|
57703
57893
|
return mapDetails;
|
|
57704
57894
|
}
|
|
57705
57895
|
async getElements(mapId) {
|
|
@@ -57715,7 +57905,7 @@ class MapService {
|
|
|
57715
57905
|
}
|
|
57716
57906
|
}
|
|
57717
57907
|
});
|
|
57718
|
-
|
|
57908
|
+
logger28.debug("Retrieved elements", { mapId, count: elements.length });
|
|
57719
57909
|
return elements;
|
|
57720
57910
|
}
|
|
57721
57911
|
async getObjects(mapId, userId) {
|
|
@@ -57736,7 +57926,7 @@ class MapService {
|
|
|
57736
57926
|
}
|
|
57737
57927
|
}
|
|
57738
57928
|
});
|
|
57739
|
-
|
|
57929
|
+
logger28.debug("Retrieved objects", { mapId, userId, count: objects.length });
|
|
57740
57930
|
return objects.map((object) => this.formatMapObjectWithItem(object));
|
|
57741
57931
|
}
|
|
57742
57932
|
async createObject(mapId, data, user) {
|
|
@@ -57763,7 +57953,7 @@ class MapService {
|
|
|
57763
57953
|
throw new NotFoundError("Item", data.itemId);
|
|
57764
57954
|
}
|
|
57765
57955
|
if (!item.isPlaceable) {
|
|
57766
|
-
|
|
57956
|
+
logger28.warn("Attempted to place non-placeable item", {
|
|
57767
57957
|
userId: user.id,
|
|
57768
57958
|
itemId: data.itemId,
|
|
57769
57959
|
mapId
|
|
@@ -57777,7 +57967,7 @@ class MapService {
|
|
|
57777
57967
|
};
|
|
57778
57968
|
const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
|
|
57779
57969
|
if (!createdObject) {
|
|
57780
|
-
|
|
57970
|
+
logger28.error("Map object insert returned no rows", {
|
|
57781
57971
|
userId: user.id,
|
|
57782
57972
|
mapId,
|
|
57783
57973
|
itemId: data.itemId
|
|
@@ -57801,12 +57991,12 @@ class MapService {
|
|
|
57801
57991
|
}
|
|
57802
57992
|
});
|
|
57803
57993
|
if (!objectWithItem) {
|
|
57804
|
-
|
|
57994
|
+
logger28.error("Map object query after insert returned no rows", {
|
|
57805
57995
|
objectId: createdObject.id
|
|
57806
57996
|
});
|
|
57807
57997
|
throw new InternalError("Failed to retrieve created object");
|
|
57808
57998
|
}
|
|
57809
|
-
|
|
57999
|
+
logger28.info("Created object", {
|
|
57810
58000
|
userId: user.id,
|
|
57811
58001
|
mapId,
|
|
57812
58002
|
objectId: createdObject.id,
|
|
@@ -57830,7 +58020,7 @@ class MapService {
|
|
|
57830
58020
|
if (result.length === 0) {
|
|
57831
58021
|
throw new NotFoundError("MapObject", objectId);
|
|
57832
58022
|
}
|
|
57833
|
-
|
|
58023
|
+
logger28.info("Deleted object", {
|
|
57834
58024
|
userId: user.id,
|
|
57835
58025
|
mapId,
|
|
57836
58026
|
objectId
|
|
@@ -57859,13 +58049,13 @@ class MapService {
|
|
|
57859
58049
|
};
|
|
57860
58050
|
}
|
|
57861
58051
|
}
|
|
57862
|
-
var
|
|
58052
|
+
var logger28;
|
|
57863
58053
|
var init_map_service = __esm(() => {
|
|
57864
58054
|
init_drizzle_orm();
|
|
57865
58055
|
init_tables_index();
|
|
57866
58056
|
init_src2();
|
|
57867
58057
|
init_errors();
|
|
57868
|
-
|
|
58058
|
+
logger28 = log.scope("MapService");
|
|
57869
58059
|
});
|
|
57870
58060
|
|
|
57871
58061
|
class RealtimeService {
|
|
@@ -57899,20 +58089,20 @@ class RealtimeService {
|
|
|
57899
58089
|
}
|
|
57900
58090
|
const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
|
|
57901
58091
|
const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
|
|
57902
|
-
|
|
58092
|
+
logger29.info("Generated token", {
|
|
57903
58093
|
userId: user.id,
|
|
57904
58094
|
gameId: resolvedGameId || "global"
|
|
57905
58095
|
});
|
|
57906
58096
|
return { token };
|
|
57907
58097
|
}
|
|
57908
58098
|
}
|
|
57909
|
-
var
|
|
58099
|
+
var logger29;
|
|
57910
58100
|
var init_realtime_service = __esm(() => {
|
|
57911
58101
|
init_drizzle_orm();
|
|
57912
58102
|
init_tables_index();
|
|
57913
58103
|
init_src2();
|
|
57914
58104
|
init_errors();
|
|
57915
|
-
|
|
58105
|
+
logger29 = log.scope("RealtimeService");
|
|
57916
58106
|
});
|
|
57917
58107
|
|
|
57918
58108
|
class SessionService {
|
|
@@ -57946,10 +58136,10 @@ class SessionService {
|
|
|
57946
58136
|
};
|
|
57947
58137
|
const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
|
|
57948
58138
|
if (!newSession?.sessionId) {
|
|
57949
|
-
|
|
58139
|
+
logger30.error("Game session insert returned no rows", { userId, gameId });
|
|
57950
58140
|
throw new InternalError("Failed to create game session");
|
|
57951
58141
|
}
|
|
57952
|
-
|
|
58142
|
+
logger30.info("Started new session", {
|
|
57953
58143
|
sessionId: newSession.sessionId,
|
|
57954
58144
|
gameId,
|
|
57955
58145
|
userId
|
|
@@ -57970,23 +58160,23 @@ class SessionService {
|
|
|
57970
58160
|
return { success: true, message: "Session already ended" };
|
|
57971
58161
|
}
|
|
57972
58162
|
await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
|
|
57973
|
-
|
|
58163
|
+
logger30.info("Ended session", { sessionId, gameId, userId });
|
|
57974
58164
|
return { success: true };
|
|
57975
58165
|
}
|
|
57976
58166
|
async mintToken(gameIdOrSlug, userId) {
|
|
57977
58167
|
const gameId = await this.resolveGameId(gameIdOrSlug);
|
|
57978
58168
|
const result = await this.deps.mintGameToken(gameId, userId);
|
|
57979
|
-
|
|
58169
|
+
logger30.debug("Minted game token", { gameId, userId });
|
|
57980
58170
|
return result;
|
|
57981
58171
|
}
|
|
57982
58172
|
}
|
|
57983
|
-
var
|
|
58173
|
+
var logger30;
|
|
57984
58174
|
var init_session_service = __esm(() => {
|
|
57985
58175
|
init_drizzle_orm();
|
|
57986
58176
|
init_tables_index();
|
|
57987
58177
|
init_src2();
|
|
57988
58178
|
init_errors();
|
|
57989
|
-
|
|
58179
|
+
logger30 = log.scope("SessionService");
|
|
57990
58180
|
});
|
|
57991
58181
|
|
|
57992
58182
|
class ShopService {
|
|
@@ -58031,7 +58221,7 @@ class ShopService {
|
|
|
58031
58221
|
const shopItems = [];
|
|
58032
58222
|
for (const listing of listingsWithRelations) {
|
|
58033
58223
|
if (!listing.item || !listing.currency) {
|
|
58034
|
-
|
|
58224
|
+
logger31.warn("Listing missing item or currency, skipping", {
|
|
58035
58225
|
listingId: listing.id
|
|
58036
58226
|
});
|
|
58037
58227
|
} else {
|
|
@@ -58048,7 +58238,7 @@ class ShopService {
|
|
|
58048
58238
|
});
|
|
58049
58239
|
}
|
|
58050
58240
|
}
|
|
58051
|
-
|
|
58241
|
+
logger31.debug("Retrieved shop view", {
|
|
58052
58242
|
userId: user.id,
|
|
58053
58243
|
itemCount: shopItems.length,
|
|
58054
58244
|
currencyCount: shopCurrencies.length
|
|
@@ -58059,12 +58249,12 @@ class ShopService {
|
|
|
58059
58249
|
};
|
|
58060
58250
|
}
|
|
58061
58251
|
}
|
|
58062
|
-
var
|
|
58252
|
+
var logger31;
|
|
58063
58253
|
var init_shop_service = __esm(() => {
|
|
58064
58254
|
init_drizzle_orm();
|
|
58065
58255
|
init_tables_index();
|
|
58066
58256
|
init_src2();
|
|
58067
|
-
|
|
58257
|
+
logger31 = log.scope("ShopService");
|
|
58068
58258
|
});
|
|
58069
58259
|
|
|
58070
58260
|
class SpriteService {
|
|
@@ -58080,17 +58270,17 @@ class SpriteService {
|
|
|
58080
58270
|
if (!template) {
|
|
58081
58271
|
throw new NotFoundError("SpriteTemplate", slug2);
|
|
58082
58272
|
}
|
|
58083
|
-
|
|
58273
|
+
logger32.debug("Retrieved sprite", { slug: slug2 });
|
|
58084
58274
|
return template;
|
|
58085
58275
|
}
|
|
58086
58276
|
}
|
|
58087
|
-
var
|
|
58277
|
+
var logger32;
|
|
58088
58278
|
var init_sprite_service = __esm(() => {
|
|
58089
58279
|
init_drizzle_orm();
|
|
58090
58280
|
init_tables_index();
|
|
58091
58281
|
init_src2();
|
|
58092
58282
|
init_errors();
|
|
58093
|
-
|
|
58283
|
+
logger32 = log.scope("SpriteService");
|
|
58094
58284
|
});
|
|
58095
58285
|
|
|
58096
58286
|
class UserService {
|
|
@@ -58104,12 +58294,12 @@ class UserService {
|
|
|
58104
58294
|
where: eq(users.id, user.id)
|
|
58105
58295
|
});
|
|
58106
58296
|
if (!userData) {
|
|
58107
|
-
|
|
58297
|
+
logger33.error("User not found", { userId: user.id });
|
|
58108
58298
|
throw new NotFoundError("User", user.id);
|
|
58109
58299
|
}
|
|
58110
58300
|
const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
|
|
58111
58301
|
if (gameId) {
|
|
58112
|
-
|
|
58302
|
+
logger33.debug("Fetched user profile (game context)", { userId: user.id, gameId });
|
|
58113
58303
|
return {
|
|
58114
58304
|
id: userData.id,
|
|
58115
58305
|
name: userData.name,
|
|
@@ -58122,7 +58312,7 @@ class UserService {
|
|
|
58122
58312
|
const timebackAccount = await db2.query.accounts.findFirst({
|
|
58123
58313
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
58124
58314
|
});
|
|
58125
|
-
|
|
58315
|
+
logger33.debug("Fetched user profile (platform context)", { userId: user.id });
|
|
58126
58316
|
return {
|
|
58127
58317
|
id: userData.id,
|
|
58128
58318
|
name: userData.name,
|
|
@@ -58145,7 +58335,7 @@ class UserService {
|
|
|
58145
58335
|
columns: { name: true }
|
|
58146
58336
|
});
|
|
58147
58337
|
if (!userData) {
|
|
58148
|
-
|
|
58338
|
+
logger33.error("Demo user not found", { userId });
|
|
58149
58339
|
throw new NotFoundError("User", userId);
|
|
58150
58340
|
}
|
|
58151
58341
|
return {
|
|
@@ -58159,10 +58349,10 @@ class UserService {
|
|
|
58159
58349
|
updatedAt: new Date
|
|
58160
58350
|
}).where(eq(users.id, userId)).returning({ name: users.name });
|
|
58161
58351
|
if (!updatedUser) {
|
|
58162
|
-
|
|
58352
|
+
logger33.error("Demo user not found for profile update", { userId });
|
|
58163
58353
|
throw new NotFoundError("User", userId);
|
|
58164
58354
|
}
|
|
58165
|
-
|
|
58355
|
+
logger33.debug("Updated demo profile", { userId, displayName });
|
|
58166
58356
|
return {
|
|
58167
58357
|
displayName: updatedUser.name,
|
|
58168
58358
|
isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
|
|
@@ -58175,7 +58365,7 @@ class UserService {
|
|
|
58175
58365
|
]);
|
|
58176
58366
|
const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
58177
58367
|
const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
58178
|
-
|
|
58368
|
+
logger33.debug("Fetched Timeback data", {
|
|
58179
58369
|
timebackId,
|
|
58180
58370
|
role,
|
|
58181
58371
|
enrollmentCount: enrollments.length,
|
|
@@ -58184,9 +58374,9 @@ class UserService {
|
|
|
58184
58374
|
return { id: timebackId, role, enrollments, organizations };
|
|
58185
58375
|
}
|
|
58186
58376
|
async fetchStudentProfile(timebackId) {
|
|
58187
|
-
|
|
58377
|
+
logger33.debug("Fetching student profile", { timebackId });
|
|
58188
58378
|
if (!this.deps.timeback) {
|
|
58189
|
-
|
|
58379
|
+
logger33.warn("Timeback client not available");
|
|
58190
58380
|
return { role: "student", organizations: [] };
|
|
58191
58381
|
}
|
|
58192
58382
|
try {
|
|
@@ -58214,14 +58404,14 @@ class UserService {
|
|
|
58214
58404
|
}
|
|
58215
58405
|
return { role, organizations: [...orgMap.values()] };
|
|
58216
58406
|
} catch (error) {
|
|
58217
|
-
|
|
58407
|
+
logger33.warn("Failed to fetch student profile", { error, timebackId });
|
|
58218
58408
|
return { role: "student", organizations: [] };
|
|
58219
58409
|
}
|
|
58220
58410
|
}
|
|
58221
58411
|
async fetchEnrollments(timebackId) {
|
|
58222
|
-
|
|
58412
|
+
logger33.debug("Fetching enrollments", { timebackId });
|
|
58223
58413
|
if (!this.deps.timeback) {
|
|
58224
|
-
|
|
58414
|
+
logger33.warn("Timeback client not available");
|
|
58225
58415
|
return [];
|
|
58226
58416
|
}
|
|
58227
58417
|
try {
|
|
@@ -58242,7 +58432,7 @@ class UserService {
|
|
|
58242
58432
|
orgId: courseToSchool.get(i2.courseId)
|
|
58243
58433
|
}));
|
|
58244
58434
|
} catch (error) {
|
|
58245
|
-
|
|
58435
|
+
logger33.warn("Failed to fetch enrollments", { error, timebackId });
|
|
58246
58436
|
return [];
|
|
58247
58437
|
}
|
|
58248
58438
|
}
|
|
@@ -58257,14 +58447,14 @@ class UserService {
|
|
|
58257
58447
|
return organizations.filter((o) => enrollmentOrgIds.has(o.id));
|
|
58258
58448
|
}
|
|
58259
58449
|
}
|
|
58260
|
-
var
|
|
58450
|
+
var logger33;
|
|
58261
58451
|
var init_user_service = __esm(() => {
|
|
58262
58452
|
init_drizzle_orm();
|
|
58263
58453
|
init_src();
|
|
58264
58454
|
init_tables_index();
|
|
58265
58455
|
init_src2();
|
|
58266
58456
|
init_errors();
|
|
58267
|
-
|
|
58457
|
+
logger33 = log.scope("UserService");
|
|
58268
58458
|
});
|
|
58269
58459
|
|
|
58270
58460
|
class VerifyService {
|
|
@@ -58273,16 +58463,16 @@ class VerifyService {
|
|
|
58273
58463
|
this.deps = deps;
|
|
58274
58464
|
}
|
|
58275
58465
|
async verifyGameToken(token) {
|
|
58276
|
-
|
|
58466
|
+
logger34.debug("Verifying game token");
|
|
58277
58467
|
const payload = await this.deps.validateGameToken(token);
|
|
58278
58468
|
if (!payload) {
|
|
58279
|
-
|
|
58469
|
+
logger34.warn("Invalid or expired game token presented");
|
|
58280
58470
|
throw new ValidationError("Invalid or expired token");
|
|
58281
58471
|
}
|
|
58282
58472
|
const gameId = payload.sub;
|
|
58283
58473
|
const userId = payload.uid;
|
|
58284
58474
|
if (typeof gameId !== "string" || typeof userId !== "string") {
|
|
58285
|
-
|
|
58475
|
+
logger34.warn("Game token missing required claims", {
|
|
58286
58476
|
hasGameId: typeof gameId === "string",
|
|
58287
58477
|
hasUserId: typeof userId === "string"
|
|
58288
58478
|
});
|
|
@@ -58293,7 +58483,7 @@ class VerifyService {
|
|
|
58293
58483
|
where: eq(users.id, userId)
|
|
58294
58484
|
});
|
|
58295
58485
|
if (!userData) {
|
|
58296
|
-
|
|
58486
|
+
logger34.error("User not found for valid token", {
|
|
58297
58487
|
userId
|
|
58298
58488
|
});
|
|
58299
58489
|
throw new NotFoundError("User", userId);
|
|
@@ -58307,7 +58497,7 @@ class VerifyService {
|
|
|
58307
58497
|
family_name: undefined,
|
|
58308
58498
|
timeback_id: userData.timebackId || undefined
|
|
58309
58499
|
};
|
|
58310
|
-
|
|
58500
|
+
logger34.info("Token verified", { gameId, userId });
|
|
58311
58501
|
return {
|
|
58312
58502
|
claims: payload,
|
|
58313
58503
|
gameId,
|
|
@@ -58315,13 +58505,13 @@ class VerifyService {
|
|
|
58315
58505
|
};
|
|
58316
58506
|
}
|
|
58317
58507
|
}
|
|
58318
|
-
var
|
|
58508
|
+
var logger34;
|
|
58319
58509
|
var init_verify_service = __esm(() => {
|
|
58320
58510
|
init_drizzle_orm();
|
|
58321
58511
|
init_tables_index();
|
|
58322
58512
|
init_src2();
|
|
58323
58513
|
init_errors();
|
|
58324
|
-
|
|
58514
|
+
logger34 = log.scope("VerifyService");
|
|
58325
58515
|
});
|
|
58326
58516
|
function createStandaloneServices(deps) {
|
|
58327
58517
|
const { db: db2, auth: auth2, timeback: timeback2 } = deps;
|
|
@@ -58939,7 +59129,6 @@ async function request({
|
|
|
58939
59129
|
method,
|
|
58940
59130
|
headers,
|
|
58941
59131
|
body: payload,
|
|
58942
|
-
credentials: "omit",
|
|
58943
59132
|
signal: controller.signal
|
|
58944
59133
|
});
|
|
58945
59134
|
clearTimeout(timeoutId);
|
|
@@ -59523,10 +59712,11 @@ function createOneRosterNamespace(client) {
|
|
|
59523
59712
|
const url = `${ONEROSTER_ENDPOINTS4.assessmentResults}?filter=${encodeURIComponent(filter)}`;
|
|
59524
59713
|
const response = await client["request"](url, "GET");
|
|
59525
59714
|
const results = response.assessmentResults || [];
|
|
59526
|
-
|
|
59715
|
+
const firstResult = results[0];
|
|
59716
|
+
if (!firstResult) {
|
|
59527
59717
|
return null;
|
|
59528
59718
|
}
|
|
59529
|
-
let maxAttemptResult =
|
|
59719
|
+
let maxAttemptResult = firstResult;
|
|
59530
59720
|
let maxAttemptNumber = maxAttemptResult.metadata?.attemptNumber || 0;
|
|
59531
59721
|
let activeAttemptCount = 0;
|
|
59532
59722
|
for (const result of results) {
|
|
@@ -59560,10 +59750,11 @@ function createOneRosterNamespace(client) {
|
|
|
59560
59750
|
if (!response || !response.users || !Array.isArray(response.users)) {
|
|
59561
59751
|
throw new Error(`Invalid response format from OneRoster API when searching for user with email: ${email}. Expected { users: [...] } but received: ${JSON.stringify(response)}`);
|
|
59562
59752
|
}
|
|
59563
|
-
|
|
59753
|
+
const user = response.users[0];
|
|
59754
|
+
if (!user) {
|
|
59564
59755
|
throw new Error(`User not found with email: ${email}. Ensure the user exists in OneRoster and has a valid email address. If this is a new user, they must be created in OneRoster first.`);
|
|
59565
59756
|
}
|
|
59566
|
-
return
|
|
59757
|
+
return user;
|
|
59567
59758
|
},
|
|
59568
59759
|
listBySourcedIds: async (sourcedIds, batchSize = 50) => {
|
|
59569
59760
|
if (sourcedIds.length === 0) {
|
|
@@ -59845,6 +60036,9 @@ class TimebackCache {
|
|
|
59845
60036
|
return;
|
|
59846
60037
|
}
|
|
59847
60038
|
const oldestKey = this.accessOrder[0];
|
|
60039
|
+
if (!oldestKey) {
|
|
60040
|
+
return;
|
|
60041
|
+
}
|
|
59848
60042
|
this.delete(oldestKey);
|
|
59849
60043
|
log.debug(`[${this.name}] Evicted LRU entry`, { key: oldestKey });
|
|
59850
60044
|
}
|
|
@@ -59901,6 +60095,9 @@ class TimebackCacheManager {
|
|
|
59901
60095
|
setEnrollments(studentId, enrollments) {
|
|
59902
60096
|
this.enrollmentCache.set(studentId, enrollments);
|
|
59903
60097
|
}
|
|
60098
|
+
clearEnrollments(studentId) {
|
|
60099
|
+
return this.enrollmentCache.delete(studentId);
|
|
60100
|
+
}
|
|
59904
60101
|
clearAll() {
|
|
59905
60102
|
this.studentCache.clear();
|
|
59906
60103
|
this.assessmentLineItemCache.clear();
|
|
@@ -59939,6 +60136,41 @@ class MasteryTracker {
|
|
|
59939
60136
|
if (typeof masteredUnits !== "number" || masteredUnits <= 0) {
|
|
59940
60137
|
return;
|
|
59941
60138
|
}
|
|
60139
|
+
const status = await this.calculateStatus({
|
|
60140
|
+
studentId,
|
|
60141
|
+
courseId,
|
|
60142
|
+
resourceId,
|
|
60143
|
+
additionalMasteredUnits: masteredUnits
|
|
60144
|
+
});
|
|
60145
|
+
if (!status) {
|
|
60146
|
+
return;
|
|
60147
|
+
}
|
|
60148
|
+
return {
|
|
60149
|
+
pctCompleteApp: status.pctCompleteApp,
|
|
60150
|
+
masteryAchieved: status.historicalMasteredUnits < status.masterableUnits && status.isComplete
|
|
60151
|
+
};
|
|
60152
|
+
}
|
|
60153
|
+
async getStatus(input) {
|
|
60154
|
+
const status = await this.calculateStatus({
|
|
60155
|
+
...input,
|
|
60156
|
+
additionalMasteredUnits: 0
|
|
60157
|
+
});
|
|
60158
|
+
if (!status) {
|
|
60159
|
+
return;
|
|
60160
|
+
}
|
|
60161
|
+
return {
|
|
60162
|
+
masteredUnits: status.masteredUnits,
|
|
60163
|
+
masterableUnits: status.masterableUnits,
|
|
60164
|
+
pctCompleteApp: status.pctCompleteApp,
|
|
60165
|
+
isComplete: status.isComplete
|
|
60166
|
+
};
|
|
60167
|
+
}
|
|
60168
|
+
async calculateStatus({
|
|
60169
|
+
studentId,
|
|
60170
|
+
courseId,
|
|
60171
|
+
resourceId,
|
|
60172
|
+
additionalMasteredUnits
|
|
60173
|
+
}) {
|
|
59942
60174
|
const masterableUnits = await this.resolveMasterableUnits(resourceId);
|
|
59943
60175
|
if (!masterableUnits || masterableUnits <= 0) {
|
|
59944
60176
|
log.warn("[MasteryTracker] No masterableUnits configured for course", {
|
|
@@ -59956,11 +60188,16 @@ class MasteryTracker {
|
|
|
59956
60188
|
return;
|
|
59957
60189
|
}
|
|
59958
60190
|
const historicalMasteredUnits = this.sumAnalyticsMetric(facts, "masteredUnits");
|
|
59959
|
-
const totalMastered = historicalMasteredUnits +
|
|
60191
|
+
const totalMastered = historicalMasteredUnits + additionalMasteredUnits;
|
|
59960
60192
|
const rawPct = totalMastered / masterableUnits * 100;
|
|
59961
60193
|
const pctCompleteApp = Math.min(100, Math.max(0, Math.round(rawPct)));
|
|
59962
|
-
|
|
59963
|
-
|
|
60194
|
+
return {
|
|
60195
|
+
masteredUnits: totalMastered,
|
|
60196
|
+
masterableUnits,
|
|
60197
|
+
pctCompleteApp,
|
|
60198
|
+
isComplete: totalMastered >= masterableUnits,
|
|
60199
|
+
historicalMasteredUnits
|
|
60200
|
+
};
|
|
59964
60201
|
}
|
|
59965
60202
|
async createCompletionEntry(studentId, courseId, classId, appName) {
|
|
59966
60203
|
const ids = deriveSourcedIds2(courseId);
|
|
@@ -60556,6 +60793,7 @@ class TimebackClient {
|
|
|
60556
60793
|
progressRecorder;
|
|
60557
60794
|
sessionRecorder;
|
|
60558
60795
|
adminEventRecorder;
|
|
60796
|
+
masteryTracker;
|
|
60559
60797
|
constructor(config2) {
|
|
60560
60798
|
this.baseUrl = TimebackClient.resolveBaseUrl(config2?.baseUrl);
|
|
60561
60799
|
this.environment = process.env[ENV_VARS4.environment] === "staging" ? "staging" : "production";
|
|
@@ -60573,8 +60811,8 @@ class TimebackClient {
|
|
|
60573
60811
|
this.edubridge = createEduBridgeNamespace(this);
|
|
60574
60812
|
this.cacheManager = new TimebackCacheManager;
|
|
60575
60813
|
this.studentResolver = new StudentResolver(this.cacheManager, this.oneroster);
|
|
60576
|
-
|
|
60577
|
-
this.progressRecorder = new ProgressRecorder(this.studentResolver, this.cacheManager, this.oneroster, this.caliper, masteryTracker);
|
|
60814
|
+
this.masteryTracker = new MasteryTracker(this.cacheManager, this.oneroster, this.edubridge);
|
|
60815
|
+
this.progressRecorder = new ProgressRecorder(this.studentResolver, this.cacheManager, this.oneroster, this.caliper, this.masteryTracker);
|
|
60578
60816
|
this.sessionRecorder = new SessionRecorder(this.studentResolver, this.caliper);
|
|
60579
60817
|
this.adminEventRecorder = new AdminEventRecorder(this.studentResolver, this.oneroster, this.caliper, this.environment);
|
|
60580
60818
|
if (this.credentials) {
|
|
@@ -60732,6 +60970,18 @@ class TimebackClient {
|
|
|
60732
60970
|
this.cacheManager.setEnrollments(studentId, enrollments);
|
|
60733
60971
|
return enrollments;
|
|
60734
60972
|
}
|
|
60973
|
+
invalidateEnrollments(studentId) {
|
|
60974
|
+
this.cacheManager.clearEnrollments(studentId);
|
|
60975
|
+
}
|
|
60976
|
+
async getMasteryStatus(courseId, studentId) {
|
|
60977
|
+
await this._ensureAuthenticated();
|
|
60978
|
+
const ids = deriveSourcedIds2(courseId);
|
|
60979
|
+
return this.masteryTracker.getStatus({
|
|
60980
|
+
studentId,
|
|
60981
|
+
courseId,
|
|
60982
|
+
resourceId: ids.resource
|
|
60983
|
+
});
|
|
60984
|
+
}
|
|
60735
60985
|
async getStudentXp(studentId, options) {
|
|
60736
60986
|
await this._ensureAuthenticated();
|
|
60737
60987
|
const enrollments = await this.edubridge.enrollments.listByUser(studentId);
|
|
@@ -63277,7 +63527,7 @@ var colorStatus = async (status) => {
|
|
|
63277
63527
|
}
|
|
63278
63528
|
return `${status}`;
|
|
63279
63529
|
};
|
|
63280
|
-
var
|
|
63530
|
+
var logger35 = (fn = console.log) => {
|
|
63281
63531
|
return async function logger2(c, next) {
|
|
63282
63532
|
const { method, url } = c.req;
|
|
63283
63533
|
const path2 = url.slice(url.indexOf("/", 8));
|
|
@@ -63454,7 +63704,7 @@ function createApp(db2, options) {
|
|
|
63454
63704
|
const app = new Hono2;
|
|
63455
63705
|
app.use("*", cors({ origin: "*", credentials: true }));
|
|
63456
63706
|
if (options.verbose && !options.quiet) {
|
|
63457
|
-
app.use("*",
|
|
63707
|
+
app.use("*", logger35());
|
|
63458
63708
|
}
|
|
63459
63709
|
app.use("/api/*", async (c, next) => {
|
|
63460
63710
|
c.set("db", db2);
|
|
@@ -70156,12 +70406,12 @@ var init_session2 = __esm(() => {
|
|
|
70156
70406
|
init_utils();
|
|
70157
70407
|
init_dist5();
|
|
70158
70408
|
PglitePreparedQuery = class PglitePreparedQuery2 extends PgPreparedQuery {
|
|
70159
|
-
constructor(client, queryString, params,
|
|
70409
|
+
constructor(client, queryString, params, logger36, fields, name3, _isResponseInArrayMode, customResultMapper) {
|
|
70160
70410
|
super({ sql: queryString, params });
|
|
70161
70411
|
this.client = client;
|
|
70162
70412
|
this.queryString = queryString;
|
|
70163
70413
|
this.params = params;
|
|
70164
|
-
this.logger =
|
|
70414
|
+
this.logger = logger36;
|
|
70165
70415
|
this.fields = fields;
|
|
70166
70416
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
70167
70417
|
this.customResultMapper = customResultMapper;
|
|
@@ -70263,11 +70513,11 @@ var init_session2 = __esm(() => {
|
|
|
70263
70513
|
});
|
|
70264
70514
|
function construct(client, config2 = {}) {
|
|
70265
70515
|
const dialect2 = new PgDialect({ casing: config2.casing });
|
|
70266
|
-
let
|
|
70516
|
+
let logger36;
|
|
70267
70517
|
if (config2.logger === true) {
|
|
70268
|
-
|
|
70518
|
+
logger36 = new DefaultLogger;
|
|
70269
70519
|
} else if (config2.logger !== false) {
|
|
70270
|
-
|
|
70520
|
+
logger36 = config2.logger;
|
|
70271
70521
|
}
|
|
70272
70522
|
let schema2;
|
|
70273
70523
|
if (config2.schema) {
|
|
@@ -70278,7 +70528,7 @@ function construct(client, config2 = {}) {
|
|
|
70278
70528
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
70279
70529
|
};
|
|
70280
70530
|
}
|
|
70281
|
-
const driver = new PgliteDriver(client, dialect2, { logger:
|
|
70531
|
+
const driver = new PgliteDriver(client, dialect2, { logger: logger36 });
|
|
70282
70532
|
const session2 = driver.createSession(schema2);
|
|
70283
70533
|
const db2 = new PgliteDatabase(dialect2, session2, schema2);
|
|
70284
70534
|
db2.$client = client;
|
|
@@ -118923,8 +119173,8 @@ var init_currencies = __esm(() => {
|
|
|
118923
119173
|
init_tables_index();
|
|
118924
119174
|
init_constants();
|
|
118925
119175
|
});
|
|
118926
|
-
function setLogger(
|
|
118927
|
-
customLogger =
|
|
119176
|
+
function setLogger(logger36) {
|
|
119177
|
+
customLogger = logger36;
|
|
118928
119178
|
}
|
|
118929
119179
|
function getLogger() {
|
|
118930
119180
|
if (customLogger) {
|
|
@@ -118937,10 +119187,10 @@ function getLogger() {
|
|
|
118937
119187
|
};
|
|
118938
119188
|
}
|
|
118939
119189
|
var customLogger;
|
|
118940
|
-
var
|
|
119190
|
+
var logger36;
|
|
118941
119191
|
var init_adapter = __esm(() => {
|
|
118942
119192
|
init_config();
|
|
118943
|
-
|
|
119193
|
+
logger36 = {
|
|
118944
119194
|
info: (msg) => {
|
|
118945
119195
|
if (customLogger || !config.embedded) {
|
|
118946
119196
|
getLogger().info(msg);
|
|
@@ -119020,7 +119270,7 @@ async function seedCoreGames(db2) {
|
|
|
119020
119270
|
try {
|
|
119021
119271
|
await db2.insert(games).values(gameData).onConflictDoNothing();
|
|
119022
119272
|
} catch (error2) {
|
|
119023
|
-
|
|
119273
|
+
logger36.error(`Error seeding core game '${gameData.slug}': ${error2}`);
|
|
119024
119274
|
}
|
|
119025
119275
|
}
|
|
119026
119276
|
}
|
|
@@ -119066,7 +119316,7 @@ async function seedCurrentProjectGame(db2, project) {
|
|
|
119066
119316
|
}
|
|
119067
119317
|
return newGame;
|
|
119068
119318
|
} catch (error2) {
|
|
119069
|
-
|
|
119319
|
+
logger36.error(`❌ Error seeding project game: ${error2}`);
|
|
119070
119320
|
throw error2;
|
|
119071
119321
|
}
|
|
119072
119322
|
}
|
|
@@ -120427,6 +120677,7 @@ var TimebackSubjectSchema;
|
|
|
120427
120677
|
var UpdateTimebackXpRequestSchema;
|
|
120428
120678
|
var TimebackActivityDataSchema;
|
|
120429
120679
|
var EndActivityRequestSchema;
|
|
120680
|
+
var AdvanceCourseRequestSchema;
|
|
120430
120681
|
var HeartbeatRequestSchema;
|
|
120431
120682
|
var PopulateStudentRequestSchema;
|
|
120432
120683
|
var DerivedPlatformCourseConfigSchema;
|
|
@@ -120494,6 +120745,11 @@ var init_schemas11 = __esm(() => {
|
|
|
120494
120745
|
masteredUnits: exports_external.number().nonnegative().optional(),
|
|
120495
120746
|
extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
120496
120747
|
});
|
|
120748
|
+
AdvanceCourseRequestSchema = exports_external.object({
|
|
120749
|
+
gameId: exports_external.string().uuid(),
|
|
120750
|
+
studentId: exports_external.string().min(1),
|
|
120751
|
+
subject: TimebackSubjectSchema.optional()
|
|
120752
|
+
});
|
|
120497
120753
|
HeartbeatRequestSchema = exports_external.object({
|
|
120498
120754
|
gameId: exports_external.string().uuid(),
|
|
120499
120755
|
studentId: exports_external.string().min(1),
|
|
@@ -120763,7 +121019,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120763
121019
|
where: eq(users.id, existingAccount.userId)
|
|
120764
121020
|
});
|
|
120765
121021
|
if (user) {
|
|
120766
|
-
|
|
121022
|
+
logger37.info("Found user by LTI account", {
|
|
120767
121023
|
userId: user.id,
|
|
120768
121024
|
ltiTimebackId
|
|
120769
121025
|
});
|
|
@@ -120792,13 +121048,13 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120792
121048
|
updatedAt: new Date
|
|
120793
121049
|
}).returning({ id: accounts.id });
|
|
120794
121050
|
if (!account) {
|
|
120795
|
-
|
|
121051
|
+
logger37.error("LTI account link insert returned no rows", {
|
|
120796
121052
|
userId: existingUser.id,
|
|
120797
121053
|
ltiTimebackId
|
|
120798
121054
|
});
|
|
120799
121055
|
throw new InternalError("Failed to link LTI account");
|
|
120800
121056
|
}
|
|
120801
|
-
|
|
121057
|
+
logger37.info("Linked LTI account to existing user", {
|
|
120802
121058
|
userId: existingUser.id,
|
|
120803
121059
|
ltiTimebackId
|
|
120804
121060
|
});
|
|
@@ -120818,7 +121074,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120818
121074
|
updatedAt: new Date
|
|
120819
121075
|
}).returning();
|
|
120820
121076
|
if (!insertedUser) {
|
|
120821
|
-
|
|
121077
|
+
logger37.error("LTI user insert returned no rows", { email, ltiTimebackId });
|
|
120822
121078
|
throw new InternalError("Failed to create user");
|
|
120823
121079
|
}
|
|
120824
121080
|
await tx.insert(accounts).values({
|
|
@@ -120833,7 +121089,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120833
121089
|
createdAt: new Date,
|
|
120834
121090
|
updatedAt: new Date
|
|
120835
121091
|
});
|
|
120836
|
-
|
|
121092
|
+
logger37.info("Provisioned new user from LTI", {
|
|
120837
121093
|
userId: insertedUser.id,
|
|
120838
121094
|
ltiTimebackId
|
|
120839
121095
|
});
|
|
@@ -120841,7 +121097,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
120841
121097
|
});
|
|
120842
121098
|
return createdUser;
|
|
120843
121099
|
}
|
|
120844
|
-
var
|
|
121100
|
+
var logger37;
|
|
120845
121101
|
var init_lti_provisioning = __esm(() => {
|
|
120846
121102
|
init_drizzle_orm();
|
|
120847
121103
|
init_src();
|
|
@@ -120849,7 +121105,7 @@ var init_lti_provisioning = __esm(() => {
|
|
|
120849
121105
|
init_src2();
|
|
120850
121106
|
init_errors();
|
|
120851
121107
|
init_lti_util();
|
|
120852
|
-
|
|
121108
|
+
logger37 = log.scope("LtiProvisioning");
|
|
120853
121109
|
});
|
|
120854
121110
|
function formatZodError(error2) {
|
|
120855
121111
|
const flat = error2.flatten();
|
|
@@ -120892,7 +121148,7 @@ var init_utils11 = __esm(() => {
|
|
|
120892
121148
|
init_timeback_util();
|
|
120893
121149
|
init_validation_util();
|
|
120894
121150
|
});
|
|
120895
|
-
var
|
|
121151
|
+
var logger38;
|
|
120896
121152
|
var listCurrent;
|
|
120897
121153
|
var listHistory;
|
|
120898
121154
|
var postProgress;
|
|
@@ -120903,14 +121159,14 @@ var init_achievement_controller = __esm(() => {
|
|
|
120903
121159
|
init_src2();
|
|
120904
121160
|
init_errors();
|
|
120905
121161
|
init_utils11();
|
|
120906
|
-
|
|
121162
|
+
logger38 = log.scope("AchievementController");
|
|
120907
121163
|
listCurrent = requireNonAnonymous(async (ctx) => {
|
|
120908
|
-
|
|
121164
|
+
logger38.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
120909
121165
|
return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
|
|
120910
121166
|
});
|
|
120911
121167
|
listHistory = requireNonAnonymous(async (ctx) => {
|
|
120912
121168
|
const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
|
|
120913
|
-
|
|
121169
|
+
logger38.debug("Listing achievement history", { userId: ctx.user.id, limit });
|
|
120914
121170
|
return ctx.services.achievement.listHistory(ctx.user, limit);
|
|
120915
121171
|
});
|
|
120916
121172
|
postProgress = requireNonAnonymous(async (ctx) => {
|
|
@@ -120921,12 +121177,12 @@ var init_achievement_controller = __esm(() => {
|
|
|
120921
121177
|
} catch (error2) {
|
|
120922
121178
|
if (error2 instanceof exports_external.ZodError) {
|
|
120923
121179
|
const details = formatZodError(error2);
|
|
120924
|
-
|
|
121180
|
+
logger38.warn("Submit achievement progress validation failed", { details });
|
|
120925
121181
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
120926
121182
|
}
|
|
120927
121183
|
throw ApiError.badRequest("Invalid JSON body");
|
|
120928
121184
|
}
|
|
120929
|
-
|
|
121185
|
+
logger38.debug("Submitting progress", {
|
|
120930
121186
|
userId: ctx.user.id,
|
|
120931
121187
|
achievementId: body2.achievementId
|
|
120932
121188
|
});
|
|
@@ -120938,15 +121194,15 @@ var init_achievement_controller = __esm(() => {
|
|
|
120938
121194
|
postProgress
|
|
120939
121195
|
};
|
|
120940
121196
|
});
|
|
120941
|
-
var
|
|
121197
|
+
var logger39;
|
|
120942
121198
|
var getAllowedOrigins;
|
|
120943
121199
|
var init_admin_controller = __esm(() => {
|
|
120944
121200
|
init_src2();
|
|
120945
121201
|
init_utils11();
|
|
120946
|
-
|
|
121202
|
+
logger39 = log.scope("AdminController");
|
|
120947
121203
|
getAllowedOrigins = requireAdmin(async (ctx) => {
|
|
120948
121204
|
const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
|
|
120949
|
-
|
|
121205
|
+
logger39.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
|
|
120950
121206
|
if (shouldRefresh) {
|
|
120951
121207
|
await ctx.providers.cache.refreshGameOrigins();
|
|
120952
121208
|
}
|
|
@@ -120959,7 +121215,7 @@ var init_admin_controller = __esm(() => {
|
|
|
120959
121215
|
};
|
|
120960
121216
|
});
|
|
120961
121217
|
});
|
|
120962
|
-
var
|
|
121218
|
+
var logger40;
|
|
120963
121219
|
var listFiles;
|
|
120964
121220
|
var getFile;
|
|
120965
121221
|
var putFile;
|
|
@@ -120971,7 +121227,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
120971
121227
|
init_src2();
|
|
120972
121228
|
init_errors();
|
|
120973
121229
|
init_utils11();
|
|
120974
|
-
|
|
121230
|
+
logger40 = log.scope("BucketController");
|
|
120975
121231
|
listFiles = requireDeveloper(async (ctx) => {
|
|
120976
121232
|
const slug2 = ctx.params.slug;
|
|
120977
121233
|
if (!slug2) {
|
|
@@ -120979,7 +121235,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
120979
121235
|
}
|
|
120980
121236
|
const url = ctx.url;
|
|
120981
121237
|
const prefix2 = url.searchParams.get("prefix") || undefined;
|
|
120982
|
-
|
|
121238
|
+
logger40.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
120983
121239
|
const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
|
|
120984
121240
|
return { files };
|
|
120985
121241
|
});
|
|
@@ -120989,7 +121245,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
120989
121245
|
if (!slug2 || !key) {
|
|
120990
121246
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
120991
121247
|
}
|
|
120992
|
-
|
|
121248
|
+
logger40.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
|
|
120993
121249
|
const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
|
|
120994
121250
|
return new Response(Buffer.from(object.body), {
|
|
120995
121251
|
status: 200,
|
|
@@ -121008,7 +121264,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
121008
121264
|
const arrayBuffer = await ctx.request.arrayBuffer();
|
|
121009
121265
|
const body2 = new Uint8Array(arrayBuffer);
|
|
121010
121266
|
const contentType = ctx.request.headers.get("content-type") || undefined;
|
|
121011
|
-
|
|
121267
|
+
logger40.debug("Uploading file", {
|
|
121012
121268
|
userId: ctx.user.id,
|
|
121013
121269
|
slug: slug2,
|
|
121014
121270
|
key,
|
|
@@ -121024,7 +121280,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
121024
121280
|
if (!slug2 || !key) {
|
|
121025
121281
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
121026
121282
|
}
|
|
121027
|
-
|
|
121283
|
+
logger40.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
|
|
121028
121284
|
await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
|
|
121029
121285
|
return { success: true, key };
|
|
121030
121286
|
});
|
|
@@ -121036,12 +121292,12 @@ var init_bucket_controller = __esm(() => {
|
|
|
121036
121292
|
} catch (error2) {
|
|
121037
121293
|
if (error2 instanceof exports_external.ZodError) {
|
|
121038
121294
|
const details = formatZodError(error2);
|
|
121039
|
-
|
|
121295
|
+
logger40.warn("Initiate upload validation failed", { details });
|
|
121040
121296
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121041
121297
|
}
|
|
121042
121298
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121043
121299
|
}
|
|
121044
|
-
|
|
121300
|
+
logger40.debug("Initiating multipart upload", {
|
|
121045
121301
|
userId: ctx.user.id,
|
|
121046
121302
|
gameId: body2.gameId,
|
|
121047
121303
|
fileName: body2.fileName
|
|
@@ -121056,10 +121312,10 @@ async function listComponents(ctx) {
|
|
|
121056
121312
|
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
121057
121313
|
level = Math.floor(Math.max(0, parsed));
|
|
121058
121314
|
}
|
|
121059
|
-
|
|
121315
|
+
logger41.debug("Listing components", { level });
|
|
121060
121316
|
return ctx.services.character.listAvailableComponents(level);
|
|
121061
121317
|
}
|
|
121062
|
-
var
|
|
121318
|
+
var logger41;
|
|
121063
121319
|
var get;
|
|
121064
121320
|
var getByUserId;
|
|
121065
121321
|
var create;
|
|
@@ -121073,9 +121329,9 @@ var init_character_controller = __esm(() => {
|
|
|
121073
121329
|
init_src2();
|
|
121074
121330
|
init_errors();
|
|
121075
121331
|
init_utils11();
|
|
121076
|
-
|
|
121332
|
+
logger41 = log.scope("CharacterController");
|
|
121077
121333
|
get = requireNonAnonymous(async (ctx) => {
|
|
121078
|
-
|
|
121334
|
+
logger41.debug("Getting character", { userId: ctx.user.id });
|
|
121079
121335
|
return ctx.services.character.getByUser(ctx.user);
|
|
121080
121336
|
});
|
|
121081
121337
|
getByUserId = requireNonAnonymous(async (ctx) => {
|
|
@@ -121083,7 +121339,7 @@ var init_character_controller = __esm(() => {
|
|
|
121083
121339
|
if (!userId) {
|
|
121084
121340
|
throw ApiError.badRequest("User ID is required in the URL path");
|
|
121085
121341
|
}
|
|
121086
|
-
|
|
121342
|
+
logger41.debug("Getting character by user ID", { requestedUserId: userId });
|
|
121087
121343
|
return ctx.services.character.getByUserId(userId);
|
|
121088
121344
|
});
|
|
121089
121345
|
create = requireNonAnonymous(async (ctx) => {
|
|
@@ -121094,12 +121350,12 @@ var init_character_controller = __esm(() => {
|
|
|
121094
121350
|
} catch (error2) {
|
|
121095
121351
|
if (error2 instanceof exports_external.ZodError) {
|
|
121096
121352
|
const details = formatZodError(error2);
|
|
121097
|
-
|
|
121353
|
+
logger41.warn("Create character validation failed", { details });
|
|
121098
121354
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121099
121355
|
}
|
|
121100
121356
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121101
121357
|
}
|
|
121102
|
-
|
|
121358
|
+
logger41.debug("Creating character", {
|
|
121103
121359
|
userId: ctx.user.id,
|
|
121104
121360
|
bodyComponentId: body2.bodyComponentId,
|
|
121105
121361
|
hairstyleComponentId: body2.hairstyleComponentId
|
|
@@ -121114,12 +121370,12 @@ var init_character_controller = __esm(() => {
|
|
|
121114
121370
|
} catch (error2) {
|
|
121115
121371
|
if (error2 instanceof exports_external.ZodError) {
|
|
121116
121372
|
const details = formatZodError(error2);
|
|
121117
|
-
|
|
121373
|
+
logger41.warn("Update character validation failed", { details });
|
|
121118
121374
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121119
121375
|
}
|
|
121120
121376
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121121
121377
|
}
|
|
121122
|
-
|
|
121378
|
+
logger41.debug("Updating character", {
|
|
121123
121379
|
userId: ctx.user.id,
|
|
121124
121380
|
bodyComponentId: body2.bodyComponentId,
|
|
121125
121381
|
hairstyleComponentId: body2.hairstyleComponentId,
|
|
@@ -121135,12 +121391,12 @@ var init_character_controller = __esm(() => {
|
|
|
121135
121391
|
} catch (error2) {
|
|
121136
121392
|
if (error2 instanceof exports_external.ZodError) {
|
|
121137
121393
|
const details = formatZodError(error2);
|
|
121138
|
-
|
|
121394
|
+
logger41.warn("Equip accessory validation failed", { details });
|
|
121139
121395
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121140
121396
|
}
|
|
121141
121397
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121142
121398
|
}
|
|
121143
|
-
|
|
121399
|
+
logger41.debug("Equipping accessory", {
|
|
121144
121400
|
userId: ctx.user.id,
|
|
121145
121401
|
slot: body2.slot,
|
|
121146
121402
|
accessoryComponentId: body2.accessoryComponentId
|
|
@@ -121152,7 +121408,7 @@ var init_character_controller = __esm(() => {
|
|
|
121152
121408
|
if (!slot) {
|
|
121153
121409
|
throw ApiError.badRequest("Slot is required in the URL path");
|
|
121154
121410
|
}
|
|
121155
|
-
|
|
121411
|
+
logger41.debug("Removing accessory", { userId: ctx.user.id, slot });
|
|
121156
121412
|
await ctx.services.character.removeAccessory(slot, ctx.user);
|
|
121157
121413
|
return { success: true };
|
|
121158
121414
|
});
|
|
@@ -121166,7 +121422,7 @@ var init_character_controller = __esm(() => {
|
|
|
121166
121422
|
removeAccessory
|
|
121167
121423
|
};
|
|
121168
121424
|
});
|
|
121169
|
-
var
|
|
121425
|
+
var logger42;
|
|
121170
121426
|
var list;
|
|
121171
121427
|
var getById;
|
|
121172
121428
|
var create2;
|
|
@@ -121180,9 +121436,9 @@ var init_currency_controller = __esm(() => {
|
|
|
121180
121436
|
init_src4();
|
|
121181
121437
|
init_errors();
|
|
121182
121438
|
init_utils11();
|
|
121183
|
-
|
|
121439
|
+
logger42 = log.scope("CurrencyController");
|
|
121184
121440
|
list = requireNonAnonymous(async (ctx) => {
|
|
121185
|
-
|
|
121441
|
+
logger42.debug("Listing currencies", { userId: ctx.user.id });
|
|
121186
121442
|
return ctx.services.currency.list();
|
|
121187
121443
|
});
|
|
121188
121444
|
getById = requireNonAnonymous(async (ctx) => {
|
|
@@ -121193,7 +121449,7 @@ var init_currency_controller = __esm(() => {
|
|
|
121193
121449
|
if (!isValidUUID(currencyId)) {
|
|
121194
121450
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
121195
121451
|
}
|
|
121196
|
-
|
|
121452
|
+
logger42.debug("Getting currency", { userId: ctx.user.id, currencyId });
|
|
121197
121453
|
return ctx.services.currency.getById(currencyId);
|
|
121198
121454
|
});
|
|
121199
121455
|
create2 = requireAdmin(async (ctx) => {
|
|
@@ -121204,12 +121460,12 @@ var init_currency_controller = __esm(() => {
|
|
|
121204
121460
|
} catch (error2) {
|
|
121205
121461
|
if (error2 instanceof exports_external.ZodError) {
|
|
121206
121462
|
const details = formatZodError(error2);
|
|
121207
|
-
|
|
121463
|
+
logger42.warn("Create currency validation failed", { details });
|
|
121208
121464
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121209
121465
|
}
|
|
121210
121466
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121211
121467
|
}
|
|
121212
|
-
|
|
121468
|
+
logger42.debug("Creating currency", {
|
|
121213
121469
|
userId: ctx.user.id,
|
|
121214
121470
|
symbol: body2.symbol,
|
|
121215
121471
|
itemId: body2.itemId,
|
|
@@ -121232,12 +121488,12 @@ var init_currency_controller = __esm(() => {
|
|
|
121232
121488
|
} catch (error2) {
|
|
121233
121489
|
if (error2 instanceof exports_external.ZodError) {
|
|
121234
121490
|
const details = formatZodError(error2);
|
|
121235
|
-
|
|
121491
|
+
logger42.warn("Update currency validation failed", { details });
|
|
121236
121492
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121237
121493
|
}
|
|
121238
121494
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121239
121495
|
}
|
|
121240
|
-
|
|
121496
|
+
logger42.debug("Updating currency", {
|
|
121241
121497
|
userId: ctx.user.id,
|
|
121242
121498
|
currencyId,
|
|
121243
121499
|
symbol: body2.symbol,
|
|
@@ -121254,7 +121510,7 @@ var init_currency_controller = __esm(() => {
|
|
|
121254
121510
|
if (!isValidUUID(currencyId)) {
|
|
121255
121511
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
121256
121512
|
}
|
|
121257
|
-
|
|
121513
|
+
logger42.debug("Deleting currency", { userId: ctx.user.id, currencyId });
|
|
121258
121514
|
await ctx.services.currency.delete(currencyId);
|
|
121259
121515
|
});
|
|
121260
121516
|
currencyController = {
|
|
@@ -121265,7 +121521,7 @@ var init_currency_controller = __esm(() => {
|
|
|
121265
121521
|
remove
|
|
121266
121522
|
};
|
|
121267
121523
|
});
|
|
121268
|
-
var
|
|
121524
|
+
var logger43;
|
|
121269
121525
|
var reset;
|
|
121270
121526
|
var init_database_controller = __esm(() => {
|
|
121271
121527
|
init_esm();
|
|
@@ -121273,7 +121529,7 @@ var init_database_controller = __esm(() => {
|
|
|
121273
121529
|
init_src2();
|
|
121274
121530
|
init_errors();
|
|
121275
121531
|
init_utils11();
|
|
121276
|
-
|
|
121532
|
+
logger43 = log.scope("DatabaseController");
|
|
121277
121533
|
reset = requireDeveloper(async (ctx) => {
|
|
121278
121534
|
const slug2 = ctx.params.slug;
|
|
121279
121535
|
if (!slug2) {
|
|
@@ -121286,11 +121542,11 @@ var init_database_controller = __esm(() => {
|
|
|
121286
121542
|
} catch (error2) {
|
|
121287
121543
|
if (error2 instanceof exports_external.ZodError) {
|
|
121288
121544
|
const details = formatZodError(error2);
|
|
121289
|
-
|
|
121545
|
+
logger43.warn("Database reset validation failed", { details });
|
|
121290
121546
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121291
121547
|
}
|
|
121292
121548
|
}
|
|
121293
|
-
|
|
121549
|
+
logger43.debug("Resetting database", {
|
|
121294
121550
|
userId: ctx.user.id,
|
|
121295
121551
|
slug: slug2,
|
|
121296
121552
|
hasSchema: Boolean(body2.schema)
|
|
@@ -121306,7 +121562,7 @@ async function createJob(ctx) {
|
|
|
121306
121562
|
let body2;
|
|
121307
121563
|
try {
|
|
121308
121564
|
const json4 = await ctx.request.json();
|
|
121309
|
-
|
|
121565
|
+
logger44.debug("Deploy request body", {
|
|
121310
121566
|
keys: Object.keys(json4 || {}),
|
|
121311
121567
|
hasUploadToken: Boolean(json4?.uploadToken),
|
|
121312
121568
|
hasCode: Boolean(json4?.code),
|
|
@@ -121316,7 +121572,7 @@ async function createJob(ctx) {
|
|
|
121316
121572
|
} catch (error2) {
|
|
121317
121573
|
if (error2 instanceof exports_external.ZodError) {
|
|
121318
121574
|
const details = formatZodError(error2);
|
|
121319
|
-
|
|
121575
|
+
logger44.warn("Deploy validation failed", { details });
|
|
121320
121576
|
throw ApiError.unprocessableEntity("Invalid deploy request", details);
|
|
121321
121577
|
}
|
|
121322
121578
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -121337,7 +121593,7 @@ async function getJob(ctx) {
|
|
|
121337
121593
|
}
|
|
121338
121594
|
return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
|
|
121339
121595
|
}
|
|
121340
|
-
var
|
|
121596
|
+
var logger44;
|
|
121341
121597
|
var deploy;
|
|
121342
121598
|
var init_deploy_controller = __esm(() => {
|
|
121343
121599
|
init_esm();
|
|
@@ -121345,26 +121601,26 @@ var init_deploy_controller = __esm(() => {
|
|
|
121345
121601
|
init_src2();
|
|
121346
121602
|
init_errors();
|
|
121347
121603
|
init_utils11();
|
|
121348
|
-
|
|
121604
|
+
logger44 = log.scope("DeployController");
|
|
121349
121605
|
deploy = {
|
|
121350
121606
|
createJob: requireDeveloper(createJob),
|
|
121351
121607
|
getJob: requireDeveloper(getJob)
|
|
121352
121608
|
};
|
|
121353
121609
|
});
|
|
121354
|
-
var
|
|
121610
|
+
var logger45;
|
|
121355
121611
|
var apply;
|
|
121356
121612
|
var getStatus;
|
|
121357
121613
|
var developer;
|
|
121358
121614
|
var init_developer_controller = __esm(() => {
|
|
121359
121615
|
init_src2();
|
|
121360
121616
|
init_utils11();
|
|
121361
|
-
|
|
121617
|
+
logger45 = log.scope("DeveloperController");
|
|
121362
121618
|
apply = requireNonAnonymous(async (ctx) => {
|
|
121363
|
-
|
|
121619
|
+
logger45.debug("Applying for developer status", { userId: ctx.user.id });
|
|
121364
121620
|
await ctx.services.developer.apply(ctx.user);
|
|
121365
121621
|
});
|
|
121366
121622
|
getStatus = requireNonAnonymous(async (ctx) => {
|
|
121367
|
-
|
|
121623
|
+
logger45.debug("Getting developer status", { userId: ctx.user.id });
|
|
121368
121624
|
const status = await ctx.services.developer.getStatus(ctx.user.id);
|
|
121369
121625
|
return { status };
|
|
121370
121626
|
});
|
|
@@ -121373,7 +121629,7 @@ var init_developer_controller = __esm(() => {
|
|
|
121373
121629
|
getStatus
|
|
121374
121630
|
};
|
|
121375
121631
|
});
|
|
121376
|
-
var
|
|
121632
|
+
var logger46;
|
|
121377
121633
|
var add;
|
|
121378
121634
|
var list2;
|
|
121379
121635
|
var getStatus2;
|
|
@@ -121386,7 +121642,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121386
121642
|
init_config2();
|
|
121387
121643
|
init_errors();
|
|
121388
121644
|
init_utils11();
|
|
121389
|
-
|
|
121645
|
+
logger46 = log.scope("DomainController");
|
|
121390
121646
|
add = requireDeveloper(async (ctx) => {
|
|
121391
121647
|
const slug2 = ctx.params.slug;
|
|
121392
121648
|
if (!slug2) {
|
|
@@ -121399,13 +121655,13 @@ var init_domain_controller = __esm(() => {
|
|
|
121399
121655
|
} catch (error2) {
|
|
121400
121656
|
if (error2 instanceof exports_external.ZodError) {
|
|
121401
121657
|
const details = formatZodError(error2);
|
|
121402
|
-
|
|
121658
|
+
logger46.warn("Add domain validation failed", { details });
|
|
121403
121659
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121404
121660
|
}
|
|
121405
121661
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121406
121662
|
}
|
|
121407
121663
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121408
|
-
|
|
121664
|
+
logger46.debug("Adding domain", {
|
|
121409
121665
|
userId: ctx.user.id,
|
|
121410
121666
|
slug: slug2,
|
|
121411
121667
|
hostname: body2.hostname,
|
|
@@ -121419,7 +121675,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121419
121675
|
throw ApiError.badRequest("Missing game slug");
|
|
121420
121676
|
}
|
|
121421
121677
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121422
|
-
|
|
121678
|
+
logger46.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
|
|
121423
121679
|
const domains22 = await ctx.services.domain.list(slug2, environment, ctx.user);
|
|
121424
121680
|
return { domains: domains22 };
|
|
121425
121681
|
});
|
|
@@ -121434,7 +121690,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121434
121690
|
}
|
|
121435
121691
|
const refresh = ctx.url.searchParams.get("refresh") === "true";
|
|
121436
121692
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121437
|
-
|
|
121693
|
+
logger46.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
|
|
121438
121694
|
return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
|
|
121439
121695
|
});
|
|
121440
121696
|
remove2 = requireDeveloper(async (ctx) => {
|
|
@@ -121447,7 +121703,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121447
121703
|
throw ApiError.badRequest("Missing hostname");
|
|
121448
121704
|
}
|
|
121449
121705
|
const environment = getPlatformEnvironment(ctx.config);
|
|
121450
|
-
|
|
121706
|
+
logger46.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
|
|
121451
121707
|
await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
|
|
121452
121708
|
});
|
|
121453
121709
|
domains2 = {
|
|
@@ -121457,7 +121713,7 @@ var init_domain_controller = __esm(() => {
|
|
|
121457
121713
|
remove: remove2
|
|
121458
121714
|
};
|
|
121459
121715
|
});
|
|
121460
|
-
var
|
|
121716
|
+
var logger47;
|
|
121461
121717
|
var list3;
|
|
121462
121718
|
var listManageable;
|
|
121463
121719
|
var getSubjects;
|
|
@@ -121474,17 +121730,17 @@ var init_game_controller = __esm(() => {
|
|
|
121474
121730
|
init_src4();
|
|
121475
121731
|
init_errors();
|
|
121476
121732
|
init_utils11();
|
|
121477
|
-
|
|
121733
|
+
logger47 = log.scope("GameController");
|
|
121478
121734
|
list3 = requireNonAnonymous(async (ctx) => {
|
|
121479
|
-
|
|
121735
|
+
logger47.debug("Listing games", { userId: ctx.user.id });
|
|
121480
121736
|
return ctx.services.game.list(ctx.user);
|
|
121481
121737
|
});
|
|
121482
121738
|
listManageable = requireNonAnonymous(async (ctx) => {
|
|
121483
|
-
|
|
121739
|
+
logger47.debug("Listing manageable games", { userId: ctx.user.id });
|
|
121484
121740
|
return ctx.services.game.listManageable(ctx.user);
|
|
121485
121741
|
});
|
|
121486
121742
|
getSubjects = requireNonAnonymous(async (ctx) => {
|
|
121487
|
-
|
|
121743
|
+
logger47.debug("Getting game subjects", { userId: ctx.user.id });
|
|
121488
121744
|
return ctx.services.game.getSubjects();
|
|
121489
121745
|
});
|
|
121490
121746
|
getById2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121495,7 +121751,7 @@ var init_game_controller = __esm(() => {
|
|
|
121495
121751
|
if (!isValidUUID(gameId)) {
|
|
121496
121752
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121497
121753
|
}
|
|
121498
|
-
|
|
121754
|
+
logger47.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
|
|
121499
121755
|
return ctx.services.game.getById(gameId, ctx.user);
|
|
121500
121756
|
});
|
|
121501
121757
|
getBySlug = requireNonAnonymous(async (ctx) => {
|
|
@@ -121503,7 +121759,7 @@ var init_game_controller = __esm(() => {
|
|
|
121503
121759
|
if (!slug2) {
|
|
121504
121760
|
throw ApiError.badRequest("Missing game slug");
|
|
121505
121761
|
}
|
|
121506
|
-
|
|
121762
|
+
logger47.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
|
|
121507
121763
|
return ctx.services.game.getBySlug(slug2, ctx.user);
|
|
121508
121764
|
});
|
|
121509
121765
|
getManifest = requireNonAnonymous(async (ctx) => {
|
|
@@ -121514,7 +121770,7 @@ var init_game_controller = __esm(() => {
|
|
|
121514
121770
|
if (!isValidUUID(gameId)) {
|
|
121515
121771
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121516
121772
|
}
|
|
121517
|
-
|
|
121773
|
+
logger47.debug("Getting game manifest by ID", {
|
|
121518
121774
|
userId: ctx.user.id,
|
|
121519
121775
|
gameId,
|
|
121520
121776
|
launchId: ctx.launchId
|
|
@@ -121533,12 +121789,12 @@ var init_game_controller = __esm(() => {
|
|
|
121533
121789
|
} catch (error2) {
|
|
121534
121790
|
if (error2 instanceof exports_external.ZodError) {
|
|
121535
121791
|
const details = formatZodError(error2);
|
|
121536
|
-
|
|
121792
|
+
logger47.warn("Upsert game validation failed", { details });
|
|
121537
121793
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121538
121794
|
}
|
|
121539
121795
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121540
121796
|
}
|
|
121541
|
-
|
|
121797
|
+
logger47.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
|
|
121542
121798
|
return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
|
|
121543
121799
|
});
|
|
121544
121800
|
remove3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121549,7 +121805,7 @@ var init_game_controller = __esm(() => {
|
|
|
121549
121805
|
if (!isValidUUID(gameId)) {
|
|
121550
121806
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121551
121807
|
}
|
|
121552
|
-
|
|
121808
|
+
logger47.debug("Deleting game", { userId: ctx.user.id, gameId });
|
|
121553
121809
|
await ctx.services.game.delete(gameId, ctx.user);
|
|
121554
121810
|
});
|
|
121555
121811
|
games2 = {
|
|
@@ -121563,7 +121819,7 @@ var init_game_controller = __esm(() => {
|
|
|
121563
121819
|
remove: remove3
|
|
121564
121820
|
};
|
|
121565
121821
|
});
|
|
121566
|
-
var
|
|
121822
|
+
var logger48;
|
|
121567
121823
|
var list4;
|
|
121568
121824
|
var addItem;
|
|
121569
121825
|
var removeItem;
|
|
@@ -121574,9 +121830,9 @@ var init_inventory_controller = __esm(() => {
|
|
|
121574
121830
|
init_src2();
|
|
121575
121831
|
init_errors();
|
|
121576
121832
|
init_utils11();
|
|
121577
|
-
|
|
121833
|
+
logger48 = log.scope("InventoryController");
|
|
121578
121834
|
list4 = requireNonAnonymous(async (ctx) => {
|
|
121579
|
-
|
|
121835
|
+
logger48.debug("Listing inventory", { userId: ctx.user.id });
|
|
121580
121836
|
return ctx.services.inventory.list(ctx.user);
|
|
121581
121837
|
});
|
|
121582
121838
|
addItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -121587,12 +121843,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
121587
121843
|
} catch (error2) {
|
|
121588
121844
|
if (error2 instanceof exports_external.ZodError) {
|
|
121589
121845
|
const details = formatZodError(error2);
|
|
121590
|
-
|
|
121846
|
+
logger48.warn("Add inventory item validation failed", { details });
|
|
121591
121847
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121592
121848
|
}
|
|
121593
121849
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121594
121850
|
}
|
|
121595
|
-
|
|
121851
|
+
logger48.debug("Adding item", {
|
|
121596
121852
|
userId: ctx.user.id,
|
|
121597
121853
|
itemId: body2.itemId,
|
|
121598
121854
|
qty: body2.qty
|
|
@@ -121607,12 +121863,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
121607
121863
|
} catch (error2) {
|
|
121608
121864
|
if (error2 instanceof exports_external.ZodError) {
|
|
121609
121865
|
const details = formatZodError(error2);
|
|
121610
|
-
|
|
121866
|
+
logger48.warn("Remove inventory item validation failed", { details });
|
|
121611
121867
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
121612
121868
|
}
|
|
121613
121869
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121614
121870
|
}
|
|
121615
|
-
|
|
121871
|
+
logger48.debug("Removing item", {
|
|
121616
121872
|
userId: ctx.user.id,
|
|
121617
121873
|
itemId: body2.itemId,
|
|
121618
121874
|
qty: body2.qty
|
|
@@ -121625,7 +121881,7 @@ var init_inventory_controller = __esm(() => {
|
|
|
121625
121881
|
removeItem
|
|
121626
121882
|
};
|
|
121627
121883
|
});
|
|
121628
|
-
var
|
|
121884
|
+
var logger49;
|
|
121629
121885
|
var list5;
|
|
121630
121886
|
var getById3;
|
|
121631
121887
|
var resolve2;
|
|
@@ -121644,10 +121900,10 @@ var init_item_controller = __esm(() => {
|
|
|
121644
121900
|
init_src4();
|
|
121645
121901
|
init_errors();
|
|
121646
121902
|
init_utils11();
|
|
121647
|
-
|
|
121903
|
+
logger49 = log.scope("ItemController");
|
|
121648
121904
|
list5 = requireNonAnonymous(async (ctx) => {
|
|
121649
121905
|
const gameId = ctx.url.searchParams.get("gameId") || undefined;
|
|
121650
|
-
|
|
121906
|
+
logger49.debug("Listing items", { userId: ctx.user.id, gameId });
|
|
121651
121907
|
return ctx.services.item.list(gameId);
|
|
121652
121908
|
});
|
|
121653
121909
|
getById3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121658,7 +121914,7 @@ var init_item_controller = __esm(() => {
|
|
|
121658
121914
|
if (!isValidUUID(itemId)) {
|
|
121659
121915
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
121660
121916
|
}
|
|
121661
|
-
|
|
121917
|
+
logger49.debug("Getting item", { userId: ctx.user.id, itemId });
|
|
121662
121918
|
return ctx.services.item.getById(itemId);
|
|
121663
121919
|
});
|
|
121664
121920
|
resolve2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -121670,7 +121926,7 @@ var init_item_controller = __esm(() => {
|
|
|
121670
121926
|
if (gameId && !isValidUUID(gameId)) {
|
|
121671
121927
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121672
121928
|
}
|
|
121673
|
-
|
|
121929
|
+
logger49.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
|
|
121674
121930
|
return ctx.services.item.resolveBySlug(slug2, gameId);
|
|
121675
121931
|
});
|
|
121676
121932
|
create3 = requireRole(["admin"], async (ctx) => {
|
|
@@ -121681,12 +121937,12 @@ var init_item_controller = __esm(() => {
|
|
|
121681
121937
|
} catch (error2) {
|
|
121682
121938
|
if (error2 instanceof exports_external.ZodError) {
|
|
121683
121939
|
const details = formatZodError(error2);
|
|
121684
|
-
|
|
121940
|
+
logger49.warn("Create item validation failed", { details });
|
|
121685
121941
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121686
121942
|
}
|
|
121687
121943
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121688
121944
|
}
|
|
121689
|
-
|
|
121945
|
+
logger49.debug("Creating item", {
|
|
121690
121946
|
userId: ctx.user.id,
|
|
121691
121947
|
slug: body2.slug,
|
|
121692
121948
|
displayName: body2.displayName
|
|
@@ -121708,7 +121964,7 @@ var init_item_controller = __esm(() => {
|
|
|
121708
121964
|
} catch (error2) {
|
|
121709
121965
|
if (error2 instanceof exports_external.ZodError) {
|
|
121710
121966
|
const details = formatZodError(error2);
|
|
121711
|
-
|
|
121967
|
+
logger49.warn("Update item validation failed", { details });
|
|
121712
121968
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121713
121969
|
}
|
|
121714
121970
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -121716,7 +121972,7 @@ var init_item_controller = __esm(() => {
|
|
|
121716
121972
|
if (Object.keys(body2).length === 0) {
|
|
121717
121973
|
throw ApiError.badRequest("No update data provided");
|
|
121718
121974
|
}
|
|
121719
|
-
|
|
121975
|
+
logger49.debug("Updating item", {
|
|
121720
121976
|
userId: ctx.user.id,
|
|
121721
121977
|
itemId,
|
|
121722
121978
|
slug: body2.slug,
|
|
@@ -121733,7 +121989,7 @@ var init_item_controller = __esm(() => {
|
|
|
121733
121989
|
if (!isValidUUID(itemId)) {
|
|
121734
121990
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
121735
121991
|
}
|
|
121736
|
-
|
|
121992
|
+
logger49.debug("Deleting item", { userId: ctx.user.id, itemId });
|
|
121737
121993
|
await ctx.services.item.delete(itemId);
|
|
121738
121994
|
});
|
|
121739
121995
|
listByGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -121744,7 +122000,7 @@ var init_item_controller = __esm(() => {
|
|
|
121744
122000
|
if (!isValidUUID(gameId)) {
|
|
121745
122001
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
121746
122002
|
}
|
|
121747
|
-
|
|
122003
|
+
logger49.debug("Listing game items", { userId: ctx.user.id, gameId });
|
|
121748
122004
|
return ctx.services.item.listByGame(gameId);
|
|
121749
122005
|
});
|
|
121750
122006
|
createForGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -121762,12 +122018,12 @@ var init_item_controller = __esm(() => {
|
|
|
121762
122018
|
} catch (error2) {
|
|
121763
122019
|
if (error2 instanceof exports_external.ZodError) {
|
|
121764
122020
|
const details = formatZodError(error2);
|
|
121765
|
-
|
|
122021
|
+
logger49.warn("Create game item validation failed", { details });
|
|
121766
122022
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121767
122023
|
}
|
|
121768
122024
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121769
122025
|
}
|
|
121770
|
-
|
|
122026
|
+
logger49.debug("Creating game item", {
|
|
121771
122027
|
userId: ctx.user.id,
|
|
121772
122028
|
gameId,
|
|
121773
122029
|
slug: body2.slug,
|
|
@@ -121794,7 +122050,7 @@ var init_item_controller = __esm(() => {
|
|
|
121794
122050
|
} catch (error2) {
|
|
121795
122051
|
if (error2 instanceof exports_external.ZodError) {
|
|
121796
122052
|
const details = formatZodError(error2);
|
|
121797
|
-
|
|
122053
|
+
logger49.warn("Update game item validation failed", { details });
|
|
121798
122054
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121799
122055
|
}
|
|
121800
122056
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -121802,7 +122058,7 @@ var init_item_controller = __esm(() => {
|
|
|
121802
122058
|
if (Object.keys(body2).length === 0) {
|
|
121803
122059
|
throw ApiError.badRequest("No update data provided");
|
|
121804
122060
|
}
|
|
121805
|
-
|
|
122061
|
+
logger49.debug("Updating game item", {
|
|
121806
122062
|
userId: ctx.user.id,
|
|
121807
122063
|
gameId,
|
|
121808
122064
|
itemId,
|
|
@@ -121824,7 +122080,7 @@ var init_item_controller = __esm(() => {
|
|
|
121824
122080
|
if (!isValidUUID(itemId)) {
|
|
121825
122081
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
121826
122082
|
}
|
|
121827
|
-
|
|
122083
|
+
logger49.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
|
|
121828
122084
|
await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
|
|
121829
122085
|
});
|
|
121830
122086
|
items2 = {
|
|
@@ -121840,7 +122096,7 @@ var init_item_controller = __esm(() => {
|
|
|
121840
122096
|
deleteForGame
|
|
121841
122097
|
};
|
|
121842
122098
|
});
|
|
121843
|
-
var
|
|
122099
|
+
var logger50;
|
|
121844
122100
|
var listKeys;
|
|
121845
122101
|
var getStats;
|
|
121846
122102
|
var seed;
|
|
@@ -121855,7 +122111,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121855
122111
|
init_src2();
|
|
121856
122112
|
init_errors();
|
|
121857
122113
|
init_utils11();
|
|
121858
|
-
|
|
122114
|
+
logger50 = log.scope("KVController");
|
|
121859
122115
|
listKeys = requireDeveloper(async (ctx) => {
|
|
121860
122116
|
const slug2 = ctx.params.slug;
|
|
121861
122117
|
if (!slug2) {
|
|
@@ -121863,7 +122119,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121863
122119
|
}
|
|
121864
122120
|
const url = ctx.url;
|
|
121865
122121
|
const prefix2 = url.searchParams.get("prefix") || undefined;
|
|
121866
|
-
|
|
122122
|
+
logger50.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
121867
122123
|
const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
|
|
121868
122124
|
return { keys };
|
|
121869
122125
|
});
|
|
@@ -121872,7 +122128,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121872
122128
|
if (!slug2) {
|
|
121873
122129
|
throw ApiError.badRequest("Missing game slug");
|
|
121874
122130
|
}
|
|
121875
|
-
|
|
122131
|
+
logger50.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
|
|
121876
122132
|
return ctx.services.kv.getStats(slug2, ctx.user);
|
|
121877
122133
|
});
|
|
121878
122134
|
seed = requireDeveloper(async (ctx) => {
|
|
@@ -121887,12 +122143,12 @@ var init_kv_controller = __esm(() => {
|
|
|
121887
122143
|
} catch (error2) {
|
|
121888
122144
|
if (error2 instanceof exports_external.ZodError) {
|
|
121889
122145
|
const details = formatZodError(error2);
|
|
121890
|
-
|
|
122146
|
+
logger50.warn("Seed validation failed", { details });
|
|
121891
122147
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121892
122148
|
}
|
|
121893
122149
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121894
122150
|
}
|
|
121895
|
-
|
|
122151
|
+
logger50.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
|
|
121896
122152
|
await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
|
|
121897
122153
|
return { success: true, count: body2.entries.length };
|
|
121898
122154
|
});
|
|
@@ -121902,7 +122158,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121902
122158
|
if (!slug2 || !key) {
|
|
121903
122159
|
throw ApiError.badRequest("Missing game slug or key");
|
|
121904
122160
|
}
|
|
121905
|
-
|
|
122161
|
+
logger50.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
|
|
121906
122162
|
const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
|
|
121907
122163
|
return { key, value };
|
|
121908
122164
|
});
|
|
@@ -121916,7 +122172,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121916
122172
|
if (!value) {
|
|
121917
122173
|
throw ApiError.badRequest("Missing value in request body");
|
|
121918
122174
|
}
|
|
121919
|
-
|
|
122175
|
+
logger50.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
|
|
121920
122176
|
await ctx.services.kv.setValue(slug2, key, value, ctx.user);
|
|
121921
122177
|
return { success: true, key };
|
|
121922
122178
|
});
|
|
@@ -121926,7 +122182,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121926
122182
|
if (!slug2 || !key) {
|
|
121927
122183
|
throw ApiError.badRequest("Missing game slug or key");
|
|
121928
122184
|
}
|
|
121929
|
-
|
|
122185
|
+
logger50.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
|
|
121930
122186
|
await ctx.services.kv.deleteValue(slug2, key, ctx.user);
|
|
121931
122187
|
return { success: true, key };
|
|
121932
122188
|
});
|
|
@@ -121936,7 +122192,7 @@ var init_kv_controller = __esm(() => {
|
|
|
121936
122192
|
if (!slug2 || !key) {
|
|
121937
122193
|
throw ApiError.badRequest("Missing game slug or key");
|
|
121938
122194
|
}
|
|
121939
|
-
|
|
122195
|
+
logger50.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
|
|
121940
122196
|
const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
|
|
121941
122197
|
return { key, metadata: metadata2 };
|
|
121942
122198
|
});
|
|
@@ -121945,12 +122201,12 @@ var init_kv_controller = __esm(() => {
|
|
|
121945
122201
|
if (!slug2) {
|
|
121946
122202
|
throw ApiError.badRequest("Missing game slug");
|
|
121947
122203
|
}
|
|
121948
|
-
|
|
122204
|
+
logger50.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
|
|
121949
122205
|
const deleted = await ctx.services.kv.clear(slug2, ctx.user);
|
|
121950
122206
|
return { success: true, deleted };
|
|
121951
122207
|
});
|
|
121952
122208
|
});
|
|
121953
|
-
var
|
|
122209
|
+
var logger51;
|
|
121954
122210
|
var submitScore;
|
|
121955
122211
|
var getGlobalLeaderboard;
|
|
121956
122212
|
var getLeaderboard;
|
|
@@ -121964,7 +122220,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
121964
122220
|
init_src2();
|
|
121965
122221
|
init_errors();
|
|
121966
122222
|
init_utils11();
|
|
121967
|
-
|
|
122223
|
+
logger51 = log.scope("LeaderboardController");
|
|
121968
122224
|
submitScore = requireAuth(async (ctx) => {
|
|
121969
122225
|
const gameId = ctx.params.gameId;
|
|
121970
122226
|
if (!gameId) {
|
|
@@ -121977,12 +122233,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
121977
122233
|
} catch (error2) {
|
|
121978
122234
|
if (error2 instanceof exports_external.ZodError) {
|
|
121979
122235
|
const details = formatZodError(error2);
|
|
121980
|
-
|
|
122236
|
+
logger51.warn("Submit score validation failed", { details });
|
|
121981
122237
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
121982
122238
|
}
|
|
121983
122239
|
throw ApiError.badRequest("Invalid JSON body");
|
|
121984
122240
|
}
|
|
121985
|
-
|
|
122241
|
+
logger51.debug("Submitting score", {
|
|
121986
122242
|
userId: ctx.user.id,
|
|
121987
122243
|
gameId,
|
|
121988
122244
|
score: body2.score
|
|
@@ -122005,12 +122261,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122005
122261
|
} catch (error2) {
|
|
122006
122262
|
if (error2 instanceof exports_external.ZodError) {
|
|
122007
122263
|
const details = formatZodError(error2);
|
|
122008
|
-
|
|
122264
|
+
logger51.warn("Get global leaderboard query validation failed", { details });
|
|
122009
122265
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
122010
122266
|
}
|
|
122011
122267
|
throw ApiError.badRequest("Invalid query parameters");
|
|
122012
122268
|
}
|
|
122013
|
-
|
|
122269
|
+
logger51.debug("Getting global leaderboard", {
|
|
122014
122270
|
userId: ctx.user.id,
|
|
122015
122271
|
gameId,
|
|
122016
122272
|
...query
|
|
@@ -122033,12 +122289,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122033
122289
|
} catch (error2) {
|
|
122034
122290
|
if (error2 instanceof exports_external.ZodError) {
|
|
122035
122291
|
const details = formatZodError(error2);
|
|
122036
|
-
|
|
122292
|
+
logger51.warn("Get leaderboard query validation failed", { details });
|
|
122037
122293
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
122038
122294
|
}
|
|
122039
122295
|
throw ApiError.badRequest("Invalid query parameters");
|
|
122040
122296
|
}
|
|
122041
|
-
|
|
122297
|
+
logger51.debug("Getting leaderboard", {
|
|
122042
122298
|
userId: ctx.user.id,
|
|
122043
122299
|
gameId,
|
|
122044
122300
|
...query
|
|
@@ -122050,7 +122306,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122050
122306
|
if (!gameId || !userId) {
|
|
122051
122307
|
throw ApiError.badRequest("Game ID and User ID are required");
|
|
122052
122308
|
}
|
|
122053
|
-
|
|
122309
|
+
logger51.debug("Getting user rank", {
|
|
122054
122310
|
requesterId: ctx.user.id,
|
|
122055
122311
|
gameId,
|
|
122056
122312
|
targetUserId: userId
|
|
@@ -122065,7 +122321,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122065
122321
|
const url = ctx.url;
|
|
122066
122322
|
const limit = Math.min(Number(url.searchParams.get("limit") || "50"), 100);
|
|
122067
122323
|
const gameId = url.searchParams.get("gameId") || undefined;
|
|
122068
|
-
|
|
122324
|
+
logger51.debug("Getting user all scores", {
|
|
122069
122325
|
requesterId: ctx.user.id,
|
|
122070
122326
|
targetUserId: userId,
|
|
122071
122327
|
gameId,
|
|
@@ -122080,7 +122336,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122080
122336
|
}
|
|
122081
122337
|
const url = ctx.url;
|
|
122082
122338
|
const limit = Math.min(Number(url.searchParams.get("limit") || "10"), 100);
|
|
122083
|
-
|
|
122339
|
+
logger51.debug("Getting user scores", {
|
|
122084
122340
|
requesterId: ctx.user.id,
|
|
122085
122341
|
gameId,
|
|
122086
122342
|
targetUserId: userId,
|
|
@@ -122098,7 +122354,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
122098
122354
|
};
|
|
122099
122355
|
});
|
|
122100
122356
|
async function listConfigs(ctx) {
|
|
122101
|
-
|
|
122357
|
+
logger52.debug("Listing level configs");
|
|
122102
122358
|
return ctx.services.level.listConfigs();
|
|
122103
122359
|
}
|
|
122104
122360
|
async function getConfig(ctx) {
|
|
@@ -122110,10 +122366,10 @@ async function getConfig(ctx) {
|
|
|
122110
122366
|
if (isNaN(level) || level < 1) {
|
|
122111
122367
|
throw ApiError.badRequest("Level must be a positive integer");
|
|
122112
122368
|
}
|
|
122113
|
-
|
|
122369
|
+
logger52.debug("Getting level config", { level });
|
|
122114
122370
|
return ctx.services.level.getConfig(level);
|
|
122115
122371
|
}
|
|
122116
|
-
var
|
|
122372
|
+
var logger52;
|
|
122117
122373
|
var getByUser;
|
|
122118
122374
|
var getProgress;
|
|
122119
122375
|
var levels;
|
|
@@ -122121,13 +122377,13 @@ var init_level_controller = __esm(() => {
|
|
|
122121
122377
|
init_src2();
|
|
122122
122378
|
init_errors();
|
|
122123
122379
|
init_utils11();
|
|
122124
|
-
|
|
122380
|
+
logger52 = log.scope("LevelController");
|
|
122125
122381
|
getByUser = requireNonAnonymous(async (ctx) => {
|
|
122126
|
-
|
|
122382
|
+
logger52.debug("Getting user level", { userId: ctx.user.id });
|
|
122127
122383
|
return ctx.services.level.getByUser(ctx.user);
|
|
122128
122384
|
});
|
|
122129
122385
|
getProgress = requireNonAnonymous(async (ctx) => {
|
|
122130
|
-
|
|
122386
|
+
logger52.debug("Getting level progress", { userId: ctx.user.id });
|
|
122131
122387
|
return ctx.services.level.getProgress(ctx.user);
|
|
122132
122388
|
});
|
|
122133
122389
|
levels = {
|
|
@@ -122137,14 +122393,14 @@ var init_level_controller = __esm(() => {
|
|
|
122137
122393
|
getProgress
|
|
122138
122394
|
};
|
|
122139
122395
|
});
|
|
122140
|
-
var
|
|
122396
|
+
var logger53;
|
|
122141
122397
|
var generateToken;
|
|
122142
122398
|
var logs;
|
|
122143
122399
|
var init_logs_controller = __esm(() => {
|
|
122144
122400
|
init_src2();
|
|
122145
122401
|
init_errors();
|
|
122146
122402
|
init_utils11();
|
|
122147
|
-
|
|
122403
|
+
logger53 = log.scope("LogsController");
|
|
122148
122404
|
generateToken = requireDeveloper(async (ctx) => {
|
|
122149
122405
|
const slug2 = ctx.params.slug;
|
|
122150
122406
|
if (!slug2) {
|
|
@@ -122163,7 +122419,7 @@ var init_logs_controller = __esm(() => {
|
|
|
122163
122419
|
}
|
|
122164
122420
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122165
122421
|
}
|
|
122166
|
-
|
|
122422
|
+
logger53.debug("Generating log stream token", {
|
|
122167
122423
|
userId: ctx.user.id,
|
|
122168
122424
|
slug: slug2,
|
|
122169
122425
|
environment: body2.environment
|
|
@@ -122174,22 +122430,22 @@ var init_logs_controller = __esm(() => {
|
|
|
122174
122430
|
generateToken
|
|
122175
122431
|
};
|
|
122176
122432
|
});
|
|
122177
|
-
var
|
|
122433
|
+
var logger54;
|
|
122178
122434
|
var getStatus3;
|
|
122179
122435
|
var lti;
|
|
122180
122436
|
var init_lti_controller = __esm(() => {
|
|
122181
122437
|
init_src2();
|
|
122182
122438
|
init_utils11();
|
|
122183
|
-
|
|
122439
|
+
logger54 = log.scope("LtiController");
|
|
122184
122440
|
getStatus3 = requireNonAnonymous(async (ctx) => {
|
|
122185
|
-
|
|
122441
|
+
logger54.debug("Getting status", { userId: ctx.user.id });
|
|
122186
122442
|
return ctx.services.lti.getStatus(ctx.user);
|
|
122187
122443
|
});
|
|
122188
122444
|
lti = {
|
|
122189
122445
|
getStatus: getStatus3
|
|
122190
122446
|
};
|
|
122191
122447
|
});
|
|
122192
|
-
var
|
|
122448
|
+
var logger55;
|
|
122193
122449
|
var getByIdentifier;
|
|
122194
122450
|
var getElements;
|
|
122195
122451
|
var getObjects;
|
|
@@ -122203,13 +122459,13 @@ var init_map_controller = __esm(() => {
|
|
|
122203
122459
|
init_src4();
|
|
122204
122460
|
init_errors();
|
|
122205
122461
|
init_utils11();
|
|
122206
|
-
|
|
122462
|
+
logger55 = log.scope("MapController");
|
|
122207
122463
|
getByIdentifier = requireNonAnonymous(async (ctx) => {
|
|
122208
122464
|
const identifier = ctx.params.identifier;
|
|
122209
122465
|
if (!identifier) {
|
|
122210
122466
|
throw ApiError.badRequest("Missing map identifier");
|
|
122211
122467
|
}
|
|
122212
|
-
|
|
122468
|
+
logger55.debug("Getting map", { userId: ctx.user.id, identifier });
|
|
122213
122469
|
return ctx.services.map.getByIdentifier(identifier);
|
|
122214
122470
|
});
|
|
122215
122471
|
getElements = requireNonAnonymous(async (ctx) => {
|
|
@@ -122220,7 +122476,7 @@ var init_map_controller = __esm(() => {
|
|
|
122220
122476
|
if (!isValidUUID(mapId)) {
|
|
122221
122477
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
122222
122478
|
}
|
|
122223
|
-
|
|
122479
|
+
logger55.debug("Getting map elements", { userId: ctx.user.id, mapId });
|
|
122224
122480
|
return ctx.services.map.getElements(mapId);
|
|
122225
122481
|
});
|
|
122226
122482
|
getObjects = requireNonAnonymous(async (ctx) => {
|
|
@@ -122231,7 +122487,7 @@ var init_map_controller = __esm(() => {
|
|
|
122231
122487
|
if (!isValidUUID(mapId)) {
|
|
122232
122488
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
122233
122489
|
}
|
|
122234
|
-
|
|
122490
|
+
logger55.debug("Getting map objects", { userId: ctx.user.id, mapId });
|
|
122235
122491
|
return ctx.services.map.getObjects(mapId, ctx.user.id);
|
|
122236
122492
|
});
|
|
122237
122493
|
createObject = requireNonAnonymous(async (ctx) => {
|
|
@@ -122253,12 +122509,12 @@ var init_map_controller = __esm(() => {
|
|
|
122253
122509
|
} catch (error2) {
|
|
122254
122510
|
if (error2 instanceof exports_external.ZodError) {
|
|
122255
122511
|
const details = formatZodError(error2);
|
|
122256
|
-
|
|
122512
|
+
logger55.warn("Create map object validation failed", { details });
|
|
122257
122513
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122258
122514
|
}
|
|
122259
122515
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122260
122516
|
}
|
|
122261
|
-
|
|
122517
|
+
logger55.debug("Creating map object", {
|
|
122262
122518
|
userId: ctx.user.id,
|
|
122263
122519
|
mapId,
|
|
122264
122520
|
itemId: body2.itemId,
|
|
@@ -122282,7 +122538,7 @@ var init_map_controller = __esm(() => {
|
|
|
122282
122538
|
if (!isValidUUID(objectId)) {
|
|
122283
122539
|
throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
|
|
122284
122540
|
}
|
|
122285
|
-
|
|
122541
|
+
logger55.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
|
|
122286
122542
|
await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
|
|
122287
122543
|
});
|
|
122288
122544
|
maps2 = {
|
|
@@ -122293,7 +122549,7 @@ var init_map_controller = __esm(() => {
|
|
|
122293
122549
|
deleteObject
|
|
122294
122550
|
};
|
|
122295
122551
|
});
|
|
122296
|
-
var
|
|
122552
|
+
var logger56;
|
|
122297
122553
|
var list6;
|
|
122298
122554
|
var updateStatus;
|
|
122299
122555
|
var getStats2;
|
|
@@ -122306,7 +122562,7 @@ var init_notification_controller = __esm(() => {
|
|
|
122306
122562
|
init_src2();
|
|
122307
122563
|
init_errors();
|
|
122308
122564
|
init_utils11();
|
|
122309
|
-
|
|
122565
|
+
logger56 = log.scope("NotificationController");
|
|
122310
122566
|
list6 = requireNonAnonymous(async (ctx) => {
|
|
122311
122567
|
const query = {
|
|
122312
122568
|
status: ctx.url.searchParams.get("status") || undefined,
|
|
@@ -122317,10 +122573,10 @@ var init_notification_controller = __esm(() => {
|
|
|
122317
122573
|
const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
|
|
122318
122574
|
if (!result.success) {
|
|
122319
122575
|
const details = formatZodError(result.error);
|
|
122320
|
-
|
|
122576
|
+
logger56.warn("List notifications query validation failed", { details });
|
|
122321
122577
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
122322
122578
|
}
|
|
122323
|
-
|
|
122579
|
+
logger56.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
|
|
122324
122580
|
return ctx.services.notification.list(ctx.user, result.data);
|
|
122325
122581
|
});
|
|
122326
122582
|
updateStatus = requireNonAnonymous(async (ctx) => {
|
|
@@ -122335,12 +122591,12 @@ var init_notification_controller = __esm(() => {
|
|
|
122335
122591
|
} catch (error2) {
|
|
122336
122592
|
if (error2 instanceof exports_external.ZodError) {
|
|
122337
122593
|
const details = formatZodError(error2);
|
|
122338
|
-
|
|
122594
|
+
logger56.warn("Update notification status validation failed", { details });
|
|
122339
122595
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122340
122596
|
}
|
|
122341
122597
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122342
122598
|
}
|
|
122343
|
-
|
|
122599
|
+
logger56.debug("Updating status", {
|
|
122344
122600
|
userId: ctx.user.id,
|
|
122345
122601
|
notificationId,
|
|
122346
122602
|
status: body2.status
|
|
@@ -122350,7 +122606,7 @@ var init_notification_controller = __esm(() => {
|
|
|
122350
122606
|
getStats2 = requireNonAnonymous(async (ctx) => {
|
|
122351
122607
|
const startDate = ctx.url.searchParams.get("startDate");
|
|
122352
122608
|
const endDate = ctx.url.searchParams.get("endDate");
|
|
122353
|
-
|
|
122609
|
+
logger56.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
|
|
122354
122610
|
return ctx.services.notification.getStats(ctx.user, {
|
|
122355
122611
|
startDate: startDate ? new Date(startDate) : undefined,
|
|
122356
122612
|
endDate: endDate ? new Date(endDate) : undefined
|
|
@@ -122364,12 +122620,12 @@ var init_notification_controller = __esm(() => {
|
|
|
122364
122620
|
} catch (error2) {
|
|
122365
122621
|
if (error2 instanceof exports_external.ZodError) {
|
|
122366
122622
|
const details = formatZodError(error2);
|
|
122367
|
-
|
|
122623
|
+
logger56.warn("Create notification validation failed", { details });
|
|
122368
122624
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122369
122625
|
}
|
|
122370
122626
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122371
122627
|
}
|
|
122372
|
-
|
|
122628
|
+
logger56.debug("Creating notification", {
|
|
122373
122629
|
userId: ctx.user.id,
|
|
122374
122630
|
targetUserId: body2.userId,
|
|
122375
122631
|
type: body2.type
|
|
@@ -122387,12 +122643,12 @@ var init_notification_controller = __esm(() => {
|
|
|
122387
122643
|
});
|
|
122388
122644
|
});
|
|
122389
122645
|
deliver = requireNonAnonymous(async (ctx) => {
|
|
122390
|
-
|
|
122646
|
+
logger56.debug("Delivering notifications", { userId: ctx.user.id });
|
|
122391
122647
|
try {
|
|
122392
122648
|
await ctx.services.notification.deliverPending(ctx.user.id);
|
|
122393
122649
|
return { success: true };
|
|
122394
122650
|
} catch (error2) {
|
|
122395
|
-
|
|
122651
|
+
logger56.error("Failed to deliver notifications", { error: error2 });
|
|
122396
122652
|
throw ApiError.internal("Failed to deliver notifications");
|
|
122397
122653
|
}
|
|
122398
122654
|
});
|
|
@@ -122404,16 +122660,16 @@ var init_notification_controller = __esm(() => {
|
|
|
122404
122660
|
deliver
|
|
122405
122661
|
};
|
|
122406
122662
|
});
|
|
122407
|
-
var
|
|
122663
|
+
var logger57;
|
|
122408
122664
|
var generateToken2;
|
|
122409
122665
|
var realtime;
|
|
122410
122666
|
var init_realtime_controller = __esm(() => {
|
|
122411
122667
|
init_src2();
|
|
122412
122668
|
init_utils11();
|
|
122413
|
-
|
|
122669
|
+
logger57 = log.scope("RealtimeController");
|
|
122414
122670
|
generateToken2 = requireNonAnonymous(async (ctx) => {
|
|
122415
122671
|
const gameIdOrSlug = ctx.params.gameId;
|
|
122416
|
-
|
|
122672
|
+
logger57.debug("Generating token", {
|
|
122417
122673
|
userId: ctx.user.id,
|
|
122418
122674
|
gameId: gameIdOrSlug || "global",
|
|
122419
122675
|
launchId: ctx.launchId
|
|
@@ -122424,7 +122680,7 @@ var init_realtime_controller = __esm(() => {
|
|
|
122424
122680
|
generateToken: generateToken2
|
|
122425
122681
|
};
|
|
122426
122682
|
});
|
|
122427
|
-
var
|
|
122683
|
+
var logger58;
|
|
122428
122684
|
var listKeys2;
|
|
122429
122685
|
var setSecrets;
|
|
122430
122686
|
var deleteSecret;
|
|
@@ -122435,13 +122691,13 @@ var init_secrets_controller = __esm(() => {
|
|
|
122435
122691
|
init_src2();
|
|
122436
122692
|
init_errors();
|
|
122437
122693
|
init_utils11();
|
|
122438
|
-
|
|
122694
|
+
logger58 = log.scope("SecretsController");
|
|
122439
122695
|
listKeys2 = requireDeveloper(async (ctx) => {
|
|
122440
122696
|
const slug2 = ctx.params.slug;
|
|
122441
122697
|
if (!slug2) {
|
|
122442
122698
|
throw ApiError.badRequest("Missing game slug");
|
|
122443
122699
|
}
|
|
122444
|
-
|
|
122700
|
+
logger58.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
|
|
122445
122701
|
const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
|
|
122446
122702
|
return { keys };
|
|
122447
122703
|
});
|
|
@@ -122457,12 +122713,12 @@ var init_secrets_controller = __esm(() => {
|
|
|
122457
122713
|
} catch (error2) {
|
|
122458
122714
|
if (error2 instanceof exports_external.ZodError) {
|
|
122459
122715
|
const details = formatZodError(error2);
|
|
122460
|
-
|
|
122716
|
+
logger58.warn("Set secrets validation failed", { details });
|
|
122461
122717
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122462
122718
|
}
|
|
122463
122719
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122464
122720
|
}
|
|
122465
|
-
|
|
122721
|
+
logger58.debug("Setting secrets", {
|
|
122466
122722
|
userId: ctx.user.id,
|
|
122467
122723
|
slug: slug2,
|
|
122468
122724
|
keyCount: Object.keys(body2).length
|
|
@@ -122479,7 +122735,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
122479
122735
|
if (!key) {
|
|
122480
122736
|
throw ApiError.badRequest("Missing secret key");
|
|
122481
122737
|
}
|
|
122482
|
-
|
|
122738
|
+
logger58.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
|
|
122483
122739
|
await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
|
|
122484
122740
|
return { success: true };
|
|
122485
122741
|
});
|
|
@@ -122489,7 +122745,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
122489
122745
|
deleteSecret
|
|
122490
122746
|
};
|
|
122491
122747
|
});
|
|
122492
|
-
var
|
|
122748
|
+
var logger59;
|
|
122493
122749
|
var seed2;
|
|
122494
122750
|
var init_seed_controller = __esm(() => {
|
|
122495
122751
|
init_esm();
|
|
@@ -122497,7 +122753,7 @@ var init_seed_controller = __esm(() => {
|
|
|
122497
122753
|
init_src2();
|
|
122498
122754
|
init_errors();
|
|
122499
122755
|
init_utils11();
|
|
122500
|
-
|
|
122756
|
+
logger59 = log.scope("SeedController");
|
|
122501
122757
|
seed2 = requireDeveloper(async (ctx) => {
|
|
122502
122758
|
const slug2 = ctx.params.slug;
|
|
122503
122759
|
if (!slug2) {
|
|
@@ -122510,12 +122766,12 @@ var init_seed_controller = __esm(() => {
|
|
|
122510
122766
|
} catch (error2) {
|
|
122511
122767
|
if (error2 instanceof exports_external.ZodError) {
|
|
122512
122768
|
const details = formatZodError(error2);
|
|
122513
|
-
|
|
122769
|
+
logger59.warn("Seed database validation failed", { details });
|
|
122514
122770
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122515
122771
|
}
|
|
122516
122772
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122517
122773
|
}
|
|
122518
|
-
|
|
122774
|
+
logger59.debug("Seeding database", {
|
|
122519
122775
|
userId: ctx.user.id,
|
|
122520
122776
|
slug: slug2,
|
|
122521
122777
|
codeLength: body2.code.length,
|
|
@@ -122524,7 +122780,7 @@ var init_seed_controller = __esm(() => {
|
|
|
122524
122780
|
return ctx.services.seed.seed(slug2, body2.code, ctx.user, body2.secrets);
|
|
122525
122781
|
});
|
|
122526
122782
|
});
|
|
122527
|
-
var
|
|
122783
|
+
var logger60;
|
|
122528
122784
|
var start2;
|
|
122529
122785
|
var end;
|
|
122530
122786
|
var mintToken;
|
|
@@ -122533,13 +122789,13 @@ var init_session_controller = __esm(() => {
|
|
|
122533
122789
|
init_src2();
|
|
122534
122790
|
init_errors();
|
|
122535
122791
|
init_utils11();
|
|
122536
|
-
|
|
122792
|
+
logger60 = log.scope("SessionController");
|
|
122537
122793
|
start2 = requireAuth(async (ctx) => {
|
|
122538
122794
|
const gameIdOrSlug = ctx.params.gameId;
|
|
122539
122795
|
if (!gameIdOrSlug) {
|
|
122540
122796
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
122541
122797
|
}
|
|
122542
|
-
|
|
122798
|
+
logger60.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
122543
122799
|
return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
|
|
122544
122800
|
});
|
|
122545
122801
|
end = requireAuth(async (ctx) => {
|
|
@@ -122551,7 +122807,7 @@ var init_session_controller = __esm(() => {
|
|
|
122551
122807
|
if (!sessionId) {
|
|
122552
122808
|
throw ApiError.badRequest("Missing session ID");
|
|
122553
122809
|
}
|
|
122554
|
-
|
|
122810
|
+
logger60.debug("Ending session", {
|
|
122555
122811
|
userId: ctx.user.id,
|
|
122556
122812
|
gameIdOrSlug,
|
|
122557
122813
|
sessionId,
|
|
@@ -122564,7 +122820,7 @@ var init_session_controller = __esm(() => {
|
|
|
122564
122820
|
if (!gameIdOrSlug) {
|
|
122565
122821
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
122566
122822
|
}
|
|
122567
|
-
|
|
122823
|
+
logger60.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
122568
122824
|
return ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
|
|
122569
122825
|
});
|
|
122570
122826
|
sessions2 = {
|
|
@@ -122573,22 +122829,22 @@ var init_session_controller = __esm(() => {
|
|
|
122573
122829
|
mintToken
|
|
122574
122830
|
};
|
|
122575
122831
|
});
|
|
122576
|
-
var
|
|
122832
|
+
var logger61;
|
|
122577
122833
|
var getShopView;
|
|
122578
122834
|
var shop;
|
|
122579
122835
|
var init_shop_controller = __esm(() => {
|
|
122580
122836
|
init_src2();
|
|
122581
122837
|
init_utils11();
|
|
122582
|
-
|
|
122838
|
+
logger61 = log.scope("ShopController");
|
|
122583
122839
|
getShopView = requireNonAnonymous(async (ctx) => {
|
|
122584
|
-
|
|
122840
|
+
logger61.debug("Getting shop view", { userId: ctx.user.id });
|
|
122585
122841
|
return ctx.services.shop.getShopView(ctx.user);
|
|
122586
122842
|
});
|
|
122587
122843
|
shop = {
|
|
122588
122844
|
getShopView
|
|
122589
122845
|
};
|
|
122590
122846
|
});
|
|
122591
|
-
var
|
|
122847
|
+
var logger62;
|
|
122592
122848
|
var list7;
|
|
122593
122849
|
var getById4;
|
|
122594
122850
|
var create5;
|
|
@@ -122607,9 +122863,9 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122607
122863
|
init_src4();
|
|
122608
122864
|
init_errors();
|
|
122609
122865
|
init_utils11();
|
|
122610
|
-
|
|
122866
|
+
logger62 = log.scope("ShopListingController");
|
|
122611
122867
|
list7 = requireAdmin(async (ctx) => {
|
|
122612
|
-
|
|
122868
|
+
logger62.debug("Listing shop listings", { userId: ctx.user.id });
|
|
122613
122869
|
return ctx.services.shopListing.list();
|
|
122614
122870
|
});
|
|
122615
122871
|
getById4 = requireAdmin(async (ctx) => {
|
|
@@ -122620,7 +122876,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122620
122876
|
if (!isValidUUID(listingId)) {
|
|
122621
122877
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
122622
122878
|
}
|
|
122623
|
-
|
|
122879
|
+
logger62.debug("Getting listing", { userId: ctx.user.id, listingId });
|
|
122624
122880
|
return ctx.services.shopListing.getById(listingId);
|
|
122625
122881
|
});
|
|
122626
122882
|
create5 = requireAdmin(async (ctx) => {
|
|
@@ -122631,12 +122887,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122631
122887
|
} catch (error2) {
|
|
122632
122888
|
if (error2 instanceof exports_external.ZodError) {
|
|
122633
122889
|
const details = formatZodError(error2);
|
|
122634
|
-
|
|
122890
|
+
logger62.warn("Create shop listing validation failed", { details });
|
|
122635
122891
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122636
122892
|
}
|
|
122637
122893
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122638
122894
|
}
|
|
122639
|
-
|
|
122895
|
+
logger62.debug("Creating listing", {
|
|
122640
122896
|
userId: ctx.user.id,
|
|
122641
122897
|
itemId: body2.itemId,
|
|
122642
122898
|
currencyId: body2.currencyId,
|
|
@@ -122659,12 +122915,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122659
122915
|
} catch (error2) {
|
|
122660
122916
|
if (error2 instanceof exports_external.ZodError) {
|
|
122661
122917
|
const details = formatZodError(error2);
|
|
122662
|
-
|
|
122918
|
+
logger62.warn("Update shop listing validation failed", { details });
|
|
122663
122919
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122664
122920
|
}
|
|
122665
122921
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122666
122922
|
}
|
|
122667
|
-
|
|
122923
|
+
logger62.debug("Updating listing", {
|
|
122668
122924
|
userId: ctx.user.id,
|
|
122669
122925
|
listingId,
|
|
122670
122926
|
price: body2.price,
|
|
@@ -122681,7 +122937,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122681
122937
|
if (!isValidUUID(listingId)) {
|
|
122682
122938
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
122683
122939
|
}
|
|
122684
|
-
|
|
122940
|
+
logger62.debug("Deleting listing", { userId: ctx.user.id, listingId });
|
|
122685
122941
|
await ctx.services.shopListing.delete(listingId);
|
|
122686
122942
|
});
|
|
122687
122943
|
listByGame2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -122692,7 +122948,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122692
122948
|
if (!isValidUUID(gameId)) {
|
|
122693
122949
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
122694
122950
|
}
|
|
122695
|
-
|
|
122951
|
+
logger62.debug("Listing game listings", { userId: ctx.user.id, gameId });
|
|
122696
122952
|
return ctx.services.shopListing.listByGame(gameId, ctx.user);
|
|
122697
122953
|
});
|
|
122698
122954
|
getByGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -122707,7 +122963,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122707
122963
|
if (!isValidUUID(itemId)) {
|
|
122708
122964
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
122709
122965
|
}
|
|
122710
|
-
|
|
122966
|
+
logger62.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
|
|
122711
122967
|
return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
|
|
122712
122968
|
});
|
|
122713
122969
|
createForGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -122729,12 +122985,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122729
122985
|
} catch (error2) {
|
|
122730
122986
|
if (error2 instanceof exports_external.ZodError) {
|
|
122731
122987
|
const details = formatZodError(error2);
|
|
122732
|
-
|
|
122988
|
+
logger62.warn("Create game item listing validation failed", { details });
|
|
122733
122989
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122734
122990
|
}
|
|
122735
122991
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122736
122992
|
}
|
|
122737
|
-
|
|
122993
|
+
logger62.debug("Creating game item listing", {
|
|
122738
122994
|
userId: ctx.user.id,
|
|
122739
122995
|
gameId,
|
|
122740
122996
|
itemId,
|
|
@@ -122762,12 +123018,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122762
123018
|
} catch (error2) {
|
|
122763
123019
|
if (error2 instanceof exports_external.ZodError) {
|
|
122764
123020
|
const details = formatZodError(error2);
|
|
122765
|
-
|
|
123021
|
+
logger62.warn("Update game item listing validation failed", { details });
|
|
122766
123022
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122767
123023
|
}
|
|
122768
123024
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122769
123025
|
}
|
|
122770
|
-
|
|
123026
|
+
logger62.debug("Updating game item listing", {
|
|
122771
123027
|
userId: ctx.user.id,
|
|
122772
123028
|
gameId,
|
|
122773
123029
|
itemId,
|
|
@@ -122789,7 +123045,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
122789
123045
|
if (!isValidUUID(itemId)) {
|
|
122790
123046
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
122791
123047
|
}
|
|
122792
|
-
|
|
123048
|
+
logger62.debug("Deleting game item listing", {
|
|
122793
123049
|
userId: ctx.user.id,
|
|
122794
123050
|
gameId,
|
|
122795
123051
|
itemId
|
|
@@ -122814,20 +123070,20 @@ async function getBySlug2(ctx) {
|
|
|
122814
123070
|
if (!slug2) {
|
|
122815
123071
|
throw ApiError.badRequest("Template slug is required");
|
|
122816
123072
|
}
|
|
122817
|
-
|
|
123073
|
+
logger63.debug("Getting sprite by slug", { slug: slug2 });
|
|
122818
123074
|
return ctx.services.sprite.getBySlug(slug2);
|
|
122819
123075
|
}
|
|
122820
|
-
var
|
|
123076
|
+
var logger63;
|
|
122821
123077
|
var sprites;
|
|
122822
123078
|
var init_sprite_controller = __esm(() => {
|
|
122823
123079
|
init_src2();
|
|
122824
123080
|
init_errors();
|
|
122825
|
-
|
|
123081
|
+
logger63 = log.scope("SpriteController");
|
|
122826
123082
|
sprites = {
|
|
122827
123083
|
getBySlug: getBySlug2
|
|
122828
123084
|
};
|
|
122829
123085
|
});
|
|
122830
|
-
var
|
|
123086
|
+
var logger64;
|
|
122831
123087
|
var getTodayXp;
|
|
122832
123088
|
var getTotalXp;
|
|
122833
123089
|
var updateTodayXp;
|
|
@@ -122842,6 +123098,7 @@ var getConfig2;
|
|
|
122842
123098
|
var deleteIntegrations;
|
|
122843
123099
|
var endActivity;
|
|
122844
123100
|
var heartbeat;
|
|
123101
|
+
var advanceCourse;
|
|
122845
123102
|
var getStudentXp;
|
|
122846
123103
|
var getRoster;
|
|
122847
123104
|
var getStudentOverview;
|
|
@@ -122861,15 +123118,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
122861
123118
|
init_src4();
|
|
122862
123119
|
init_errors();
|
|
122863
123120
|
init_utils11();
|
|
122864
|
-
|
|
123121
|
+
logger64 = log.scope("TimebackController");
|
|
122865
123122
|
getTodayXp = requireNonAnonymous(async (ctx) => {
|
|
122866
123123
|
const date4 = ctx.url.searchParams.get("date") || undefined;
|
|
122867
123124
|
const tz = ctx.url.searchParams.get("tz") || undefined;
|
|
122868
|
-
|
|
123125
|
+
logger64.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
|
|
122869
123126
|
return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
|
|
122870
123127
|
});
|
|
122871
123128
|
getTotalXp = requireNonAnonymous(async (ctx) => {
|
|
122872
|
-
|
|
123129
|
+
logger64.debug("Getting total XP", { userId: ctx.user.id });
|
|
122873
123130
|
return ctx.services.timeback.getTotalXp(ctx.user.id);
|
|
122874
123131
|
});
|
|
122875
123132
|
updateTodayXp = requireNonAnonymous(async (ctx) => {
|
|
@@ -122880,18 +123137,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
122880
123137
|
} catch (error2) {
|
|
122881
123138
|
if (error2 instanceof exports_external.ZodError) {
|
|
122882
123139
|
const details = formatZodError(error2);
|
|
122883
|
-
|
|
123140
|
+
logger64.warn("Update today XP validation failed", { details });
|
|
122884
123141
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122885
123142
|
}
|
|
122886
123143
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122887
123144
|
}
|
|
122888
|
-
|
|
123145
|
+
logger64.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
|
|
122889
123146
|
return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
|
|
122890
123147
|
});
|
|
122891
123148
|
getXpHistory = requireNonAnonymous(async (ctx) => {
|
|
122892
123149
|
const startDate = ctx.url.searchParams.get("startDate") || undefined;
|
|
122893
123150
|
const endDate = ctx.url.searchParams.get("endDate") || undefined;
|
|
122894
|
-
|
|
123151
|
+
logger64.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
|
|
122895
123152
|
return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
|
|
122896
123153
|
});
|
|
122897
123154
|
populateStudent = requireNonAnonymous(async (ctx) => {
|
|
@@ -122902,18 +123159,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
122902
123159
|
} catch (error2) {
|
|
122903
123160
|
if (error2 instanceof exports_external.ZodError) {
|
|
122904
123161
|
const details = formatZodError(error2);
|
|
122905
|
-
|
|
123162
|
+
logger64.warn("Populate student validation failed", { details });
|
|
122906
123163
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122907
123164
|
}
|
|
122908
123165
|
}
|
|
122909
|
-
|
|
123166
|
+
logger64.debug("Populating student", {
|
|
122910
123167
|
userId: ctx.user.id,
|
|
122911
123168
|
hasProvidedNames: Boolean(providedNames)
|
|
122912
123169
|
});
|
|
122913
123170
|
return ctx.services.timeback.populateStudent(ctx.user, providedNames);
|
|
122914
123171
|
});
|
|
122915
123172
|
getUser = requireNonAnonymous(async (ctx) => {
|
|
122916
|
-
|
|
123173
|
+
logger64.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
122917
123174
|
return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
|
|
122918
123175
|
});
|
|
122919
123176
|
getUserById = requireNonAnonymous(async (ctx) => {
|
|
@@ -122921,7 +123178,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122921
123178
|
if (!timebackId) {
|
|
122922
123179
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
122923
123180
|
}
|
|
122924
|
-
|
|
123181
|
+
logger64.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
|
|
122925
123182
|
return ctx.services.timeback.getUserDataByTimebackId(timebackId);
|
|
122926
123183
|
});
|
|
122927
123184
|
setupIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -122932,12 +123189,12 @@ var init_timeback_controller = __esm(() => {
|
|
|
122932
123189
|
} catch (error2) {
|
|
122933
123190
|
if (error2 instanceof exports_external.ZodError) {
|
|
122934
123191
|
const details = formatZodError(error2);
|
|
122935
|
-
|
|
123192
|
+
logger64.warn("Setup integration validation failed", { details });
|
|
122936
123193
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122937
123194
|
}
|
|
122938
123195
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122939
123196
|
}
|
|
122940
|
-
|
|
123197
|
+
logger64.debug("Setting up integration", {
|
|
122941
123198
|
userId: ctx.user.id,
|
|
122942
123199
|
gameId: body2.gameId
|
|
122943
123200
|
});
|
|
@@ -122951,7 +123208,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122951
123208
|
if (!isValidUUID(gameId)) {
|
|
122952
123209
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122953
123210
|
}
|
|
122954
|
-
|
|
123211
|
+
logger64.debug("Getting integrations", { userId: ctx.user.id, gameId });
|
|
122955
123212
|
return ctx.services.timeback.getIntegrations(gameId, ctx.user);
|
|
122956
123213
|
});
|
|
122957
123214
|
verifyIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -122962,7 +123219,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122962
123219
|
if (!isValidUUID(gameId)) {
|
|
122963
123220
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122964
123221
|
}
|
|
122965
|
-
|
|
123222
|
+
logger64.debug("Verifying integration", { userId: ctx.user.id, gameId });
|
|
122966
123223
|
return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
|
|
122967
123224
|
});
|
|
122968
123225
|
getConfig2 = requireDeveloper(async (ctx) => {
|
|
@@ -122973,7 +123230,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122973
123230
|
if (!isValidUUID(gameId)) {
|
|
122974
123231
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122975
123232
|
}
|
|
122976
|
-
|
|
123233
|
+
logger64.debug("Getting config", { userId: ctx.user.id, gameId });
|
|
122977
123234
|
return ctx.services.timeback.getConfig(gameId, ctx.user);
|
|
122978
123235
|
});
|
|
122979
123236
|
deleteIntegrations = requireDeveloper(async (ctx) => {
|
|
@@ -122984,7 +123241,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122984
123241
|
if (!isValidUUID(gameId)) {
|
|
122985
123242
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
122986
123243
|
}
|
|
122987
|
-
|
|
123244
|
+
logger64.debug("Deleting integrations", { userId: ctx.user.id, gameId });
|
|
122988
123245
|
await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
|
|
122989
123246
|
});
|
|
122990
123247
|
endActivity = requireDeveloper(async (ctx) => {
|
|
@@ -122995,7 +123252,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
122995
123252
|
} catch (error2) {
|
|
122996
123253
|
if (error2 instanceof exports_external.ZodError) {
|
|
122997
123254
|
const details = formatZodError(error2);
|
|
122998
|
-
|
|
123255
|
+
logger64.warn("End activity validation failed", { details });
|
|
122999
123256
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123000
123257
|
}
|
|
123001
123258
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -123013,7 +123270,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123013
123270
|
masteredUnits,
|
|
123014
123271
|
extensions
|
|
123015
123272
|
} = body2;
|
|
123016
|
-
|
|
123273
|
+
logger64.debug("Ending activity", { userId: ctx.user.id, gameId });
|
|
123017
123274
|
return ctx.services.timeback.endActivity({
|
|
123018
123275
|
gameId,
|
|
123019
123276
|
studentId,
|
|
@@ -123037,7 +123294,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123037
123294
|
} catch (error2) {
|
|
123038
123295
|
if (error2 instanceof exports_external.ZodError) {
|
|
123039
123296
|
const details = formatZodError(error2);
|
|
123040
|
-
|
|
123297
|
+
logger64.warn("Heartbeat validation failed", { details });
|
|
123041
123298
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123042
123299
|
}
|
|
123043
123300
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -123053,7 +123310,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123053
123310
|
windowSequence,
|
|
123054
123311
|
isFinal
|
|
123055
123312
|
} = body2;
|
|
123056
|
-
|
|
123313
|
+
logger64.debug("Recording heartbeat", {
|
|
123057
123314
|
userId: ctx.user.id,
|
|
123058
123315
|
gameId,
|
|
123059
123316
|
runId,
|
|
@@ -123076,6 +123333,19 @@ var init_timeback_controller = __esm(() => {
|
|
|
123076
123333
|
user: ctx.user
|
|
123077
123334
|
});
|
|
123078
123335
|
});
|
|
123336
|
+
advanceCourse = requireDeveloper(async (ctx) => {
|
|
123337
|
+
const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
|
|
123338
|
+
logger64.debug("Advancing student manually", {
|
|
123339
|
+
userId: ctx.user.id,
|
|
123340
|
+
gameId: body2.gameId,
|
|
123341
|
+
studentId: body2.studentId,
|
|
123342
|
+
subject: body2.subject
|
|
123343
|
+
});
|
|
123344
|
+
return ctx.services.timeback.advanceCourse({
|
|
123345
|
+
...body2,
|
|
123346
|
+
user: ctx.user
|
|
123347
|
+
});
|
|
123348
|
+
});
|
|
123079
123349
|
getStudentXp = requireDeveloper(async (ctx) => {
|
|
123080
123350
|
const timebackId = ctx.params.timebackId;
|
|
123081
123351
|
if (!timebackId) {
|
|
@@ -123106,7 +123376,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123106
123376
|
perCourse: includeOptions.includes("percourse"),
|
|
123107
123377
|
today: includeOptions.includes("today")
|
|
123108
123378
|
};
|
|
123109
|
-
|
|
123379
|
+
logger64.debug("Getting student XP", {
|
|
123110
123380
|
requesterId: ctx.user.id,
|
|
123111
123381
|
timebackId,
|
|
123112
123382
|
gameId,
|
|
@@ -123127,7 +123397,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123127
123397
|
if (!gameId || !courseId) {
|
|
123128
123398
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
123129
123399
|
}
|
|
123130
|
-
|
|
123400
|
+
logger64.debug("Getting course roster", {
|
|
123131
123401
|
requesterId: ctx.user.id,
|
|
123132
123402
|
gameId,
|
|
123133
123403
|
courseId
|
|
@@ -123141,7 +123411,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123141
123411
|
if (!timebackId || !gameId) {
|
|
123142
123412
|
throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
|
|
123143
123413
|
}
|
|
123144
|
-
|
|
123414
|
+
logger64.debug("Getting student overview", {
|
|
123145
123415
|
requesterId: ctx.user.id,
|
|
123146
123416
|
timebackId,
|
|
123147
123417
|
gameId,
|
|
@@ -123160,7 +123430,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123160
123430
|
if (!timebackId || !courseId || !gameId) {
|
|
123161
123431
|
throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
|
|
123162
123432
|
}
|
|
123163
|
-
|
|
123433
|
+
logger64.debug("Getting student activity", {
|
|
123164
123434
|
requesterId: ctx.user.id,
|
|
123165
123435
|
timebackId,
|
|
123166
123436
|
courseId,
|
|
@@ -123178,7 +123448,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123178
123448
|
});
|
|
123179
123449
|
grantXp = requireDeveloper(async (ctx) => {
|
|
123180
123450
|
const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
|
|
123181
|
-
|
|
123451
|
+
logger64.debug("Granting manual XP", {
|
|
123182
123452
|
requesterId: ctx.user.id,
|
|
123183
123453
|
gameId: body2.gameId,
|
|
123184
123454
|
courseId: body2.courseId,
|
|
@@ -123190,7 +123460,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123190
123460
|
});
|
|
123191
123461
|
adjustTime = requireDeveloper(async (ctx) => {
|
|
123192
123462
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
|
|
123193
|
-
|
|
123463
|
+
logger64.debug("Adjusting time spent", {
|
|
123194
123464
|
requesterId: ctx.user.id,
|
|
123195
123465
|
gameId: body2.gameId,
|
|
123196
123466
|
courseId: body2.courseId,
|
|
@@ -123202,7 +123472,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123202
123472
|
});
|
|
123203
123473
|
adjustMastery = requireDeveloper(async (ctx) => {
|
|
123204
123474
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
|
|
123205
|
-
|
|
123475
|
+
logger64.debug("Adjusting mastered units", {
|
|
123206
123476
|
requesterId: ctx.user.id,
|
|
123207
123477
|
gameId: body2.gameId,
|
|
123208
123478
|
courseId: body2.courseId,
|
|
@@ -123214,7 +123484,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123214
123484
|
});
|
|
123215
123485
|
toggleCompletion = requireGameManagementAccess(async (ctx) => {
|
|
123216
123486
|
const body2 = await parseRequestBody(ctx.request, ToggleCourseCompletionRequestSchema);
|
|
123217
|
-
|
|
123487
|
+
logger64.debug("Toggling course completion", {
|
|
123218
123488
|
requesterId: ctx.user.id,
|
|
123219
123489
|
gameId: body2.gameId,
|
|
123220
123490
|
courseId: body2.courseId,
|
|
@@ -123230,7 +123500,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123230
123500
|
if (!gameId || !courseId) {
|
|
123231
123501
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
123232
123502
|
}
|
|
123233
|
-
|
|
123503
|
+
logger64.debug("Searching students for enrollment", {
|
|
123234
123504
|
requesterId: ctx.user.id,
|
|
123235
123505
|
gameId,
|
|
123236
123506
|
courseId,
|
|
@@ -123240,7 +123510,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123240
123510
|
});
|
|
123241
123511
|
enrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
123242
123512
|
const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
|
|
123243
|
-
|
|
123513
|
+
logger64.debug("Enrolling student", {
|
|
123244
123514
|
requesterId: ctx.user.id,
|
|
123245
123515
|
gameId: body2.gameId,
|
|
123246
123516
|
courseId: body2.courseId,
|
|
@@ -123250,7 +123520,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123250
123520
|
});
|
|
123251
123521
|
unenrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
123252
123522
|
const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
|
|
123253
|
-
|
|
123523
|
+
logger64.debug("Unenrolling student", {
|
|
123254
123524
|
requesterId: ctx.user.id,
|
|
123255
123525
|
gameId: body2.gameId,
|
|
123256
123526
|
courseId: body2.courseId,
|
|
@@ -123273,6 +123543,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123273
123543
|
deleteIntegrations,
|
|
123274
123544
|
endActivity,
|
|
123275
123545
|
heartbeat,
|
|
123546
|
+
advanceCourse,
|
|
123276
123547
|
getStudentXp,
|
|
123277
123548
|
getRoster,
|
|
123278
123549
|
getStudentOverview,
|
|
@@ -123286,7 +123557,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
123286
123557
|
unenrollStudent
|
|
123287
123558
|
};
|
|
123288
123559
|
});
|
|
123289
|
-
var
|
|
123560
|
+
var logger65;
|
|
123290
123561
|
var initiate;
|
|
123291
123562
|
var init_upload_controller = __esm(() => {
|
|
123292
123563
|
init_esm();
|
|
@@ -123294,7 +123565,7 @@ var init_upload_controller = __esm(() => {
|
|
|
123294
123565
|
init_src2();
|
|
123295
123566
|
init_errors();
|
|
123296
123567
|
init_utils11();
|
|
123297
|
-
|
|
123568
|
+
logger65 = log.scope("UploadController");
|
|
123298
123569
|
initiate = requireDeveloper(async (ctx) => {
|
|
123299
123570
|
let body2;
|
|
123300
123571
|
try {
|
|
@@ -123303,16 +123574,16 @@ var init_upload_controller = __esm(() => {
|
|
|
123303
123574
|
} catch (error2) {
|
|
123304
123575
|
if (error2 instanceof exports_external.ZodError) {
|
|
123305
123576
|
const details = formatZodError(error2);
|
|
123306
|
-
|
|
123577
|
+
logger65.warn("Initiate upload validation failed", { details });
|
|
123307
123578
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123308
123579
|
}
|
|
123309
123580
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123310
123581
|
}
|
|
123311
|
-
|
|
123582
|
+
logger65.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
|
|
123312
123583
|
return ctx.services.upload.initiate(body2, ctx.user);
|
|
123313
123584
|
});
|
|
123314
123585
|
});
|
|
123315
|
-
var
|
|
123586
|
+
var logger66;
|
|
123316
123587
|
var getMe;
|
|
123317
123588
|
var getDemoProfile;
|
|
123318
123589
|
var updateDemoProfile;
|
|
@@ -123321,18 +123592,18 @@ var init_user_controller = __esm(() => {
|
|
|
123321
123592
|
init_schemas_index();
|
|
123322
123593
|
init_src2();
|
|
123323
123594
|
init_utils11();
|
|
123324
|
-
|
|
123595
|
+
logger66 = log.scope("UserController");
|
|
123325
123596
|
getMe = requireNonAnonymous(async (ctx) => {
|
|
123326
|
-
|
|
123597
|
+
logger66.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
123327
123598
|
return ctx.services.user.getMe(ctx.user, ctx.gameId);
|
|
123328
123599
|
});
|
|
123329
123600
|
getDemoProfile = requireAnonymous(async (ctx) => {
|
|
123330
|
-
|
|
123601
|
+
logger66.debug("Getting demo profile", { userId: ctx.user.id });
|
|
123331
123602
|
return ctx.services.user.getDemoProfile(ctx.user.id);
|
|
123332
123603
|
});
|
|
123333
123604
|
updateDemoProfile = requireAnonymous(async (ctx) => {
|
|
123334
123605
|
const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
|
|
123335
|
-
|
|
123606
|
+
logger66.debug("Updating demo profile", {
|
|
123336
123607
|
userId: ctx.user.id,
|
|
123337
123608
|
displayName: body2.displayName
|
|
123338
123609
|
});
|
|
@@ -123344,13 +123615,13 @@ var init_user_controller = __esm(() => {
|
|
|
123344
123615
|
updateDemoProfile
|
|
123345
123616
|
};
|
|
123346
123617
|
});
|
|
123347
|
-
var
|
|
123618
|
+
var logger67;
|
|
123348
123619
|
var init_verify_controller = __esm(() => {
|
|
123349
123620
|
init_schemas_index();
|
|
123350
123621
|
init_src2();
|
|
123351
123622
|
init_errors();
|
|
123352
123623
|
init_utils11();
|
|
123353
|
-
|
|
123624
|
+
logger67 = log.scope("VerifyController");
|
|
123354
123625
|
});
|
|
123355
123626
|
var init_controllers = __esm(() => {
|
|
123356
123627
|
init_achievement_controller();
|
|
@@ -123647,7 +123918,7 @@ var init_uploads = __esm(() => {
|
|
|
123647
123918
|
gameUploadsRouter.post("/uploads/finalize", finalizeHandler);
|
|
123648
123919
|
gameUploadsRouter.post("/uploads/finalize/", finalizeHandler);
|
|
123649
123920
|
});
|
|
123650
|
-
var
|
|
123921
|
+
var logger68;
|
|
123651
123922
|
var gameDeployRouter;
|
|
123652
123923
|
var init_deploy = __esm(() => {
|
|
123653
123924
|
init_drizzle_orm();
|
|
@@ -123658,7 +123929,7 @@ var init_deploy = __esm(() => {
|
|
|
123658
123929
|
init_src2();
|
|
123659
123930
|
init_api();
|
|
123660
123931
|
init_uploads();
|
|
123661
|
-
|
|
123932
|
+
logger68 = log.scope("SandboxDeploy");
|
|
123662
123933
|
gameDeployRouter = new Hono2;
|
|
123663
123934
|
gameDeployRouter.post("/:slug/deploy", async (c2) => {
|
|
123664
123935
|
const user = c2.get("user");
|
|
@@ -123775,7 +124046,7 @@ var init_deploy = __esm(() => {
|
|
|
123775
124046
|
completedAt: now2
|
|
123776
124047
|
};
|
|
123777
124048
|
const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
|
|
123778
|
-
|
|
124049
|
+
logger68.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
|
|
123779
124050
|
return c2.json({
|
|
123780
124051
|
id: insertedJob.id,
|
|
123781
124052
|
status: "succeeded",
|
|
@@ -124281,6 +124552,7 @@ var init_timeback6 = __esm(() => {
|
|
|
124281
124552
|
timebackRouter.delete("/integrations/:gameId", handle2(timeback2.deleteIntegrations, { status: 204 }));
|
|
124282
124553
|
timebackRouter.post("/end-activity", handle2(timeback2.endActivity));
|
|
124283
124554
|
timebackRouter.post("/heartbeat", handle2(timeback2.heartbeat));
|
|
124555
|
+
timebackRouter.post("/advance-course", handle2(timeback2.advanceCourse));
|
|
124284
124556
|
timebackRouter.get("/user", async (c2) => {
|
|
124285
124557
|
const user = c2.get("user");
|
|
124286
124558
|
const gameId = c2.get("gameId");
|
|
@@ -124366,7 +124638,7 @@ function verifyMockToken(idToken) {
|
|
|
124366
124638
|
throw new Error("Invalid LTI token format");
|
|
124367
124639
|
}
|
|
124368
124640
|
}
|
|
124369
|
-
var
|
|
124641
|
+
var logger69;
|
|
124370
124642
|
var ltiRouter;
|
|
124371
124643
|
var init_lti = __esm(() => {
|
|
124372
124644
|
init_drizzle_orm();
|
|
@@ -124377,7 +124649,7 @@ var init_lti = __esm(() => {
|
|
|
124377
124649
|
init_src2();
|
|
124378
124650
|
init_constants();
|
|
124379
124651
|
init_api();
|
|
124380
|
-
|
|
124652
|
+
logger69 = log.scope("SandboxLti");
|
|
124381
124653
|
ltiRouter = new Hono2;
|
|
124382
124654
|
ltiRouter.post("/launch", async (c2) => {
|
|
124383
124655
|
const db2 = c2.get("db");
|
|
@@ -124395,7 +124667,7 @@ var init_lti = __esm(() => {
|
|
|
124395
124667
|
claims = verifyMockToken(idToken);
|
|
124396
124668
|
} catch (error2) {
|
|
124397
124669
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
124398
|
-
|
|
124670
|
+
logger69.error("LTI token verification failed", { error: errorMessage });
|
|
124399
124671
|
return c2.json({
|
|
124400
124672
|
error: "invalid_token",
|
|
124401
124673
|
message: errorMessage
|
|
@@ -124403,7 +124675,7 @@ var init_lti = __esm(() => {
|
|
|
124403
124675
|
}
|
|
124404
124676
|
const validationError = validateLtiClaims(claims);
|
|
124405
124677
|
if (validationError) {
|
|
124406
|
-
|
|
124678
|
+
logger69.warn("LTI claims validation failed", {
|
|
124407
124679
|
error: validationError,
|
|
124408
124680
|
sub: claims.sub
|
|
124409
124681
|
});
|
|
@@ -124423,7 +124695,7 @@ var init_lti = __esm(() => {
|
|
|
124423
124695
|
createdAt: new Date,
|
|
124424
124696
|
updatedAt: new Date
|
|
124425
124697
|
});
|
|
124426
|
-
|
|
124698
|
+
logger69.info("LTI launch successful", { userId: user.id });
|
|
124427
124699
|
const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
|
|
124428
124700
|
const currentHost = new URL(c2.req.url).hostname;
|
|
124429
124701
|
const redirectPath = extractRedirectPath(targetUri, currentHost);
|
|
@@ -124431,7 +124703,7 @@ var init_lti = __esm(() => {
|
|
|
124431
124703
|
return c2.redirect(redirectPath);
|
|
124432
124704
|
} catch (error2) {
|
|
124433
124705
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
124434
|
-
|
|
124706
|
+
logger69.error("Unexpected error during LTI launch", { error: errorMessage });
|
|
124435
124707
|
return c2.json({
|
|
124436
124708
|
error: "unexpected_error",
|
|
124437
124709
|
message: "An unexpected error occurred during LTI launch"
|
|
@@ -125022,10 +125294,10 @@ var ACHIEVEMENT_DEFINITIONS2 = [
|
|
|
125022
125294
|
var TypeScriptPackages2 = {
|
|
125023
125295
|
tsc: "tsc",
|
|
125024
125296
|
nativePreview: "@typescript/native-preview",
|
|
125025
|
-
|
|
125297
|
+
nativePreviewBeta: "@typescript/native-preview@beta"
|
|
125026
125298
|
};
|
|
125027
125299
|
var TYPESCRIPT_RUNNER2 = {
|
|
125028
|
-
package: TypeScriptPackages2.
|
|
125300
|
+
package: TypeScriptPackages2.nativePreviewBeta,
|
|
125029
125301
|
bin: "tsgo"
|
|
125030
125302
|
};
|
|
125031
125303
|
// ../constants/src/overworld.ts
|
|
@@ -125334,10 +125606,10 @@ var init_typescript2 = __esm7(() => {
|
|
|
125334
125606
|
TypeScriptPackages3 = {
|
|
125335
125607
|
tsc: "tsc",
|
|
125336
125608
|
nativePreview: "@typescript/native-preview",
|
|
125337
|
-
|
|
125609
|
+
nativePreviewBeta: "@typescript/native-preview@beta"
|
|
125338
125610
|
};
|
|
125339
125611
|
TYPESCRIPT_RUNNER3 = {
|
|
125340
|
-
package: TypeScriptPackages3.
|
|
125612
|
+
package: TypeScriptPackages3.nativePreviewBeta,
|
|
125341
125613
|
bin: "tsgo"
|
|
125342
125614
|
};
|
|
125343
125615
|
});
|
|
@@ -125419,7 +125691,8 @@ var init_timeback7 = __esm7(() => {
|
|
|
125419
125691
|
TIMEBACK_ROUTES2 = {
|
|
125420
125692
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
125421
125693
|
GET_XP: "/integrations/timeback/xp",
|
|
125422
|
-
HEARTBEAT: "/integrations/timeback/heartbeat"
|
|
125694
|
+
HEARTBEAT: "/integrations/timeback/heartbeat",
|
|
125695
|
+
ADVANCE_COURSE: "/integrations/timeback/advance-course"
|
|
125423
125696
|
};
|
|
125424
125697
|
TIMEBACK_COURSE_DEFAULTS2 = {
|
|
125425
125698
|
gradingScheme: "STANDARD",
|
|
@@ -126096,7 +126369,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
|
126096
126369
|
// package.json
|
|
126097
126370
|
var package_default2 = {
|
|
126098
126371
|
name: "@playcademy/vite-plugin",
|
|
126099
|
-
version: "0.2.26-beta.
|
|
126372
|
+
version: "0.2.26-beta.5",
|
|
126100
126373
|
type: "module",
|
|
126101
126374
|
exports: {
|
|
126102
126375
|
".": {
|