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