@playcademy/sandbox 0.3.18-beta.2 → 0.3.19-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +848 -502
- package/dist/server.js +848 -502
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -1316,7 +1316,7 @@ var package_default;
|
|
|
1316
1316
|
var init_package = __esm(() => {
|
|
1317
1317
|
package_default = {
|
|
1318
1318
|
name: "@playcademy/sandbox",
|
|
1319
|
-
version: "0.3.
|
|
1319
|
+
version: "0.3.19-beta.1",
|
|
1320
1320
|
description: "Local development server for Playcademy game development",
|
|
1321
1321
|
type: "module",
|
|
1322
1322
|
exports: {
|
|
@@ -30453,6 +30453,24 @@ var init_src4 = __esm(() => {
|
|
|
30453
30453
|
init_pure();
|
|
30454
30454
|
});
|
|
30455
30455
|
|
|
30456
|
+
// ../utils/src/timeback.ts
|
|
30457
|
+
function formatGradeLabel(grade) {
|
|
30458
|
+
switch (grade) {
|
|
30459
|
+
case -1: {
|
|
30460
|
+
return "Pre-K";
|
|
30461
|
+
}
|
|
30462
|
+
case 0: {
|
|
30463
|
+
return "Kindergarten";
|
|
30464
|
+
}
|
|
30465
|
+
case 13: {
|
|
30466
|
+
return "AP";
|
|
30467
|
+
}
|
|
30468
|
+
default: {
|
|
30469
|
+
return `Grade ${grade}`;
|
|
30470
|
+
}
|
|
30471
|
+
}
|
|
30472
|
+
}
|
|
30473
|
+
|
|
30456
30474
|
// ../../node_modules/.bun/drizzle-zod@0.7.1+e9f18f9688af15ce/node_modules/drizzle-zod/index.mjs
|
|
30457
30475
|
function isColumnType(column2, columnTypes) {
|
|
30458
30476
|
return columnTypes.includes(column2.columnType);
|
|
@@ -31162,7 +31180,7 @@ function isValidAdminAttributionDate(value) {
|
|
|
31162
31180
|
const date3 = new Date(Date.UTC(year, month - 1, day, 12, 0, 0));
|
|
31163
31181
|
return date3.getUTCFullYear() === year && date3.getUTCMonth() + 1 === month && date3.getUTCDate() === day;
|
|
31164
31182
|
}
|
|
31165
|
-
var TIMEBACK_GRADES, TIMEBACK_SUBJECTS4, TimebackGradeSchema, TimebackSubjectSchema, UpdateTimebackXpRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameActivityMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, HeartbeatRequestSchema, PopulateStudentRequestSchema, DerivedPlatformCourseConfigSchema, TimebackBaseConfigSchema, PlatformTimebackSetupRequestSchema, AdminTimebackMutationBaseSchema, AdminAttributionDateSchema, GrantTimebackXpRequestSchema, AdjustTimebackTimeRequestSchema, AdjustTimebackMasteryRequestSchema, EnrollStudentRequestSchema, UnenrollStudentRequestSchema, ReactivateEnrollmentRequestSchema, InsertAssessmentTestSchema, CreateAssessmentRequestSchema, ReorderAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
|
|
31183
|
+
var TIMEBACK_GRADES, TIMEBACK_SUBJECTS4, TimebackGradeSchema, TimebackSubjectSchema, UpdateTimebackXpRequestSchema, CourseGoalsSchema, UpdateGameTimebackIntegrationRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameActivityMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, HeartbeatRequestSchema, PopulateStudentRequestSchema, DerivedPlatformCourseConfigSchema, TimebackBaseConfigSchema, PlatformTimebackSetupRequestSchema, AdminTimebackMutationBaseSchema, AdminAttributionDateSchema, ADMIN_GRANT_XP_MIN = -1e5, ADMIN_GRANT_XP_MAX = 1e5, ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE, GrantTimebackXpRequestSchema, AdjustTimebackTimeRequestSchema, AdjustTimebackMasteryRequestSchema, ReconcileMasteryForConfigChangeSchema, EnrollStudentRequestSchema, UnenrollStudentRequestSchema, ReactivateEnrollmentRequestSchema, InsertAssessmentTestSchema, CreateAssessmentRequestSchema, ReorderAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
|
|
31166
31184
|
var init_schemas11 = __esm(() => {
|
|
31167
31185
|
init_drizzle_zod();
|
|
31168
31186
|
init_esm();
|
|
@@ -31187,6 +31205,24 @@ var init_schemas11 = __esm(() => {
|
|
|
31187
31205
|
xp: exports_external.number().min(0, "XP must be a non-negative number"),
|
|
31188
31206
|
userTimestamp: exports_external.string().datetime().optional()
|
|
31189
31207
|
});
|
|
31208
|
+
CourseGoalsSchema = exports_external.object({
|
|
31209
|
+
dailyXp: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31210
|
+
dailyLessons: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31211
|
+
dailyActiveMinutes: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31212
|
+
dailyAccuracy: exports_external.number().int().min(0).max(100).nullable().optional(),
|
|
31213
|
+
dailyMasteredUnits: exports_external.number().int().nonnegative().nullable().optional()
|
|
31214
|
+
});
|
|
31215
|
+
UpdateGameTimebackIntegrationRequestSchema = exports_external.object({
|
|
31216
|
+
title: exports_external.string().trim().min(1).optional(),
|
|
31217
|
+
courseCode: exports_external.string().trim().min(1).optional(),
|
|
31218
|
+
subject: TimebackSubjectSchema.optional(),
|
|
31219
|
+
totalXp: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31220
|
+
masterableUnits: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31221
|
+
goals: CourseGoalsSchema.optional(),
|
|
31222
|
+
publishStatus: exports_external.enum(["draft", "testing", "published", "deactivated"]).nullable().optional(),
|
|
31223
|
+
isSupplemental: exports_external.boolean().optional(),
|
|
31224
|
+
timebackVisible: exports_external.boolean().nullable().optional()
|
|
31225
|
+
});
|
|
31190
31226
|
TimebackActivityDataSchema = exports_external.object({
|
|
31191
31227
|
activityId: exports_external.string().min(1),
|
|
31192
31228
|
activityName: exports_external.string().optional(),
|
|
@@ -31340,8 +31376,9 @@ var init_schemas11 = __esm(() => {
|
|
|
31340
31376
|
});
|
|
31341
31377
|
}
|
|
31342
31378
|
});
|
|
31379
|
+
ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE = `Amount must be between ${ADMIN_GRANT_XP_MIN} and ${ADMIN_GRANT_XP_MAX}`;
|
|
31343
31380
|
GrantTimebackXpRequestSchema = AdminTimebackMutationBaseSchema.extend({
|
|
31344
|
-
xp: exports_external.number().min(
|
|
31381
|
+
xp: exports_external.number().min(ADMIN_GRANT_XP_MIN, ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE).max(ADMIN_GRANT_XP_MAX, ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE).refine((value) => value !== 0, { message: "Amount cannot be 0" }),
|
|
31345
31382
|
date: AdminAttributionDateSchema.optional(),
|
|
31346
31383
|
useCurrentTime: exports_external.boolean().optional()
|
|
31347
31384
|
});
|
|
@@ -31355,6 +31392,13 @@ var init_schemas11 = __esm(() => {
|
|
|
31355
31392
|
date: AdminAttributionDateSchema.optional(),
|
|
31356
31393
|
useCurrentTime: exports_external.boolean().optional()
|
|
31357
31394
|
});
|
|
31395
|
+
ReconcileMasteryForConfigChangeSchema = exports_external.object({
|
|
31396
|
+
gameId: exports_external.string().uuid(),
|
|
31397
|
+
courseId: exports_external.string().min(1),
|
|
31398
|
+
oldMasterableUnits: exports_external.number().int().positive(),
|
|
31399
|
+
newMasterableUnits: exports_external.number().int().positive(),
|
|
31400
|
+
affectedStudentIds: exports_external.array(exports_external.string().min(1)).min(1).max(500)
|
|
31401
|
+
});
|
|
31358
31402
|
EnrollStudentRequestSchema = exports_external.object({
|
|
31359
31403
|
gameId: exports_external.string().uuid(),
|
|
31360
31404
|
courseId: exports_external.string().min(1),
|
|
@@ -31510,6 +31554,65 @@ var init_timeback_admin_util = __esm(() => {
|
|
|
31510
31554
|
init_errors();
|
|
31511
31555
|
});
|
|
31512
31556
|
|
|
31557
|
+
// ../api-core/src/utils/timeback-mastery-completion.util.ts
|
|
31558
|
+
async function upsertMasteryCompletionEntry(params) {
|
|
31559
|
+
const { client, courseId, studentId, appName, action } = params;
|
|
31560
|
+
const ids = deriveSourcedIds(courseId);
|
|
31561
|
+
const lineItemId = `${ids.course}-mastery-completion-assessment`;
|
|
31562
|
+
const resultId = `${lineItemId}:${studentId}:completion`;
|
|
31563
|
+
if (action === "complete") {
|
|
31564
|
+
await client.oneroster.assessmentLineItems.findOrCreate(lineItemId, {
|
|
31565
|
+
sourcedId: lineItemId,
|
|
31566
|
+
title: "Mastery Completion",
|
|
31567
|
+
status: ONEROSTER_STATUS.active,
|
|
31568
|
+
course: { sourcedId: ids.course },
|
|
31569
|
+
...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
|
|
31570
|
+
});
|
|
31571
|
+
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
31572
|
+
sourcedId: resultId,
|
|
31573
|
+
status: ONEROSTER_STATUS.active,
|
|
31574
|
+
assessmentLineItem: { sourcedId: lineItemId },
|
|
31575
|
+
student: { sourcedId: studentId },
|
|
31576
|
+
score: 100,
|
|
31577
|
+
scoreDate: new Date().toISOString(),
|
|
31578
|
+
scoreStatus: SCORE_STATUS.fullyGraded,
|
|
31579
|
+
inProgress: "false",
|
|
31580
|
+
metadata: {
|
|
31581
|
+
isMasteryCompletion: true,
|
|
31582
|
+
adminAction: true,
|
|
31583
|
+
appName
|
|
31584
|
+
}
|
|
31585
|
+
});
|
|
31586
|
+
} else {
|
|
31587
|
+
try {
|
|
31588
|
+
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
31589
|
+
sourcedId: resultId,
|
|
31590
|
+
status: ONEROSTER_STATUS.active,
|
|
31591
|
+
assessmentLineItem: { sourcedId: lineItemId },
|
|
31592
|
+
student: { sourcedId: studentId },
|
|
31593
|
+
score: 0,
|
|
31594
|
+
scoreDate: new Date().toISOString(),
|
|
31595
|
+
scoreStatus: SCORE_STATUS.notSubmitted,
|
|
31596
|
+
inProgress: "true",
|
|
31597
|
+
metadata: {
|
|
31598
|
+
isMasteryCompletion: true,
|
|
31599
|
+
adminAction: true,
|
|
31600
|
+
appName
|
|
31601
|
+
}
|
|
31602
|
+
});
|
|
31603
|
+
} catch {
|
|
31604
|
+
logger17.debug("No completion entry to revoke", { studentId, courseId });
|
|
31605
|
+
}
|
|
31606
|
+
}
|
|
31607
|
+
}
|
|
31608
|
+
var logger17;
|
|
31609
|
+
var init_timeback_mastery_completion_util = __esm(() => {
|
|
31610
|
+
init_src2();
|
|
31611
|
+
init_constants4();
|
|
31612
|
+
init_utils6();
|
|
31613
|
+
logger17 = log.scope("timeback-mastery-completion");
|
|
31614
|
+
});
|
|
31615
|
+
|
|
31513
31616
|
// ../api-core/src/utils/timeback.util.ts
|
|
31514
31617
|
function isRecord2(value) {
|
|
31515
31618
|
return typeof value === "object" && value !== null;
|
|
@@ -31867,7 +31970,7 @@ class TimebackAdminService {
|
|
|
31867
31970
|
}
|
|
31868
31971
|
requireClient() {
|
|
31869
31972
|
if (!this.deps.timeback) {
|
|
31870
|
-
|
|
31973
|
+
logger18.error("Timeback client not available in context");
|
|
31871
31974
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
31872
31975
|
}
|
|
31873
31976
|
return this.deps.timeback;
|
|
@@ -32087,7 +32190,7 @@ class TimebackAdminService {
|
|
|
32087
32190
|
});
|
|
32088
32191
|
return [enrollmentId, this.summarizeAnalyticsFacts(analytics.facts)];
|
|
32089
32192
|
} catch (error) {
|
|
32090
|
-
|
|
32193
|
+
logger18.warn("Failed to load enrollment analytics summary", {
|
|
32091
32194
|
enrollmentId,
|
|
32092
32195
|
error: error instanceof Error ? error.message : String(error)
|
|
32093
32196
|
});
|
|
@@ -32117,7 +32220,7 @@ class TimebackAdminService {
|
|
|
32117
32220
|
const events = await this.fetchCaliperEventsForStudent(client, studentId, source, eventLimit);
|
|
32118
32221
|
return TimebackAdminService.mapRecentActivityItems(events, relevantCourseIds).slice(0, maxResults);
|
|
32119
32222
|
} catch (error) {
|
|
32120
|
-
|
|
32223
|
+
logger18.warn("Failed to load recent Caliper activity", {
|
|
32121
32224
|
studentId,
|
|
32122
32225
|
gameId: source.gameId,
|
|
32123
32226
|
sourceMode: source.sourceMode,
|
|
@@ -32296,7 +32399,7 @@ class TimebackAdminService {
|
|
|
32296
32399
|
}) : undefined;
|
|
32297
32400
|
return {
|
|
32298
32401
|
courseId: integration.courseId,
|
|
32299
|
-
title: enrollment?.course.title || `${integration.subject}
|
|
32402
|
+
title: enrollment?.course.title || `${integration.subject} ${formatGradeLabel(integration.grade)}`,
|
|
32300
32403
|
grade: integration.grade,
|
|
32301
32404
|
subject: integration.subject,
|
|
32302
32405
|
enrollmentId: enrollment?.id || null,
|
|
@@ -32443,60 +32546,44 @@ class TimebackAdminService {
|
|
|
32443
32546
|
const wasMastered = currentMastered >= masterableUnits;
|
|
32444
32547
|
const willBeMastered = currentMastered + data.units >= masterableUnits;
|
|
32445
32548
|
if (wasMastered !== willBeMastered) {
|
|
32446
|
-
|
|
32447
|
-
|
|
32448
|
-
|
|
32449
|
-
|
|
32450
|
-
|
|
32451
|
-
|
|
32452
|
-
|
|
32453
|
-
status: ONEROSTER_STATUS.active,
|
|
32454
|
-
course: { sourcedId: ids.course },
|
|
32455
|
-
...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
|
|
32456
|
-
});
|
|
32457
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
32458
|
-
sourcedId: resultId,
|
|
32459
|
-
status: ONEROSTER_STATUS.active,
|
|
32460
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
32461
|
-
student: { sourcedId: data.studentId },
|
|
32462
|
-
score: 100,
|
|
32463
|
-
scoreDate: new Date().toISOString(),
|
|
32464
|
-
scoreStatus: SCORE_STATUS.fullyGraded,
|
|
32465
|
-
inProgress: "false",
|
|
32466
|
-
metadata: {
|
|
32467
|
-
isMasteryCompletion: true,
|
|
32468
|
-
adminAction: true,
|
|
32469
|
-
appName
|
|
32470
|
-
}
|
|
32471
|
-
});
|
|
32472
|
-
} else {
|
|
32473
|
-
try {
|
|
32474
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
32475
|
-
sourcedId: resultId,
|
|
32476
|
-
status: ONEROSTER_STATUS.active,
|
|
32477
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
32478
|
-
student: { sourcedId: data.studentId },
|
|
32479
|
-
score: 0,
|
|
32480
|
-
scoreDate: new Date().toISOString(),
|
|
32481
|
-
scoreStatus: SCORE_STATUS.notSubmitted,
|
|
32482
|
-
inProgress: "true",
|
|
32483
|
-
metadata: {
|
|
32484
|
-
isMasteryCompletion: true,
|
|
32485
|
-
adminAction: true,
|
|
32486
|
-
appName
|
|
32487
|
-
}
|
|
32488
|
-
});
|
|
32489
|
-
} catch {
|
|
32490
|
-
logger17.debug("No completion entry to revoke", {
|
|
32491
|
-
studentId: data.studentId,
|
|
32492
|
-
courseId: data.courseId
|
|
32493
|
-
});
|
|
32494
|
-
}
|
|
32495
|
-
}
|
|
32549
|
+
await upsertMasteryCompletionEntry({
|
|
32550
|
+
client,
|
|
32551
|
+
courseId: data.courseId,
|
|
32552
|
+
studentId: data.studentId,
|
|
32553
|
+
appName,
|
|
32554
|
+
action: willBeMastered ? "complete" : "revoke"
|
|
32555
|
+
});
|
|
32496
32556
|
}
|
|
32497
32557
|
}
|
|
32498
32558
|
return { status: "ok" };
|
|
32499
32559
|
}
|
|
32560
|
+
async reconcileMasteryForConfigChange(gameId, courseId, user, context) {
|
|
32561
|
+
const { client, appName } = await this.resolveAdminMutationContext(gameId, courseId, user);
|
|
32562
|
+
const action = context.newMasterableUnits < context.oldMasterableUnits ? "complete" : "revoke";
|
|
32563
|
+
const failed = [];
|
|
32564
|
+
let processed = 0;
|
|
32565
|
+
await TimebackAdminService.runWithConcurrency(context.affectedStudentIds, 8, async (studentId) => {
|
|
32566
|
+
try {
|
|
32567
|
+
await upsertMasteryCompletionEntry({
|
|
32568
|
+
client,
|
|
32569
|
+
courseId,
|
|
32570
|
+
studentId,
|
|
32571
|
+
appName,
|
|
32572
|
+
action
|
|
32573
|
+
});
|
|
32574
|
+
processed++;
|
|
32575
|
+
} catch (error) {
|
|
32576
|
+
logger18.warn("Failed to reconcile mastery completion for student", {
|
|
32577
|
+
studentId,
|
|
32578
|
+
courseId,
|
|
32579
|
+
action,
|
|
32580
|
+
error: error instanceof Error ? error.message : String(error)
|
|
32581
|
+
});
|
|
32582
|
+
failed.push(studentId);
|
|
32583
|
+
}
|
|
32584
|
+
});
|
|
32585
|
+
return { processed, failed };
|
|
32586
|
+
}
|
|
32500
32587
|
async searchStudentsForEnrollment(gameId, courseId, query, user) {
|
|
32501
32588
|
const client = this.requireClient();
|
|
32502
32589
|
await this.deps.validateGameManagementAccess(user, gameId);
|
|
@@ -32523,7 +32610,7 @@ class TimebackAdminService {
|
|
|
32523
32610
|
const response = await client["request"](endpoint, "GET");
|
|
32524
32611
|
allUsers = response.users || [];
|
|
32525
32612
|
} catch (error) {
|
|
32526
|
-
|
|
32613
|
+
logger18.warn("Failed to search OneRoster users", {
|
|
32527
32614
|
query: trimmedQuery,
|
|
32528
32615
|
error: error instanceof Error ? error.message : String(error)
|
|
32529
32616
|
});
|
|
@@ -32668,7 +32755,7 @@ class TimebackAdminService {
|
|
|
32668
32755
|
return results;
|
|
32669
32756
|
}
|
|
32670
32757
|
}
|
|
32671
|
-
var
|
|
32758
|
+
var logger18;
|
|
32672
32759
|
var init_timeback_admin_service = __esm(() => {
|
|
32673
32760
|
init_drizzle_orm();
|
|
32674
32761
|
init_src();
|
|
@@ -32681,8 +32768,9 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
32681
32768
|
init_errors();
|
|
32682
32769
|
init_timeback_admin_metrics_util();
|
|
32683
32770
|
init_timeback_admin_util();
|
|
32771
|
+
init_timeback_mastery_completion_util();
|
|
32684
32772
|
init_timeback_util();
|
|
32685
|
-
|
|
32773
|
+
logger18 = log.scope("TimebackAdminService");
|
|
32686
32774
|
});
|
|
32687
32775
|
|
|
32688
32776
|
// ../timeback/dist/errors.js
|
|
@@ -32929,7 +33017,7 @@ class TimebackAssessmentsService {
|
|
|
32929
33017
|
isActive: row.bankActive
|
|
32930
33018
|
};
|
|
32931
33019
|
} catch {
|
|
32932
|
-
|
|
33020
|
+
logger19.warn("Failed to fetch QTI test metadata", {
|
|
32933
33021
|
identifier: row.qtiTestIdentifier
|
|
32934
33022
|
});
|
|
32935
33023
|
return {
|
|
@@ -32983,7 +33071,7 @@ class TimebackAssessmentsService {
|
|
|
32983
33071
|
});
|
|
32984
33072
|
} catch (error) {
|
|
32985
33073
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
32986
|
-
|
|
33074
|
+
logger19.info("QTI test already exists (idempotent retry)", {
|
|
32987
33075
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
32988
33076
|
});
|
|
32989
33077
|
} else {
|
|
@@ -32996,7 +33084,7 @@ class TimebackAssessmentsService {
|
|
|
32996
33084
|
qtiTestIdentifier: input.qtiTestIdentifier,
|
|
32997
33085
|
sortOrder: maxSortOrder + 1
|
|
32998
33086
|
}).returning();
|
|
32999
|
-
|
|
33087
|
+
logger19.info("Assessment created", {
|
|
33000
33088
|
integrationId,
|
|
33001
33089
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
33002
33090
|
});
|
|
@@ -33018,13 +33106,13 @@ class TimebackAssessmentsService {
|
|
|
33018
33106
|
}
|
|
33019
33107
|
await client.qti.tests.delete(qtiTestIdentifier);
|
|
33020
33108
|
} catch (error) {
|
|
33021
|
-
|
|
33109
|
+
logger19.warn("Partial QTI cleanup during assessment deletion", {
|
|
33022
33110
|
qtiTestIdentifier,
|
|
33023
33111
|
error: error instanceof Error ? error.message : String(error)
|
|
33024
33112
|
});
|
|
33025
33113
|
}
|
|
33026
33114
|
await this.deps.db.delete(gameTimebackAssessmentTests).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33027
|
-
|
|
33115
|
+
logger19.info("Assessment deleted", { integrationId, qtiTestIdentifier });
|
|
33028
33116
|
}
|
|
33029
33117
|
async reorderAssessments(integrationId, identifiers) {
|
|
33030
33118
|
await this.requireIntegration(integrationId);
|
|
@@ -33069,7 +33157,7 @@ class TimebackAssessmentsService {
|
|
|
33069
33157
|
return client.qti.tests.reorderItems(qtiTestIdentifier, partId, sectionId, items2);
|
|
33070
33158
|
}
|
|
33071
33159
|
async activateAssessment(integrationId, qtiTestIdentifier) {
|
|
33072
|
-
|
|
33160
|
+
logger19.debug("Activating assessment", { integrationId, qtiTestIdentifier });
|
|
33073
33161
|
const client = this.requireClient();
|
|
33074
33162
|
const integration = await this.requireIntegration(integrationId);
|
|
33075
33163
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -33107,7 +33195,7 @@ class TimebackAssessmentsService {
|
|
|
33107
33195
|
});
|
|
33108
33196
|
}
|
|
33109
33197
|
} catch {
|
|
33110
|
-
|
|
33198
|
+
logger19.warn("Failed to reactivate existing child resource, will create new", {
|
|
33111
33199
|
childResourceId
|
|
33112
33200
|
});
|
|
33113
33201
|
childResourceId = null;
|
|
@@ -33120,7 +33208,7 @@ class TimebackAssessmentsService {
|
|
|
33120
33208
|
const resourceUrl = resource.metadata?.url;
|
|
33121
33209
|
if (resourceUrl === qtiTestUrl) {
|
|
33122
33210
|
childResourceId = resourceId;
|
|
33123
|
-
|
|
33211
|
+
logger19.info("Found existing child Resource for QTI test (idempotent retry)", {
|
|
33124
33212
|
qtiTestIdentifier,
|
|
33125
33213
|
childResourceId
|
|
33126
33214
|
});
|
|
@@ -33129,7 +33217,7 @@ class TimebackAssessmentsService {
|
|
|
33129
33217
|
} catch {}
|
|
33130
33218
|
}
|
|
33131
33219
|
if (!childResourceId) {
|
|
33132
|
-
|
|
33220
|
+
logger19.debug("Creating child resource", { qtiTestIdentifier, qtiTestUrl });
|
|
33133
33221
|
const childResult = await client.oneroster.resources.create({
|
|
33134
33222
|
resource: {
|
|
33135
33223
|
status: "active",
|
|
@@ -33157,10 +33245,10 @@ class TimebackAssessmentsService {
|
|
|
33157
33245
|
}
|
|
33158
33246
|
}
|
|
33159
33247
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: childResourceId, bankActive: true }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33160
|
-
|
|
33248
|
+
logger19.info("Assessment activated", { integrationId, qtiTestIdentifier, childResourceId });
|
|
33161
33249
|
}
|
|
33162
33250
|
async deactivateAssessment(integrationId, qtiTestIdentifier) {
|
|
33163
|
-
|
|
33251
|
+
logger19.debug("Deactivating assessment", { integrationId, qtiTestIdentifier });
|
|
33164
33252
|
const client = this.requireClient();
|
|
33165
33253
|
const integration = await this.requireIntegration(integrationId);
|
|
33166
33254
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -33173,7 +33261,7 @@ class TimebackAssessmentsService {
|
|
|
33173
33261
|
const childResourceId = row.bankResourceId;
|
|
33174
33262
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
33175
33263
|
try {
|
|
33176
|
-
|
|
33264
|
+
logger19.debug("Reading parent resource for deactivation", {
|
|
33177
33265
|
resourceId: bankIds.resource
|
|
33178
33266
|
});
|
|
33179
33267
|
const parentResource = await client.oneroster.resources.get(bankIds.resource);
|
|
@@ -33192,22 +33280,22 @@ class TimebackAssessmentsService {
|
|
|
33192
33280
|
});
|
|
33193
33281
|
}
|
|
33194
33282
|
} catch (error) {
|
|
33195
|
-
|
|
33283
|
+
logger19.warn("Failed to update parent resource during deactivation", {
|
|
33196
33284
|
bankResourceId: bankIds.resource,
|
|
33197
33285
|
error: error instanceof Error ? error.message : String(error)
|
|
33198
33286
|
});
|
|
33199
33287
|
}
|
|
33200
33288
|
try {
|
|
33201
|
-
|
|
33289
|
+
logger19.debug("Deleting child resource", { childResourceId });
|
|
33202
33290
|
await client.oneroster.resources.delete(childResourceId);
|
|
33203
33291
|
} catch (error) {
|
|
33204
|
-
|
|
33292
|
+
logger19.warn("Failed to delete child resource (may already be deleted)", {
|
|
33205
33293
|
childResourceId,
|
|
33206
33294
|
error: error instanceof Error ? error.message : String(error)
|
|
33207
33295
|
});
|
|
33208
33296
|
}
|
|
33209
33297
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankActive: false }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33210
|
-
|
|
33298
|
+
logger19.info("Assessment deactivated", { integrationId, qtiTestIdentifier });
|
|
33211
33299
|
}
|
|
33212
33300
|
isAssessmentActive(row) {
|
|
33213
33301
|
return row.bankActive;
|
|
@@ -33238,14 +33326,14 @@ class TimebackAssessmentsService {
|
|
|
33238
33326
|
status: "tobedeleted"
|
|
33239
33327
|
});
|
|
33240
33328
|
} catch (error) {
|
|
33241
|
-
|
|
33329
|
+
logger19.warn("Failed to delete component resource", { error });
|
|
33242
33330
|
}
|
|
33243
33331
|
for (const row of activeRows) {
|
|
33244
33332
|
if (row.bankResourceId) {
|
|
33245
33333
|
try {
|
|
33246
33334
|
await client.oneroster.resources.delete(row.bankResourceId);
|
|
33247
33335
|
} catch (error) {
|
|
33248
|
-
|
|
33336
|
+
logger19.warn("Failed to delete child resource", {
|
|
33249
33337
|
childResourceId: row.bankResourceId,
|
|
33250
33338
|
error
|
|
33251
33339
|
});
|
|
@@ -33255,17 +33343,17 @@ class TimebackAssessmentsService {
|
|
|
33255
33343
|
try {
|
|
33256
33344
|
await client.oneroster.resources.delete(bankIds.resource);
|
|
33257
33345
|
} catch (error) {
|
|
33258
|
-
|
|
33346
|
+
logger19.warn("Failed to delete parent resource", { error });
|
|
33259
33347
|
}
|
|
33260
33348
|
try {
|
|
33261
33349
|
await client.oneroster.courseComponents.update(bankIds.component, {
|
|
33262
33350
|
status: "tobedeleted"
|
|
33263
33351
|
});
|
|
33264
33352
|
} catch (error) {
|
|
33265
|
-
|
|
33353
|
+
logger19.warn("Failed to delete course component", { error });
|
|
33266
33354
|
}
|
|
33267
33355
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: null, bankActive: false }).where(eq(gameTimebackAssessmentTests.integrationId, integrationId));
|
|
33268
|
-
|
|
33356
|
+
logger19.info("Bank destroyed", { integrationId });
|
|
33269
33357
|
}
|
|
33270
33358
|
requireClient() {
|
|
33271
33359
|
if (!this.deps.timeback) {
|
|
@@ -33294,7 +33382,7 @@ class TimebackAssessmentsService {
|
|
|
33294
33382
|
async ensureBank(integration) {
|
|
33295
33383
|
const client = this.requireClient();
|
|
33296
33384
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
33297
|
-
|
|
33385
|
+
logger19.debug("Ensuring assessment bank hierarchy", {
|
|
33298
33386
|
courseId: integration.courseId,
|
|
33299
33387
|
bankIds
|
|
33300
33388
|
});
|
|
@@ -33311,7 +33399,7 @@ class TimebackAssessmentsService {
|
|
|
33311
33399
|
});
|
|
33312
33400
|
} catch (error) {
|
|
33313
33401
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33314
|
-
|
|
33402
|
+
logger19.debug("Course component already exists", { sourcedId: bankIds.component });
|
|
33315
33403
|
} else {
|
|
33316
33404
|
throw error;
|
|
33317
33405
|
}
|
|
@@ -33335,7 +33423,7 @@ class TimebackAssessmentsService {
|
|
|
33335
33423
|
});
|
|
33336
33424
|
} catch (error) {
|
|
33337
33425
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33338
|
-
|
|
33426
|
+
logger19.debug("Parent resource already exists", { sourcedId: bankIds.resource });
|
|
33339
33427
|
} else {
|
|
33340
33428
|
throw error;
|
|
33341
33429
|
}
|
|
@@ -33355,14 +33443,14 @@ class TimebackAssessmentsService {
|
|
|
33355
33443
|
});
|
|
33356
33444
|
} catch (error) {
|
|
33357
33445
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33358
|
-
|
|
33446
|
+
logger19.debug("Component resource already exists", {
|
|
33359
33447
|
sourcedId: bankIds.componentResource
|
|
33360
33448
|
});
|
|
33361
33449
|
} else {
|
|
33362
33450
|
throw error;
|
|
33363
33451
|
}
|
|
33364
33452
|
}
|
|
33365
|
-
|
|
33453
|
+
logger19.info("Assessment bank hierarchy created", {
|
|
33366
33454
|
courseId: integration.courseId
|
|
33367
33455
|
});
|
|
33368
33456
|
}
|
|
@@ -33377,7 +33465,7 @@ class TimebackAssessmentsService {
|
|
|
33377
33465
|
return Math.max(...rows.map((r) => r.sortOrder));
|
|
33378
33466
|
}
|
|
33379
33467
|
}
|
|
33380
|
-
var
|
|
33468
|
+
var logger19;
|
|
33381
33469
|
var init_timeback_assessments_service = __esm(() => {
|
|
33382
33470
|
init_drizzle_orm();
|
|
33383
33471
|
init_tables_index();
|
|
@@ -33386,7 +33474,7 @@ var init_timeback_assessments_service = __esm(() => {
|
|
|
33386
33474
|
init_errors4();
|
|
33387
33475
|
init_utils6();
|
|
33388
33476
|
init_errors();
|
|
33389
|
-
|
|
33477
|
+
logger19 = log.scope("TimebackAssessmentsService");
|
|
33390
33478
|
});
|
|
33391
33479
|
|
|
33392
33480
|
// ../api-core/src/utils/timeback-promotion.util.ts
|
|
@@ -33402,7 +33490,7 @@ async function promoteCompletedCourse({
|
|
|
33402
33490
|
});
|
|
33403
33491
|
const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
|
|
33404
33492
|
if (!nextIntegration) {
|
|
33405
|
-
|
|
33493
|
+
logger20.debug("Skipping promotion because no next course is configured", {
|
|
33406
33494
|
gameId: currentIntegration.gameId,
|
|
33407
33495
|
studentId,
|
|
33408
33496
|
grade: currentIntegration.grade,
|
|
@@ -33419,7 +33507,7 @@ async function promoteCompletedCourse({
|
|
|
33419
33507
|
const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
|
|
33420
33508
|
if (!currentEnrollment) {
|
|
33421
33509
|
if (nextEnrollment) {
|
|
33422
|
-
|
|
33510
|
+
logger20.debug("Skipping promotion because student is already on the next course", {
|
|
33423
33511
|
gameId: currentIntegration.gameId,
|
|
33424
33512
|
studentId,
|
|
33425
33513
|
grade: currentIntegration.grade,
|
|
@@ -33433,7 +33521,7 @@ async function promoteCompletedCourse({
|
|
|
33433
33521
|
nextCourseId: nextIntegration.courseId
|
|
33434
33522
|
};
|
|
33435
33523
|
}
|
|
33436
|
-
|
|
33524
|
+
logger20.debug("Skipping promotion because student is not enrolled in the current course", {
|
|
33437
33525
|
gameId: currentIntegration.gameId,
|
|
33438
33526
|
studentId,
|
|
33439
33527
|
grade: currentIntegration.grade,
|
|
@@ -33464,7 +33552,7 @@ async function promoteCompletedCourse({
|
|
|
33464
33552
|
client.invalidateEnrollments(studentId);
|
|
33465
33553
|
}
|
|
33466
33554
|
}
|
|
33467
|
-
|
|
33555
|
+
logger20.info("Promoted student to next course", {
|
|
33468
33556
|
gameId: currentIntegration.gameId,
|
|
33469
33557
|
studentId,
|
|
33470
33558
|
subject: currentIntegration.subject,
|
|
@@ -33479,16 +33567,16 @@ async function promoteCompletedCourse({
|
|
|
33479
33567
|
nextCourseId: nextIntegration.courseId
|
|
33480
33568
|
};
|
|
33481
33569
|
}
|
|
33482
|
-
var
|
|
33570
|
+
var logger20;
|
|
33483
33571
|
var init_timeback_promotion_util = __esm(() => {
|
|
33484
33572
|
init_drizzle_orm();
|
|
33485
33573
|
init_tables_index();
|
|
33486
33574
|
init_src2();
|
|
33487
|
-
|
|
33575
|
+
logger20 = log.scope("TimebackPromotion");
|
|
33488
33576
|
});
|
|
33489
33577
|
|
|
33490
33578
|
// ../api-core/src/services/timeback.service.ts
|
|
33491
|
-
var
|
|
33579
|
+
var logger21, TimebackService;
|
|
33492
33580
|
var init_timeback_service = __esm(() => {
|
|
33493
33581
|
init_drizzle_orm();
|
|
33494
33582
|
init_src();
|
|
@@ -33499,7 +33587,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33499
33587
|
init_errors();
|
|
33500
33588
|
init_timeback_promotion_util();
|
|
33501
33589
|
init_timeback_util();
|
|
33502
|
-
|
|
33590
|
+
logger21 = log.scope("TimebackService");
|
|
33503
33591
|
TimebackService = class TimebackService {
|
|
33504
33592
|
static HEARTBEAT_DEDUPE_TTL_MS = 5 * 60 * 1000;
|
|
33505
33593
|
static processedHeartbeatWindows = new Map;
|
|
@@ -33545,7 +33633,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33545
33633
|
}
|
|
33546
33634
|
requireClient() {
|
|
33547
33635
|
if (!this.deps.timeback) {
|
|
33548
|
-
|
|
33636
|
+
logger21.error("Timeback client not available in context");
|
|
33549
33637
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
33550
33638
|
}
|
|
33551
33639
|
return this.deps.timeback;
|
|
@@ -33598,7 +33686,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33598
33686
|
set: { xp: sql`excluded.xp`, updatedAt: new Date }
|
|
33599
33687
|
}).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
|
|
33600
33688
|
if (!result) {
|
|
33601
|
-
|
|
33689
|
+
logger21.error("Daily XP upsert returned no rows", { userId, date: targetDate });
|
|
33602
33690
|
throw new InternalError("Failed to update daily XP record");
|
|
33603
33691
|
}
|
|
33604
33692
|
return { xp: result.xp, date: result.date.toISOString() };
|
|
@@ -33629,7 +33717,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33629
33717
|
columns: { id: true, timebackId: true }
|
|
33630
33718
|
});
|
|
33631
33719
|
if (dbUser?.timebackId) {
|
|
33632
|
-
|
|
33720
|
+
logger21.info("Student already onboarded", { userId: user.id });
|
|
33633
33721
|
return { status: "already_populated" };
|
|
33634
33722
|
}
|
|
33635
33723
|
let timebackId;
|
|
@@ -33638,7 +33726,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33638
33726
|
const existingUser = await client.oneroster.users.findByEmail(user.email);
|
|
33639
33727
|
timebackId = existingUser.sourcedId;
|
|
33640
33728
|
name3 = `${existingUser.givenName} ${existingUser.familyName}`;
|
|
33641
|
-
|
|
33729
|
+
logger21.info("Found existing student in OneRoster", {
|
|
33642
33730
|
userId: user.id,
|
|
33643
33731
|
timebackId
|
|
33644
33732
|
});
|
|
@@ -33667,7 +33755,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33667
33755
|
}
|
|
33668
33756
|
timebackId = response.sourcedIdPairs.allocatedSourcedId;
|
|
33669
33757
|
name3 = `${providedNames.firstName} ${providedNames.lastName}`;
|
|
33670
|
-
|
|
33758
|
+
logger21.info("Created student in OneRoster", { userId: user.id, timebackId });
|
|
33671
33759
|
}
|
|
33672
33760
|
const assessments = await this.fetchAssessments(timebackId);
|
|
33673
33761
|
await db2.transaction(async (tx) => {
|
|
@@ -33701,7 +33789,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33701
33789
|
}
|
|
33702
33790
|
const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
|
|
33703
33791
|
if (!updated) {
|
|
33704
|
-
|
|
33792
|
+
logger21.error("User Timeback ID update returned no rows", {
|
|
33705
33793
|
userId: user.id,
|
|
33706
33794
|
timebackId
|
|
33707
33795
|
});
|
|
@@ -33725,13 +33813,13 @@ var init_timeback_service = __esm(() => {
|
|
|
33725
33813
|
}
|
|
33726
33814
|
offset += limit;
|
|
33727
33815
|
}
|
|
33728
|
-
|
|
33816
|
+
logger21.debug("Fetched assessments", {
|
|
33729
33817
|
studentSourcedId,
|
|
33730
33818
|
totalCount: allAssessments.length
|
|
33731
33819
|
});
|
|
33732
33820
|
return allAssessments;
|
|
33733
33821
|
} catch (error) {
|
|
33734
|
-
|
|
33822
|
+
logger21.warn("Failed to fetch assessments", { studentSourcedId, error });
|
|
33735
33823
|
return [];
|
|
33736
33824
|
}
|
|
33737
33825
|
}
|
|
@@ -33844,7 +33932,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33844
33932
|
masterableUnits: derivedMasterableUnits
|
|
33845
33933
|
} = courseConfig;
|
|
33846
33934
|
if (!isTimebackSubject(subjectInput)) {
|
|
33847
|
-
|
|
33935
|
+
logger21.warn("Invalid Timeback subject in course config", {
|
|
33848
33936
|
subject: subjectInput,
|
|
33849
33937
|
courseCode,
|
|
33850
33938
|
title
|
|
@@ -33852,7 +33940,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33852
33940
|
throw new ValidationError(`Invalid subject "${subjectInput}"`);
|
|
33853
33941
|
}
|
|
33854
33942
|
if (!isTimebackGrade(grade)) {
|
|
33855
|
-
|
|
33943
|
+
logger21.warn("Invalid Timeback grade in course config", {
|
|
33856
33944
|
grade,
|
|
33857
33945
|
courseCode,
|
|
33858
33946
|
title
|
|
@@ -33864,7 +33952,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33864
33952
|
const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
|
|
33865
33953
|
const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
|
|
33866
33954
|
if (typeof totalXp !== "number") {
|
|
33867
|
-
|
|
33955
|
+
logger21.warn("Course missing totalXp in Timeback config", {
|
|
33868
33956
|
courseCode,
|
|
33869
33957
|
title
|
|
33870
33958
|
});
|
|
@@ -33880,7 +33968,9 @@ var init_timeback_service = __esm(() => {
|
|
|
33880
33968
|
courseCode,
|
|
33881
33969
|
level,
|
|
33882
33970
|
gradingScheme: "STANDARD",
|
|
33883
|
-
metadata: metadata2
|
|
33971
|
+
metadata: TimebackService.patchCourseMetadata(metadata2, totalXp, {
|
|
33972
|
+
masterableUnits: masterableUnits ?? null
|
|
33973
|
+
})
|
|
33884
33974
|
},
|
|
33885
33975
|
component: {
|
|
33886
33976
|
...baseConfig.component,
|
|
@@ -33905,7 +33995,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33905
33995
|
const existingIntegration = existing.find((i2) => i2.grade === grade && i2.subject === subject);
|
|
33906
33996
|
if (existingIntegration) {
|
|
33907
33997
|
await client.update(existingIntegration.courseId, fullConfig);
|
|
33908
|
-
const [updated] = await db2.update(gameTimebackIntegrations).set({ totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
|
|
33998
|
+
const [updated] = await db2.update(gameTimebackIntegrations).set({ subject, totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
|
|
33909
33999
|
if (updated) {
|
|
33910
34000
|
integrations.push(this.toGameTimebackIntegration(updated));
|
|
33911
34001
|
}
|
|
@@ -33930,6 +34020,60 @@ var init_timeback_service = __esm(() => {
|
|
|
33930
34020
|
});
|
|
33931
34021
|
return rows.map((row) => this.toGameTimebackIntegration(row));
|
|
33932
34022
|
}
|
|
34023
|
+
async getIntegrationConfig(gameId, courseId, user) {
|
|
34024
|
+
const client = this.requireClient();
|
|
34025
|
+
await this.deps.validateGameManagementAccess(user, gameId);
|
|
34026
|
+
const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
34027
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
|
|
34028
|
+
});
|
|
34029
|
+
if (!integration) {
|
|
34030
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
34031
|
+
}
|
|
34032
|
+
const config2 = await client.getConfig(courseId);
|
|
34033
|
+
return this.toGameTimebackIntegrationConfig(integration, config2);
|
|
34034
|
+
}
|
|
34035
|
+
async updateIntegration(gameId, courseId, user, patch) {
|
|
34036
|
+
const client = this.requireClient();
|
|
34037
|
+
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34038
|
+
const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
34039
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
|
|
34040
|
+
});
|
|
34041
|
+
if (!integration) {
|
|
34042
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
34043
|
+
}
|
|
34044
|
+
const timebackConfig = await client.getConfig(courseId);
|
|
34045
|
+
const liveSubject = timebackConfig.course.subjects[0];
|
|
34046
|
+
const subject = patch.subject ?? (isTimebackSubject(liveSubject) ? liveSubject : integration.subject);
|
|
34047
|
+
if (!isTimebackSubject(subject)) {
|
|
34048
|
+
throw new ValidationError(`Invalid subject "${subject}"`);
|
|
34049
|
+
}
|
|
34050
|
+
if (subject !== integration.subject) {
|
|
34051
|
+
const subjectConflict = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
34052
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.grade, integration.grade), eq(gameTimebackIntegrations.subject, subject))
|
|
34053
|
+
});
|
|
34054
|
+
if (subjectConflict && subjectConflict.id !== integration.id) {
|
|
34055
|
+
throw new ValidationError(`A TimeBack integration already exists for ${subject} Grade ${integration.grade}`);
|
|
34056
|
+
}
|
|
34057
|
+
}
|
|
34058
|
+
const totalXp = "totalXp" in patch ? patch.totalXp ?? null : TimebackService.getTotalXpFromConfig(timebackConfig) ?? integration.totalXp ?? null;
|
|
34059
|
+
const masterableUnits = "masterableUnits" in patch ? patch.masterableUnits ?? null : TimebackService.getMasterableUnitsFromConfig(timebackConfig);
|
|
34060
|
+
await client.update(courseId, TimebackService.patchTimebackConfig(timebackConfig, {
|
|
34061
|
+
...patch,
|
|
34062
|
+
subject,
|
|
34063
|
+
totalXp,
|
|
34064
|
+
masterableUnits,
|
|
34065
|
+
grade: integration.grade
|
|
34066
|
+
}));
|
|
34067
|
+
const [updated] = await this.deps.db.update(gameTimebackIntegrations).set({
|
|
34068
|
+
subject,
|
|
34069
|
+
totalXp,
|
|
34070
|
+
updatedAt: new Date
|
|
34071
|
+
}).where(eq(gameTimebackIntegrations.id, integration.id)).returning();
|
|
34072
|
+
if (!updated) {
|
|
34073
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
34074
|
+
}
|
|
34075
|
+
return this.toGameTimebackIntegration(updated);
|
|
34076
|
+
}
|
|
33933
34077
|
async verifyIntegration(gameId, user) {
|
|
33934
34078
|
const client = this.requireClient();
|
|
33935
34079
|
const db2 = this.deps.db;
|
|
@@ -33987,6 +34131,146 @@ var init_timeback_service = __esm(() => {
|
|
|
33987
34131
|
}
|
|
33988
34132
|
await db2.delete(gameTimebackIntegrations).where(eq(gameTimebackIntegrations.gameId, gameId));
|
|
33989
34133
|
}
|
|
34134
|
+
static getMasterableUnitsFromConfig(config2) {
|
|
34135
|
+
const playcademyMetadata = config2.resource.metadata?.playcademy;
|
|
34136
|
+
if (!isPlaycademyResourceMetadata(playcademyMetadata)) {
|
|
34137
|
+
return null;
|
|
34138
|
+
}
|
|
34139
|
+
return playcademyMetadata?.mastery?.masterableUnits ?? null;
|
|
34140
|
+
}
|
|
34141
|
+
static getTotalXpFromConfig(config2) {
|
|
34142
|
+
const courseMetadata = isCourseMetadata(config2.course.metadata) ? config2.course.metadata : undefined;
|
|
34143
|
+
if (typeof courseMetadata?.metrics?.totalXp === "number") {
|
|
34144
|
+
return courseMetadata.metrics.totalXp;
|
|
34145
|
+
}
|
|
34146
|
+
const resourceMetadata = config2.resource.metadata;
|
|
34147
|
+
if (isRecord2(resourceMetadata) && typeof resourceMetadata.xp === "number") {
|
|
34148
|
+
return resourceMetadata.xp;
|
|
34149
|
+
}
|
|
34150
|
+
return null;
|
|
34151
|
+
}
|
|
34152
|
+
static patchCourseMetadata(metadata2, totalXp, options) {
|
|
34153
|
+
const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
|
|
34154
|
+
const currentMetrics = isRecord2(nextMetadata.metrics) ? nextMetadata.metrics : {};
|
|
34155
|
+
const metrics = { ...currentMetrics };
|
|
34156
|
+
if (totalXp === null) {
|
|
34157
|
+
delete metrics.totalXp;
|
|
34158
|
+
} else {
|
|
34159
|
+
metrics.totalXp = totalXp;
|
|
34160
|
+
}
|
|
34161
|
+
if (options?.masterableUnits !== undefined) {
|
|
34162
|
+
if (options.masterableUnits === null) {
|
|
34163
|
+
delete metrics.totalLessons;
|
|
34164
|
+
} else {
|
|
34165
|
+
metrics.totalLessons = options.masterableUnits;
|
|
34166
|
+
}
|
|
34167
|
+
}
|
|
34168
|
+
metrics.totalGrades = 1;
|
|
34169
|
+
if (Object.keys(metrics).length > 0) {
|
|
34170
|
+
nextMetadata.metrics = metrics;
|
|
34171
|
+
} else {
|
|
34172
|
+
delete nextMetadata.metrics;
|
|
34173
|
+
}
|
|
34174
|
+
const goals = options?.goals;
|
|
34175
|
+
if (goals !== undefined) {
|
|
34176
|
+
if (goals === null) {
|
|
34177
|
+
delete nextMetadata.goals;
|
|
34178
|
+
} else {
|
|
34179
|
+
const currentGoals = isRecord2(nextMetadata.goals) ? nextMetadata.goals : {};
|
|
34180
|
+
const nextGoals = { ...currentGoals };
|
|
34181
|
+
for (const [key, value] of Object.entries(goals)) {
|
|
34182
|
+
if (value === null) {
|
|
34183
|
+
delete nextGoals[key];
|
|
34184
|
+
} else if (value !== undefined) {
|
|
34185
|
+
nextGoals[key] = value;
|
|
34186
|
+
}
|
|
34187
|
+
}
|
|
34188
|
+
if (Object.keys(nextGoals).length > 0) {
|
|
34189
|
+
nextMetadata.goals = nextGoals;
|
|
34190
|
+
} else {
|
|
34191
|
+
delete nextMetadata.goals;
|
|
34192
|
+
}
|
|
34193
|
+
}
|
|
34194
|
+
}
|
|
34195
|
+
if (options?.publishStatus !== undefined) {
|
|
34196
|
+
if (options.publishStatus === null) {
|
|
34197
|
+
delete nextMetadata.publishStatus;
|
|
34198
|
+
const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
|
|
34199
|
+
delete alphaLearn.publishStatus;
|
|
34200
|
+
if (Object.keys(alphaLearn).length > 0) {
|
|
34201
|
+
nextMetadata.AlphaLearn = alphaLearn;
|
|
34202
|
+
} else {
|
|
34203
|
+
delete nextMetadata.AlphaLearn;
|
|
34204
|
+
}
|
|
34205
|
+
} else {
|
|
34206
|
+
nextMetadata.publishStatus = options.publishStatus;
|
|
34207
|
+
const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
|
|
34208
|
+
alphaLearn.publishStatus = options.publishStatus === "published" ? "active" : options.publishStatus;
|
|
34209
|
+
nextMetadata.AlphaLearn = alphaLearn;
|
|
34210
|
+
}
|
|
34211
|
+
}
|
|
34212
|
+
if (options?.isSupplemental !== undefined) {
|
|
34213
|
+
nextMetadata.isSupplemental = options.isSupplemental;
|
|
34214
|
+
}
|
|
34215
|
+
if (options?.timebackVisible !== undefined) {
|
|
34216
|
+
if (options.timebackVisible === null) {
|
|
34217
|
+
delete nextMetadata.timebackVisible;
|
|
34218
|
+
} else {
|
|
34219
|
+
nextMetadata.timebackVisible = options.timebackVisible;
|
|
34220
|
+
}
|
|
34221
|
+
}
|
|
34222
|
+
return Object.keys(nextMetadata).length > 0 ? nextMetadata : undefined;
|
|
34223
|
+
}
|
|
34224
|
+
static patchResourceMetadata(metadata2, options) {
|
|
34225
|
+
const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
|
|
34226
|
+
const playcademyMetadata = isRecord2(nextMetadata.playcademy) ? { ...nextMetadata.playcademy } : {};
|
|
34227
|
+
const masteryMetadata = isRecord2(playcademyMetadata.mastery) ? { ...playcademyMetadata.mastery } : {};
|
|
34228
|
+
nextMetadata.subject = options.subject;
|
|
34229
|
+
nextMetadata.grades = [options.grade];
|
|
34230
|
+
if (options.totalXp === null) {
|
|
34231
|
+
delete nextMetadata.xp;
|
|
34232
|
+
} else {
|
|
34233
|
+
nextMetadata.xp = options.totalXp;
|
|
34234
|
+
}
|
|
34235
|
+
if (options.masterableUnits === null) {
|
|
34236
|
+
delete masteryMetadata.masterableUnits;
|
|
34237
|
+
} else {
|
|
34238
|
+
masteryMetadata.masterableUnits = options.masterableUnits;
|
|
34239
|
+
}
|
|
34240
|
+
if (Object.keys(masteryMetadata).length > 0) {
|
|
34241
|
+
playcademyMetadata.mastery = masteryMetadata;
|
|
34242
|
+
} else {
|
|
34243
|
+
delete playcademyMetadata.mastery;
|
|
34244
|
+
}
|
|
34245
|
+
if (Object.keys(playcademyMetadata).length > 0) {
|
|
34246
|
+
nextMetadata.playcademy = playcademyMetadata;
|
|
34247
|
+
} else {
|
|
34248
|
+
delete nextMetadata.playcademy;
|
|
34249
|
+
}
|
|
34250
|
+
return nextMetadata;
|
|
34251
|
+
}
|
|
34252
|
+
static patchTimebackConfig(config2, patch) {
|
|
34253
|
+
return {
|
|
34254
|
+
...config2,
|
|
34255
|
+
course: {
|
|
34256
|
+
...config2.course,
|
|
34257
|
+
title: patch.title ?? config2.course.title,
|
|
34258
|
+
courseCode: patch.courseCode ?? config2.course.courseCode,
|
|
34259
|
+
subjects: [patch.subject],
|
|
34260
|
+
metadata: TimebackService.patchCourseMetadata(config2.course.metadata, patch.totalXp, {
|
|
34261
|
+
masterableUnits: patch.masterableUnits,
|
|
34262
|
+
goals: patch.goals,
|
|
34263
|
+
publishStatus: patch.publishStatus,
|
|
34264
|
+
isSupplemental: patch.isSupplemental,
|
|
34265
|
+
timebackVisible: patch.timebackVisible
|
|
34266
|
+
})
|
|
34267
|
+
},
|
|
34268
|
+
resource: {
|
|
34269
|
+
...config2.resource,
|
|
34270
|
+
metadata: TimebackService.patchResourceMetadata(config2.resource.metadata, patch)
|
|
34271
|
+
}
|
|
34272
|
+
};
|
|
34273
|
+
}
|
|
33990
34274
|
toGameTimebackIntegration(integration) {
|
|
33991
34275
|
return {
|
|
33992
34276
|
id: integration.id,
|
|
@@ -34000,6 +34284,21 @@ var init_timeback_service = __esm(() => {
|
|
|
34000
34284
|
lastVerifiedAt: integration.lastVerifiedAt ?? null
|
|
34001
34285
|
};
|
|
34002
34286
|
}
|
|
34287
|
+
toGameTimebackIntegrationConfig(integration, config2) {
|
|
34288
|
+
const subject = config2.course.subjects[0] ?? integration.subject;
|
|
34289
|
+
if (!isTimebackSubject(subject)) {
|
|
34290
|
+
throw new ValidationError(`Invalid subject "${subject}"`);
|
|
34291
|
+
}
|
|
34292
|
+
return {
|
|
34293
|
+
integration: this.toGameTimebackIntegration(integration),
|
|
34294
|
+
title: config2.course.title,
|
|
34295
|
+
courseCode: config2.course.courseCode,
|
|
34296
|
+
subject,
|
|
34297
|
+
totalXp: TimebackService.getTotalXpFromConfig(config2) ?? integration.totalXp ?? null,
|
|
34298
|
+
masterableUnits: TimebackService.getMasterableUnitsFromConfig(config2),
|
|
34299
|
+
metadata: isCourseMetadata(config2.course.metadata) ? config2.course.metadata : null
|
|
34300
|
+
};
|
|
34301
|
+
}
|
|
34003
34302
|
async endActivity({
|
|
34004
34303
|
gameId,
|
|
34005
34304
|
studentId,
|
|
@@ -34065,7 +34364,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34065
34364
|
...runId ? { runId } : {}
|
|
34066
34365
|
});
|
|
34067
34366
|
}
|
|
34068
|
-
|
|
34367
|
+
logger21.info("Recorded activity completion", {
|
|
34069
34368
|
gameId,
|
|
34070
34369
|
courseId: integration.courseId,
|
|
34071
34370
|
studentId,
|
|
@@ -34119,7 +34418,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34119
34418
|
masteredUnits: masteryStatus.masteredUnits,
|
|
34120
34419
|
masterableUnits: masteryStatus.masterableUnits
|
|
34121
34420
|
};
|
|
34122
|
-
|
|
34421
|
+
logger21.debug("Skipping course advancement because mastery is incomplete", {
|
|
34123
34422
|
gameId,
|
|
34124
34423
|
studentId,
|
|
34125
34424
|
subject: currentIntegration.subject,
|
|
@@ -34137,7 +34436,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34137
34436
|
studentId,
|
|
34138
34437
|
enrollments
|
|
34139
34438
|
});
|
|
34140
|
-
|
|
34439
|
+
logger21.info("Manually advanced student", {
|
|
34141
34440
|
gameId,
|
|
34142
34441
|
studentId,
|
|
34143
34442
|
subject: currentIntegration.subject,
|
|
@@ -34170,7 +34469,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34170
34469
|
const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
|
|
34171
34470
|
const effectiveResumeId = resumeId ?? runId;
|
|
34172
34471
|
if (TimebackService.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
|
|
34173
|
-
|
|
34472
|
+
logger21.debug("Skipping duplicate heartbeat window", {
|
|
34174
34473
|
gameId,
|
|
34175
34474
|
studentId,
|
|
34176
34475
|
runId,
|
|
@@ -34183,7 +34482,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34183
34482
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34184
34483
|
const inFlightHeartbeat = TimebackService.getInFlightHeartbeatWindow(heartbeatWindowKey);
|
|
34185
34484
|
if (inFlightHeartbeat) {
|
|
34186
|
-
|
|
34485
|
+
logger21.debug("Joining in-flight heartbeat window", {
|
|
34187
34486
|
gameId,
|
|
34188
34487
|
studentId,
|
|
34189
34488
|
runId,
|
|
@@ -34220,7 +34519,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34220
34519
|
});
|
|
34221
34520
|
}
|
|
34222
34521
|
TimebackService.markHeartbeatWindowProcessed(heartbeatWindowKey);
|
|
34223
|
-
|
|
34522
|
+
logger21.debug("Recorded heartbeat", {
|
|
34224
34523
|
gameId,
|
|
34225
34524
|
courseId: integration.courseId,
|
|
34226
34525
|
studentId,
|
|
@@ -34255,7 +34554,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34255
34554
|
});
|
|
34256
34555
|
courseIds = integrations.map((i2) => i2.courseId);
|
|
34257
34556
|
if (courseIds.length === 0) {
|
|
34258
|
-
|
|
34557
|
+
logger21.debug("No integrations found for game, returning 0 XP", {
|
|
34259
34558
|
timebackId,
|
|
34260
34559
|
gameId: options.gameId,
|
|
34261
34560
|
grade: options.grade,
|
|
@@ -34272,7 +34571,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34272
34571
|
courseIds: courseIds.length > 0 ? courseIds : undefined,
|
|
34273
34572
|
include: options?.include
|
|
34274
34573
|
});
|
|
34275
|
-
|
|
34574
|
+
logger21.debug("Retrieved student XP", {
|
|
34276
34575
|
timebackId,
|
|
34277
34576
|
gameId: options?.gameId,
|
|
34278
34577
|
grade: options?.grade,
|
|
@@ -34301,15 +34600,15 @@ class UploadService {
|
|
|
34301
34600
|
const { fileName, gameId } = request;
|
|
34302
34601
|
const bucketName = this.deps.uploadBucket;
|
|
34303
34602
|
if (!bucketName) {
|
|
34304
|
-
|
|
34603
|
+
logger22.error("Upload bucket not configured in environment");
|
|
34305
34604
|
throw new ValidationError("Upload bucket not configured");
|
|
34306
34605
|
}
|
|
34307
34606
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34308
34607
|
const version2 = ulid();
|
|
34309
34608
|
const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
|
|
34310
|
-
|
|
34609
|
+
logger22.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
|
|
34311
34610
|
const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
|
|
34312
|
-
|
|
34611
|
+
logger22.info("Presigned URL generated", {
|
|
34313
34612
|
userId: user.id,
|
|
34314
34613
|
gameId,
|
|
34315
34614
|
version: version2
|
|
@@ -34322,12 +34621,12 @@ class UploadService {
|
|
|
34322
34621
|
};
|
|
34323
34622
|
}
|
|
34324
34623
|
}
|
|
34325
|
-
var
|
|
34624
|
+
var logger22;
|
|
34326
34625
|
var init_upload_service = __esm(() => {
|
|
34327
34626
|
init_node();
|
|
34328
34627
|
init_src2();
|
|
34329
34628
|
init_errors();
|
|
34330
|
-
|
|
34629
|
+
logger22 = log.scope("UploadService");
|
|
34331
34630
|
});
|
|
34332
34631
|
|
|
34333
34632
|
// ../api-core/src/services/factory/platform.ts
|
|
@@ -34641,7 +34940,7 @@ class AchievementService {
|
|
|
34641
34940
|
results.push(result);
|
|
34642
34941
|
}
|
|
34643
34942
|
}
|
|
34644
|
-
|
|
34943
|
+
logger23.debug("Listed current achievements", { userId: user.id, count: results.length });
|
|
34645
34944
|
return results;
|
|
34646
34945
|
}
|
|
34647
34946
|
async listHistory(user, limit) {
|
|
@@ -34659,14 +34958,14 @@ class AchievementService {
|
|
|
34659
34958
|
createdAt: c.createdAt,
|
|
34660
34959
|
scopeKey: c.scopeKey
|
|
34661
34960
|
}));
|
|
34662
|
-
|
|
34961
|
+
logger23.debug("Listed achievement history", { userId: user.id, count: results.length });
|
|
34663
34962
|
return results;
|
|
34664
34963
|
}
|
|
34665
34964
|
async submitProgress(achievementId, user) {
|
|
34666
34965
|
const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
|
|
34667
34966
|
broadcast: false
|
|
34668
34967
|
});
|
|
34669
|
-
|
|
34968
|
+
logger23.debug("Submitted progress", {
|
|
34670
34969
|
userId: user.id,
|
|
34671
34970
|
achievementId,
|
|
34672
34971
|
wasNewClaim
|
|
@@ -34698,7 +34997,7 @@ class AchievementService {
|
|
|
34698
34997
|
rewardCredits
|
|
34699
34998
|
}).returning();
|
|
34700
34999
|
if (!newClaim) {
|
|
34701
|
-
|
|
35000
|
+
logger23.error("Achievement claim insert returned no rows", {
|
|
34702
35001
|
userId,
|
|
34703
35002
|
achievementId,
|
|
34704
35003
|
scopeKey
|
|
@@ -34707,7 +35006,7 @@ class AchievementService {
|
|
|
34707
35006
|
}
|
|
34708
35007
|
await this.deps.addCredits(userId, rewardCredits);
|
|
34709
35008
|
await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
|
|
34710
|
-
|
|
35009
|
+
logger23.info("Awarded achievement", {
|
|
34711
35010
|
userId,
|
|
34712
35011
|
achievementId,
|
|
34713
35012
|
scopeKey,
|
|
@@ -34744,7 +35043,7 @@ class AchievementService {
|
|
|
34744
35043
|
return { title, body: body2 };
|
|
34745
35044
|
}
|
|
34746
35045
|
}
|
|
34747
|
-
var
|
|
35046
|
+
var logger23;
|
|
34748
35047
|
var init_achievement_service = __esm(() => {
|
|
34749
35048
|
init_drizzle_orm();
|
|
34750
35049
|
init_tables_index();
|
|
@@ -34753,7 +35052,7 @@ var init_achievement_service = __esm(() => {
|
|
|
34753
35052
|
init_errors();
|
|
34754
35053
|
init_leaderboard_util();
|
|
34755
35054
|
init_scope_util();
|
|
34756
|
-
|
|
35055
|
+
logger23 = log.scope("AchievementService");
|
|
34757
35056
|
});
|
|
34758
35057
|
|
|
34759
35058
|
// ../api-core/src/services/inventory.service.ts
|
|
@@ -34781,7 +35080,7 @@ class InventoryService {
|
|
|
34781
35080
|
},
|
|
34782
35081
|
updatedAt: inventoryItems.updatedAt
|
|
34783
35082
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
34784
|
-
|
|
35083
|
+
logger24.debug("Listed inventory", { userId: user.id, count: inventory.length });
|
|
34785
35084
|
return inventory;
|
|
34786
35085
|
}
|
|
34787
35086
|
async addItem(itemId, quantity, user) {
|
|
@@ -34798,7 +35097,7 @@ class InventoryService {
|
|
|
34798
35097
|
const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
|
|
34799
35098
|
return inserted?.quantity ?? 0;
|
|
34800
35099
|
});
|
|
34801
|
-
|
|
35100
|
+
logger24.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
|
|
34802
35101
|
return { newTotal };
|
|
34803
35102
|
}
|
|
34804
35103
|
async removeItem(itemId, quantity, user) {
|
|
@@ -34809,7 +35108,7 @@ class InventoryService {
|
|
|
34809
35108
|
}
|
|
34810
35109
|
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);
|
|
34811
35110
|
if (!currentItem) {
|
|
34812
|
-
|
|
35111
|
+
logger24.warn("Insufficient inventory for removal", {
|
|
34813
35112
|
userId: user.id,
|
|
34814
35113
|
itemId,
|
|
34815
35114
|
requestedQuantity: quantity
|
|
@@ -34819,13 +35118,13 @@ class InventoryService {
|
|
|
34819
35118
|
const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
|
|
34820
35119
|
return updated?.quantity ?? 0;
|
|
34821
35120
|
});
|
|
34822
|
-
|
|
35121
|
+
logger24.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
|
|
34823
35122
|
return { newTotal };
|
|
34824
35123
|
}
|
|
34825
35124
|
async addCredits(userId, amount) {
|
|
34826
35125
|
const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
34827
35126
|
if (!creditsItem) {
|
|
34828
|
-
|
|
35127
|
+
logger24.error("Primary currency not found", {
|
|
34829
35128
|
userId,
|
|
34830
35129
|
amount
|
|
34831
35130
|
});
|
|
@@ -34838,17 +35137,17 @@ class InventoryService {
|
|
|
34838
35137
|
updatedAt: new Date
|
|
34839
35138
|
}
|
|
34840
35139
|
});
|
|
34841
|
-
|
|
35140
|
+
logger24.debug("Added credits", { userId, amount });
|
|
34842
35141
|
}
|
|
34843
35142
|
}
|
|
34844
|
-
var
|
|
35143
|
+
var logger24;
|
|
34845
35144
|
var init_inventory_service = __esm(() => {
|
|
34846
35145
|
init_drizzle_orm();
|
|
34847
35146
|
init_src();
|
|
34848
35147
|
init_tables_index();
|
|
34849
35148
|
init_src2();
|
|
34850
35149
|
init_errors();
|
|
34851
|
-
|
|
35150
|
+
logger24 = log.scope("InventoryService");
|
|
34852
35151
|
});
|
|
34853
35152
|
|
|
34854
35153
|
// ../api-core/src/services/leaderboard.service.ts
|
|
@@ -34880,7 +35179,7 @@ class LeaderboardService {
|
|
|
34880
35179
|
sessionId
|
|
34881
35180
|
}).returning();
|
|
34882
35181
|
if (!newScore) {
|
|
34883
|
-
|
|
35182
|
+
logger25.error("Score insert returned no rows", { userId, gameId, score: input.score });
|
|
34884
35183
|
throw new InternalError("Failed to insert score");
|
|
34885
35184
|
}
|
|
34886
35185
|
const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
|
|
@@ -34908,7 +35207,7 @@ class LeaderboardService {
|
|
|
34908
35207
|
movedUpWithinTop3
|
|
34909
35208
|
});
|
|
34910
35209
|
}
|
|
34911
|
-
|
|
35210
|
+
logger25.info("Score submitted", {
|
|
34912
35211
|
gameId,
|
|
34913
35212
|
userId,
|
|
34914
35213
|
isAnonymousUser,
|
|
@@ -34985,7 +35284,7 @@ class LeaderboardService {
|
|
|
34985
35284
|
});
|
|
34986
35285
|
}
|
|
34987
35286
|
} catch (error) {
|
|
34988
|
-
|
|
35287
|
+
logger25.warn("Failed to publish notification", { error });
|
|
34989
35288
|
}
|
|
34990
35289
|
}
|
|
34991
35290
|
async getLeaderboard(gameId, query, isAnonymousUser) {
|
|
@@ -35104,7 +35403,7 @@ class LeaderboardService {
|
|
|
35104
35403
|
return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
|
|
35105
35404
|
}
|
|
35106
35405
|
}
|
|
35107
|
-
var
|
|
35406
|
+
var logger25;
|
|
35108
35407
|
var init_leaderboard_service = __esm(() => {
|
|
35109
35408
|
init_drizzle_orm();
|
|
35110
35409
|
init_src();
|
|
@@ -35114,7 +35413,7 @@ var init_leaderboard_service = __esm(() => {
|
|
|
35114
35413
|
init_notification();
|
|
35115
35414
|
init_errors();
|
|
35116
35415
|
init_leaderboard_util();
|
|
35117
|
-
|
|
35416
|
+
logger25 = log.scope("LeaderboardService");
|
|
35118
35417
|
});
|
|
35119
35418
|
|
|
35120
35419
|
// ../api-core/src/services/level.service.ts
|
|
@@ -35130,9 +35429,9 @@ class LevelService {
|
|
|
35130
35429
|
for (const config2 of configs) {
|
|
35131
35430
|
levelConfigCache.set(config2.level, config2);
|
|
35132
35431
|
}
|
|
35133
|
-
|
|
35432
|
+
logger26.info("Cache pre-warmed", { count: configs.length });
|
|
35134
35433
|
} catch (error) {
|
|
35135
|
-
|
|
35434
|
+
logger26.error("Cache pre-warm failed", { error });
|
|
35136
35435
|
}
|
|
35137
35436
|
}
|
|
35138
35437
|
async getConfig(level) {
|
|
@@ -35166,7 +35465,7 @@ class LevelService {
|
|
|
35166
35465
|
totalXP
|
|
35167
35466
|
}).returning();
|
|
35168
35467
|
if (!newUserLevel) {
|
|
35169
|
-
|
|
35468
|
+
logger26.error("User level insert returned no rows", { userId: user.id });
|
|
35170
35469
|
throw new InternalError("Failed to create user level cache record");
|
|
35171
35470
|
}
|
|
35172
35471
|
userLevel = newUserLevel;
|
|
@@ -35181,7 +35480,7 @@ class LevelService {
|
|
|
35181
35480
|
userLevel = updatedUserLevel;
|
|
35182
35481
|
}
|
|
35183
35482
|
}
|
|
35184
|
-
|
|
35483
|
+
logger26.debug("Retrieved user level", {
|
|
35185
35484
|
userId: user.id,
|
|
35186
35485
|
totalXP,
|
|
35187
35486
|
currentLevel,
|
|
@@ -35192,7 +35491,7 @@ class LevelService {
|
|
|
35192
35491
|
async getProgress(user) {
|
|
35193
35492
|
const userLevel = await this.getByUser(user);
|
|
35194
35493
|
const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
|
|
35195
|
-
|
|
35494
|
+
logger26.debug("Retrieved progress", { userId: user.id });
|
|
35196
35495
|
return {
|
|
35197
35496
|
level: userLevel.currentLevel,
|
|
35198
35497
|
currentXp: userLevel.currentXp,
|
|
@@ -35226,7 +35525,7 @@ class LevelService {
|
|
|
35226
35525
|
if (leveledUp && previousUserLevel) {
|
|
35227
35526
|
await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
|
|
35228
35527
|
}
|
|
35229
|
-
|
|
35528
|
+
logger26.info("Synced from Timeback", {
|
|
35230
35529
|
userId,
|
|
35231
35530
|
totalXP,
|
|
35232
35531
|
currentLevel,
|
|
@@ -35267,7 +35566,7 @@ class LevelService {
|
|
|
35267
35566
|
}
|
|
35268
35567
|
if (totalCredits > 0) {
|
|
35269
35568
|
await this.deps.addCredits(userId, totalCredits);
|
|
35270
|
-
|
|
35569
|
+
logger26.info("Awarded level-up credits", {
|
|
35271
35570
|
userId,
|
|
35272
35571
|
fromLevel,
|
|
35273
35572
|
toLevel,
|
|
@@ -35305,14 +35604,14 @@ class LevelService {
|
|
|
35305
35604
|
};
|
|
35306
35605
|
}
|
|
35307
35606
|
}
|
|
35308
|
-
var
|
|
35607
|
+
var logger26, levelConfigCache = null;
|
|
35309
35608
|
var init_level_service = __esm(() => {
|
|
35310
35609
|
init_drizzle_orm();
|
|
35311
35610
|
init_src();
|
|
35312
35611
|
init_tables_index();
|
|
35313
35612
|
init_src2();
|
|
35314
35613
|
init_errors();
|
|
35315
|
-
|
|
35614
|
+
logger26 = log.scope("LevelService");
|
|
35316
35615
|
});
|
|
35317
35616
|
|
|
35318
35617
|
// ../realtime/src/server/domain/events.ts
|
|
@@ -35333,13 +35632,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
|
|
|
35333
35632
|
});
|
|
35334
35633
|
if (!res.ok) {
|
|
35335
35634
|
const text3 = await res.text().catch(() => "");
|
|
35336
|
-
|
|
35635
|
+
logger27.warn("Failed to publish to user", {
|
|
35337
35636
|
status: res.status,
|
|
35338
35637
|
body: text3
|
|
35339
35638
|
});
|
|
35340
35639
|
}
|
|
35341
35640
|
} catch (error) {
|
|
35342
|
-
|
|
35641
|
+
logger27.error("Publish to user error", { error });
|
|
35343
35642
|
}
|
|
35344
35643
|
}
|
|
35345
35644
|
|
|
@@ -35361,7 +35660,7 @@ class NotificationService {
|
|
|
35361
35660
|
conditions2.push(eq(notifications.type, type));
|
|
35362
35661
|
}
|
|
35363
35662
|
const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
|
|
35364
|
-
|
|
35663
|
+
logger27.debug("Listed notifications", { userId: user.id, count: results.length });
|
|
35365
35664
|
return results;
|
|
35366
35665
|
}
|
|
35367
35666
|
async updateStatus(notificationId, status, method) {
|
|
@@ -35380,7 +35679,7 @@ class NotificationService {
|
|
|
35380
35679
|
if (!updated) {
|
|
35381
35680
|
throw new NotFoundError("Notification", notificationId);
|
|
35382
35681
|
}
|
|
35383
|
-
|
|
35682
|
+
logger27.debug("Updated status", { notificationId, status });
|
|
35384
35683
|
return updated;
|
|
35385
35684
|
}
|
|
35386
35685
|
async getStats(user, options) {
|
|
@@ -35406,7 +35705,7 @@ class NotificationService {
|
|
|
35406
35705
|
const clicked = statsMap.clicked || 0;
|
|
35407
35706
|
const dismissed = statsMap.dismissed || 0;
|
|
35408
35707
|
const expired = statsMap.expired || 0;
|
|
35409
|
-
|
|
35708
|
+
logger27.debug("Retrieved stats", { userId: user.id, total });
|
|
35410
35709
|
return {
|
|
35411
35710
|
total,
|
|
35412
35711
|
delivered,
|
|
@@ -35455,7 +35754,7 @@ class NotificationService {
|
|
|
35455
35754
|
options: { data, clickUrl, metadata: metadata2 }
|
|
35456
35755
|
});
|
|
35457
35756
|
}
|
|
35458
|
-
|
|
35757
|
+
logger27.debug("Created notification", {
|
|
35459
35758
|
userId,
|
|
35460
35759
|
type,
|
|
35461
35760
|
id: notificationId,
|
|
@@ -35463,7 +35762,7 @@ class NotificationService {
|
|
|
35463
35762
|
});
|
|
35464
35763
|
return notificationId;
|
|
35465
35764
|
} catch (error) {
|
|
35466
|
-
|
|
35765
|
+
logger27.error("Failed to create notification", { userId, type, error });
|
|
35467
35766
|
return null;
|
|
35468
35767
|
}
|
|
35469
35768
|
}
|
|
@@ -35477,7 +35776,7 @@ class NotificationService {
|
|
|
35477
35776
|
}) {
|
|
35478
35777
|
const realtimeConfig = this.deps.realtime;
|
|
35479
35778
|
if (!realtimeConfig) {
|
|
35480
|
-
|
|
35779
|
+
logger27.warn("No realtime config for publish");
|
|
35481
35780
|
return;
|
|
35482
35781
|
}
|
|
35483
35782
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -35519,13 +35818,13 @@ class NotificationService {
|
|
|
35519
35818
|
metadata: data.metadata || {}
|
|
35520
35819
|
}).returning();
|
|
35521
35820
|
if (!notification) {
|
|
35522
|
-
|
|
35821
|
+
logger27.error("Notification insert returned no rows", {
|
|
35523
35822
|
userId: data.userId,
|
|
35524
35823
|
type: data.type
|
|
35525
35824
|
});
|
|
35526
35825
|
throw new InternalError("Failed to create notification");
|
|
35527
35826
|
}
|
|
35528
|
-
|
|
35827
|
+
logger27.info("Inserted notification", {
|
|
35529
35828
|
notificationId: notification.id,
|
|
35530
35829
|
userId: notification.userId,
|
|
35531
35830
|
type: notification.type
|
|
@@ -35535,7 +35834,7 @@ class NotificationService {
|
|
|
35535
35834
|
async deliverPending(userId) {
|
|
35536
35835
|
const realtimeConfig = this.deps.realtime;
|
|
35537
35836
|
if (!realtimeConfig) {
|
|
35538
|
-
|
|
35837
|
+
logger27.warn("No realtime config for delivery");
|
|
35539
35838
|
return;
|
|
35540
35839
|
}
|
|
35541
35840
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -35562,13 +35861,13 @@ class NotificationService {
|
|
|
35562
35861
|
metadata: notification.metadata,
|
|
35563
35862
|
clickUrl: notification.clickUrl
|
|
35564
35863
|
});
|
|
35565
|
-
|
|
35864
|
+
logger27.info("Delivered notification", {
|
|
35566
35865
|
notificationId: notification.id,
|
|
35567
35866
|
userId,
|
|
35568
35867
|
type: notification.type
|
|
35569
35868
|
});
|
|
35570
35869
|
} catch (error) {
|
|
35571
|
-
|
|
35870
|
+
logger27.warn("Failed to deliver", {
|
|
35572
35871
|
notificationId: notification.id,
|
|
35573
35872
|
error
|
|
35574
35873
|
});
|
|
@@ -35576,7 +35875,7 @@ class NotificationService {
|
|
|
35576
35875
|
}
|
|
35577
35876
|
}
|
|
35578
35877
|
}
|
|
35579
|
-
var
|
|
35878
|
+
var logger27;
|
|
35580
35879
|
var init_notification_service = __esm(() => {
|
|
35581
35880
|
init_drizzle_orm();
|
|
35582
35881
|
init_src();
|
|
@@ -35585,7 +35884,7 @@ var init_notification_service = __esm(() => {
|
|
|
35585
35884
|
init_events();
|
|
35586
35885
|
init_notification();
|
|
35587
35886
|
init_errors();
|
|
35588
|
-
|
|
35887
|
+
logger27 = log.scope("NotificationService");
|
|
35589
35888
|
});
|
|
35590
35889
|
|
|
35591
35890
|
// ../api-core/src/services/factory/player.ts
|
|
@@ -35709,7 +36008,7 @@ class CharacterService {
|
|
|
35709
36008
|
createdAt: characterComponents.createdAt,
|
|
35710
36009
|
updatedAt: characterComponents.updatedAt
|
|
35711
36010
|
}).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
|
|
35712
|
-
|
|
36011
|
+
logger28.debug("Listed available components", {
|
|
35713
36012
|
level,
|
|
35714
36013
|
count: components.length
|
|
35715
36014
|
});
|
|
@@ -35727,7 +36026,7 @@ class CharacterService {
|
|
|
35727
36026
|
}
|
|
35728
36027
|
}
|
|
35729
36028
|
});
|
|
35730
|
-
|
|
36029
|
+
logger28.debug("Retrieved character", { userId: user.id, found: Boolean(pc) });
|
|
35731
36030
|
return pc ?? null;
|
|
35732
36031
|
}
|
|
35733
36032
|
async getByUserId(userId) {
|
|
@@ -35742,7 +36041,7 @@ class CharacterService {
|
|
|
35742
36041
|
}
|
|
35743
36042
|
}
|
|
35744
36043
|
});
|
|
35745
|
-
|
|
36044
|
+
logger28.debug("Retrieved character by ID", { userId, found: Boolean(pc) });
|
|
35746
36045
|
return pc ?? null;
|
|
35747
36046
|
}
|
|
35748
36047
|
async create(input, user) {
|
|
@@ -35757,13 +36056,13 @@ class CharacterService {
|
|
|
35757
36056
|
}
|
|
35758
36057
|
const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
|
|
35759
36058
|
if (!characterRow) {
|
|
35760
|
-
|
|
36059
|
+
logger28.error("Character insert returned no rows", { userId: user.id });
|
|
35761
36060
|
throw new InternalError("Failed to create character in database");
|
|
35762
36061
|
}
|
|
35763
36062
|
await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
|
|
35764
36063
|
return characterRow;
|
|
35765
36064
|
});
|
|
35766
|
-
|
|
36065
|
+
logger28.info("Created character", { userId: user.id, characterId: result.id });
|
|
35767
36066
|
return result;
|
|
35768
36067
|
}
|
|
35769
36068
|
async update(input, user) {
|
|
@@ -35775,7 +36074,7 @@ class CharacterService {
|
|
|
35775
36074
|
if (!row) {
|
|
35776
36075
|
throw new NotFoundError("Player character");
|
|
35777
36076
|
}
|
|
35778
|
-
|
|
36077
|
+
logger28.info("Updated character", {
|
|
35779
36078
|
userId: user.id,
|
|
35780
36079
|
characterId: row.id,
|
|
35781
36080
|
updatedFields: Object.keys(input)
|
|
@@ -35797,7 +36096,7 @@ class CharacterService {
|
|
|
35797
36096
|
const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
|
|
35798
36097
|
const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
|
|
35799
36098
|
if (!validation.isValid) {
|
|
35800
|
-
|
|
36099
|
+
logger28.warn("Accessory validation failed", {
|
|
35801
36100
|
userId: user.id,
|
|
35802
36101
|
slot,
|
|
35803
36102
|
accessoryComponentId,
|
|
@@ -35813,14 +36112,14 @@ class CharacterService {
|
|
|
35813
36112
|
slot
|
|
35814
36113
|
}).returning();
|
|
35815
36114
|
if (!result) {
|
|
35816
|
-
|
|
36115
|
+
logger28.error("Accessory insert returned no rows", {
|
|
35817
36116
|
userId: user.id,
|
|
35818
36117
|
slot,
|
|
35819
36118
|
accessoryComponentId
|
|
35820
36119
|
});
|
|
35821
36120
|
throw new InternalError("Failed to equip accessory");
|
|
35822
36121
|
}
|
|
35823
|
-
|
|
36122
|
+
logger28.info("Equipped accessory", {
|
|
35824
36123
|
userId: user.id,
|
|
35825
36124
|
slot,
|
|
35826
36125
|
accessoryComponentId
|
|
@@ -35841,7 +36140,7 @@ class CharacterService {
|
|
|
35841
36140
|
const playerLevel = userLevel?.currentLevel ?? 1;
|
|
35842
36141
|
const validation = validateAccessoryRemoval(slot, playerLevel);
|
|
35843
36142
|
if (!validation.isValid) {
|
|
35844
|
-
|
|
36143
|
+
logger28.warn("Accessory removal validation failed", {
|
|
35845
36144
|
userId: user.id,
|
|
35846
36145
|
slot,
|
|
35847
36146
|
playerLevel,
|
|
@@ -35850,17 +36149,17 @@ class CharacterService {
|
|
|
35850
36149
|
throw new ValidationError(validation.error ?? "Invalid accessory removal");
|
|
35851
36150
|
}
|
|
35852
36151
|
await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
|
|
35853
|
-
|
|
36152
|
+
logger28.info("Removed accessory", { userId: user.id, slot });
|
|
35854
36153
|
}
|
|
35855
36154
|
}
|
|
35856
|
-
var
|
|
36155
|
+
var logger28;
|
|
35857
36156
|
var init_character_service = __esm(() => {
|
|
35858
36157
|
init_drizzle_orm();
|
|
35859
36158
|
init_tables_index();
|
|
35860
36159
|
init_src2();
|
|
35861
36160
|
init_errors();
|
|
35862
36161
|
init_accessory_util();
|
|
35863
|
-
|
|
36162
|
+
logger28 = log.scope("CharacterService");
|
|
35864
36163
|
});
|
|
35865
36164
|
|
|
35866
36165
|
// ../api-core/src/services/currency.service.ts
|
|
@@ -35872,7 +36171,7 @@ class CurrencyService {
|
|
|
35872
36171
|
async list() {
|
|
35873
36172
|
const db2 = this.deps.db;
|
|
35874
36173
|
const allCurrencies = await db2.query.currencies.findMany();
|
|
35875
|
-
|
|
36174
|
+
logger29.debug("Listed currencies", { count: allCurrencies.length });
|
|
35876
36175
|
return allCurrencies;
|
|
35877
36176
|
}
|
|
35878
36177
|
async getById(currencyId) {
|
|
@@ -35883,7 +36182,7 @@ class CurrencyService {
|
|
|
35883
36182
|
if (!currency) {
|
|
35884
36183
|
throw new NotFoundError("Currency", currencyId);
|
|
35885
36184
|
}
|
|
35886
|
-
|
|
36185
|
+
logger29.debug("Retrieved currency", { currencyId });
|
|
35887
36186
|
return currency;
|
|
35888
36187
|
}
|
|
35889
36188
|
async create(data) {
|
|
@@ -35891,13 +36190,13 @@ class CurrencyService {
|
|
|
35891
36190
|
try {
|
|
35892
36191
|
const [newCurrency] = await db2.insert(currencies).values(data).returning();
|
|
35893
36192
|
if (!newCurrency) {
|
|
35894
|
-
|
|
36193
|
+
logger29.error("Currency insert returned no rows", {
|
|
35895
36194
|
itemId: data.itemId,
|
|
35896
36195
|
symbol: data.symbol
|
|
35897
36196
|
});
|
|
35898
36197
|
throw new InternalError("Failed to create currency");
|
|
35899
36198
|
}
|
|
35900
|
-
|
|
36199
|
+
logger29.info("Created currency", {
|
|
35901
36200
|
currencyId: newCurrency.id,
|
|
35902
36201
|
itemId: newCurrency.itemId,
|
|
35903
36202
|
symbol: newCurrency.symbol,
|
|
@@ -35926,7 +36225,7 @@ class CurrencyService {
|
|
|
35926
36225
|
if (!updatedCurrency) {
|
|
35927
36226
|
throw new NotFoundError("Currency", currencyId);
|
|
35928
36227
|
}
|
|
35929
|
-
|
|
36228
|
+
logger29.info("Updated currency", {
|
|
35930
36229
|
currencyId: updatedCurrency.id,
|
|
35931
36230
|
updatedFields: Object.keys(data)
|
|
35932
36231
|
});
|
|
@@ -35952,16 +36251,16 @@ class CurrencyService {
|
|
|
35952
36251
|
if (result.length === 0) {
|
|
35953
36252
|
throw new NotFoundError("Currency", currencyId);
|
|
35954
36253
|
}
|
|
35955
|
-
|
|
36254
|
+
logger29.info("Deleted currency", { currencyId });
|
|
35956
36255
|
}
|
|
35957
36256
|
}
|
|
35958
|
-
var
|
|
36257
|
+
var logger29;
|
|
35959
36258
|
var init_currency_service = __esm(() => {
|
|
35960
36259
|
init_drizzle_orm();
|
|
35961
36260
|
init_tables_index();
|
|
35962
36261
|
init_src2();
|
|
35963
36262
|
init_errors();
|
|
35964
|
-
|
|
36263
|
+
logger29 = log.scope("CurrencyService");
|
|
35965
36264
|
});
|
|
35966
36265
|
|
|
35967
36266
|
// ../api-core/src/services/logs.service.ts
|
|
@@ -35980,11 +36279,11 @@ class LogsService {
|
|
|
35980
36279
|
if (!game) {
|
|
35981
36280
|
throw new NotFoundError("Game", slug2);
|
|
35982
36281
|
}
|
|
35983
|
-
|
|
36282
|
+
logger30.info("Admin accessing game logs", { adminId: user.id, slug: slug2, sstStage });
|
|
35984
36283
|
} else {
|
|
35985
36284
|
const isApprovedDev = user.developerStatus === "approved";
|
|
35986
36285
|
if (!isApprovedDev) {
|
|
35987
|
-
|
|
36286
|
+
logger30.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
|
|
35988
36287
|
throw new AccessDeniedError("Must be an approved developer");
|
|
35989
36288
|
}
|
|
35990
36289
|
const game = await db2.query.games.findFirst({
|
|
@@ -35999,7 +36298,7 @@ class LogsService {
|
|
|
35999
36298
|
columns: { id: true }
|
|
36000
36299
|
});
|
|
36001
36300
|
if (!membership) {
|
|
36002
|
-
|
|
36301
|
+
logger30.warn("Developer attempted access to unowned game logs", {
|
|
36003
36302
|
userId: user.id,
|
|
36004
36303
|
slug: slug2
|
|
36005
36304
|
});
|
|
@@ -36008,7 +36307,7 @@ class LogsService {
|
|
|
36008
36307
|
}
|
|
36009
36308
|
const workerId = getDeploymentId(slug2, sstStage);
|
|
36010
36309
|
const token = await this.deps.mintLogStreamToken(user.id, workerId);
|
|
36011
|
-
|
|
36310
|
+
logger30.debug("Generated log stream token", {
|
|
36012
36311
|
userId: user.id,
|
|
36013
36312
|
slug: slug2,
|
|
36014
36313
|
workerId
|
|
@@ -36016,14 +36315,14 @@ class LogsService {
|
|
|
36016
36315
|
return { token, workerId };
|
|
36017
36316
|
}
|
|
36018
36317
|
}
|
|
36019
|
-
var
|
|
36318
|
+
var logger30;
|
|
36020
36319
|
var init_logs_service = __esm(() => {
|
|
36021
36320
|
init_drizzle_orm();
|
|
36022
36321
|
init_tables_index();
|
|
36023
36322
|
init_src2();
|
|
36024
36323
|
init_errors();
|
|
36025
36324
|
init_deployment_util();
|
|
36026
|
-
|
|
36325
|
+
logger30 = log.scope("LogsService");
|
|
36027
36326
|
});
|
|
36028
36327
|
|
|
36029
36328
|
// ../api-core/src/services/lti.service.ts
|
|
@@ -36076,7 +36375,7 @@ class MapService {
|
|
|
36076
36375
|
if (!mapDetails) {
|
|
36077
36376
|
throw new NotFoundError("Map", identifier);
|
|
36078
36377
|
}
|
|
36079
|
-
|
|
36378
|
+
logger31.debug("Retrieved map", { identifier });
|
|
36080
36379
|
return mapDetails;
|
|
36081
36380
|
}
|
|
36082
36381
|
async getElements(mapId) {
|
|
@@ -36092,7 +36391,7 @@ class MapService {
|
|
|
36092
36391
|
}
|
|
36093
36392
|
}
|
|
36094
36393
|
});
|
|
36095
|
-
|
|
36394
|
+
logger31.debug("Retrieved elements", { mapId, count: elements.length });
|
|
36096
36395
|
return elements;
|
|
36097
36396
|
}
|
|
36098
36397
|
async getObjects(mapId, userId) {
|
|
@@ -36113,7 +36412,7 @@ class MapService {
|
|
|
36113
36412
|
}
|
|
36114
36413
|
}
|
|
36115
36414
|
});
|
|
36116
|
-
|
|
36415
|
+
logger31.debug("Retrieved objects", { mapId, userId, count: objects.length });
|
|
36117
36416
|
return objects.map((object) => this.formatMapObjectWithItem(object));
|
|
36118
36417
|
}
|
|
36119
36418
|
async createObject(mapId, data, user) {
|
|
@@ -36140,7 +36439,7 @@ class MapService {
|
|
|
36140
36439
|
throw new NotFoundError("Item", data.itemId);
|
|
36141
36440
|
}
|
|
36142
36441
|
if (!item.isPlaceable) {
|
|
36143
|
-
|
|
36442
|
+
logger31.warn("Attempted to place non-placeable item", {
|
|
36144
36443
|
userId: user.id,
|
|
36145
36444
|
itemId: data.itemId,
|
|
36146
36445
|
mapId
|
|
@@ -36154,7 +36453,7 @@ class MapService {
|
|
|
36154
36453
|
};
|
|
36155
36454
|
const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
|
|
36156
36455
|
if (!createdObject) {
|
|
36157
|
-
|
|
36456
|
+
logger31.error("Map object insert returned no rows", {
|
|
36158
36457
|
userId: user.id,
|
|
36159
36458
|
mapId,
|
|
36160
36459
|
itemId: data.itemId
|
|
@@ -36178,12 +36477,12 @@ class MapService {
|
|
|
36178
36477
|
}
|
|
36179
36478
|
});
|
|
36180
36479
|
if (!objectWithItem) {
|
|
36181
|
-
|
|
36480
|
+
logger31.error("Map object query after insert returned no rows", {
|
|
36182
36481
|
objectId: createdObject.id
|
|
36183
36482
|
});
|
|
36184
36483
|
throw new InternalError("Failed to retrieve created object");
|
|
36185
36484
|
}
|
|
36186
|
-
|
|
36485
|
+
logger31.info("Created object", {
|
|
36187
36486
|
userId: user.id,
|
|
36188
36487
|
mapId,
|
|
36189
36488
|
objectId: createdObject.id,
|
|
@@ -36207,7 +36506,7 @@ class MapService {
|
|
|
36207
36506
|
if (result.length === 0) {
|
|
36208
36507
|
throw new NotFoundError("MapObject", objectId);
|
|
36209
36508
|
}
|
|
36210
|
-
|
|
36509
|
+
logger31.info("Deleted object", {
|
|
36211
36510
|
userId: user.id,
|
|
36212
36511
|
mapId,
|
|
36213
36512
|
objectId
|
|
@@ -36236,13 +36535,13 @@ class MapService {
|
|
|
36236
36535
|
};
|
|
36237
36536
|
}
|
|
36238
36537
|
}
|
|
36239
|
-
var
|
|
36538
|
+
var logger31;
|
|
36240
36539
|
var init_map_service = __esm(() => {
|
|
36241
36540
|
init_drizzle_orm();
|
|
36242
36541
|
init_tables_index();
|
|
36243
36542
|
init_src2();
|
|
36244
36543
|
init_errors();
|
|
36245
|
-
|
|
36544
|
+
logger31 = log.scope("MapService");
|
|
36246
36545
|
});
|
|
36247
36546
|
|
|
36248
36547
|
// ../api-core/src/services/realtime.service.ts
|
|
@@ -36277,20 +36576,20 @@ class RealtimeService {
|
|
|
36277
36576
|
}
|
|
36278
36577
|
const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
|
|
36279
36578
|
const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
|
|
36280
|
-
|
|
36579
|
+
logger32.info("Generated token", {
|
|
36281
36580
|
userId: user.id,
|
|
36282
36581
|
gameId: resolvedGameId || "global"
|
|
36283
36582
|
});
|
|
36284
36583
|
return { token };
|
|
36285
36584
|
}
|
|
36286
36585
|
}
|
|
36287
|
-
var
|
|
36586
|
+
var logger32;
|
|
36288
36587
|
var init_realtime_service = __esm(() => {
|
|
36289
36588
|
init_drizzle_orm();
|
|
36290
36589
|
init_tables_index();
|
|
36291
36590
|
init_src2();
|
|
36292
36591
|
init_errors();
|
|
36293
|
-
|
|
36592
|
+
logger32 = log.scope("RealtimeService");
|
|
36294
36593
|
});
|
|
36295
36594
|
|
|
36296
36595
|
// ../api-core/src/services/session.service.ts
|
|
@@ -36325,10 +36624,10 @@ class SessionService {
|
|
|
36325
36624
|
};
|
|
36326
36625
|
const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
|
|
36327
36626
|
if (!newSession?.sessionId) {
|
|
36328
|
-
|
|
36627
|
+
logger33.error("Game session insert returned no rows", { userId, gameId });
|
|
36329
36628
|
throw new InternalError("Failed to create game session");
|
|
36330
36629
|
}
|
|
36331
|
-
|
|
36630
|
+
logger33.info("Started new session", {
|
|
36332
36631
|
sessionId: newSession.sessionId,
|
|
36333
36632
|
gameId,
|
|
36334
36633
|
userId
|
|
@@ -36349,23 +36648,23 @@ class SessionService {
|
|
|
36349
36648
|
return { success: true, message: "Session already ended" };
|
|
36350
36649
|
}
|
|
36351
36650
|
await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
|
|
36352
|
-
|
|
36651
|
+
logger33.info("Ended session", { sessionId, gameId, userId });
|
|
36353
36652
|
return { success: true };
|
|
36354
36653
|
}
|
|
36355
36654
|
async mintToken(gameIdOrSlug, userId) {
|
|
36356
36655
|
const gameId = await this.resolveGameId(gameIdOrSlug);
|
|
36357
36656
|
const result = await this.deps.mintGameToken(gameId, userId);
|
|
36358
|
-
|
|
36657
|
+
logger33.debug("Minted game token", { gameId, userId });
|
|
36359
36658
|
return result;
|
|
36360
36659
|
}
|
|
36361
36660
|
}
|
|
36362
|
-
var
|
|
36661
|
+
var logger33;
|
|
36363
36662
|
var init_session_service = __esm(() => {
|
|
36364
36663
|
init_drizzle_orm();
|
|
36365
36664
|
init_tables_index();
|
|
36366
36665
|
init_src2();
|
|
36367
36666
|
init_errors();
|
|
36368
|
-
|
|
36667
|
+
logger33 = log.scope("SessionService");
|
|
36369
36668
|
});
|
|
36370
36669
|
|
|
36371
36670
|
// ../api-core/src/services/shop.service.ts
|
|
@@ -36411,7 +36710,7 @@ class ShopService {
|
|
|
36411
36710
|
const shopItems = [];
|
|
36412
36711
|
for (const listing of listingsWithRelations) {
|
|
36413
36712
|
if (!listing.item || !listing.currency) {
|
|
36414
|
-
|
|
36713
|
+
logger34.warn("Listing missing item or currency, skipping", {
|
|
36415
36714
|
listingId: listing.id
|
|
36416
36715
|
});
|
|
36417
36716
|
} else {
|
|
@@ -36428,7 +36727,7 @@ class ShopService {
|
|
|
36428
36727
|
});
|
|
36429
36728
|
}
|
|
36430
36729
|
}
|
|
36431
|
-
|
|
36730
|
+
logger34.debug("Retrieved shop view", {
|
|
36432
36731
|
userId: user.id,
|
|
36433
36732
|
itemCount: shopItems.length,
|
|
36434
36733
|
currencyCount: shopCurrencies.length
|
|
@@ -36439,12 +36738,12 @@ class ShopService {
|
|
|
36439
36738
|
};
|
|
36440
36739
|
}
|
|
36441
36740
|
}
|
|
36442
|
-
var
|
|
36741
|
+
var logger34;
|
|
36443
36742
|
var init_shop_service = __esm(() => {
|
|
36444
36743
|
init_drizzle_orm();
|
|
36445
36744
|
init_tables_index();
|
|
36446
36745
|
init_src2();
|
|
36447
|
-
|
|
36746
|
+
logger34 = log.scope("ShopService");
|
|
36448
36747
|
});
|
|
36449
36748
|
|
|
36450
36749
|
// ../api-core/src/services/sprite.service.ts
|
|
@@ -36461,17 +36760,17 @@ class SpriteService {
|
|
|
36461
36760
|
if (!template) {
|
|
36462
36761
|
throw new NotFoundError("SpriteTemplate", slug2);
|
|
36463
36762
|
}
|
|
36464
|
-
|
|
36763
|
+
logger35.debug("Retrieved sprite", { slug: slug2 });
|
|
36465
36764
|
return template;
|
|
36466
36765
|
}
|
|
36467
36766
|
}
|
|
36468
|
-
var
|
|
36767
|
+
var logger35;
|
|
36469
36768
|
var init_sprite_service = __esm(() => {
|
|
36470
36769
|
init_drizzle_orm();
|
|
36471
36770
|
init_tables_index();
|
|
36472
36771
|
init_src2();
|
|
36473
36772
|
init_errors();
|
|
36474
|
-
|
|
36773
|
+
logger35 = log.scope("SpriteService");
|
|
36475
36774
|
});
|
|
36476
36775
|
|
|
36477
36776
|
// ../api-core/src/services/user.service.ts
|
|
@@ -36486,12 +36785,12 @@ class UserService {
|
|
|
36486
36785
|
where: eq(users.id, user.id)
|
|
36487
36786
|
});
|
|
36488
36787
|
if (!userData) {
|
|
36489
|
-
|
|
36788
|
+
logger36.error("User not found", { userId: user.id });
|
|
36490
36789
|
throw new NotFoundError("User", user.id);
|
|
36491
36790
|
}
|
|
36492
36791
|
const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
|
|
36493
36792
|
if (gameId) {
|
|
36494
|
-
|
|
36793
|
+
logger36.debug("Fetched user profile (game context)", { userId: user.id, gameId });
|
|
36495
36794
|
return {
|
|
36496
36795
|
id: userData.id,
|
|
36497
36796
|
name: userData.name,
|
|
@@ -36504,7 +36803,7 @@ class UserService {
|
|
|
36504
36803
|
const timebackAccount = await db2.query.accounts.findFirst({
|
|
36505
36804
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
36506
36805
|
});
|
|
36507
|
-
|
|
36806
|
+
logger36.debug("Fetched user profile (platform context)", { userId: user.id });
|
|
36508
36807
|
return {
|
|
36509
36808
|
id: userData.id,
|
|
36510
36809
|
name: userData.name,
|
|
@@ -36527,7 +36826,7 @@ class UserService {
|
|
|
36527
36826
|
columns: { name: true }
|
|
36528
36827
|
});
|
|
36529
36828
|
if (!userData) {
|
|
36530
|
-
|
|
36829
|
+
logger36.error("Demo user not found", { userId });
|
|
36531
36830
|
throw new NotFoundError("User", userId);
|
|
36532
36831
|
}
|
|
36533
36832
|
return {
|
|
@@ -36541,10 +36840,10 @@ class UserService {
|
|
|
36541
36840
|
updatedAt: new Date
|
|
36542
36841
|
}).where(eq(users.id, userId)).returning({ name: users.name });
|
|
36543
36842
|
if (!updatedUser) {
|
|
36544
|
-
|
|
36843
|
+
logger36.error("Demo user not found for profile update", { userId });
|
|
36545
36844
|
throw new NotFoundError("User", userId);
|
|
36546
36845
|
}
|
|
36547
|
-
|
|
36846
|
+
logger36.debug("Updated demo profile", { userId, displayName });
|
|
36548
36847
|
return {
|
|
36549
36848
|
displayName: updatedUser.name,
|
|
36550
36849
|
isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
|
|
@@ -36557,7 +36856,7 @@ class UserService {
|
|
|
36557
36856
|
]);
|
|
36558
36857
|
const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
36559
36858
|
const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
36560
|
-
|
|
36859
|
+
logger36.debug("Fetched Timeback data", {
|
|
36561
36860
|
timebackId,
|
|
36562
36861
|
role,
|
|
36563
36862
|
enrollmentCount: enrollments.length,
|
|
@@ -36566,9 +36865,9 @@ class UserService {
|
|
|
36566
36865
|
return { id: timebackId, role, enrollments, organizations };
|
|
36567
36866
|
}
|
|
36568
36867
|
async fetchStudentProfile(timebackId) {
|
|
36569
|
-
|
|
36868
|
+
logger36.debug("Fetching student profile", { timebackId });
|
|
36570
36869
|
if (!this.deps.timeback) {
|
|
36571
|
-
|
|
36870
|
+
logger36.warn("Timeback client not available");
|
|
36572
36871
|
return { role: "student", organizations: [] };
|
|
36573
36872
|
}
|
|
36574
36873
|
try {
|
|
@@ -36596,14 +36895,14 @@ class UserService {
|
|
|
36596
36895
|
}
|
|
36597
36896
|
return { role, organizations: [...orgMap.values()] };
|
|
36598
36897
|
} catch (error) {
|
|
36599
|
-
|
|
36898
|
+
logger36.warn("Failed to fetch student profile", { error, timebackId });
|
|
36600
36899
|
return { role: "student", organizations: [] };
|
|
36601
36900
|
}
|
|
36602
36901
|
}
|
|
36603
36902
|
async fetchEnrollments(timebackId) {
|
|
36604
|
-
|
|
36903
|
+
logger36.debug("Fetching enrollments", { timebackId });
|
|
36605
36904
|
if (!this.deps.timeback) {
|
|
36606
|
-
|
|
36905
|
+
logger36.warn("Timeback client not available");
|
|
36607
36906
|
return [];
|
|
36608
36907
|
}
|
|
36609
36908
|
try {
|
|
@@ -36624,7 +36923,7 @@ class UserService {
|
|
|
36624
36923
|
orgId: courseToSchool.get(i2.courseId)
|
|
36625
36924
|
}));
|
|
36626
36925
|
} catch (error) {
|
|
36627
|
-
|
|
36926
|
+
logger36.warn("Failed to fetch enrollments", { error, timebackId });
|
|
36628
36927
|
return [];
|
|
36629
36928
|
}
|
|
36630
36929
|
}
|
|
@@ -36639,14 +36938,14 @@ class UserService {
|
|
|
36639
36938
|
return organizations.filter((o) => enrollmentOrgIds.has(o.id));
|
|
36640
36939
|
}
|
|
36641
36940
|
}
|
|
36642
|
-
var
|
|
36941
|
+
var logger36;
|
|
36643
36942
|
var init_user_service = __esm(() => {
|
|
36644
36943
|
init_drizzle_orm();
|
|
36645
36944
|
init_src();
|
|
36646
36945
|
init_tables_index();
|
|
36647
36946
|
init_src2();
|
|
36648
36947
|
init_errors();
|
|
36649
|
-
|
|
36948
|
+
logger36 = log.scope("UserService");
|
|
36650
36949
|
});
|
|
36651
36950
|
|
|
36652
36951
|
// ../api-core/src/services/verify.service.ts
|
|
@@ -36656,16 +36955,16 @@ class VerifyService {
|
|
|
36656
36955
|
this.deps = deps;
|
|
36657
36956
|
}
|
|
36658
36957
|
async verifyGameToken(token) {
|
|
36659
|
-
|
|
36958
|
+
logger37.debug("Verifying game token");
|
|
36660
36959
|
const payload = await this.deps.validateGameToken(token);
|
|
36661
36960
|
if (!payload) {
|
|
36662
|
-
|
|
36961
|
+
logger37.warn("Invalid or expired game token presented");
|
|
36663
36962
|
throw new ValidationError("Invalid or expired token");
|
|
36664
36963
|
}
|
|
36665
36964
|
const gameId = payload.sub;
|
|
36666
36965
|
const userId = payload.uid;
|
|
36667
36966
|
if (typeof gameId !== "string" || typeof userId !== "string") {
|
|
36668
|
-
|
|
36967
|
+
logger37.warn("Game token missing required claims", {
|
|
36669
36968
|
hasGameId: typeof gameId === "string",
|
|
36670
36969
|
hasUserId: typeof userId === "string"
|
|
36671
36970
|
});
|
|
@@ -36676,7 +36975,7 @@ class VerifyService {
|
|
|
36676
36975
|
where: eq(users.id, userId)
|
|
36677
36976
|
});
|
|
36678
36977
|
if (!userData) {
|
|
36679
|
-
|
|
36978
|
+
logger37.error("User not found for valid token", {
|
|
36680
36979
|
userId
|
|
36681
36980
|
});
|
|
36682
36981
|
throw new NotFoundError("User", userId);
|
|
@@ -36690,7 +36989,7 @@ class VerifyService {
|
|
|
36690
36989
|
family_name: undefined,
|
|
36691
36990
|
timeback_id: userData.timebackId || undefined
|
|
36692
36991
|
};
|
|
36693
|
-
|
|
36992
|
+
logger37.info("Token verified", { gameId, userId });
|
|
36694
36993
|
return {
|
|
36695
36994
|
claims: payload,
|
|
36696
36995
|
gameId,
|
|
@@ -36698,13 +36997,13 @@ class VerifyService {
|
|
|
36698
36997
|
};
|
|
36699
36998
|
}
|
|
36700
36999
|
}
|
|
36701
|
-
var
|
|
37000
|
+
var logger37;
|
|
36702
37001
|
var init_verify_service = __esm(() => {
|
|
36703
37002
|
init_drizzle_orm();
|
|
36704
37003
|
init_tables_index();
|
|
36705
37004
|
init_src2();
|
|
36706
37005
|
init_errors();
|
|
36707
|
-
|
|
37006
|
+
logger37 = log.scope("VerifyService");
|
|
36708
37007
|
});
|
|
36709
37008
|
|
|
36710
37009
|
// ../api-core/src/services/factory/standalone.ts
|
|
@@ -41822,7 +42121,7 @@ var humanize = (times) => {
|
|
|
41822
42121
|
}
|
|
41823
42122
|
}
|
|
41824
42123
|
return `${status}`;
|
|
41825
|
-
},
|
|
42124
|
+
}, logger38 = (fn = console.log) => {
|
|
41826
42125
|
return async function logger2(c, next) {
|
|
41827
42126
|
const { method, url: url2 } = c.req;
|
|
41828
42127
|
const path = url2.slice(url2.indexOf("/", 8));
|
|
@@ -42003,7 +42302,7 @@ function createApp(db2, options) {
|
|
|
42003
42302
|
const app = new Hono2;
|
|
42004
42303
|
app.use("*", cors({ origin: "*", credentials: true }));
|
|
42005
42304
|
if (options.verbose && !options.quiet) {
|
|
42006
|
-
app.use("*",
|
|
42305
|
+
app.use("*", logger38());
|
|
42007
42306
|
}
|
|
42008
42307
|
app.use("/api/*", async (c, next) => {
|
|
42009
42308
|
c.set("db", db2);
|
|
@@ -48436,12 +48735,12 @@ var init_session2 = __esm(() => {
|
|
|
48436
48735
|
init_utils();
|
|
48437
48736
|
init_dist5();
|
|
48438
48737
|
PglitePreparedQuery = class PglitePreparedQuery extends PgPreparedQuery {
|
|
48439
|
-
constructor(client, queryString, params,
|
|
48738
|
+
constructor(client, queryString, params, logger39, fields, name3, _isResponseInArrayMode, customResultMapper) {
|
|
48440
48739
|
super({ sql: queryString, params });
|
|
48441
48740
|
this.client = client;
|
|
48442
48741
|
this.queryString = queryString;
|
|
48443
48742
|
this.params = params;
|
|
48444
|
-
this.logger =
|
|
48743
|
+
this.logger = logger39;
|
|
48445
48744
|
this.fields = fields;
|
|
48446
48745
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
48447
48746
|
this.customResultMapper = customResultMapper;
|
|
@@ -48545,11 +48844,11 @@ var init_session2 = __esm(() => {
|
|
|
48545
48844
|
// ../../node_modules/.bun/drizzle-orm@0.42.0+f8aef3f54a4d48e2/node_modules/drizzle-orm/pglite/driver.js
|
|
48546
48845
|
function construct(client, config2 = {}) {
|
|
48547
48846
|
const dialect2 = new PgDialect({ casing: config2.casing });
|
|
48548
|
-
let
|
|
48847
|
+
let logger39;
|
|
48549
48848
|
if (config2.logger === true) {
|
|
48550
|
-
|
|
48849
|
+
logger39 = new DefaultLogger;
|
|
48551
48850
|
} else if (config2.logger !== false) {
|
|
48552
|
-
|
|
48851
|
+
logger39 = config2.logger;
|
|
48553
48852
|
}
|
|
48554
48853
|
let schema2;
|
|
48555
48854
|
if (config2.schema) {
|
|
@@ -48560,7 +48859,7 @@ function construct(client, config2 = {}) {
|
|
|
48560
48859
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
48561
48860
|
};
|
|
48562
48861
|
}
|
|
48563
|
-
const driver = new PgliteDriver(client, dialect2, { logger:
|
|
48862
|
+
const driver = new PgliteDriver(client, dialect2, { logger: logger39 });
|
|
48564
48863
|
const session2 = driver.createSession(schema2);
|
|
48565
48864
|
const db2 = new PgliteDatabase(dialect2, session2, schema2);
|
|
48566
48865
|
db2.$client = client;
|
|
@@ -94774,8 +95073,8 @@ var init_currencies = __esm(() => {
|
|
|
94774
95073
|
});
|
|
94775
95074
|
|
|
94776
95075
|
// src/lib/logging/adapter.ts
|
|
94777
|
-
function setLogger(
|
|
94778
|
-
customLogger =
|
|
95076
|
+
function setLogger(logger39) {
|
|
95077
|
+
customLogger = logger39;
|
|
94779
95078
|
}
|
|
94780
95079
|
function getLogger() {
|
|
94781
95080
|
if (customLogger) {
|
|
@@ -94787,10 +95086,10 @@ function getLogger() {
|
|
|
94787
95086
|
error: (msg) => console.error(msg)
|
|
94788
95087
|
};
|
|
94789
95088
|
}
|
|
94790
|
-
var customLogger,
|
|
95089
|
+
var customLogger, logger39;
|
|
94791
95090
|
var init_adapter = __esm(() => {
|
|
94792
95091
|
init_config();
|
|
94793
|
-
|
|
95092
|
+
logger39 = {
|
|
94794
95093
|
info: (msg) => {
|
|
94795
95094
|
if (customLogger || !config.embedded) {
|
|
94796
95095
|
getLogger().info(msg);
|
|
@@ -94880,7 +95179,7 @@ async function seedCoreGames(db2) {
|
|
|
94880
95179
|
role: "owner"
|
|
94881
95180
|
}).onConflictDoNothing();
|
|
94882
95181
|
} catch (error2) {
|
|
94883
|
-
|
|
95182
|
+
logger39.error(`Error seeding core game '${gameData.slug}': ${error2}`);
|
|
94884
95183
|
}
|
|
94885
95184
|
}
|
|
94886
95185
|
}
|
|
@@ -94930,7 +95229,7 @@ async function seedCurrentProjectGame(db2, project) {
|
|
|
94930
95229
|
}
|
|
94931
95230
|
return newGame;
|
|
94932
95231
|
} catch (error2) {
|
|
94933
|
-
|
|
95232
|
+
logger39.error(`❌ Error seeding project game: ${error2}`);
|
|
94934
95233
|
throw error2;
|
|
94935
95234
|
}
|
|
94936
95235
|
}
|
|
@@ -95723,7 +96022,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95723
96022
|
where: eq(users.id, existingAccount.userId)
|
|
95724
96023
|
});
|
|
95725
96024
|
if (user) {
|
|
95726
|
-
|
|
96025
|
+
logger40.info("Found user by LTI account", {
|
|
95727
96026
|
userId: user.id,
|
|
95728
96027
|
ltiTimebackId
|
|
95729
96028
|
});
|
|
@@ -95752,13 +96051,13 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95752
96051
|
updatedAt: new Date
|
|
95753
96052
|
}).returning({ id: accounts.id });
|
|
95754
96053
|
if (!account) {
|
|
95755
|
-
|
|
96054
|
+
logger40.error("LTI account link insert returned no rows", {
|
|
95756
96055
|
userId: existingUser.id,
|
|
95757
96056
|
ltiTimebackId
|
|
95758
96057
|
});
|
|
95759
96058
|
throw new InternalError("Failed to link LTI account");
|
|
95760
96059
|
}
|
|
95761
|
-
|
|
96060
|
+
logger40.info("Linked LTI account to existing user", {
|
|
95762
96061
|
userId: existingUser.id,
|
|
95763
96062
|
ltiTimebackId
|
|
95764
96063
|
});
|
|
@@ -95778,7 +96077,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95778
96077
|
updatedAt: new Date
|
|
95779
96078
|
}).returning();
|
|
95780
96079
|
if (!insertedUser) {
|
|
95781
|
-
|
|
96080
|
+
logger40.error("LTI user insert returned no rows", { email, ltiTimebackId });
|
|
95782
96081
|
throw new InternalError("Failed to create user");
|
|
95783
96082
|
}
|
|
95784
96083
|
await tx.insert(accounts).values({
|
|
@@ -95793,7 +96092,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95793
96092
|
createdAt: new Date,
|
|
95794
96093
|
updatedAt: new Date
|
|
95795
96094
|
});
|
|
95796
|
-
|
|
96095
|
+
logger40.info("Provisioned new user from LTI", {
|
|
95797
96096
|
userId: insertedUser.id,
|
|
95798
96097
|
ltiTimebackId
|
|
95799
96098
|
});
|
|
@@ -95801,7 +96100,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95801
96100
|
});
|
|
95802
96101
|
return createdUser;
|
|
95803
96102
|
}
|
|
95804
|
-
var
|
|
96103
|
+
var logger40;
|
|
95805
96104
|
var init_lti_provisioning = __esm(() => {
|
|
95806
96105
|
init_drizzle_orm();
|
|
95807
96106
|
init_src();
|
|
@@ -95809,7 +96108,7 @@ var init_lti_provisioning = __esm(() => {
|
|
|
95809
96108
|
init_src2();
|
|
95810
96109
|
init_errors();
|
|
95811
96110
|
init_lti_util();
|
|
95812
|
-
|
|
96111
|
+
logger40 = log.scope("LtiProvisioning");
|
|
95813
96112
|
});
|
|
95814
96113
|
|
|
95815
96114
|
// ../api-core/src/utils/validation.util.ts
|
|
@@ -95857,21 +96156,21 @@ var init_utils11 = __esm(() => {
|
|
|
95857
96156
|
});
|
|
95858
96157
|
|
|
95859
96158
|
// ../api-core/src/controllers/achievement.controller.ts
|
|
95860
|
-
var
|
|
96159
|
+
var logger41, listCurrent, listHistory, postProgress, achievements3;
|
|
95861
96160
|
var init_achievement_controller = __esm(() => {
|
|
95862
96161
|
init_esm();
|
|
95863
96162
|
init_schemas_index();
|
|
95864
96163
|
init_src2();
|
|
95865
96164
|
init_errors();
|
|
95866
96165
|
init_utils11();
|
|
95867
|
-
|
|
96166
|
+
logger41 = log.scope("AchievementController");
|
|
95868
96167
|
listCurrent = requireNonAnonymous(async (ctx) => {
|
|
95869
|
-
|
|
96168
|
+
logger41.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
95870
96169
|
return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
|
|
95871
96170
|
});
|
|
95872
96171
|
listHistory = requireNonAnonymous(async (ctx) => {
|
|
95873
96172
|
const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
|
|
95874
|
-
|
|
96173
|
+
logger41.debug("Listing achievement history", { userId: ctx.user.id, limit });
|
|
95875
96174
|
return ctx.services.achievement.listHistory(ctx.user, limit);
|
|
95876
96175
|
});
|
|
95877
96176
|
postProgress = requireNonAnonymous(async (ctx) => {
|
|
@@ -95882,12 +96181,12 @@ var init_achievement_controller = __esm(() => {
|
|
|
95882
96181
|
} catch (error2) {
|
|
95883
96182
|
if (error2 instanceof exports_external.ZodError) {
|
|
95884
96183
|
const details = formatZodError(error2);
|
|
95885
|
-
|
|
96184
|
+
logger41.warn("Submit achievement progress validation failed", { details });
|
|
95886
96185
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
95887
96186
|
}
|
|
95888
96187
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95889
96188
|
}
|
|
95890
|
-
|
|
96189
|
+
logger41.debug("Submitting progress", {
|
|
95891
96190
|
userId: ctx.user.id,
|
|
95892
96191
|
achievementId: body2.achievementId
|
|
95893
96192
|
});
|
|
@@ -95901,14 +96200,14 @@ var init_achievement_controller = __esm(() => {
|
|
|
95901
96200
|
});
|
|
95902
96201
|
|
|
95903
96202
|
// ../api-core/src/controllers/admin.controller.ts
|
|
95904
|
-
var
|
|
96203
|
+
var logger42, getAllowedOrigins;
|
|
95905
96204
|
var init_admin_controller = __esm(() => {
|
|
95906
96205
|
init_src2();
|
|
95907
96206
|
init_utils11();
|
|
95908
|
-
|
|
96207
|
+
logger42 = log.scope("AdminController");
|
|
95909
96208
|
getAllowedOrigins = requireAdmin(async (ctx) => {
|
|
95910
96209
|
const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
|
|
95911
|
-
|
|
96210
|
+
logger42.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
|
|
95912
96211
|
if (shouldRefresh) {
|
|
95913
96212
|
await ctx.providers.cache.refreshGameOrigins();
|
|
95914
96213
|
}
|
|
@@ -95923,14 +96222,14 @@ var init_admin_controller = __esm(() => {
|
|
|
95923
96222
|
});
|
|
95924
96223
|
|
|
95925
96224
|
// ../api-core/src/controllers/bucket.controller.ts
|
|
95926
|
-
var
|
|
96225
|
+
var logger43, listFiles, getFile, putFile, deleteFile, initiateUpload;
|
|
95927
96226
|
var init_bucket_controller = __esm(() => {
|
|
95928
96227
|
init_esm();
|
|
95929
96228
|
init_schemas_index();
|
|
95930
96229
|
init_src2();
|
|
95931
96230
|
init_errors();
|
|
95932
96231
|
init_utils11();
|
|
95933
|
-
|
|
96232
|
+
logger43 = log.scope("BucketController");
|
|
95934
96233
|
listFiles = requireDeveloper(async (ctx) => {
|
|
95935
96234
|
const slug2 = ctx.params.slug;
|
|
95936
96235
|
if (!slug2) {
|
|
@@ -95938,7 +96237,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95938
96237
|
}
|
|
95939
96238
|
const url2 = ctx.url;
|
|
95940
96239
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
95941
|
-
|
|
96240
|
+
logger43.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
95942
96241
|
const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
|
|
95943
96242
|
return { files };
|
|
95944
96243
|
});
|
|
@@ -95948,7 +96247,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95948
96247
|
if (!slug2 || !key) {
|
|
95949
96248
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
95950
96249
|
}
|
|
95951
|
-
|
|
96250
|
+
logger43.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
|
|
95952
96251
|
const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
|
|
95953
96252
|
return new Response(Buffer.from(object.body), {
|
|
95954
96253
|
status: 200,
|
|
@@ -95967,7 +96266,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95967
96266
|
const arrayBuffer = await ctx.request.arrayBuffer();
|
|
95968
96267
|
const body2 = new Uint8Array(arrayBuffer);
|
|
95969
96268
|
const contentType = ctx.request.headers.get("content-type") || undefined;
|
|
95970
|
-
|
|
96269
|
+
logger43.debug("Uploading file", {
|
|
95971
96270
|
userId: ctx.user.id,
|
|
95972
96271
|
slug: slug2,
|
|
95973
96272
|
key,
|
|
@@ -95983,7 +96282,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95983
96282
|
if (!slug2 || !key) {
|
|
95984
96283
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
95985
96284
|
}
|
|
95986
|
-
|
|
96285
|
+
logger43.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
|
|
95987
96286
|
await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
|
|
95988
96287
|
return { success: true, key };
|
|
95989
96288
|
});
|
|
@@ -95995,12 +96294,12 @@ var init_bucket_controller = __esm(() => {
|
|
|
95995
96294
|
} catch (error2) {
|
|
95996
96295
|
if (error2 instanceof exports_external.ZodError) {
|
|
95997
96296
|
const details = formatZodError(error2);
|
|
95998
|
-
|
|
96297
|
+
logger43.warn("Initiate upload validation failed", { details });
|
|
95999
96298
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96000
96299
|
}
|
|
96001
96300
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96002
96301
|
}
|
|
96003
|
-
|
|
96302
|
+
logger43.debug("Initiating multipart upload", {
|
|
96004
96303
|
userId: ctx.user.id,
|
|
96005
96304
|
gameId: body2.gameId,
|
|
96006
96305
|
fileName: body2.fileName
|
|
@@ -96017,19 +96316,19 @@ async function listComponents(ctx) {
|
|
|
96017
96316
|
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
96018
96317
|
level = Math.floor(Math.max(0, parsed));
|
|
96019
96318
|
}
|
|
96020
|
-
|
|
96319
|
+
logger44.debug("Listing components", { level });
|
|
96021
96320
|
return ctx.services.character.listAvailableComponents(level);
|
|
96022
96321
|
}
|
|
96023
|
-
var
|
|
96322
|
+
var logger44, get, getByUserId, create, update2, equipAccessory, removeAccessory, character2;
|
|
96024
96323
|
var init_character_controller = __esm(() => {
|
|
96025
96324
|
init_esm();
|
|
96026
96325
|
init_schemas_index();
|
|
96027
96326
|
init_src2();
|
|
96028
96327
|
init_errors();
|
|
96029
96328
|
init_utils11();
|
|
96030
|
-
|
|
96329
|
+
logger44 = log.scope("CharacterController");
|
|
96031
96330
|
get = requireNonAnonymous(async (ctx) => {
|
|
96032
|
-
|
|
96331
|
+
logger44.debug("Getting character", { userId: ctx.user.id });
|
|
96033
96332
|
return ctx.services.character.getByUser(ctx.user);
|
|
96034
96333
|
});
|
|
96035
96334
|
getByUserId = requireNonAnonymous(async (ctx) => {
|
|
@@ -96037,7 +96336,7 @@ var init_character_controller = __esm(() => {
|
|
|
96037
96336
|
if (!userId) {
|
|
96038
96337
|
throw ApiError.badRequest("User ID is required in the URL path");
|
|
96039
96338
|
}
|
|
96040
|
-
|
|
96339
|
+
logger44.debug("Getting character by user ID", { requestedUserId: userId });
|
|
96041
96340
|
return ctx.services.character.getByUserId(userId);
|
|
96042
96341
|
});
|
|
96043
96342
|
create = requireNonAnonymous(async (ctx) => {
|
|
@@ -96048,12 +96347,12 @@ var init_character_controller = __esm(() => {
|
|
|
96048
96347
|
} catch (error2) {
|
|
96049
96348
|
if (error2 instanceof exports_external.ZodError) {
|
|
96050
96349
|
const details = formatZodError(error2);
|
|
96051
|
-
|
|
96350
|
+
logger44.warn("Create character validation failed", { details });
|
|
96052
96351
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96053
96352
|
}
|
|
96054
96353
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96055
96354
|
}
|
|
96056
|
-
|
|
96355
|
+
logger44.debug("Creating character", {
|
|
96057
96356
|
userId: ctx.user.id,
|
|
96058
96357
|
bodyComponentId: body2.bodyComponentId,
|
|
96059
96358
|
hairstyleComponentId: body2.hairstyleComponentId
|
|
@@ -96068,12 +96367,12 @@ var init_character_controller = __esm(() => {
|
|
|
96068
96367
|
} catch (error2) {
|
|
96069
96368
|
if (error2 instanceof exports_external.ZodError) {
|
|
96070
96369
|
const details = formatZodError(error2);
|
|
96071
|
-
|
|
96370
|
+
logger44.warn("Update character validation failed", { details });
|
|
96072
96371
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96073
96372
|
}
|
|
96074
96373
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96075
96374
|
}
|
|
96076
|
-
|
|
96375
|
+
logger44.debug("Updating character", {
|
|
96077
96376
|
userId: ctx.user.id,
|
|
96078
96377
|
bodyComponentId: body2.bodyComponentId,
|
|
96079
96378
|
hairstyleComponentId: body2.hairstyleComponentId,
|
|
@@ -96089,12 +96388,12 @@ var init_character_controller = __esm(() => {
|
|
|
96089
96388
|
} catch (error2) {
|
|
96090
96389
|
if (error2 instanceof exports_external.ZodError) {
|
|
96091
96390
|
const details = formatZodError(error2);
|
|
96092
|
-
|
|
96391
|
+
logger44.warn("Equip accessory validation failed", { details });
|
|
96093
96392
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96094
96393
|
}
|
|
96095
96394
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96096
96395
|
}
|
|
96097
|
-
|
|
96396
|
+
logger44.debug("Equipping accessory", {
|
|
96098
96397
|
userId: ctx.user.id,
|
|
96099
96398
|
slot: body2.slot,
|
|
96100
96399
|
accessoryComponentId: body2.accessoryComponentId
|
|
@@ -96106,7 +96405,7 @@ var init_character_controller = __esm(() => {
|
|
|
96106
96405
|
if (!slot) {
|
|
96107
96406
|
throw ApiError.badRequest("Slot is required in the URL path");
|
|
96108
96407
|
}
|
|
96109
|
-
|
|
96408
|
+
logger44.debug("Removing accessory", { userId: ctx.user.id, slot });
|
|
96110
96409
|
await ctx.services.character.removeAccessory(slot, ctx.user);
|
|
96111
96410
|
return { success: true };
|
|
96112
96411
|
});
|
|
@@ -96122,7 +96421,7 @@ var init_character_controller = __esm(() => {
|
|
|
96122
96421
|
});
|
|
96123
96422
|
|
|
96124
96423
|
// ../api-core/src/controllers/currency.controller.ts
|
|
96125
|
-
var
|
|
96424
|
+
var logger45, list, getById, create2, update3, remove, currencyController;
|
|
96126
96425
|
var init_currency_controller = __esm(() => {
|
|
96127
96426
|
init_esm();
|
|
96128
96427
|
init_schemas_index();
|
|
@@ -96130,9 +96429,9 @@ var init_currency_controller = __esm(() => {
|
|
|
96130
96429
|
init_src4();
|
|
96131
96430
|
init_errors();
|
|
96132
96431
|
init_utils11();
|
|
96133
|
-
|
|
96432
|
+
logger45 = log.scope("CurrencyController");
|
|
96134
96433
|
list = requireNonAnonymous(async (ctx) => {
|
|
96135
|
-
|
|
96434
|
+
logger45.debug("Listing currencies", { userId: ctx.user.id });
|
|
96136
96435
|
return ctx.services.currency.list();
|
|
96137
96436
|
});
|
|
96138
96437
|
getById = requireNonAnonymous(async (ctx) => {
|
|
@@ -96143,7 +96442,7 @@ var init_currency_controller = __esm(() => {
|
|
|
96143
96442
|
if (!isValidUUID(currencyId)) {
|
|
96144
96443
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
96145
96444
|
}
|
|
96146
|
-
|
|
96445
|
+
logger45.debug("Getting currency", { userId: ctx.user.id, currencyId });
|
|
96147
96446
|
return ctx.services.currency.getById(currencyId);
|
|
96148
96447
|
});
|
|
96149
96448
|
create2 = requireAdmin(async (ctx) => {
|
|
@@ -96154,12 +96453,12 @@ var init_currency_controller = __esm(() => {
|
|
|
96154
96453
|
} catch (error2) {
|
|
96155
96454
|
if (error2 instanceof exports_external.ZodError) {
|
|
96156
96455
|
const details = formatZodError(error2);
|
|
96157
|
-
|
|
96456
|
+
logger45.warn("Create currency validation failed", { details });
|
|
96158
96457
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96159
96458
|
}
|
|
96160
96459
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96161
96460
|
}
|
|
96162
|
-
|
|
96461
|
+
logger45.debug("Creating currency", {
|
|
96163
96462
|
userId: ctx.user.id,
|
|
96164
96463
|
symbol: body2.symbol,
|
|
96165
96464
|
itemId: body2.itemId,
|
|
@@ -96182,12 +96481,12 @@ var init_currency_controller = __esm(() => {
|
|
|
96182
96481
|
} catch (error2) {
|
|
96183
96482
|
if (error2 instanceof exports_external.ZodError) {
|
|
96184
96483
|
const details = formatZodError(error2);
|
|
96185
|
-
|
|
96484
|
+
logger45.warn("Update currency validation failed", { details });
|
|
96186
96485
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96187
96486
|
}
|
|
96188
96487
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96189
96488
|
}
|
|
96190
|
-
|
|
96489
|
+
logger45.debug("Updating currency", {
|
|
96191
96490
|
userId: ctx.user.id,
|
|
96192
96491
|
currencyId,
|
|
96193
96492
|
symbol: body2.symbol,
|
|
@@ -96204,7 +96503,7 @@ var init_currency_controller = __esm(() => {
|
|
|
96204
96503
|
if (!isValidUUID(currencyId)) {
|
|
96205
96504
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
96206
96505
|
}
|
|
96207
|
-
|
|
96506
|
+
logger45.debug("Deleting currency", { userId: ctx.user.id, currencyId });
|
|
96208
96507
|
await ctx.services.currency.delete(currencyId);
|
|
96209
96508
|
});
|
|
96210
96509
|
currencyController = {
|
|
@@ -96217,14 +96516,14 @@ var init_currency_controller = __esm(() => {
|
|
|
96217
96516
|
});
|
|
96218
96517
|
|
|
96219
96518
|
// ../api-core/src/controllers/database.controller.ts
|
|
96220
|
-
var
|
|
96519
|
+
var logger46, reset;
|
|
96221
96520
|
var init_database_controller = __esm(() => {
|
|
96222
96521
|
init_esm();
|
|
96223
96522
|
init_schemas_index();
|
|
96224
96523
|
init_src2();
|
|
96225
96524
|
init_errors();
|
|
96226
96525
|
init_utils11();
|
|
96227
|
-
|
|
96526
|
+
logger46 = log.scope("DatabaseController");
|
|
96228
96527
|
reset = requireDeveloper(async (ctx) => {
|
|
96229
96528
|
const slug2 = ctx.params.slug;
|
|
96230
96529
|
if (!slug2) {
|
|
@@ -96237,11 +96536,11 @@ var init_database_controller = __esm(() => {
|
|
|
96237
96536
|
} catch (error2) {
|
|
96238
96537
|
if (error2 instanceof exports_external.ZodError) {
|
|
96239
96538
|
const details = formatZodError(error2);
|
|
96240
|
-
|
|
96539
|
+
logger46.warn("Database reset validation failed", { details });
|
|
96241
96540
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96242
96541
|
}
|
|
96243
96542
|
}
|
|
96244
|
-
|
|
96543
|
+
logger46.debug("Resetting database", {
|
|
96245
96544
|
userId: ctx.user.id,
|
|
96246
96545
|
slug: slug2,
|
|
96247
96546
|
hasSchema: Boolean(body2.schema)
|
|
@@ -96259,7 +96558,7 @@ async function createJob(ctx) {
|
|
|
96259
96558
|
let body2;
|
|
96260
96559
|
try {
|
|
96261
96560
|
const json4 = await ctx.request.json();
|
|
96262
|
-
|
|
96561
|
+
logger47.debug("Deploy request body", {
|
|
96263
96562
|
keys: Object.keys(json4 || {}),
|
|
96264
96563
|
hasUploadToken: Boolean(json4?.uploadToken),
|
|
96265
96564
|
hasCode: Boolean(json4?.code),
|
|
@@ -96269,7 +96568,7 @@ async function createJob(ctx) {
|
|
|
96269
96568
|
} catch (error2) {
|
|
96270
96569
|
if (error2 instanceof exports_external.ZodError) {
|
|
96271
96570
|
const details = formatZodError(error2);
|
|
96272
|
-
|
|
96571
|
+
logger47.warn("Deploy validation failed", { details });
|
|
96273
96572
|
throw ApiError.unprocessableEntity("Invalid deploy request", details);
|
|
96274
96573
|
}
|
|
96275
96574
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96290,14 +96589,14 @@ async function getJob(ctx) {
|
|
|
96290
96589
|
}
|
|
96291
96590
|
return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
|
|
96292
96591
|
}
|
|
96293
|
-
var
|
|
96592
|
+
var logger47, deploy;
|
|
96294
96593
|
var init_deploy_controller = __esm(() => {
|
|
96295
96594
|
init_esm();
|
|
96296
96595
|
init_schemas_index();
|
|
96297
96596
|
init_src2();
|
|
96298
96597
|
init_errors();
|
|
96299
96598
|
init_utils11();
|
|
96300
|
-
|
|
96599
|
+
logger47 = log.scope("DeployController");
|
|
96301
96600
|
deploy = {
|
|
96302
96601
|
createJob: requireDeveloper(createJob),
|
|
96303
96602
|
getJob: requireDeveloper(getJob)
|
|
@@ -96305,17 +96604,17 @@ var init_deploy_controller = __esm(() => {
|
|
|
96305
96604
|
});
|
|
96306
96605
|
|
|
96307
96606
|
// ../api-core/src/controllers/developer.controller.ts
|
|
96308
|
-
var
|
|
96607
|
+
var logger48, apply, getStatus, developer;
|
|
96309
96608
|
var init_developer_controller = __esm(() => {
|
|
96310
96609
|
init_src2();
|
|
96311
96610
|
init_utils11();
|
|
96312
|
-
|
|
96611
|
+
logger48 = log.scope("DeveloperController");
|
|
96313
96612
|
apply = requireNonAnonymous(async (ctx) => {
|
|
96314
|
-
|
|
96613
|
+
logger48.debug("Applying for developer status", { userId: ctx.user.id });
|
|
96315
96614
|
await ctx.services.developer.apply(ctx.user);
|
|
96316
96615
|
});
|
|
96317
96616
|
getStatus = requireNonAnonymous(async (ctx) => {
|
|
96318
|
-
|
|
96617
|
+
logger48.debug("Getting developer status", { userId: ctx.user.id });
|
|
96319
96618
|
const status = await ctx.services.developer.getStatus(ctx.user.id);
|
|
96320
96619
|
return { status };
|
|
96321
96620
|
});
|
|
@@ -96326,7 +96625,7 @@ var init_developer_controller = __esm(() => {
|
|
|
96326
96625
|
});
|
|
96327
96626
|
|
|
96328
96627
|
// ../api-core/src/controllers/domain.controller.ts
|
|
96329
|
-
var
|
|
96628
|
+
var logger49, add, list2, getStatus2, remove2, domains2;
|
|
96330
96629
|
var init_domain_controller = __esm(() => {
|
|
96331
96630
|
init_esm();
|
|
96332
96631
|
init_schemas_index();
|
|
@@ -96334,7 +96633,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96334
96633
|
init_config2();
|
|
96335
96634
|
init_errors();
|
|
96336
96635
|
init_utils11();
|
|
96337
|
-
|
|
96636
|
+
logger49 = log.scope("DomainController");
|
|
96338
96637
|
add = requireDeveloper(async (ctx) => {
|
|
96339
96638
|
const slug2 = ctx.params.slug;
|
|
96340
96639
|
if (!slug2) {
|
|
@@ -96347,13 +96646,13 @@ var init_domain_controller = __esm(() => {
|
|
|
96347
96646
|
} catch (error2) {
|
|
96348
96647
|
if (error2 instanceof exports_external.ZodError) {
|
|
96349
96648
|
const details = formatZodError(error2);
|
|
96350
|
-
|
|
96649
|
+
logger49.warn("Add domain validation failed", { details });
|
|
96351
96650
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96352
96651
|
}
|
|
96353
96652
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96354
96653
|
}
|
|
96355
96654
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96356
|
-
|
|
96655
|
+
logger49.debug("Adding domain", {
|
|
96357
96656
|
userId: ctx.user.id,
|
|
96358
96657
|
slug: slug2,
|
|
96359
96658
|
hostname: body2.hostname,
|
|
@@ -96367,7 +96666,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96367
96666
|
throw ApiError.badRequest("Missing game slug");
|
|
96368
96667
|
}
|
|
96369
96668
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96370
|
-
|
|
96669
|
+
logger49.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
|
|
96371
96670
|
const domains2 = await ctx.services.domain.list(slug2, environment, ctx.user);
|
|
96372
96671
|
return { domains: domains2 };
|
|
96373
96672
|
});
|
|
@@ -96382,7 +96681,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96382
96681
|
}
|
|
96383
96682
|
const refresh = ctx.url.searchParams.get("refresh") === "true";
|
|
96384
96683
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96385
|
-
|
|
96684
|
+
logger49.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
|
|
96386
96685
|
return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
|
|
96387
96686
|
});
|
|
96388
96687
|
remove2 = requireDeveloper(async (ctx) => {
|
|
@@ -96395,7 +96694,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96395
96694
|
throw ApiError.badRequest("Missing hostname");
|
|
96396
96695
|
}
|
|
96397
96696
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96398
|
-
|
|
96697
|
+
logger49.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
|
|
96399
96698
|
await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
|
|
96400
96699
|
});
|
|
96401
96700
|
domains2 = {
|
|
@@ -96407,7 +96706,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96407
96706
|
});
|
|
96408
96707
|
|
|
96409
96708
|
// ../api-core/src/controllers/game.controller.ts
|
|
96410
|
-
var
|
|
96709
|
+
var logger50, list3, listAccessible, getSubjects, getById2, getBySlug, getManifest, upsertBySlug, remove3, games2;
|
|
96411
96710
|
var init_game_controller = __esm(() => {
|
|
96412
96711
|
init_esm();
|
|
96413
96712
|
init_schemas_index();
|
|
@@ -96415,17 +96714,17 @@ var init_game_controller = __esm(() => {
|
|
|
96415
96714
|
init_src4();
|
|
96416
96715
|
init_errors();
|
|
96417
96716
|
init_utils11();
|
|
96418
|
-
|
|
96717
|
+
logger50 = log.scope("GameController");
|
|
96419
96718
|
list3 = requireNonAnonymous(async (ctx) => {
|
|
96420
|
-
|
|
96719
|
+
logger50.debug("Listing games", { userId: ctx.user.id });
|
|
96421
96720
|
return ctx.services.game.list(ctx.user);
|
|
96422
96721
|
});
|
|
96423
96722
|
listAccessible = requireNonAnonymous(async (ctx) => {
|
|
96424
|
-
|
|
96723
|
+
logger50.debug("Listing accessible games", { userId: ctx.user.id });
|
|
96425
96724
|
return ctx.services.game.listAccessible(ctx.user);
|
|
96426
96725
|
});
|
|
96427
96726
|
getSubjects = requireNonAnonymous(async (ctx) => {
|
|
96428
|
-
|
|
96727
|
+
logger50.debug("Getting game subjects", { userId: ctx.user.id });
|
|
96429
96728
|
return ctx.services.game.getSubjects();
|
|
96430
96729
|
});
|
|
96431
96730
|
getById2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96436,7 +96735,7 @@ var init_game_controller = __esm(() => {
|
|
|
96436
96735
|
if (!isValidUUID(gameId)) {
|
|
96437
96736
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96438
96737
|
}
|
|
96439
|
-
|
|
96738
|
+
logger50.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
|
|
96440
96739
|
return ctx.services.game.getById(gameId, ctx.user);
|
|
96441
96740
|
});
|
|
96442
96741
|
getBySlug = requireNonAnonymous(async (ctx) => {
|
|
@@ -96444,7 +96743,7 @@ var init_game_controller = __esm(() => {
|
|
|
96444
96743
|
if (!slug2) {
|
|
96445
96744
|
throw ApiError.badRequest("Missing game slug");
|
|
96446
96745
|
}
|
|
96447
|
-
|
|
96746
|
+
logger50.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
|
|
96448
96747
|
return ctx.services.game.getBySlug(slug2, ctx.user);
|
|
96449
96748
|
});
|
|
96450
96749
|
getManifest = requireNonAnonymous(async (ctx) => {
|
|
@@ -96455,7 +96754,7 @@ var init_game_controller = __esm(() => {
|
|
|
96455
96754
|
if (!isValidUUID(gameId)) {
|
|
96456
96755
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96457
96756
|
}
|
|
96458
|
-
|
|
96757
|
+
logger50.debug("Getting game manifest by ID", {
|
|
96459
96758
|
userId: ctx.user.id,
|
|
96460
96759
|
gameId,
|
|
96461
96760
|
launchId: ctx.launchId
|
|
@@ -96474,12 +96773,12 @@ var init_game_controller = __esm(() => {
|
|
|
96474
96773
|
} catch (error2) {
|
|
96475
96774
|
if (error2 instanceof exports_external.ZodError) {
|
|
96476
96775
|
const details = formatZodError(error2);
|
|
96477
|
-
|
|
96776
|
+
logger50.warn("Upsert game validation failed", { details });
|
|
96478
96777
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96479
96778
|
}
|
|
96480
96779
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96481
96780
|
}
|
|
96482
|
-
|
|
96781
|
+
logger50.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
|
|
96483
96782
|
return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
|
|
96484
96783
|
});
|
|
96485
96784
|
remove3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96490,7 +96789,7 @@ var init_game_controller = __esm(() => {
|
|
|
96490
96789
|
if (!isValidUUID(gameId)) {
|
|
96491
96790
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96492
96791
|
}
|
|
96493
|
-
|
|
96792
|
+
logger50.debug("Deleting game", { userId: ctx.user.id, gameId });
|
|
96494
96793
|
await ctx.services.game.delete(gameId, ctx.user);
|
|
96495
96794
|
});
|
|
96496
96795
|
games2 = {
|
|
@@ -96506,16 +96805,16 @@ var init_game_controller = __esm(() => {
|
|
|
96506
96805
|
});
|
|
96507
96806
|
|
|
96508
96807
|
// ../api-core/src/controllers/inventory.controller.ts
|
|
96509
|
-
var
|
|
96808
|
+
var logger51, list4, addItem, removeItem, inventory;
|
|
96510
96809
|
var init_inventory_controller = __esm(() => {
|
|
96511
96810
|
init_esm();
|
|
96512
96811
|
init_schemas_index();
|
|
96513
96812
|
init_src2();
|
|
96514
96813
|
init_errors();
|
|
96515
96814
|
init_utils11();
|
|
96516
|
-
|
|
96815
|
+
logger51 = log.scope("InventoryController");
|
|
96517
96816
|
list4 = requireNonAnonymous(async (ctx) => {
|
|
96518
|
-
|
|
96817
|
+
logger51.debug("Listing inventory", { userId: ctx.user.id });
|
|
96519
96818
|
return ctx.services.inventory.list(ctx.user);
|
|
96520
96819
|
});
|
|
96521
96820
|
addItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -96526,12 +96825,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
96526
96825
|
} catch (error2) {
|
|
96527
96826
|
if (error2 instanceof exports_external.ZodError) {
|
|
96528
96827
|
const details = formatZodError(error2);
|
|
96529
|
-
|
|
96828
|
+
logger51.warn("Add inventory item validation failed", { details });
|
|
96530
96829
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96531
96830
|
}
|
|
96532
96831
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96533
96832
|
}
|
|
96534
|
-
|
|
96833
|
+
logger51.debug("Adding item", {
|
|
96535
96834
|
userId: ctx.user.id,
|
|
96536
96835
|
itemId: body2.itemId,
|
|
96537
96836
|
qty: body2.qty
|
|
@@ -96546,12 +96845,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
96546
96845
|
} catch (error2) {
|
|
96547
96846
|
if (error2 instanceof exports_external.ZodError) {
|
|
96548
96847
|
const details = formatZodError(error2);
|
|
96549
|
-
|
|
96848
|
+
logger51.warn("Remove inventory item validation failed", { details });
|
|
96550
96849
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96551
96850
|
}
|
|
96552
96851
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96553
96852
|
}
|
|
96554
|
-
|
|
96853
|
+
logger51.debug("Removing item", {
|
|
96555
96854
|
userId: ctx.user.id,
|
|
96556
96855
|
itemId: body2.itemId,
|
|
96557
96856
|
qty: body2.qty
|
|
@@ -96566,7 +96865,7 @@ var init_inventory_controller = __esm(() => {
|
|
|
96566
96865
|
});
|
|
96567
96866
|
|
|
96568
96867
|
// ../api-core/src/controllers/item.controller.ts
|
|
96569
|
-
var
|
|
96868
|
+
var logger52, list5, getById3, resolve2, create3, update4, remove4, listByGame, createForGame, updateForGame, deleteForGame, items2;
|
|
96570
96869
|
var init_item_controller = __esm(() => {
|
|
96571
96870
|
init_esm();
|
|
96572
96871
|
init_schemas_index();
|
|
@@ -96574,10 +96873,10 @@ var init_item_controller = __esm(() => {
|
|
|
96574
96873
|
init_src4();
|
|
96575
96874
|
init_errors();
|
|
96576
96875
|
init_utils11();
|
|
96577
|
-
|
|
96876
|
+
logger52 = log.scope("ItemController");
|
|
96578
96877
|
list5 = requireNonAnonymous(async (ctx) => {
|
|
96579
96878
|
const gameId = ctx.url.searchParams.get("gameId") || undefined;
|
|
96580
|
-
|
|
96879
|
+
logger52.debug("Listing items", { userId: ctx.user.id, gameId });
|
|
96581
96880
|
return ctx.services.item.list(gameId);
|
|
96582
96881
|
});
|
|
96583
96882
|
getById3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96588,7 +96887,7 @@ var init_item_controller = __esm(() => {
|
|
|
96588
96887
|
if (!isValidUUID(itemId)) {
|
|
96589
96888
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96590
96889
|
}
|
|
96591
|
-
|
|
96890
|
+
logger52.debug("Getting item", { userId: ctx.user.id, itemId });
|
|
96592
96891
|
return ctx.services.item.getById(itemId);
|
|
96593
96892
|
});
|
|
96594
96893
|
resolve2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96600,7 +96899,7 @@ var init_item_controller = __esm(() => {
|
|
|
96600
96899
|
if (gameId && !isValidUUID(gameId)) {
|
|
96601
96900
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96602
96901
|
}
|
|
96603
|
-
|
|
96902
|
+
logger52.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
|
|
96604
96903
|
return ctx.services.item.resolveBySlug(slug2, gameId);
|
|
96605
96904
|
});
|
|
96606
96905
|
create3 = requireRole(["admin"], async (ctx) => {
|
|
@@ -96611,12 +96910,12 @@ var init_item_controller = __esm(() => {
|
|
|
96611
96910
|
} catch (error2) {
|
|
96612
96911
|
if (error2 instanceof exports_external.ZodError) {
|
|
96613
96912
|
const details = formatZodError(error2);
|
|
96614
|
-
|
|
96913
|
+
logger52.warn("Create item validation failed", { details });
|
|
96615
96914
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96616
96915
|
}
|
|
96617
96916
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96618
96917
|
}
|
|
96619
|
-
|
|
96918
|
+
logger52.debug("Creating item", {
|
|
96620
96919
|
userId: ctx.user.id,
|
|
96621
96920
|
slug: body2.slug,
|
|
96622
96921
|
displayName: body2.displayName
|
|
@@ -96638,7 +96937,7 @@ var init_item_controller = __esm(() => {
|
|
|
96638
96937
|
} catch (error2) {
|
|
96639
96938
|
if (error2 instanceof exports_external.ZodError) {
|
|
96640
96939
|
const details = formatZodError(error2);
|
|
96641
|
-
|
|
96940
|
+
logger52.warn("Update item validation failed", { details });
|
|
96642
96941
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96643
96942
|
}
|
|
96644
96943
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96646,7 +96945,7 @@ var init_item_controller = __esm(() => {
|
|
|
96646
96945
|
if (Object.keys(body2).length === 0) {
|
|
96647
96946
|
throw ApiError.badRequest("No update data provided");
|
|
96648
96947
|
}
|
|
96649
|
-
|
|
96948
|
+
logger52.debug("Updating item", {
|
|
96650
96949
|
userId: ctx.user.id,
|
|
96651
96950
|
itemId,
|
|
96652
96951
|
slug: body2.slug,
|
|
@@ -96663,7 +96962,7 @@ var init_item_controller = __esm(() => {
|
|
|
96663
96962
|
if (!isValidUUID(itemId)) {
|
|
96664
96963
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96665
96964
|
}
|
|
96666
|
-
|
|
96965
|
+
logger52.debug("Deleting item", { userId: ctx.user.id, itemId });
|
|
96667
96966
|
await ctx.services.item.delete(itemId);
|
|
96668
96967
|
});
|
|
96669
96968
|
listByGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -96674,7 +96973,7 @@ var init_item_controller = __esm(() => {
|
|
|
96674
96973
|
if (!isValidUUID(gameId)) {
|
|
96675
96974
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96676
96975
|
}
|
|
96677
|
-
|
|
96976
|
+
logger52.debug("Listing game items", { userId: ctx.user.id, gameId });
|
|
96678
96977
|
return ctx.services.item.listByGame(gameId);
|
|
96679
96978
|
});
|
|
96680
96979
|
createForGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -96692,12 +96991,12 @@ var init_item_controller = __esm(() => {
|
|
|
96692
96991
|
} catch (error2) {
|
|
96693
96992
|
if (error2 instanceof exports_external.ZodError) {
|
|
96694
96993
|
const details = formatZodError(error2);
|
|
96695
|
-
|
|
96994
|
+
logger52.warn("Create game item validation failed", { details });
|
|
96696
96995
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96697
96996
|
}
|
|
96698
96997
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96699
96998
|
}
|
|
96700
|
-
|
|
96999
|
+
logger52.debug("Creating game item", {
|
|
96701
97000
|
userId: ctx.user.id,
|
|
96702
97001
|
gameId,
|
|
96703
97002
|
slug: body2.slug,
|
|
@@ -96724,7 +97023,7 @@ var init_item_controller = __esm(() => {
|
|
|
96724
97023
|
} catch (error2) {
|
|
96725
97024
|
if (error2 instanceof exports_external.ZodError) {
|
|
96726
97025
|
const details = formatZodError(error2);
|
|
96727
|
-
|
|
97026
|
+
logger52.warn("Update game item validation failed", { details });
|
|
96728
97027
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96729
97028
|
}
|
|
96730
97029
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96732,7 +97031,7 @@ var init_item_controller = __esm(() => {
|
|
|
96732
97031
|
if (Object.keys(body2).length === 0) {
|
|
96733
97032
|
throw ApiError.badRequest("No update data provided");
|
|
96734
97033
|
}
|
|
96735
|
-
|
|
97034
|
+
logger52.debug("Updating game item", {
|
|
96736
97035
|
userId: ctx.user.id,
|
|
96737
97036
|
gameId,
|
|
96738
97037
|
itemId,
|
|
@@ -96754,7 +97053,7 @@ var init_item_controller = __esm(() => {
|
|
|
96754
97053
|
if (!isValidUUID(itemId)) {
|
|
96755
97054
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96756
97055
|
}
|
|
96757
|
-
|
|
97056
|
+
logger52.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
|
|
96758
97057
|
await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
|
|
96759
97058
|
});
|
|
96760
97059
|
items2 = {
|
|
@@ -96772,14 +97071,14 @@ var init_item_controller = __esm(() => {
|
|
|
96772
97071
|
});
|
|
96773
97072
|
|
|
96774
97073
|
// ../api-core/src/controllers/kv.controller.ts
|
|
96775
|
-
var
|
|
97074
|
+
var logger53, listKeys, getStats, seed, getValue2, setValue2, deleteValue, getMetadata, clear;
|
|
96776
97075
|
var init_kv_controller = __esm(() => {
|
|
96777
97076
|
init_esm();
|
|
96778
97077
|
init_schemas_index();
|
|
96779
97078
|
init_src2();
|
|
96780
97079
|
init_errors();
|
|
96781
97080
|
init_utils11();
|
|
96782
|
-
|
|
97081
|
+
logger53 = log.scope("KVController");
|
|
96783
97082
|
listKeys = requireDeveloper(async (ctx) => {
|
|
96784
97083
|
const slug2 = ctx.params.slug;
|
|
96785
97084
|
if (!slug2) {
|
|
@@ -96787,7 +97086,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96787
97086
|
}
|
|
96788
97087
|
const url2 = ctx.url;
|
|
96789
97088
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
96790
|
-
|
|
97089
|
+
logger53.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
96791
97090
|
const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
|
|
96792
97091
|
return { keys };
|
|
96793
97092
|
});
|
|
@@ -96796,7 +97095,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96796
97095
|
if (!slug2) {
|
|
96797
97096
|
throw ApiError.badRequest("Missing game slug");
|
|
96798
97097
|
}
|
|
96799
|
-
|
|
97098
|
+
logger53.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
|
|
96800
97099
|
return ctx.services.kv.getStats(slug2, ctx.user);
|
|
96801
97100
|
});
|
|
96802
97101
|
seed = requireDeveloper(async (ctx) => {
|
|
@@ -96811,12 +97110,12 @@ var init_kv_controller = __esm(() => {
|
|
|
96811
97110
|
} catch (error2) {
|
|
96812
97111
|
if (error2 instanceof exports_external.ZodError) {
|
|
96813
97112
|
const details = formatZodError(error2);
|
|
96814
|
-
|
|
97113
|
+
logger53.warn("Seed validation failed", { details });
|
|
96815
97114
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96816
97115
|
}
|
|
96817
97116
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96818
97117
|
}
|
|
96819
|
-
|
|
97118
|
+
logger53.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
|
|
96820
97119
|
await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
|
|
96821
97120
|
return { success: true, count: body2.entries.length };
|
|
96822
97121
|
});
|
|
@@ -96826,7 +97125,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96826
97125
|
if (!slug2 || !key) {
|
|
96827
97126
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96828
97127
|
}
|
|
96829
|
-
|
|
97128
|
+
logger53.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
|
|
96830
97129
|
const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
|
|
96831
97130
|
return { key, value };
|
|
96832
97131
|
});
|
|
@@ -96840,7 +97139,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96840
97139
|
if (!value) {
|
|
96841
97140
|
throw ApiError.badRequest("Missing value in request body");
|
|
96842
97141
|
}
|
|
96843
|
-
|
|
97142
|
+
logger53.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
|
|
96844
97143
|
await ctx.services.kv.setValue(slug2, key, value, ctx.user);
|
|
96845
97144
|
return { success: true, key };
|
|
96846
97145
|
});
|
|
@@ -96850,7 +97149,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96850
97149
|
if (!slug2 || !key) {
|
|
96851
97150
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96852
97151
|
}
|
|
96853
|
-
|
|
97152
|
+
logger53.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
|
|
96854
97153
|
await ctx.services.kv.deleteValue(slug2, key, ctx.user);
|
|
96855
97154
|
return { success: true, key };
|
|
96856
97155
|
});
|
|
@@ -96860,7 +97159,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96860
97159
|
if (!slug2 || !key) {
|
|
96861
97160
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96862
97161
|
}
|
|
96863
|
-
|
|
97162
|
+
logger53.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
|
|
96864
97163
|
const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
|
|
96865
97164
|
return { key, metadata: metadata2 };
|
|
96866
97165
|
});
|
|
@@ -96869,21 +97168,21 @@ var init_kv_controller = __esm(() => {
|
|
|
96869
97168
|
if (!slug2) {
|
|
96870
97169
|
throw ApiError.badRequest("Missing game slug");
|
|
96871
97170
|
}
|
|
96872
|
-
|
|
97171
|
+
logger53.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
|
|
96873
97172
|
const deleted = await ctx.services.kv.clear(slug2, ctx.user);
|
|
96874
97173
|
return { success: true, deleted };
|
|
96875
97174
|
});
|
|
96876
97175
|
});
|
|
96877
97176
|
|
|
96878
97177
|
// ../api-core/src/controllers/leaderboard.controller.ts
|
|
96879
|
-
var
|
|
97178
|
+
var logger54, submitScore, getGlobalLeaderboard, getLeaderboard, getUserRank, getUserAllScores, getUserScores, leaderboard;
|
|
96880
97179
|
var init_leaderboard_controller = __esm(() => {
|
|
96881
97180
|
init_esm();
|
|
96882
97181
|
init_schemas_index();
|
|
96883
97182
|
init_src2();
|
|
96884
97183
|
init_errors();
|
|
96885
97184
|
init_utils11();
|
|
96886
|
-
|
|
97185
|
+
logger54 = log.scope("LeaderboardController");
|
|
96887
97186
|
submitScore = requireAuth(async (ctx) => {
|
|
96888
97187
|
const gameId = ctx.params.gameId;
|
|
96889
97188
|
if (!gameId) {
|
|
@@ -96896,12 +97195,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96896
97195
|
} catch (error2) {
|
|
96897
97196
|
if (error2 instanceof exports_external.ZodError) {
|
|
96898
97197
|
const details = formatZodError(error2);
|
|
96899
|
-
|
|
97198
|
+
logger54.warn("Submit score validation failed", { details });
|
|
96900
97199
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96901
97200
|
}
|
|
96902
97201
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96903
97202
|
}
|
|
96904
|
-
|
|
97203
|
+
logger54.debug("Submitting score", {
|
|
96905
97204
|
userId: ctx.user.id,
|
|
96906
97205
|
gameId,
|
|
96907
97206
|
score: body2.score
|
|
@@ -96924,12 +97223,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96924
97223
|
} catch (error2) {
|
|
96925
97224
|
if (error2 instanceof exports_external.ZodError) {
|
|
96926
97225
|
const details = formatZodError(error2);
|
|
96927
|
-
|
|
97226
|
+
logger54.warn("Get global leaderboard query validation failed", { details });
|
|
96928
97227
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
96929
97228
|
}
|
|
96930
97229
|
throw ApiError.badRequest("Invalid query parameters");
|
|
96931
97230
|
}
|
|
96932
|
-
|
|
97231
|
+
logger54.debug("Getting global leaderboard", {
|
|
96933
97232
|
userId: ctx.user.id,
|
|
96934
97233
|
gameId,
|
|
96935
97234
|
...query
|
|
@@ -96952,12 +97251,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96952
97251
|
} catch (error2) {
|
|
96953
97252
|
if (error2 instanceof exports_external.ZodError) {
|
|
96954
97253
|
const details = formatZodError(error2);
|
|
96955
|
-
|
|
97254
|
+
logger54.warn("Get leaderboard query validation failed", { details });
|
|
96956
97255
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
96957
97256
|
}
|
|
96958
97257
|
throw ApiError.badRequest("Invalid query parameters");
|
|
96959
97258
|
}
|
|
96960
|
-
|
|
97259
|
+
logger54.debug("Getting leaderboard", {
|
|
96961
97260
|
userId: ctx.user.id,
|
|
96962
97261
|
gameId,
|
|
96963
97262
|
...query
|
|
@@ -96969,7 +97268,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96969
97268
|
if (!gameId || !userId) {
|
|
96970
97269
|
throw ApiError.badRequest("Game ID and User ID are required");
|
|
96971
97270
|
}
|
|
96972
|
-
|
|
97271
|
+
logger54.debug("Getting user rank", {
|
|
96973
97272
|
requesterId: ctx.user.id,
|
|
96974
97273
|
gameId,
|
|
96975
97274
|
targetUserId: userId
|
|
@@ -96984,7 +97283,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96984
97283
|
const url2 = ctx.url;
|
|
96985
97284
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "50"), 100);
|
|
96986
97285
|
const gameId = url2.searchParams.get("gameId") || undefined;
|
|
96987
|
-
|
|
97286
|
+
logger54.debug("Getting user all scores", {
|
|
96988
97287
|
requesterId: ctx.user.id,
|
|
96989
97288
|
targetUserId: userId,
|
|
96990
97289
|
gameId,
|
|
@@ -96999,7 +97298,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96999
97298
|
}
|
|
97000
97299
|
const url2 = ctx.url;
|
|
97001
97300
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "10"), 100);
|
|
97002
|
-
|
|
97301
|
+
logger54.debug("Getting user scores", {
|
|
97003
97302
|
requesterId: ctx.user.id,
|
|
97004
97303
|
gameId,
|
|
97005
97304
|
targetUserId: userId,
|
|
@@ -97019,7 +97318,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
97019
97318
|
|
|
97020
97319
|
// ../api-core/src/controllers/level.controller.ts
|
|
97021
97320
|
async function listConfigs(ctx) {
|
|
97022
|
-
|
|
97321
|
+
logger55.debug("Listing level configs");
|
|
97023
97322
|
return ctx.services.level.listConfigs();
|
|
97024
97323
|
}
|
|
97025
97324
|
async function getConfig(ctx) {
|
|
@@ -97031,21 +97330,21 @@ async function getConfig(ctx) {
|
|
|
97031
97330
|
if (isNaN(level) || level < 1) {
|
|
97032
97331
|
throw ApiError.badRequest("Level must be a positive integer");
|
|
97033
97332
|
}
|
|
97034
|
-
|
|
97333
|
+
logger55.debug("Getting level config", { level });
|
|
97035
97334
|
return ctx.services.level.getConfig(level);
|
|
97036
97335
|
}
|
|
97037
|
-
var
|
|
97336
|
+
var logger55, getByUser, getProgress, levels;
|
|
97038
97337
|
var init_level_controller = __esm(() => {
|
|
97039
97338
|
init_src2();
|
|
97040
97339
|
init_errors();
|
|
97041
97340
|
init_utils11();
|
|
97042
|
-
|
|
97341
|
+
logger55 = log.scope("LevelController");
|
|
97043
97342
|
getByUser = requireNonAnonymous(async (ctx) => {
|
|
97044
|
-
|
|
97343
|
+
logger55.debug("Getting user level", { userId: ctx.user.id });
|
|
97045
97344
|
return ctx.services.level.getByUser(ctx.user);
|
|
97046
97345
|
});
|
|
97047
97346
|
getProgress = requireNonAnonymous(async (ctx) => {
|
|
97048
|
-
|
|
97347
|
+
logger55.debug("Getting level progress", { userId: ctx.user.id });
|
|
97049
97348
|
return ctx.services.level.getProgress(ctx.user);
|
|
97050
97349
|
});
|
|
97051
97350
|
levels = {
|
|
@@ -97057,12 +97356,12 @@ var init_level_controller = __esm(() => {
|
|
|
97057
97356
|
});
|
|
97058
97357
|
|
|
97059
97358
|
// ../api-core/src/controllers/logs.controller.ts
|
|
97060
|
-
var
|
|
97359
|
+
var logger56, generateToken, logs;
|
|
97061
97360
|
var init_logs_controller = __esm(() => {
|
|
97062
97361
|
init_src2();
|
|
97063
97362
|
init_errors();
|
|
97064
97363
|
init_utils11();
|
|
97065
|
-
|
|
97364
|
+
logger56 = log.scope("LogsController");
|
|
97066
97365
|
generateToken = requireDeveloper(async (ctx) => {
|
|
97067
97366
|
const slug2 = ctx.params.slug;
|
|
97068
97367
|
if (!slug2) {
|
|
@@ -97081,7 +97380,7 @@ var init_logs_controller = __esm(() => {
|
|
|
97081
97380
|
}
|
|
97082
97381
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97083
97382
|
}
|
|
97084
|
-
|
|
97383
|
+
logger56.debug("Generating log stream token", {
|
|
97085
97384
|
userId: ctx.user.id,
|
|
97086
97385
|
slug: slug2,
|
|
97087
97386
|
environment: body2.environment
|
|
@@ -97100,13 +97399,13 @@ var init_logs_controller = __esm(() => {
|
|
|
97100
97399
|
});
|
|
97101
97400
|
|
|
97102
97401
|
// ../api-core/src/controllers/lti.controller.ts
|
|
97103
|
-
var
|
|
97402
|
+
var logger57, getStatus3, lti;
|
|
97104
97403
|
var init_lti_controller = __esm(() => {
|
|
97105
97404
|
init_src2();
|
|
97106
97405
|
init_utils11();
|
|
97107
|
-
|
|
97406
|
+
logger57 = log.scope("LtiController");
|
|
97108
97407
|
getStatus3 = requireNonAnonymous(async (ctx) => {
|
|
97109
|
-
|
|
97408
|
+
logger57.debug("Getting status", { userId: ctx.user.id });
|
|
97110
97409
|
return ctx.services.lti.getStatus(ctx.user);
|
|
97111
97410
|
});
|
|
97112
97411
|
lti = {
|
|
@@ -97115,7 +97414,7 @@ var init_lti_controller = __esm(() => {
|
|
|
97115
97414
|
});
|
|
97116
97415
|
|
|
97117
97416
|
// ../api-core/src/controllers/map.controller.ts
|
|
97118
|
-
var
|
|
97417
|
+
var logger58, getByIdentifier, getElements, getObjects, createObject, deleteObject, maps2;
|
|
97119
97418
|
var init_map_controller = __esm(() => {
|
|
97120
97419
|
init_esm();
|
|
97121
97420
|
init_schemas_index();
|
|
@@ -97123,13 +97422,13 @@ var init_map_controller = __esm(() => {
|
|
|
97123
97422
|
init_src4();
|
|
97124
97423
|
init_errors();
|
|
97125
97424
|
init_utils11();
|
|
97126
|
-
|
|
97425
|
+
logger58 = log.scope("MapController");
|
|
97127
97426
|
getByIdentifier = requireNonAnonymous(async (ctx) => {
|
|
97128
97427
|
const identifier = ctx.params.identifier;
|
|
97129
97428
|
if (!identifier) {
|
|
97130
97429
|
throw ApiError.badRequest("Missing map identifier");
|
|
97131
97430
|
}
|
|
97132
|
-
|
|
97431
|
+
logger58.debug("Getting map", { userId: ctx.user.id, identifier });
|
|
97133
97432
|
return ctx.services.map.getByIdentifier(identifier);
|
|
97134
97433
|
});
|
|
97135
97434
|
getElements = requireNonAnonymous(async (ctx) => {
|
|
@@ -97140,7 +97439,7 @@ var init_map_controller = __esm(() => {
|
|
|
97140
97439
|
if (!isValidUUID(mapId)) {
|
|
97141
97440
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
97142
97441
|
}
|
|
97143
|
-
|
|
97442
|
+
logger58.debug("Getting map elements", { userId: ctx.user.id, mapId });
|
|
97144
97443
|
return ctx.services.map.getElements(mapId);
|
|
97145
97444
|
});
|
|
97146
97445
|
getObjects = requireNonAnonymous(async (ctx) => {
|
|
@@ -97151,7 +97450,7 @@ var init_map_controller = __esm(() => {
|
|
|
97151
97450
|
if (!isValidUUID(mapId)) {
|
|
97152
97451
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
97153
97452
|
}
|
|
97154
|
-
|
|
97453
|
+
logger58.debug("Getting map objects", { userId: ctx.user.id, mapId });
|
|
97155
97454
|
return ctx.services.map.getObjects(mapId, ctx.user.id);
|
|
97156
97455
|
});
|
|
97157
97456
|
createObject = requireNonAnonymous(async (ctx) => {
|
|
@@ -97173,12 +97472,12 @@ var init_map_controller = __esm(() => {
|
|
|
97173
97472
|
} catch (error2) {
|
|
97174
97473
|
if (error2 instanceof exports_external.ZodError) {
|
|
97175
97474
|
const details = formatZodError(error2);
|
|
97176
|
-
|
|
97475
|
+
logger58.warn("Create map object validation failed", { details });
|
|
97177
97476
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97178
97477
|
}
|
|
97179
97478
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97180
97479
|
}
|
|
97181
|
-
|
|
97480
|
+
logger58.debug("Creating map object", {
|
|
97182
97481
|
userId: ctx.user.id,
|
|
97183
97482
|
mapId,
|
|
97184
97483
|
itemId: body2.itemId,
|
|
@@ -97202,7 +97501,7 @@ var init_map_controller = __esm(() => {
|
|
|
97202
97501
|
if (!isValidUUID(objectId)) {
|
|
97203
97502
|
throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
|
|
97204
97503
|
}
|
|
97205
|
-
|
|
97504
|
+
logger58.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
|
|
97206
97505
|
await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
|
|
97207
97506
|
});
|
|
97208
97507
|
maps2 = {
|
|
@@ -97215,14 +97514,14 @@ var init_map_controller = __esm(() => {
|
|
|
97215
97514
|
});
|
|
97216
97515
|
|
|
97217
97516
|
// ../api-core/src/controllers/notification.controller.ts
|
|
97218
|
-
var
|
|
97517
|
+
var logger59, list6, updateStatus, getStats2, create4, deliver, notifications2;
|
|
97219
97518
|
var init_notification_controller = __esm(() => {
|
|
97220
97519
|
init_esm();
|
|
97221
97520
|
init_schemas_index();
|
|
97222
97521
|
init_src2();
|
|
97223
97522
|
init_errors();
|
|
97224
97523
|
init_utils11();
|
|
97225
|
-
|
|
97524
|
+
logger59 = log.scope("NotificationController");
|
|
97226
97525
|
list6 = requireNonAnonymous(async (ctx) => {
|
|
97227
97526
|
const query = {
|
|
97228
97527
|
status: ctx.url.searchParams.get("status") || undefined,
|
|
@@ -97233,10 +97532,10 @@ var init_notification_controller = __esm(() => {
|
|
|
97233
97532
|
const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
|
|
97234
97533
|
if (!result.success) {
|
|
97235
97534
|
const details = formatZodError(result.error);
|
|
97236
|
-
|
|
97535
|
+
logger59.warn("List notifications query validation failed", { details });
|
|
97237
97536
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
97238
97537
|
}
|
|
97239
|
-
|
|
97538
|
+
logger59.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
|
|
97240
97539
|
return ctx.services.notification.list(ctx.user, result.data);
|
|
97241
97540
|
});
|
|
97242
97541
|
updateStatus = requireNonAnonymous(async (ctx) => {
|
|
@@ -97251,12 +97550,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97251
97550
|
} catch (error2) {
|
|
97252
97551
|
if (error2 instanceof exports_external.ZodError) {
|
|
97253
97552
|
const details = formatZodError(error2);
|
|
97254
|
-
|
|
97553
|
+
logger59.warn("Update notification status validation failed", { details });
|
|
97255
97554
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
97256
97555
|
}
|
|
97257
97556
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97258
97557
|
}
|
|
97259
|
-
|
|
97558
|
+
logger59.debug("Updating status", {
|
|
97260
97559
|
userId: ctx.user.id,
|
|
97261
97560
|
notificationId,
|
|
97262
97561
|
status: body2.status
|
|
@@ -97266,7 +97565,7 @@ var init_notification_controller = __esm(() => {
|
|
|
97266
97565
|
getStats2 = requireNonAnonymous(async (ctx) => {
|
|
97267
97566
|
const startDate = ctx.url.searchParams.get("startDate");
|
|
97268
97567
|
const endDate = ctx.url.searchParams.get("endDate");
|
|
97269
|
-
|
|
97568
|
+
logger59.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
|
|
97270
97569
|
return ctx.services.notification.getStats(ctx.user, {
|
|
97271
97570
|
startDate: startDate ? new Date(startDate) : undefined,
|
|
97272
97571
|
endDate: endDate ? new Date(endDate) : undefined
|
|
@@ -97280,12 +97579,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97280
97579
|
} catch (error2) {
|
|
97281
97580
|
if (error2 instanceof exports_external.ZodError) {
|
|
97282
97581
|
const details = formatZodError(error2);
|
|
97283
|
-
|
|
97582
|
+
logger59.warn("Create notification validation failed", { details });
|
|
97284
97583
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
97285
97584
|
}
|
|
97286
97585
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97287
97586
|
}
|
|
97288
|
-
|
|
97587
|
+
logger59.debug("Creating notification", {
|
|
97289
97588
|
userId: ctx.user.id,
|
|
97290
97589
|
targetUserId: body2.userId,
|
|
97291
97590
|
type: body2.type
|
|
@@ -97303,12 +97602,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97303
97602
|
});
|
|
97304
97603
|
});
|
|
97305
97604
|
deliver = requireNonAnonymous(async (ctx) => {
|
|
97306
|
-
|
|
97605
|
+
logger59.debug("Delivering notifications", { userId: ctx.user.id });
|
|
97307
97606
|
try {
|
|
97308
97607
|
await ctx.services.notification.deliverPending(ctx.user.id);
|
|
97309
97608
|
return { success: true };
|
|
97310
97609
|
} catch (error2) {
|
|
97311
|
-
|
|
97610
|
+
logger59.error("Failed to deliver notifications", { error: error2 });
|
|
97312
97611
|
throw ApiError.internal("Failed to deliver notifications");
|
|
97313
97612
|
}
|
|
97314
97613
|
});
|
|
@@ -97322,14 +97621,14 @@ var init_notification_controller = __esm(() => {
|
|
|
97322
97621
|
});
|
|
97323
97622
|
|
|
97324
97623
|
// ../api-core/src/controllers/realtime.controller.ts
|
|
97325
|
-
var
|
|
97624
|
+
var logger60, generateToken2, realtime;
|
|
97326
97625
|
var init_realtime_controller = __esm(() => {
|
|
97327
97626
|
init_src2();
|
|
97328
97627
|
init_utils11();
|
|
97329
|
-
|
|
97628
|
+
logger60 = log.scope("RealtimeController");
|
|
97330
97629
|
generateToken2 = requireNonAnonymous(async (ctx) => {
|
|
97331
97630
|
const gameIdOrSlug = ctx.params.gameId;
|
|
97332
|
-
|
|
97631
|
+
logger60.debug("Generating token", {
|
|
97333
97632
|
userId: ctx.user.id,
|
|
97334
97633
|
gameId: gameIdOrSlug || "global",
|
|
97335
97634
|
launchId: ctx.launchId
|
|
@@ -97342,20 +97641,20 @@ var init_realtime_controller = __esm(() => {
|
|
|
97342
97641
|
});
|
|
97343
97642
|
|
|
97344
97643
|
// ../api-core/src/controllers/secrets.controller.ts
|
|
97345
|
-
var
|
|
97644
|
+
var logger61, listKeys2, setSecrets, deleteSecret, secrets;
|
|
97346
97645
|
var init_secrets_controller = __esm(() => {
|
|
97347
97646
|
init_esm();
|
|
97348
97647
|
init_schemas_index();
|
|
97349
97648
|
init_src2();
|
|
97350
97649
|
init_errors();
|
|
97351
97650
|
init_utils11();
|
|
97352
|
-
|
|
97651
|
+
logger61 = log.scope("SecretsController");
|
|
97353
97652
|
listKeys2 = requireDeveloper(async (ctx) => {
|
|
97354
97653
|
const slug2 = ctx.params.slug;
|
|
97355
97654
|
if (!slug2) {
|
|
97356
97655
|
throw ApiError.badRequest("Missing game slug");
|
|
97357
97656
|
}
|
|
97358
|
-
|
|
97657
|
+
logger61.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
|
|
97359
97658
|
const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
|
|
97360
97659
|
return { keys };
|
|
97361
97660
|
});
|
|
@@ -97371,12 +97670,12 @@ var init_secrets_controller = __esm(() => {
|
|
|
97371
97670
|
} catch (error2) {
|
|
97372
97671
|
if (error2 instanceof exports_external.ZodError) {
|
|
97373
97672
|
const details = formatZodError(error2);
|
|
97374
|
-
|
|
97673
|
+
logger61.warn("Set secrets validation failed", { details });
|
|
97375
97674
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97376
97675
|
}
|
|
97377
97676
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97378
97677
|
}
|
|
97379
|
-
|
|
97678
|
+
logger61.debug("Setting secrets", {
|
|
97380
97679
|
userId: ctx.user.id,
|
|
97381
97680
|
slug: slug2,
|
|
97382
97681
|
keyCount: Object.keys(body2).length
|
|
@@ -97393,7 +97692,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
97393
97692
|
if (!key) {
|
|
97394
97693
|
throw ApiError.badRequest("Missing secret key");
|
|
97395
97694
|
}
|
|
97396
|
-
|
|
97695
|
+
logger61.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
|
|
97397
97696
|
await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
|
|
97398
97697
|
return { success: true };
|
|
97399
97698
|
});
|
|
@@ -97405,14 +97704,14 @@ var init_secrets_controller = __esm(() => {
|
|
|
97405
97704
|
});
|
|
97406
97705
|
|
|
97407
97706
|
// ../api-core/src/controllers/seed.controller.ts
|
|
97408
|
-
var
|
|
97707
|
+
var logger62, seed2;
|
|
97409
97708
|
var init_seed_controller = __esm(() => {
|
|
97410
97709
|
init_esm();
|
|
97411
97710
|
init_schemas_index();
|
|
97412
97711
|
init_src2();
|
|
97413
97712
|
init_errors();
|
|
97414
97713
|
init_utils11();
|
|
97415
|
-
|
|
97714
|
+
logger62 = log.scope("SeedController");
|
|
97416
97715
|
seed2 = requireDeveloper(async (ctx) => {
|
|
97417
97716
|
const slug2 = ctx.params.slug;
|
|
97418
97717
|
if (!slug2) {
|
|
@@ -97425,12 +97724,12 @@ var init_seed_controller = __esm(() => {
|
|
|
97425
97724
|
} catch (error2) {
|
|
97426
97725
|
if (error2 instanceof exports_external.ZodError) {
|
|
97427
97726
|
const details = formatZodError(error2);
|
|
97428
|
-
|
|
97727
|
+
logger62.warn("Seed database validation failed", { details });
|
|
97429
97728
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97430
97729
|
}
|
|
97431
97730
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97432
97731
|
}
|
|
97433
|
-
|
|
97732
|
+
logger62.debug("Seeding database", {
|
|
97434
97733
|
userId: ctx.user.id,
|
|
97435
97734
|
slug: slug2,
|
|
97436
97735
|
codeLength: body2.code.length,
|
|
@@ -97441,19 +97740,19 @@ var init_seed_controller = __esm(() => {
|
|
|
97441
97740
|
});
|
|
97442
97741
|
|
|
97443
97742
|
// ../api-core/src/controllers/session.controller.ts
|
|
97444
|
-
var
|
|
97743
|
+
var logger63, start2, end, mintToken, sessions2;
|
|
97445
97744
|
var init_session_controller = __esm(() => {
|
|
97446
97745
|
init_src2();
|
|
97447
97746
|
init_tunnel();
|
|
97448
97747
|
init_errors();
|
|
97449
97748
|
init_utils11();
|
|
97450
|
-
|
|
97749
|
+
logger63 = log.scope("SessionController");
|
|
97451
97750
|
start2 = requireAuth(async (ctx) => {
|
|
97452
97751
|
const gameIdOrSlug = ctx.params.gameId;
|
|
97453
97752
|
if (!gameIdOrSlug) {
|
|
97454
97753
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
97455
97754
|
}
|
|
97456
|
-
|
|
97755
|
+
logger63.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
97457
97756
|
return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
|
|
97458
97757
|
});
|
|
97459
97758
|
end = requireAuth(async (ctx) => {
|
|
@@ -97465,7 +97764,7 @@ var init_session_controller = __esm(() => {
|
|
|
97465
97764
|
if (!sessionId) {
|
|
97466
97765
|
throw ApiError.badRequest("Missing session ID");
|
|
97467
97766
|
}
|
|
97468
|
-
|
|
97767
|
+
logger63.debug("Ending session", {
|
|
97469
97768
|
userId: ctx.user.id,
|
|
97470
97769
|
gameIdOrSlug,
|
|
97471
97770
|
sessionId,
|
|
@@ -97478,7 +97777,7 @@ var init_session_controller = __esm(() => {
|
|
|
97478
97777
|
if (!gameIdOrSlug) {
|
|
97479
97778
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
97480
97779
|
}
|
|
97481
|
-
|
|
97780
|
+
logger63.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
97482
97781
|
const { token, exp } = await ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
|
|
97483
97782
|
let baseUrl;
|
|
97484
97783
|
if (ctx.config.isLocal) {
|
|
@@ -97496,13 +97795,13 @@ var init_session_controller = __esm(() => {
|
|
|
97496
97795
|
});
|
|
97497
97796
|
|
|
97498
97797
|
// ../api-core/src/controllers/shop.controller.ts
|
|
97499
|
-
var
|
|
97798
|
+
var logger64, getShopView, shop;
|
|
97500
97799
|
var init_shop_controller = __esm(() => {
|
|
97501
97800
|
init_src2();
|
|
97502
97801
|
init_utils11();
|
|
97503
|
-
|
|
97802
|
+
logger64 = log.scope("ShopController");
|
|
97504
97803
|
getShopView = requireNonAnonymous(async (ctx) => {
|
|
97505
|
-
|
|
97804
|
+
logger64.debug("Getting shop view", { userId: ctx.user.id });
|
|
97506
97805
|
return ctx.services.shop.getShopView(ctx.user);
|
|
97507
97806
|
});
|
|
97508
97807
|
shop = {
|
|
@@ -97511,7 +97810,7 @@ var init_shop_controller = __esm(() => {
|
|
|
97511
97810
|
});
|
|
97512
97811
|
|
|
97513
97812
|
// ../api-core/src/controllers/shop-listing.controller.ts
|
|
97514
|
-
var
|
|
97813
|
+
var logger65, list7, getById4, create5, update5, remove5, listByGame2, getByGameItem, createForGameItem, updateForGameItem, deleteForGameItem, shopListings2;
|
|
97515
97814
|
var init_shop_listing_controller = __esm(() => {
|
|
97516
97815
|
init_esm();
|
|
97517
97816
|
init_schemas_index();
|
|
@@ -97519,9 +97818,9 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97519
97818
|
init_src4();
|
|
97520
97819
|
init_errors();
|
|
97521
97820
|
init_utils11();
|
|
97522
|
-
|
|
97821
|
+
logger65 = log.scope("ShopListingController");
|
|
97523
97822
|
list7 = requireAdmin(async (ctx) => {
|
|
97524
|
-
|
|
97823
|
+
logger65.debug("Listing shop listings", { userId: ctx.user.id });
|
|
97525
97824
|
return ctx.services.shopListing.list();
|
|
97526
97825
|
});
|
|
97527
97826
|
getById4 = requireAdmin(async (ctx) => {
|
|
@@ -97532,7 +97831,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97532
97831
|
if (!isValidUUID(listingId)) {
|
|
97533
97832
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
97534
97833
|
}
|
|
97535
|
-
|
|
97834
|
+
logger65.debug("Getting listing", { userId: ctx.user.id, listingId });
|
|
97536
97835
|
return ctx.services.shopListing.getById(listingId);
|
|
97537
97836
|
});
|
|
97538
97837
|
create5 = requireAdmin(async (ctx) => {
|
|
@@ -97543,12 +97842,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97543
97842
|
} catch (error2) {
|
|
97544
97843
|
if (error2 instanceof exports_external.ZodError) {
|
|
97545
97844
|
const details = formatZodError(error2);
|
|
97546
|
-
|
|
97845
|
+
logger65.warn("Create shop listing validation failed", { details });
|
|
97547
97846
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97548
97847
|
}
|
|
97549
97848
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97550
97849
|
}
|
|
97551
|
-
|
|
97850
|
+
logger65.debug("Creating listing", {
|
|
97552
97851
|
userId: ctx.user.id,
|
|
97553
97852
|
itemId: body2.itemId,
|
|
97554
97853
|
currencyId: body2.currencyId,
|
|
@@ -97571,12 +97870,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97571
97870
|
} catch (error2) {
|
|
97572
97871
|
if (error2 instanceof exports_external.ZodError) {
|
|
97573
97872
|
const details = formatZodError(error2);
|
|
97574
|
-
|
|
97873
|
+
logger65.warn("Update shop listing validation failed", { details });
|
|
97575
97874
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97576
97875
|
}
|
|
97577
97876
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97578
97877
|
}
|
|
97579
|
-
|
|
97878
|
+
logger65.debug("Updating listing", {
|
|
97580
97879
|
userId: ctx.user.id,
|
|
97581
97880
|
listingId,
|
|
97582
97881
|
price: body2.price,
|
|
@@ -97593,7 +97892,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97593
97892
|
if (!isValidUUID(listingId)) {
|
|
97594
97893
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
97595
97894
|
}
|
|
97596
|
-
|
|
97895
|
+
logger65.debug("Deleting listing", { userId: ctx.user.id, listingId });
|
|
97597
97896
|
await ctx.services.shopListing.delete(listingId);
|
|
97598
97897
|
});
|
|
97599
97898
|
listByGame2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -97604,7 +97903,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97604
97903
|
if (!isValidUUID(gameId)) {
|
|
97605
97904
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
97606
97905
|
}
|
|
97607
|
-
|
|
97906
|
+
logger65.debug("Listing game listings", { userId: ctx.user.id, gameId });
|
|
97608
97907
|
return ctx.services.shopListing.listByGame(gameId, ctx.user);
|
|
97609
97908
|
});
|
|
97610
97909
|
getByGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -97619,7 +97918,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97619
97918
|
if (!isValidUUID(itemId)) {
|
|
97620
97919
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
97621
97920
|
}
|
|
97622
|
-
|
|
97921
|
+
logger65.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
|
|
97623
97922
|
return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
|
|
97624
97923
|
});
|
|
97625
97924
|
createForGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -97641,12 +97940,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97641
97940
|
} catch (error2) {
|
|
97642
97941
|
if (error2 instanceof exports_external.ZodError) {
|
|
97643
97942
|
const details = formatZodError(error2);
|
|
97644
|
-
|
|
97943
|
+
logger65.warn("Create game item listing validation failed", { details });
|
|
97645
97944
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97646
97945
|
}
|
|
97647
97946
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97648
97947
|
}
|
|
97649
|
-
|
|
97948
|
+
logger65.debug("Creating game item listing", {
|
|
97650
97949
|
userId: ctx.user.id,
|
|
97651
97950
|
gameId,
|
|
97652
97951
|
itemId,
|
|
@@ -97674,12 +97973,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97674
97973
|
} catch (error2) {
|
|
97675
97974
|
if (error2 instanceof exports_external.ZodError) {
|
|
97676
97975
|
const details = formatZodError(error2);
|
|
97677
|
-
|
|
97976
|
+
logger65.warn("Update game item listing validation failed", { details });
|
|
97678
97977
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97679
97978
|
}
|
|
97680
97979
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97681
97980
|
}
|
|
97682
|
-
|
|
97981
|
+
logger65.debug("Updating game item listing", {
|
|
97683
97982
|
userId: ctx.user.id,
|
|
97684
97983
|
gameId,
|
|
97685
97984
|
itemId,
|
|
@@ -97701,7 +98000,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97701
98000
|
if (!isValidUUID(itemId)) {
|
|
97702
98001
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
97703
98002
|
}
|
|
97704
|
-
|
|
98003
|
+
logger65.debug("Deleting game item listing", {
|
|
97705
98004
|
userId: ctx.user.id,
|
|
97706
98005
|
gameId,
|
|
97707
98006
|
itemId
|
|
@@ -97728,21 +98027,21 @@ async function getBySlug2(ctx) {
|
|
|
97728
98027
|
if (!slug2) {
|
|
97729
98028
|
throw ApiError.badRequest("Template slug is required");
|
|
97730
98029
|
}
|
|
97731
|
-
|
|
98030
|
+
logger66.debug("Getting sprite by slug", { slug: slug2 });
|
|
97732
98031
|
return ctx.services.sprite.getBySlug(slug2);
|
|
97733
98032
|
}
|
|
97734
|
-
var
|
|
98033
|
+
var logger66, sprites;
|
|
97735
98034
|
var init_sprite_controller = __esm(() => {
|
|
97736
98035
|
init_src2();
|
|
97737
98036
|
init_errors();
|
|
97738
|
-
|
|
98037
|
+
logger66 = log.scope("SpriteController");
|
|
97739
98038
|
sprites = {
|
|
97740
98039
|
getBySlug: getBySlug2
|
|
97741
98040
|
};
|
|
97742
98041
|
});
|
|
97743
98042
|
|
|
97744
98043
|
// ../api-core/src/controllers/timeback.controller.ts
|
|
97745
|
-
var
|
|
98044
|
+
var logger67, getTodayXp, getTotalXp, updateTodayXp, getXpHistory, populateStudent, getUser, getUserById, setupIntegration, getIntegrations, updateIntegration, getIntegrationConfig, verifyIntegration, getConfig2, deleteIntegrations, endActivity, heartbeat, advanceCourse, getStudentXp, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getActivityDetail, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, deleteAssessment, reorderAssessments, reorderQuestions, activateAssessment, deactivateAssessment, listQuestions, createQuestion, updateQuestion, deleteQuestion, getAssessmentBankStatus, destroyAssessmentBank, timeback2;
|
|
97746
98045
|
var init_timeback_controller = __esm(() => {
|
|
97747
98046
|
init_esm();
|
|
97748
98047
|
init_schemas_index();
|
|
@@ -97750,15 +98049,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
97750
98049
|
init_src4();
|
|
97751
98050
|
init_errors();
|
|
97752
98051
|
init_utils11();
|
|
97753
|
-
|
|
98052
|
+
logger67 = log.scope("TimebackController");
|
|
97754
98053
|
getTodayXp = requireNonAnonymous(async (ctx) => {
|
|
97755
98054
|
const date4 = ctx.url.searchParams.get("date") || undefined;
|
|
97756
98055
|
const tz = ctx.url.searchParams.get("tz") || undefined;
|
|
97757
|
-
|
|
98056
|
+
logger67.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
|
|
97758
98057
|
return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
|
|
97759
98058
|
});
|
|
97760
98059
|
getTotalXp = requireNonAnonymous(async (ctx) => {
|
|
97761
|
-
|
|
98060
|
+
logger67.debug("Getting total XP", { userId: ctx.user.id });
|
|
97762
98061
|
return ctx.services.timeback.getTotalXp(ctx.user.id);
|
|
97763
98062
|
});
|
|
97764
98063
|
updateTodayXp = requireNonAnonymous(async (ctx) => {
|
|
@@ -97769,18 +98068,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
97769
98068
|
} catch (error2) {
|
|
97770
98069
|
if (error2 instanceof exports_external.ZodError) {
|
|
97771
98070
|
const details = formatZodError(error2);
|
|
97772
|
-
|
|
98071
|
+
logger67.warn("Update today XP validation failed", { details });
|
|
97773
98072
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97774
98073
|
}
|
|
97775
98074
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97776
98075
|
}
|
|
97777
|
-
|
|
98076
|
+
logger67.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
|
|
97778
98077
|
return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
|
|
97779
98078
|
});
|
|
97780
98079
|
getXpHistory = requireNonAnonymous(async (ctx) => {
|
|
97781
98080
|
const startDate = ctx.url.searchParams.get("startDate") || undefined;
|
|
97782
98081
|
const endDate = ctx.url.searchParams.get("endDate") || undefined;
|
|
97783
|
-
|
|
98082
|
+
logger67.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
|
|
97784
98083
|
return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
|
|
97785
98084
|
});
|
|
97786
98085
|
populateStudent = requireNonAnonymous(async (ctx) => {
|
|
@@ -97791,18 +98090,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
97791
98090
|
} catch (error2) {
|
|
97792
98091
|
if (error2 instanceof exports_external.ZodError) {
|
|
97793
98092
|
const details = formatZodError(error2);
|
|
97794
|
-
|
|
98093
|
+
logger67.warn("Populate student validation failed", { details });
|
|
97795
98094
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97796
98095
|
}
|
|
97797
98096
|
}
|
|
97798
|
-
|
|
98097
|
+
logger67.debug("Populating student", {
|
|
97799
98098
|
userId: ctx.user.id,
|
|
97800
98099
|
hasProvidedNames: Boolean(providedNames)
|
|
97801
98100
|
});
|
|
97802
98101
|
return ctx.services.timeback.populateStudent(ctx.user, providedNames);
|
|
97803
98102
|
});
|
|
97804
98103
|
getUser = requireNonAnonymous(async (ctx) => {
|
|
97805
|
-
|
|
98104
|
+
logger67.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
97806
98105
|
return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
|
|
97807
98106
|
});
|
|
97808
98107
|
getUserById = requireNonAnonymous(async (ctx) => {
|
|
@@ -97810,7 +98109,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97810
98109
|
if (!timebackId) {
|
|
97811
98110
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
97812
98111
|
}
|
|
97813
|
-
|
|
98112
|
+
logger67.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
|
|
97814
98113
|
return ctx.services.timeback.getUserDataByTimebackId(timebackId);
|
|
97815
98114
|
});
|
|
97816
98115
|
setupIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -97821,12 +98120,12 @@ var init_timeback_controller = __esm(() => {
|
|
|
97821
98120
|
} catch (error2) {
|
|
97822
98121
|
if (error2 instanceof exports_external.ZodError) {
|
|
97823
98122
|
const details = formatZodError(error2);
|
|
97824
|
-
|
|
98123
|
+
logger67.warn("Setup integration validation failed", { details });
|
|
97825
98124
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97826
98125
|
}
|
|
97827
98126
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97828
98127
|
}
|
|
97829
|
-
|
|
98128
|
+
logger67.debug("Setting up integration", {
|
|
97830
98129
|
userId: ctx.user.id,
|
|
97831
98130
|
gameId: body2.gameId
|
|
97832
98131
|
});
|
|
@@ -97840,9 +98139,37 @@ var init_timeback_controller = __esm(() => {
|
|
|
97840
98139
|
if (!isValidUUID(gameId)) {
|
|
97841
98140
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97842
98141
|
}
|
|
97843
|
-
|
|
98142
|
+
logger67.debug("Getting integrations", { userId: ctx.user.id, gameId });
|
|
97844
98143
|
return ctx.services.timeback.getIntegrations(gameId, ctx.user);
|
|
97845
98144
|
});
|
|
98145
|
+
updateIntegration = requireDeveloper(async (ctx) => {
|
|
98146
|
+
const { gameId, courseId } = ctx.params;
|
|
98147
|
+
if (!gameId || !courseId) {
|
|
98148
|
+
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98149
|
+
}
|
|
98150
|
+
if (!isValidUUID(gameId)) {
|
|
98151
|
+
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
98152
|
+
}
|
|
98153
|
+
const body2 = await parseRequestBody(ctx.request, UpdateGameTimebackIntegrationRequestSchema);
|
|
98154
|
+
logger67.debug("Updating integration", {
|
|
98155
|
+
userId: ctx.user.id,
|
|
98156
|
+
gameId,
|
|
98157
|
+
courseId,
|
|
98158
|
+
fields: Object.keys(body2)
|
|
98159
|
+
});
|
|
98160
|
+
return ctx.services.timeback.updateIntegration(gameId, courseId, ctx.user, body2);
|
|
98161
|
+
});
|
|
98162
|
+
getIntegrationConfig = requireGameManagementAccess(async (ctx) => {
|
|
98163
|
+
const { gameId, courseId } = ctx.params;
|
|
98164
|
+
if (!gameId || !courseId) {
|
|
98165
|
+
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98166
|
+
}
|
|
98167
|
+
if (!isValidUUID(gameId)) {
|
|
98168
|
+
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
98169
|
+
}
|
|
98170
|
+
logger67.debug("Getting integration config", { userId: ctx.user.id, gameId, courseId });
|
|
98171
|
+
return ctx.services.timeback.getIntegrationConfig(gameId, courseId, ctx.user);
|
|
98172
|
+
});
|
|
97846
98173
|
verifyIntegration = requireDeveloper(async (ctx) => {
|
|
97847
98174
|
const gameId = ctx.params.gameId;
|
|
97848
98175
|
if (!gameId) {
|
|
@@ -97851,7 +98178,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97851
98178
|
if (!isValidUUID(gameId)) {
|
|
97852
98179
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97853
98180
|
}
|
|
97854
|
-
|
|
98181
|
+
logger67.debug("Verifying integration", { userId: ctx.user.id, gameId });
|
|
97855
98182
|
return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
|
|
97856
98183
|
});
|
|
97857
98184
|
getConfig2 = requireDeveloper(async (ctx) => {
|
|
@@ -97862,7 +98189,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97862
98189
|
if (!isValidUUID(gameId)) {
|
|
97863
98190
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97864
98191
|
}
|
|
97865
|
-
|
|
98192
|
+
logger67.debug("Getting config", { userId: ctx.user.id, gameId });
|
|
97866
98193
|
return ctx.services.timeback.getConfig(gameId, ctx.user);
|
|
97867
98194
|
});
|
|
97868
98195
|
deleteIntegrations = requireDeveloper(async (ctx) => {
|
|
@@ -97873,7 +98200,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97873
98200
|
if (!isValidUUID(gameId)) {
|
|
97874
98201
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97875
98202
|
}
|
|
97876
|
-
|
|
98203
|
+
logger67.debug("Deleting integrations", { userId: ctx.user.id, gameId });
|
|
97877
98204
|
await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
|
|
97878
98205
|
});
|
|
97879
98206
|
endActivity = requireDeveloper(async (ctx) => {
|
|
@@ -97884,7 +98211,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97884
98211
|
} catch (error2) {
|
|
97885
98212
|
if (error2 instanceof exports_external.ZodError) {
|
|
97886
98213
|
const details = formatZodError(error2);
|
|
97887
|
-
|
|
98214
|
+
logger67.warn("End activity validation failed", { details });
|
|
97888
98215
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97889
98216
|
}
|
|
97890
98217
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -97902,7 +98229,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97902
98229
|
masteredUnits,
|
|
97903
98230
|
extensions
|
|
97904
98231
|
} = body2;
|
|
97905
|
-
|
|
98232
|
+
logger67.debug("Ending activity", { userId: ctx.user.id, gameId });
|
|
97906
98233
|
return ctx.services.timeback.endActivity({
|
|
97907
98234
|
gameId,
|
|
97908
98235
|
studentId,
|
|
@@ -97926,7 +98253,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97926
98253
|
} catch (error2) {
|
|
97927
98254
|
if (error2 instanceof exports_external.ZodError) {
|
|
97928
98255
|
const details = formatZodError(error2);
|
|
97929
|
-
|
|
98256
|
+
logger67.warn("Heartbeat validation failed", { details });
|
|
97930
98257
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97931
98258
|
}
|
|
97932
98259
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -97942,7 +98269,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97942
98269
|
windowSequence,
|
|
97943
98270
|
isFinal
|
|
97944
98271
|
} = body2;
|
|
97945
|
-
|
|
98272
|
+
logger67.debug("Recording heartbeat", {
|
|
97946
98273
|
userId: ctx.user.id,
|
|
97947
98274
|
gameId,
|
|
97948
98275
|
runId,
|
|
@@ -97967,7 +98294,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97967
98294
|
});
|
|
97968
98295
|
advanceCourse = requireDeveloper(async (ctx) => {
|
|
97969
98296
|
const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
|
|
97970
|
-
|
|
98297
|
+
logger67.debug("Advancing student manually", {
|
|
97971
98298
|
userId: ctx.user.id,
|
|
97972
98299
|
gameId: body2.gameId,
|
|
97973
98300
|
studentId: body2.studentId,
|
|
@@ -98008,7 +98335,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98008
98335
|
perCourse: includeOptions.includes("percourse"),
|
|
98009
98336
|
today: includeOptions.includes("today")
|
|
98010
98337
|
};
|
|
98011
|
-
|
|
98338
|
+
logger67.debug("Getting student XP", {
|
|
98012
98339
|
requesterId: ctx.user.id,
|
|
98013
98340
|
timebackId,
|
|
98014
98341
|
gameId,
|
|
@@ -98030,7 +98357,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98030
98357
|
if (!gameId || !courseId) {
|
|
98031
98358
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98032
98359
|
}
|
|
98033
|
-
|
|
98360
|
+
logger67.debug("Getting course roster", {
|
|
98034
98361
|
requesterId: ctx.user.id,
|
|
98035
98362
|
gameId,
|
|
98036
98363
|
courseId,
|
|
@@ -98047,7 +98374,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98047
98374
|
if (!timebackId || !gameId) {
|
|
98048
98375
|
throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
|
|
98049
98376
|
}
|
|
98050
|
-
|
|
98377
|
+
logger67.debug("Getting student overview", {
|
|
98051
98378
|
requesterId: ctx.user.id,
|
|
98052
98379
|
timebackId,
|
|
98053
98380
|
gameId,
|
|
@@ -98061,7 +98388,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98061
98388
|
if (!gameId || !timebackId) {
|
|
98062
98389
|
throw ApiError.badRequest("Missing gameId or timebackId path parameter");
|
|
98063
98390
|
}
|
|
98064
|
-
|
|
98391
|
+
logger67.debug("Getting game metrics", {
|
|
98065
98392
|
requesterId: ctx.user.id,
|
|
98066
98393
|
gameId,
|
|
98067
98394
|
timebackId
|
|
@@ -98079,7 +98406,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98079
98406
|
if (!timebackId || !courseId || !gameId) {
|
|
98080
98407
|
throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
|
|
98081
98408
|
}
|
|
98082
|
-
|
|
98409
|
+
logger67.debug("Getting student activity", {
|
|
98083
98410
|
requesterId: ctx.user.id,
|
|
98084
98411
|
timebackId,
|
|
98085
98412
|
courseId,
|
|
@@ -98104,7 +98431,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98104
98431
|
if (!timebackId || !courseId || !activityId || !gameId) {
|
|
98105
98432
|
throw ApiError.badRequest("Missing timebackId, courseId, or activityId path parameter, or gameId query parameter");
|
|
98106
98433
|
}
|
|
98107
|
-
|
|
98434
|
+
logger67.debug("Getting activity detail", {
|
|
98108
98435
|
requesterId: ctx.user.id,
|
|
98109
98436
|
timebackId,
|
|
98110
98437
|
courseId,
|
|
@@ -98122,7 +98449,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98122
98449
|
});
|
|
98123
98450
|
grantXp = requireDeveloper(async (ctx) => {
|
|
98124
98451
|
const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
|
|
98125
|
-
|
|
98452
|
+
logger67.debug("Granting manual XP", {
|
|
98126
98453
|
requesterId: ctx.user.id,
|
|
98127
98454
|
gameId: body2.gameId,
|
|
98128
98455
|
courseId: body2.courseId,
|
|
@@ -98134,7 +98461,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98134
98461
|
});
|
|
98135
98462
|
adjustTime = requireDeveloper(async (ctx) => {
|
|
98136
98463
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
|
|
98137
|
-
|
|
98464
|
+
logger67.debug("Adjusting time spent", {
|
|
98138
98465
|
requesterId: ctx.user.id,
|
|
98139
98466
|
gameId: body2.gameId,
|
|
98140
98467
|
courseId: body2.courseId,
|
|
@@ -98146,7 +98473,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98146
98473
|
});
|
|
98147
98474
|
adjustMastery = requireDeveloper(async (ctx) => {
|
|
98148
98475
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
|
|
98149
|
-
|
|
98476
|
+
logger67.debug("Adjusting mastered units", {
|
|
98150
98477
|
requesterId: ctx.user.id,
|
|
98151
98478
|
gameId: body2.gameId,
|
|
98152
98479
|
courseId: body2.courseId,
|
|
@@ -98156,6 +98483,22 @@ var init_timeback_controller = __esm(() => {
|
|
|
98156
98483
|
});
|
|
98157
98484
|
return ctx.services.timebackAdmin.adjustMasteredUnits(body2, ctx.user);
|
|
98158
98485
|
});
|
|
98486
|
+
reconcileMasteryForConfigChange = requireDeveloper(async (ctx) => {
|
|
98487
|
+
const body2 = await parseRequestBody(ctx.request, ReconcileMasteryForConfigChangeSchema);
|
|
98488
|
+
logger67.debug("Reconciling mastery completion for config change", {
|
|
98489
|
+
requesterId: ctx.user.id,
|
|
98490
|
+
gameId: body2.gameId,
|
|
98491
|
+
courseId: body2.courseId,
|
|
98492
|
+
oldMasterableUnits: body2.oldMasterableUnits,
|
|
98493
|
+
newMasterableUnits: body2.newMasterableUnits,
|
|
98494
|
+
affectedCount: body2.affectedStudentIds.length
|
|
98495
|
+
});
|
|
98496
|
+
return ctx.services.timebackAdmin.reconcileMasteryForConfigChange(body2.gameId, body2.courseId, ctx.user, {
|
|
98497
|
+
oldMasterableUnits: body2.oldMasterableUnits,
|
|
98498
|
+
newMasterableUnits: body2.newMasterableUnits,
|
|
98499
|
+
affectedStudentIds: body2.affectedStudentIds
|
|
98500
|
+
});
|
|
98501
|
+
});
|
|
98159
98502
|
searchStudents = requireGameManagementAccess(async (ctx) => {
|
|
98160
98503
|
const gameId = ctx.params.gameId;
|
|
98161
98504
|
const courseId = ctx.params.courseId;
|
|
@@ -98163,7 +98506,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98163
98506
|
if (!gameId || !courseId) {
|
|
98164
98507
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98165
98508
|
}
|
|
98166
|
-
|
|
98509
|
+
logger67.debug("Searching students for enrollment", {
|
|
98167
98510
|
requesterId: ctx.user.id,
|
|
98168
98511
|
gameId,
|
|
98169
98512
|
courseId,
|
|
@@ -98173,7 +98516,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98173
98516
|
});
|
|
98174
98517
|
enrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
98175
98518
|
const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
|
|
98176
|
-
|
|
98519
|
+
logger67.debug("Enrolling student", {
|
|
98177
98520
|
requesterId: ctx.user.id,
|
|
98178
98521
|
gameId: body2.gameId,
|
|
98179
98522
|
courseId: body2.courseId,
|
|
@@ -98183,7 +98526,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98183
98526
|
});
|
|
98184
98527
|
unenrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
98185
98528
|
const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
|
|
98186
|
-
|
|
98529
|
+
logger67.debug("Unenrolling student", {
|
|
98187
98530
|
requesterId: ctx.user.id,
|
|
98188
98531
|
gameId: body2.gameId,
|
|
98189
98532
|
courseId: body2.courseId,
|
|
@@ -98193,7 +98536,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98193
98536
|
});
|
|
98194
98537
|
reactivateEnrollment = requireGameManagementAccess(async (ctx) => {
|
|
98195
98538
|
const body2 = await parseRequestBody(ctx.request, ReactivateEnrollmentRequestSchema);
|
|
98196
|
-
|
|
98539
|
+
logger67.debug("Reactivating enrollment", {
|
|
98197
98540
|
requesterId: ctx.user.id,
|
|
98198
98541
|
gameId: body2.gameId,
|
|
98199
98542
|
courseId: body2.courseId,
|
|
@@ -98333,6 +98676,8 @@ var init_timeback_controller = __esm(() => {
|
|
|
98333
98676
|
getUserById,
|
|
98334
98677
|
setupIntegration,
|
|
98335
98678
|
getIntegrations,
|
|
98679
|
+
updateIntegration,
|
|
98680
|
+
getIntegrationConfig,
|
|
98336
98681
|
verifyIntegration,
|
|
98337
98682
|
getConfig: getConfig2,
|
|
98338
98683
|
deleteIntegrations,
|
|
@@ -98348,6 +98693,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98348
98693
|
grantXp,
|
|
98349
98694
|
adjustTime,
|
|
98350
98695
|
adjustMastery,
|
|
98696
|
+
reconcileMasteryForConfigChange,
|
|
98351
98697
|
searchStudents,
|
|
98352
98698
|
enrollStudent,
|
|
98353
98699
|
unenrollStudent,
|
|
@@ -98369,14 +98715,14 @@ var init_timeback_controller = __esm(() => {
|
|
|
98369
98715
|
});
|
|
98370
98716
|
|
|
98371
98717
|
// ../api-core/src/controllers/upload.controller.ts
|
|
98372
|
-
var
|
|
98718
|
+
var logger68, initiate;
|
|
98373
98719
|
var init_upload_controller = __esm(() => {
|
|
98374
98720
|
init_esm();
|
|
98375
98721
|
init_schemas_index();
|
|
98376
98722
|
init_src2();
|
|
98377
98723
|
init_errors();
|
|
98378
98724
|
init_utils11();
|
|
98379
|
-
|
|
98725
|
+
logger68 = log.scope("UploadController");
|
|
98380
98726
|
initiate = requireDeveloper(async (ctx) => {
|
|
98381
98727
|
let body2;
|
|
98382
98728
|
try {
|
|
@@ -98385,34 +98731,34 @@ var init_upload_controller = __esm(() => {
|
|
|
98385
98731
|
} catch (error2) {
|
|
98386
98732
|
if (error2 instanceof exports_external.ZodError) {
|
|
98387
98733
|
const details = formatZodError(error2);
|
|
98388
|
-
|
|
98734
|
+
logger68.warn("Initiate upload validation failed", { details });
|
|
98389
98735
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
98390
98736
|
}
|
|
98391
98737
|
throw ApiError.badRequest("Invalid JSON body");
|
|
98392
98738
|
}
|
|
98393
|
-
|
|
98739
|
+
logger68.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
|
|
98394
98740
|
return ctx.services.upload.initiate(body2, ctx.user);
|
|
98395
98741
|
});
|
|
98396
98742
|
});
|
|
98397
98743
|
|
|
98398
98744
|
// ../api-core/src/controllers/user.controller.ts
|
|
98399
|
-
var
|
|
98745
|
+
var logger69, getMe, getDemoProfile, updateDemoProfile, users2;
|
|
98400
98746
|
var init_user_controller = __esm(() => {
|
|
98401
98747
|
init_schemas_index();
|
|
98402
98748
|
init_src2();
|
|
98403
98749
|
init_utils11();
|
|
98404
|
-
|
|
98750
|
+
logger69 = log.scope("UserController");
|
|
98405
98751
|
getMe = requireNonAnonymous(async (ctx) => {
|
|
98406
|
-
|
|
98752
|
+
logger69.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
98407
98753
|
return ctx.services.user.getMe(ctx.user, ctx.gameId);
|
|
98408
98754
|
});
|
|
98409
98755
|
getDemoProfile = requireAnonymous(async (ctx) => {
|
|
98410
|
-
|
|
98756
|
+
logger69.debug("Getting demo profile", { userId: ctx.user.id });
|
|
98411
98757
|
return ctx.services.user.getDemoProfile(ctx.user.id);
|
|
98412
98758
|
});
|
|
98413
98759
|
updateDemoProfile = requireAnonymous(async (ctx) => {
|
|
98414
98760
|
const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
|
|
98415
|
-
|
|
98761
|
+
logger69.debug("Updating demo profile", {
|
|
98416
98762
|
userId: ctx.user.id,
|
|
98417
98763
|
displayName: body2.displayName
|
|
98418
98764
|
});
|
|
@@ -98426,13 +98772,13 @@ var init_user_controller = __esm(() => {
|
|
|
98426
98772
|
});
|
|
98427
98773
|
|
|
98428
98774
|
// ../api-core/src/controllers/verify.controller.ts
|
|
98429
|
-
var
|
|
98775
|
+
var logger70;
|
|
98430
98776
|
var init_verify_controller = __esm(() => {
|
|
98431
98777
|
init_schemas_index();
|
|
98432
98778
|
init_src2();
|
|
98433
98779
|
init_errors();
|
|
98434
98780
|
init_utils11();
|
|
98435
|
-
|
|
98781
|
+
logger70 = log.scope("VerifyController");
|
|
98436
98782
|
});
|
|
98437
98783
|
|
|
98438
98784
|
// ../api-core/src/controllers/index.ts
|
|
@@ -98746,7 +99092,7 @@ var init_uploads = __esm(() => {
|
|
|
98746
99092
|
});
|
|
98747
99093
|
|
|
98748
99094
|
// src/routes/platform/games/deploy.ts
|
|
98749
|
-
var
|
|
99095
|
+
var logger71, gameDeployRouter;
|
|
98750
99096
|
var init_deploy = __esm(() => {
|
|
98751
99097
|
init_drizzle_orm();
|
|
98752
99098
|
init_dist4();
|
|
@@ -98756,7 +99102,7 @@ var init_deploy = __esm(() => {
|
|
|
98756
99102
|
init_src2();
|
|
98757
99103
|
init_api();
|
|
98758
99104
|
init_uploads();
|
|
98759
|
-
|
|
99105
|
+
logger71 = log.scope("SandboxDeploy");
|
|
98760
99106
|
gameDeployRouter = new Hono2;
|
|
98761
99107
|
gameDeployRouter.post("/:slug/deploy", async (c2) => {
|
|
98762
99108
|
const user = c2.get("user");
|
|
@@ -98882,7 +99228,7 @@ var init_deploy = __esm(() => {
|
|
|
98882
99228
|
completedAt: now2
|
|
98883
99229
|
};
|
|
98884
99230
|
const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
|
|
98885
|
-
|
|
99231
|
+
logger71.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
|
|
98886
99232
|
return c2.json({
|
|
98887
99233
|
id: insertedJob.id,
|
|
98888
99234
|
status: "succeeded",
|
|
@@ -99500,7 +99846,7 @@ var init_timeback6 = __esm(() => {
|
|
|
99500
99846
|
return {
|
|
99501
99847
|
grade: e.grade,
|
|
99502
99848
|
subject: e.subject,
|
|
99503
|
-
title: `${e.subject}
|
|
99849
|
+
title: `${e.subject} ${formatGradeLabel(e.grade)}`,
|
|
99504
99850
|
totalXp: totalXp2,
|
|
99505
99851
|
...includeToday && { todayXp: todayXp2 }
|
|
99506
99852
|
};
|
|
@@ -99529,7 +99875,7 @@ function verifyMockToken(idToken) {
|
|
|
99529
99875
|
throw new Error("Invalid LTI token format");
|
|
99530
99876
|
}
|
|
99531
99877
|
}
|
|
99532
|
-
var
|
|
99878
|
+
var logger72, ltiRouter;
|
|
99533
99879
|
var init_lti = __esm(() => {
|
|
99534
99880
|
init_drizzle_orm();
|
|
99535
99881
|
init_dist4();
|
|
@@ -99539,7 +99885,7 @@ var init_lti = __esm(() => {
|
|
|
99539
99885
|
init_src2();
|
|
99540
99886
|
init_constants();
|
|
99541
99887
|
init_api();
|
|
99542
|
-
|
|
99888
|
+
logger72 = log.scope("SandboxLti");
|
|
99543
99889
|
ltiRouter = new Hono2;
|
|
99544
99890
|
ltiRouter.post("/launch", async (c2) => {
|
|
99545
99891
|
const db2 = c2.get("db");
|
|
@@ -99557,7 +99903,7 @@ var init_lti = __esm(() => {
|
|
|
99557
99903
|
claims = verifyMockToken(idToken);
|
|
99558
99904
|
} catch (error2) {
|
|
99559
99905
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
99560
|
-
|
|
99906
|
+
logger72.error("LTI token verification failed", { error: errorMessage });
|
|
99561
99907
|
return c2.json({
|
|
99562
99908
|
error: "invalid_token",
|
|
99563
99909
|
message: errorMessage
|
|
@@ -99565,7 +99911,7 @@ var init_lti = __esm(() => {
|
|
|
99565
99911
|
}
|
|
99566
99912
|
const validationError = validateLtiClaims(claims);
|
|
99567
99913
|
if (validationError) {
|
|
99568
|
-
|
|
99914
|
+
logger72.warn("LTI claims validation failed", {
|
|
99569
99915
|
error: validationError,
|
|
99570
99916
|
sub: claims.sub
|
|
99571
99917
|
});
|
|
@@ -99585,7 +99931,7 @@ var init_lti = __esm(() => {
|
|
|
99585
99931
|
createdAt: new Date,
|
|
99586
99932
|
updatedAt: new Date
|
|
99587
99933
|
});
|
|
99588
|
-
|
|
99934
|
+
logger72.info("LTI launch successful", { userId: user.id });
|
|
99589
99935
|
const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
|
|
99590
99936
|
const currentHost = new URL(c2.req.url).hostname;
|
|
99591
99937
|
const redirectPath = extractRedirectPath(targetUri, currentHost);
|
|
@@ -99593,7 +99939,7 @@ var init_lti = __esm(() => {
|
|
|
99593
99939
|
return c2.redirect(redirectPath);
|
|
99594
99940
|
} catch (error2) {
|
|
99595
99941
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
99596
|
-
|
|
99942
|
+
logger72.error("Unexpected error during LTI launch", { error: errorMessage });
|
|
99597
99943
|
return c2.json({
|
|
99598
99944
|
error: "unexpected_error",
|
|
99599
99945
|
message: "An unexpected error occurred during LTI launch"
|