@playcademy/sandbox 0.3.18 → 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 +826 -499
- package/dist/server.js +826 -499
- 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: {
|
|
@@ -31181,7 +31181,7 @@ function isValidAdminAttributionDate(value) {
|
|
|
31181
31181
|
const date3 = new Date(Date.UTC(year, month - 1, day, 12, 0, 0));
|
|
31182
31182
|
return date3.getUTCFullYear() === year && date3.getUTCMonth() + 1 === month && date3.getUTCDate() === day;
|
|
31183
31183
|
}
|
|
31184
|
-
var TIMEBACK_GRADES, TIMEBACK_SUBJECTS4, TimebackGradeSchema, TimebackSubjectSchema, UpdateTimebackXpRequestSchema, 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, 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;
|
|
31185
31185
|
var init_schemas11 = __esm(() => {
|
|
31186
31186
|
init_drizzle_zod();
|
|
31187
31187
|
init_esm();
|
|
@@ -31206,6 +31206,24 @@ var init_schemas11 = __esm(() => {
|
|
|
31206
31206
|
xp: exports_external.number().min(0, "XP must be a non-negative number"),
|
|
31207
31207
|
userTimestamp: exports_external.string().datetime().optional()
|
|
31208
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
|
+
});
|
|
31209
31227
|
TimebackActivityDataSchema = exports_external.object({
|
|
31210
31228
|
activityId: exports_external.string().min(1),
|
|
31211
31229
|
activityName: exports_external.string().optional(),
|
|
@@ -31375,6 +31393,13 @@ var init_schemas11 = __esm(() => {
|
|
|
31375
31393
|
date: AdminAttributionDateSchema.optional(),
|
|
31376
31394
|
useCurrentTime: exports_external.boolean().optional()
|
|
31377
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
|
+
});
|
|
31378
31403
|
EnrollStudentRequestSchema = exports_external.object({
|
|
31379
31404
|
gameId: exports_external.string().uuid(),
|
|
31380
31405
|
courseId: exports_external.string().min(1),
|
|
@@ -31530,6 +31555,65 @@ var init_timeback_admin_util = __esm(() => {
|
|
|
31530
31555
|
init_errors();
|
|
31531
31556
|
});
|
|
31532
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
|
+
|
|
31533
31617
|
// ../api-core/src/utils/timeback.util.ts
|
|
31534
31618
|
function isRecord2(value) {
|
|
31535
31619
|
return typeof value === "object" && value !== null;
|
|
@@ -31887,7 +31971,7 @@ class TimebackAdminService {
|
|
|
31887
31971
|
}
|
|
31888
31972
|
requireClient() {
|
|
31889
31973
|
if (!this.deps.timeback) {
|
|
31890
|
-
|
|
31974
|
+
logger18.error("Timeback client not available in context");
|
|
31891
31975
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
31892
31976
|
}
|
|
31893
31977
|
return this.deps.timeback;
|
|
@@ -32107,7 +32191,7 @@ class TimebackAdminService {
|
|
|
32107
32191
|
});
|
|
32108
32192
|
return [enrollmentId, this.summarizeAnalyticsFacts(analytics.facts)];
|
|
32109
32193
|
} catch (error) {
|
|
32110
|
-
|
|
32194
|
+
logger18.warn("Failed to load enrollment analytics summary", {
|
|
32111
32195
|
enrollmentId,
|
|
32112
32196
|
error: error instanceof Error ? error.message : String(error)
|
|
32113
32197
|
});
|
|
@@ -32137,7 +32221,7 @@ class TimebackAdminService {
|
|
|
32137
32221
|
const events = await this.fetchCaliperEventsForStudent(client, studentId, source, eventLimit);
|
|
32138
32222
|
return TimebackAdminService.mapRecentActivityItems(events, relevantCourseIds).slice(0, maxResults);
|
|
32139
32223
|
} catch (error) {
|
|
32140
|
-
|
|
32224
|
+
logger18.warn("Failed to load recent Caliper activity", {
|
|
32141
32225
|
studentId,
|
|
32142
32226
|
gameId: source.gameId,
|
|
32143
32227
|
sourceMode: source.sourceMode,
|
|
@@ -32463,60 +32547,44 @@ class TimebackAdminService {
|
|
|
32463
32547
|
const wasMastered = currentMastered >= masterableUnits;
|
|
32464
32548
|
const willBeMastered = currentMastered + data.units >= masterableUnits;
|
|
32465
32549
|
if (wasMastered !== willBeMastered) {
|
|
32466
|
-
|
|
32467
|
-
|
|
32468
|
-
|
|
32469
|
-
|
|
32470
|
-
|
|
32471
|
-
|
|
32472
|
-
|
|
32473
|
-
status: ONEROSTER_STATUS.active,
|
|
32474
|
-
course: { sourcedId: ids.course },
|
|
32475
|
-
...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
|
|
32476
|
-
});
|
|
32477
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
32478
|
-
sourcedId: resultId,
|
|
32479
|
-
status: ONEROSTER_STATUS.active,
|
|
32480
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
32481
|
-
student: { sourcedId: data.studentId },
|
|
32482
|
-
score: 100,
|
|
32483
|
-
scoreDate: new Date().toISOString(),
|
|
32484
|
-
scoreStatus: SCORE_STATUS.fullyGraded,
|
|
32485
|
-
inProgress: "false",
|
|
32486
|
-
metadata: {
|
|
32487
|
-
isMasteryCompletion: true,
|
|
32488
|
-
adminAction: true,
|
|
32489
|
-
appName
|
|
32490
|
-
}
|
|
32491
|
-
});
|
|
32492
|
-
} else {
|
|
32493
|
-
try {
|
|
32494
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
32495
|
-
sourcedId: resultId,
|
|
32496
|
-
status: ONEROSTER_STATUS.active,
|
|
32497
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
32498
|
-
student: { sourcedId: data.studentId },
|
|
32499
|
-
score: 0,
|
|
32500
|
-
scoreDate: new Date().toISOString(),
|
|
32501
|
-
scoreStatus: SCORE_STATUS.notSubmitted,
|
|
32502
|
-
inProgress: "true",
|
|
32503
|
-
metadata: {
|
|
32504
|
-
isMasteryCompletion: true,
|
|
32505
|
-
adminAction: true,
|
|
32506
|
-
appName
|
|
32507
|
-
}
|
|
32508
|
-
});
|
|
32509
|
-
} catch {
|
|
32510
|
-
logger17.debug("No completion entry to revoke", {
|
|
32511
|
-
studentId: data.studentId,
|
|
32512
|
-
courseId: data.courseId
|
|
32513
|
-
});
|
|
32514
|
-
}
|
|
32515
|
-
}
|
|
32550
|
+
await upsertMasteryCompletionEntry({
|
|
32551
|
+
client,
|
|
32552
|
+
courseId: data.courseId,
|
|
32553
|
+
studentId: data.studentId,
|
|
32554
|
+
appName,
|
|
32555
|
+
action: willBeMastered ? "complete" : "revoke"
|
|
32556
|
+
});
|
|
32516
32557
|
}
|
|
32517
32558
|
}
|
|
32518
32559
|
return { status: "ok" };
|
|
32519
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
|
+
}
|
|
32520
32588
|
async searchStudentsForEnrollment(gameId, courseId, query, user) {
|
|
32521
32589
|
const client = this.requireClient();
|
|
32522
32590
|
await this.deps.validateGameManagementAccess(user, gameId);
|
|
@@ -32543,7 +32611,7 @@ class TimebackAdminService {
|
|
|
32543
32611
|
const response = await client["request"](endpoint, "GET");
|
|
32544
32612
|
allUsers = response.users || [];
|
|
32545
32613
|
} catch (error) {
|
|
32546
|
-
|
|
32614
|
+
logger18.warn("Failed to search OneRoster users", {
|
|
32547
32615
|
query: trimmedQuery,
|
|
32548
32616
|
error: error instanceof Error ? error.message : String(error)
|
|
32549
32617
|
});
|
|
@@ -32688,7 +32756,7 @@ class TimebackAdminService {
|
|
|
32688
32756
|
return results;
|
|
32689
32757
|
}
|
|
32690
32758
|
}
|
|
32691
|
-
var
|
|
32759
|
+
var logger18;
|
|
32692
32760
|
var init_timeback_admin_service = __esm(() => {
|
|
32693
32761
|
init_drizzle_orm();
|
|
32694
32762
|
init_src();
|
|
@@ -32701,8 +32769,9 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
32701
32769
|
init_errors();
|
|
32702
32770
|
init_timeback_admin_metrics_util();
|
|
32703
32771
|
init_timeback_admin_util();
|
|
32772
|
+
init_timeback_mastery_completion_util();
|
|
32704
32773
|
init_timeback_util();
|
|
32705
|
-
|
|
32774
|
+
logger18 = log.scope("TimebackAdminService");
|
|
32706
32775
|
});
|
|
32707
32776
|
|
|
32708
32777
|
// ../timeback/dist/errors.js
|
|
@@ -32949,7 +33018,7 @@ class TimebackAssessmentsService {
|
|
|
32949
33018
|
isActive: row.bankActive
|
|
32950
33019
|
};
|
|
32951
33020
|
} catch {
|
|
32952
|
-
|
|
33021
|
+
logger19.warn("Failed to fetch QTI test metadata", {
|
|
32953
33022
|
identifier: row.qtiTestIdentifier
|
|
32954
33023
|
});
|
|
32955
33024
|
return {
|
|
@@ -33003,7 +33072,7 @@ class TimebackAssessmentsService {
|
|
|
33003
33072
|
});
|
|
33004
33073
|
} catch (error) {
|
|
33005
33074
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33006
|
-
|
|
33075
|
+
logger19.info("QTI test already exists (idempotent retry)", {
|
|
33007
33076
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
33008
33077
|
});
|
|
33009
33078
|
} else {
|
|
@@ -33016,7 +33085,7 @@ class TimebackAssessmentsService {
|
|
|
33016
33085
|
qtiTestIdentifier: input.qtiTestIdentifier,
|
|
33017
33086
|
sortOrder: maxSortOrder + 1
|
|
33018
33087
|
}).returning();
|
|
33019
|
-
|
|
33088
|
+
logger19.info("Assessment created", {
|
|
33020
33089
|
integrationId,
|
|
33021
33090
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
33022
33091
|
});
|
|
@@ -33038,13 +33107,13 @@ class TimebackAssessmentsService {
|
|
|
33038
33107
|
}
|
|
33039
33108
|
await client.qti.tests.delete(qtiTestIdentifier);
|
|
33040
33109
|
} catch (error) {
|
|
33041
|
-
|
|
33110
|
+
logger19.warn("Partial QTI cleanup during assessment deletion", {
|
|
33042
33111
|
qtiTestIdentifier,
|
|
33043
33112
|
error: error instanceof Error ? error.message : String(error)
|
|
33044
33113
|
});
|
|
33045
33114
|
}
|
|
33046
33115
|
await this.deps.db.delete(gameTimebackAssessmentTests).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33047
|
-
|
|
33116
|
+
logger19.info("Assessment deleted", { integrationId, qtiTestIdentifier });
|
|
33048
33117
|
}
|
|
33049
33118
|
async reorderAssessments(integrationId, identifiers) {
|
|
33050
33119
|
await this.requireIntegration(integrationId);
|
|
@@ -33089,7 +33158,7 @@ class TimebackAssessmentsService {
|
|
|
33089
33158
|
return client.qti.tests.reorderItems(qtiTestIdentifier, partId, sectionId, items2);
|
|
33090
33159
|
}
|
|
33091
33160
|
async activateAssessment(integrationId, qtiTestIdentifier) {
|
|
33092
|
-
|
|
33161
|
+
logger19.debug("Activating assessment", { integrationId, qtiTestIdentifier });
|
|
33093
33162
|
const client = this.requireClient();
|
|
33094
33163
|
const integration = await this.requireIntegration(integrationId);
|
|
33095
33164
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -33127,7 +33196,7 @@ class TimebackAssessmentsService {
|
|
|
33127
33196
|
});
|
|
33128
33197
|
}
|
|
33129
33198
|
} catch {
|
|
33130
|
-
|
|
33199
|
+
logger19.warn("Failed to reactivate existing child resource, will create new", {
|
|
33131
33200
|
childResourceId
|
|
33132
33201
|
});
|
|
33133
33202
|
childResourceId = null;
|
|
@@ -33140,7 +33209,7 @@ class TimebackAssessmentsService {
|
|
|
33140
33209
|
const resourceUrl = resource.metadata?.url;
|
|
33141
33210
|
if (resourceUrl === qtiTestUrl) {
|
|
33142
33211
|
childResourceId = resourceId;
|
|
33143
|
-
|
|
33212
|
+
logger19.info("Found existing child Resource for QTI test (idempotent retry)", {
|
|
33144
33213
|
qtiTestIdentifier,
|
|
33145
33214
|
childResourceId
|
|
33146
33215
|
});
|
|
@@ -33149,7 +33218,7 @@ class TimebackAssessmentsService {
|
|
|
33149
33218
|
} catch {}
|
|
33150
33219
|
}
|
|
33151
33220
|
if (!childResourceId) {
|
|
33152
|
-
|
|
33221
|
+
logger19.debug("Creating child resource", { qtiTestIdentifier, qtiTestUrl });
|
|
33153
33222
|
const childResult = await client.oneroster.resources.create({
|
|
33154
33223
|
resource: {
|
|
33155
33224
|
status: "active",
|
|
@@ -33177,10 +33246,10 @@ class TimebackAssessmentsService {
|
|
|
33177
33246
|
}
|
|
33178
33247
|
}
|
|
33179
33248
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: childResourceId, bankActive: true }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33180
|
-
|
|
33249
|
+
logger19.info("Assessment activated", { integrationId, qtiTestIdentifier, childResourceId });
|
|
33181
33250
|
}
|
|
33182
33251
|
async deactivateAssessment(integrationId, qtiTestIdentifier) {
|
|
33183
|
-
|
|
33252
|
+
logger19.debug("Deactivating assessment", { integrationId, qtiTestIdentifier });
|
|
33184
33253
|
const client = this.requireClient();
|
|
33185
33254
|
const integration = await this.requireIntegration(integrationId);
|
|
33186
33255
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -33193,7 +33262,7 @@ class TimebackAssessmentsService {
|
|
|
33193
33262
|
const childResourceId = row.bankResourceId;
|
|
33194
33263
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
33195
33264
|
try {
|
|
33196
|
-
|
|
33265
|
+
logger19.debug("Reading parent resource for deactivation", {
|
|
33197
33266
|
resourceId: bankIds.resource
|
|
33198
33267
|
});
|
|
33199
33268
|
const parentResource = await client.oneroster.resources.get(bankIds.resource);
|
|
@@ -33212,22 +33281,22 @@ class TimebackAssessmentsService {
|
|
|
33212
33281
|
});
|
|
33213
33282
|
}
|
|
33214
33283
|
} catch (error) {
|
|
33215
|
-
|
|
33284
|
+
logger19.warn("Failed to update parent resource during deactivation", {
|
|
33216
33285
|
bankResourceId: bankIds.resource,
|
|
33217
33286
|
error: error instanceof Error ? error.message : String(error)
|
|
33218
33287
|
});
|
|
33219
33288
|
}
|
|
33220
33289
|
try {
|
|
33221
|
-
|
|
33290
|
+
logger19.debug("Deleting child resource", { childResourceId });
|
|
33222
33291
|
await client.oneroster.resources.delete(childResourceId);
|
|
33223
33292
|
} catch (error) {
|
|
33224
|
-
|
|
33293
|
+
logger19.warn("Failed to delete child resource (may already be deleted)", {
|
|
33225
33294
|
childResourceId,
|
|
33226
33295
|
error: error instanceof Error ? error.message : String(error)
|
|
33227
33296
|
});
|
|
33228
33297
|
}
|
|
33229
33298
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankActive: false }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33230
|
-
|
|
33299
|
+
logger19.info("Assessment deactivated", { integrationId, qtiTestIdentifier });
|
|
33231
33300
|
}
|
|
33232
33301
|
isAssessmentActive(row) {
|
|
33233
33302
|
return row.bankActive;
|
|
@@ -33258,14 +33327,14 @@ class TimebackAssessmentsService {
|
|
|
33258
33327
|
status: "tobedeleted"
|
|
33259
33328
|
});
|
|
33260
33329
|
} catch (error) {
|
|
33261
|
-
|
|
33330
|
+
logger19.warn("Failed to delete component resource", { error });
|
|
33262
33331
|
}
|
|
33263
33332
|
for (const row of activeRows) {
|
|
33264
33333
|
if (row.bankResourceId) {
|
|
33265
33334
|
try {
|
|
33266
33335
|
await client.oneroster.resources.delete(row.bankResourceId);
|
|
33267
33336
|
} catch (error) {
|
|
33268
|
-
|
|
33337
|
+
logger19.warn("Failed to delete child resource", {
|
|
33269
33338
|
childResourceId: row.bankResourceId,
|
|
33270
33339
|
error
|
|
33271
33340
|
});
|
|
@@ -33275,17 +33344,17 @@ class TimebackAssessmentsService {
|
|
|
33275
33344
|
try {
|
|
33276
33345
|
await client.oneroster.resources.delete(bankIds.resource);
|
|
33277
33346
|
} catch (error) {
|
|
33278
|
-
|
|
33347
|
+
logger19.warn("Failed to delete parent resource", { error });
|
|
33279
33348
|
}
|
|
33280
33349
|
try {
|
|
33281
33350
|
await client.oneroster.courseComponents.update(bankIds.component, {
|
|
33282
33351
|
status: "tobedeleted"
|
|
33283
33352
|
});
|
|
33284
33353
|
} catch (error) {
|
|
33285
|
-
|
|
33354
|
+
logger19.warn("Failed to delete course component", { error });
|
|
33286
33355
|
}
|
|
33287
33356
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: null, bankActive: false }).where(eq(gameTimebackAssessmentTests.integrationId, integrationId));
|
|
33288
|
-
|
|
33357
|
+
logger19.info("Bank destroyed", { integrationId });
|
|
33289
33358
|
}
|
|
33290
33359
|
requireClient() {
|
|
33291
33360
|
if (!this.deps.timeback) {
|
|
@@ -33314,7 +33383,7 @@ class TimebackAssessmentsService {
|
|
|
33314
33383
|
async ensureBank(integration) {
|
|
33315
33384
|
const client = this.requireClient();
|
|
33316
33385
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
33317
|
-
|
|
33386
|
+
logger19.debug("Ensuring assessment bank hierarchy", {
|
|
33318
33387
|
courseId: integration.courseId,
|
|
33319
33388
|
bankIds
|
|
33320
33389
|
});
|
|
@@ -33331,7 +33400,7 @@ class TimebackAssessmentsService {
|
|
|
33331
33400
|
});
|
|
33332
33401
|
} catch (error) {
|
|
33333
33402
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33334
|
-
|
|
33403
|
+
logger19.debug("Course component already exists", { sourcedId: bankIds.component });
|
|
33335
33404
|
} else {
|
|
33336
33405
|
throw error;
|
|
33337
33406
|
}
|
|
@@ -33355,7 +33424,7 @@ class TimebackAssessmentsService {
|
|
|
33355
33424
|
});
|
|
33356
33425
|
} catch (error) {
|
|
33357
33426
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33358
|
-
|
|
33427
|
+
logger19.debug("Parent resource already exists", { sourcedId: bankIds.resource });
|
|
33359
33428
|
} else {
|
|
33360
33429
|
throw error;
|
|
33361
33430
|
}
|
|
@@ -33375,14 +33444,14 @@ class TimebackAssessmentsService {
|
|
|
33375
33444
|
});
|
|
33376
33445
|
} catch (error) {
|
|
33377
33446
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33378
|
-
|
|
33447
|
+
logger19.debug("Component resource already exists", {
|
|
33379
33448
|
sourcedId: bankIds.componentResource
|
|
33380
33449
|
});
|
|
33381
33450
|
} else {
|
|
33382
33451
|
throw error;
|
|
33383
33452
|
}
|
|
33384
33453
|
}
|
|
33385
|
-
|
|
33454
|
+
logger19.info("Assessment bank hierarchy created", {
|
|
33386
33455
|
courseId: integration.courseId
|
|
33387
33456
|
});
|
|
33388
33457
|
}
|
|
@@ -33397,7 +33466,7 @@ class TimebackAssessmentsService {
|
|
|
33397
33466
|
return Math.max(...rows.map((r) => r.sortOrder));
|
|
33398
33467
|
}
|
|
33399
33468
|
}
|
|
33400
|
-
var
|
|
33469
|
+
var logger19;
|
|
33401
33470
|
var init_timeback_assessments_service = __esm(() => {
|
|
33402
33471
|
init_drizzle_orm();
|
|
33403
33472
|
init_tables_index();
|
|
@@ -33406,7 +33475,7 @@ var init_timeback_assessments_service = __esm(() => {
|
|
|
33406
33475
|
init_errors4();
|
|
33407
33476
|
init_utils6();
|
|
33408
33477
|
init_errors();
|
|
33409
|
-
|
|
33478
|
+
logger19 = log.scope("TimebackAssessmentsService");
|
|
33410
33479
|
});
|
|
33411
33480
|
|
|
33412
33481
|
// ../api-core/src/utils/timeback-promotion.util.ts
|
|
@@ -33422,7 +33491,7 @@ async function promoteCompletedCourse({
|
|
|
33422
33491
|
});
|
|
33423
33492
|
const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
|
|
33424
33493
|
if (!nextIntegration) {
|
|
33425
|
-
|
|
33494
|
+
logger20.debug("Skipping promotion because no next course is configured", {
|
|
33426
33495
|
gameId: currentIntegration.gameId,
|
|
33427
33496
|
studentId,
|
|
33428
33497
|
grade: currentIntegration.grade,
|
|
@@ -33439,7 +33508,7 @@ async function promoteCompletedCourse({
|
|
|
33439
33508
|
const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
|
|
33440
33509
|
if (!currentEnrollment) {
|
|
33441
33510
|
if (nextEnrollment) {
|
|
33442
|
-
|
|
33511
|
+
logger20.debug("Skipping promotion because student is already on the next course", {
|
|
33443
33512
|
gameId: currentIntegration.gameId,
|
|
33444
33513
|
studentId,
|
|
33445
33514
|
grade: currentIntegration.grade,
|
|
@@ -33453,7 +33522,7 @@ async function promoteCompletedCourse({
|
|
|
33453
33522
|
nextCourseId: nextIntegration.courseId
|
|
33454
33523
|
};
|
|
33455
33524
|
}
|
|
33456
|
-
|
|
33525
|
+
logger20.debug("Skipping promotion because student is not enrolled in the current course", {
|
|
33457
33526
|
gameId: currentIntegration.gameId,
|
|
33458
33527
|
studentId,
|
|
33459
33528
|
grade: currentIntegration.grade,
|
|
@@ -33484,7 +33553,7 @@ async function promoteCompletedCourse({
|
|
|
33484
33553
|
client.invalidateEnrollments(studentId);
|
|
33485
33554
|
}
|
|
33486
33555
|
}
|
|
33487
|
-
|
|
33556
|
+
logger20.info("Promoted student to next course", {
|
|
33488
33557
|
gameId: currentIntegration.gameId,
|
|
33489
33558
|
studentId,
|
|
33490
33559
|
subject: currentIntegration.subject,
|
|
@@ -33499,16 +33568,16 @@ async function promoteCompletedCourse({
|
|
|
33499
33568
|
nextCourseId: nextIntegration.courseId
|
|
33500
33569
|
};
|
|
33501
33570
|
}
|
|
33502
|
-
var
|
|
33571
|
+
var logger20;
|
|
33503
33572
|
var init_timeback_promotion_util = __esm(() => {
|
|
33504
33573
|
init_drizzle_orm();
|
|
33505
33574
|
init_tables_index();
|
|
33506
33575
|
init_src2();
|
|
33507
|
-
|
|
33576
|
+
logger20 = log.scope("TimebackPromotion");
|
|
33508
33577
|
});
|
|
33509
33578
|
|
|
33510
33579
|
// ../api-core/src/services/timeback.service.ts
|
|
33511
|
-
var
|
|
33580
|
+
var logger21, TimebackService;
|
|
33512
33581
|
var init_timeback_service = __esm(() => {
|
|
33513
33582
|
init_drizzle_orm();
|
|
33514
33583
|
init_src();
|
|
@@ -33519,7 +33588,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33519
33588
|
init_errors();
|
|
33520
33589
|
init_timeback_promotion_util();
|
|
33521
33590
|
init_timeback_util();
|
|
33522
|
-
|
|
33591
|
+
logger21 = log.scope("TimebackService");
|
|
33523
33592
|
TimebackService = class TimebackService {
|
|
33524
33593
|
static HEARTBEAT_DEDUPE_TTL_MS = 5 * 60 * 1000;
|
|
33525
33594
|
static processedHeartbeatWindows = new Map;
|
|
@@ -33565,7 +33634,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33565
33634
|
}
|
|
33566
33635
|
requireClient() {
|
|
33567
33636
|
if (!this.deps.timeback) {
|
|
33568
|
-
|
|
33637
|
+
logger21.error("Timeback client not available in context");
|
|
33569
33638
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
33570
33639
|
}
|
|
33571
33640
|
return this.deps.timeback;
|
|
@@ -33618,7 +33687,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33618
33687
|
set: { xp: sql`excluded.xp`, updatedAt: new Date }
|
|
33619
33688
|
}).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
|
|
33620
33689
|
if (!result) {
|
|
33621
|
-
|
|
33690
|
+
logger21.error("Daily XP upsert returned no rows", { userId, date: targetDate });
|
|
33622
33691
|
throw new InternalError("Failed to update daily XP record");
|
|
33623
33692
|
}
|
|
33624
33693
|
return { xp: result.xp, date: result.date.toISOString() };
|
|
@@ -33649,7 +33718,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33649
33718
|
columns: { id: true, timebackId: true }
|
|
33650
33719
|
});
|
|
33651
33720
|
if (dbUser?.timebackId) {
|
|
33652
|
-
|
|
33721
|
+
logger21.info("Student already onboarded", { userId: user.id });
|
|
33653
33722
|
return { status: "already_populated" };
|
|
33654
33723
|
}
|
|
33655
33724
|
let timebackId;
|
|
@@ -33658,7 +33727,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33658
33727
|
const existingUser = await client.oneroster.users.findByEmail(user.email);
|
|
33659
33728
|
timebackId = existingUser.sourcedId;
|
|
33660
33729
|
name3 = `${existingUser.givenName} ${existingUser.familyName}`;
|
|
33661
|
-
|
|
33730
|
+
logger21.info("Found existing student in OneRoster", {
|
|
33662
33731
|
userId: user.id,
|
|
33663
33732
|
timebackId
|
|
33664
33733
|
});
|
|
@@ -33687,7 +33756,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33687
33756
|
}
|
|
33688
33757
|
timebackId = response.sourcedIdPairs.allocatedSourcedId;
|
|
33689
33758
|
name3 = `${providedNames.firstName} ${providedNames.lastName}`;
|
|
33690
|
-
|
|
33759
|
+
logger21.info("Created student in OneRoster", { userId: user.id, timebackId });
|
|
33691
33760
|
}
|
|
33692
33761
|
const assessments = await this.fetchAssessments(timebackId);
|
|
33693
33762
|
await db2.transaction(async (tx) => {
|
|
@@ -33721,7 +33790,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33721
33790
|
}
|
|
33722
33791
|
const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
|
|
33723
33792
|
if (!updated) {
|
|
33724
|
-
|
|
33793
|
+
logger21.error("User Timeback ID update returned no rows", {
|
|
33725
33794
|
userId: user.id,
|
|
33726
33795
|
timebackId
|
|
33727
33796
|
});
|
|
@@ -33745,13 +33814,13 @@ var init_timeback_service = __esm(() => {
|
|
|
33745
33814
|
}
|
|
33746
33815
|
offset += limit;
|
|
33747
33816
|
}
|
|
33748
|
-
|
|
33817
|
+
logger21.debug("Fetched assessments", {
|
|
33749
33818
|
studentSourcedId,
|
|
33750
33819
|
totalCount: allAssessments.length
|
|
33751
33820
|
});
|
|
33752
33821
|
return allAssessments;
|
|
33753
33822
|
} catch (error) {
|
|
33754
|
-
|
|
33823
|
+
logger21.warn("Failed to fetch assessments", { studentSourcedId, error });
|
|
33755
33824
|
return [];
|
|
33756
33825
|
}
|
|
33757
33826
|
}
|
|
@@ -33864,7 +33933,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33864
33933
|
masterableUnits: derivedMasterableUnits
|
|
33865
33934
|
} = courseConfig;
|
|
33866
33935
|
if (!isTimebackSubject(subjectInput)) {
|
|
33867
|
-
|
|
33936
|
+
logger21.warn("Invalid Timeback subject in course config", {
|
|
33868
33937
|
subject: subjectInput,
|
|
33869
33938
|
courseCode,
|
|
33870
33939
|
title
|
|
@@ -33872,7 +33941,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33872
33941
|
throw new ValidationError(`Invalid subject "${subjectInput}"`);
|
|
33873
33942
|
}
|
|
33874
33943
|
if (!isTimebackGrade(grade)) {
|
|
33875
|
-
|
|
33944
|
+
logger21.warn("Invalid Timeback grade in course config", {
|
|
33876
33945
|
grade,
|
|
33877
33946
|
courseCode,
|
|
33878
33947
|
title
|
|
@@ -33884,7 +33953,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33884
33953
|
const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
|
|
33885
33954
|
const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
|
|
33886
33955
|
if (typeof totalXp !== "number") {
|
|
33887
|
-
|
|
33956
|
+
logger21.warn("Course missing totalXp in Timeback config", {
|
|
33888
33957
|
courseCode,
|
|
33889
33958
|
title
|
|
33890
33959
|
});
|
|
@@ -33900,7 +33969,9 @@ var init_timeback_service = __esm(() => {
|
|
|
33900
33969
|
courseCode,
|
|
33901
33970
|
level,
|
|
33902
33971
|
gradingScheme: "STANDARD",
|
|
33903
|
-
metadata: metadata2
|
|
33972
|
+
metadata: TimebackService.patchCourseMetadata(metadata2, totalXp, {
|
|
33973
|
+
masterableUnits: masterableUnits ?? null
|
|
33974
|
+
})
|
|
33904
33975
|
},
|
|
33905
33976
|
component: {
|
|
33906
33977
|
...baseConfig.component,
|
|
@@ -33925,7 +33996,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33925
33996
|
const existingIntegration = existing.find((i2) => i2.grade === grade && i2.subject === subject);
|
|
33926
33997
|
if (existingIntegration) {
|
|
33927
33998
|
await client.update(existingIntegration.courseId, fullConfig);
|
|
33928
|
-
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();
|
|
33929
34000
|
if (updated) {
|
|
33930
34001
|
integrations.push(this.toGameTimebackIntegration(updated));
|
|
33931
34002
|
}
|
|
@@ -33950,6 +34021,60 @@ var init_timeback_service = __esm(() => {
|
|
|
33950
34021
|
});
|
|
33951
34022
|
return rows.map((row) => this.toGameTimebackIntegration(row));
|
|
33952
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
|
+
}
|
|
33953
34078
|
async verifyIntegration(gameId, user) {
|
|
33954
34079
|
const client = this.requireClient();
|
|
33955
34080
|
const db2 = this.deps.db;
|
|
@@ -34007,6 +34132,146 @@ var init_timeback_service = __esm(() => {
|
|
|
34007
34132
|
}
|
|
34008
34133
|
await db2.delete(gameTimebackIntegrations).where(eq(gameTimebackIntegrations.gameId, gameId));
|
|
34009
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
|
+
}
|
|
34010
34275
|
toGameTimebackIntegration(integration) {
|
|
34011
34276
|
return {
|
|
34012
34277
|
id: integration.id,
|
|
@@ -34020,6 +34285,21 @@ var init_timeback_service = __esm(() => {
|
|
|
34020
34285
|
lastVerifiedAt: integration.lastVerifiedAt ?? null
|
|
34021
34286
|
};
|
|
34022
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
|
+
}
|
|
34023
34303
|
async endActivity({
|
|
34024
34304
|
gameId,
|
|
34025
34305
|
studentId,
|
|
@@ -34085,7 +34365,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34085
34365
|
...runId ? { runId } : {}
|
|
34086
34366
|
});
|
|
34087
34367
|
}
|
|
34088
|
-
|
|
34368
|
+
logger21.info("Recorded activity completion", {
|
|
34089
34369
|
gameId,
|
|
34090
34370
|
courseId: integration.courseId,
|
|
34091
34371
|
studentId,
|
|
@@ -34139,7 +34419,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34139
34419
|
masteredUnits: masteryStatus.masteredUnits,
|
|
34140
34420
|
masterableUnits: masteryStatus.masterableUnits
|
|
34141
34421
|
};
|
|
34142
|
-
|
|
34422
|
+
logger21.debug("Skipping course advancement because mastery is incomplete", {
|
|
34143
34423
|
gameId,
|
|
34144
34424
|
studentId,
|
|
34145
34425
|
subject: currentIntegration.subject,
|
|
@@ -34157,7 +34437,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34157
34437
|
studentId,
|
|
34158
34438
|
enrollments
|
|
34159
34439
|
});
|
|
34160
|
-
|
|
34440
|
+
logger21.info("Manually advanced student", {
|
|
34161
34441
|
gameId,
|
|
34162
34442
|
studentId,
|
|
34163
34443
|
subject: currentIntegration.subject,
|
|
@@ -34190,7 +34470,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34190
34470
|
const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
|
|
34191
34471
|
const effectiveResumeId = resumeId ?? runId;
|
|
34192
34472
|
if (TimebackService.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
|
|
34193
|
-
|
|
34473
|
+
logger21.debug("Skipping duplicate heartbeat window", {
|
|
34194
34474
|
gameId,
|
|
34195
34475
|
studentId,
|
|
34196
34476
|
runId,
|
|
@@ -34203,7 +34483,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34203
34483
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34204
34484
|
const inFlightHeartbeat = TimebackService.getInFlightHeartbeatWindow(heartbeatWindowKey);
|
|
34205
34485
|
if (inFlightHeartbeat) {
|
|
34206
|
-
|
|
34486
|
+
logger21.debug("Joining in-flight heartbeat window", {
|
|
34207
34487
|
gameId,
|
|
34208
34488
|
studentId,
|
|
34209
34489
|
runId,
|
|
@@ -34240,7 +34520,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34240
34520
|
});
|
|
34241
34521
|
}
|
|
34242
34522
|
TimebackService.markHeartbeatWindowProcessed(heartbeatWindowKey);
|
|
34243
|
-
|
|
34523
|
+
logger21.debug("Recorded heartbeat", {
|
|
34244
34524
|
gameId,
|
|
34245
34525
|
courseId: integration.courseId,
|
|
34246
34526
|
studentId,
|
|
@@ -34275,7 +34555,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34275
34555
|
});
|
|
34276
34556
|
courseIds = integrations.map((i2) => i2.courseId);
|
|
34277
34557
|
if (courseIds.length === 0) {
|
|
34278
|
-
|
|
34558
|
+
logger21.debug("No integrations found for game, returning 0 XP", {
|
|
34279
34559
|
timebackId,
|
|
34280
34560
|
gameId: options.gameId,
|
|
34281
34561
|
grade: options.grade,
|
|
@@ -34292,7 +34572,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34292
34572
|
courseIds: courseIds.length > 0 ? courseIds : undefined,
|
|
34293
34573
|
include: options?.include
|
|
34294
34574
|
});
|
|
34295
|
-
|
|
34575
|
+
logger21.debug("Retrieved student XP", {
|
|
34296
34576
|
timebackId,
|
|
34297
34577
|
gameId: options?.gameId,
|
|
34298
34578
|
grade: options?.grade,
|
|
@@ -34321,15 +34601,15 @@ class UploadService {
|
|
|
34321
34601
|
const { fileName, gameId } = request;
|
|
34322
34602
|
const bucketName = this.deps.uploadBucket;
|
|
34323
34603
|
if (!bucketName) {
|
|
34324
|
-
|
|
34604
|
+
logger22.error("Upload bucket not configured in environment");
|
|
34325
34605
|
throw new ValidationError("Upload bucket not configured");
|
|
34326
34606
|
}
|
|
34327
34607
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34328
34608
|
const version2 = ulid();
|
|
34329
34609
|
const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
|
|
34330
|
-
|
|
34610
|
+
logger22.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
|
|
34331
34611
|
const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
|
|
34332
|
-
|
|
34612
|
+
logger22.info("Presigned URL generated", {
|
|
34333
34613
|
userId: user.id,
|
|
34334
34614
|
gameId,
|
|
34335
34615
|
version: version2
|
|
@@ -34342,12 +34622,12 @@ class UploadService {
|
|
|
34342
34622
|
};
|
|
34343
34623
|
}
|
|
34344
34624
|
}
|
|
34345
|
-
var
|
|
34625
|
+
var logger22;
|
|
34346
34626
|
var init_upload_service = __esm(() => {
|
|
34347
34627
|
init_node();
|
|
34348
34628
|
init_src2();
|
|
34349
34629
|
init_errors();
|
|
34350
|
-
|
|
34630
|
+
logger22 = log.scope("UploadService");
|
|
34351
34631
|
});
|
|
34352
34632
|
|
|
34353
34633
|
// ../api-core/src/services/factory/platform.ts
|
|
@@ -34661,7 +34941,7 @@ class AchievementService {
|
|
|
34661
34941
|
results.push(result);
|
|
34662
34942
|
}
|
|
34663
34943
|
}
|
|
34664
|
-
|
|
34944
|
+
logger23.debug("Listed current achievements", { userId: user.id, count: results.length });
|
|
34665
34945
|
return results;
|
|
34666
34946
|
}
|
|
34667
34947
|
async listHistory(user, limit) {
|
|
@@ -34679,14 +34959,14 @@ class AchievementService {
|
|
|
34679
34959
|
createdAt: c.createdAt,
|
|
34680
34960
|
scopeKey: c.scopeKey
|
|
34681
34961
|
}));
|
|
34682
|
-
|
|
34962
|
+
logger23.debug("Listed achievement history", { userId: user.id, count: results.length });
|
|
34683
34963
|
return results;
|
|
34684
34964
|
}
|
|
34685
34965
|
async submitProgress(achievementId, user) {
|
|
34686
34966
|
const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
|
|
34687
34967
|
broadcast: false
|
|
34688
34968
|
});
|
|
34689
|
-
|
|
34969
|
+
logger23.debug("Submitted progress", {
|
|
34690
34970
|
userId: user.id,
|
|
34691
34971
|
achievementId,
|
|
34692
34972
|
wasNewClaim
|
|
@@ -34718,7 +34998,7 @@ class AchievementService {
|
|
|
34718
34998
|
rewardCredits
|
|
34719
34999
|
}).returning();
|
|
34720
35000
|
if (!newClaim) {
|
|
34721
|
-
|
|
35001
|
+
logger23.error("Achievement claim insert returned no rows", {
|
|
34722
35002
|
userId,
|
|
34723
35003
|
achievementId,
|
|
34724
35004
|
scopeKey
|
|
@@ -34727,7 +35007,7 @@ class AchievementService {
|
|
|
34727
35007
|
}
|
|
34728
35008
|
await this.deps.addCredits(userId, rewardCredits);
|
|
34729
35009
|
await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
|
|
34730
|
-
|
|
35010
|
+
logger23.info("Awarded achievement", {
|
|
34731
35011
|
userId,
|
|
34732
35012
|
achievementId,
|
|
34733
35013
|
scopeKey,
|
|
@@ -34764,7 +35044,7 @@ class AchievementService {
|
|
|
34764
35044
|
return { title, body: body2 };
|
|
34765
35045
|
}
|
|
34766
35046
|
}
|
|
34767
|
-
var
|
|
35047
|
+
var logger23;
|
|
34768
35048
|
var init_achievement_service = __esm(() => {
|
|
34769
35049
|
init_drizzle_orm();
|
|
34770
35050
|
init_tables_index();
|
|
@@ -34773,7 +35053,7 @@ var init_achievement_service = __esm(() => {
|
|
|
34773
35053
|
init_errors();
|
|
34774
35054
|
init_leaderboard_util();
|
|
34775
35055
|
init_scope_util();
|
|
34776
|
-
|
|
35056
|
+
logger23 = log.scope("AchievementService");
|
|
34777
35057
|
});
|
|
34778
35058
|
|
|
34779
35059
|
// ../api-core/src/services/inventory.service.ts
|
|
@@ -34801,7 +35081,7 @@ class InventoryService {
|
|
|
34801
35081
|
},
|
|
34802
35082
|
updatedAt: inventoryItems.updatedAt
|
|
34803
35083
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
34804
|
-
|
|
35084
|
+
logger24.debug("Listed inventory", { userId: user.id, count: inventory.length });
|
|
34805
35085
|
return inventory;
|
|
34806
35086
|
}
|
|
34807
35087
|
async addItem(itemId, quantity, user) {
|
|
@@ -34818,7 +35098,7 @@ class InventoryService {
|
|
|
34818
35098
|
const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
|
|
34819
35099
|
return inserted?.quantity ?? 0;
|
|
34820
35100
|
});
|
|
34821
|
-
|
|
35101
|
+
logger24.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
|
|
34822
35102
|
return { newTotal };
|
|
34823
35103
|
}
|
|
34824
35104
|
async removeItem(itemId, quantity, user) {
|
|
@@ -34829,7 +35109,7 @@ class InventoryService {
|
|
|
34829
35109
|
}
|
|
34830
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);
|
|
34831
35111
|
if (!currentItem) {
|
|
34832
|
-
|
|
35112
|
+
logger24.warn("Insufficient inventory for removal", {
|
|
34833
35113
|
userId: user.id,
|
|
34834
35114
|
itemId,
|
|
34835
35115
|
requestedQuantity: quantity
|
|
@@ -34839,13 +35119,13 @@ class InventoryService {
|
|
|
34839
35119
|
const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
|
|
34840
35120
|
return updated?.quantity ?? 0;
|
|
34841
35121
|
});
|
|
34842
|
-
|
|
35122
|
+
logger24.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
|
|
34843
35123
|
return { newTotal };
|
|
34844
35124
|
}
|
|
34845
35125
|
async addCredits(userId, amount) {
|
|
34846
35126
|
const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
34847
35127
|
if (!creditsItem) {
|
|
34848
|
-
|
|
35128
|
+
logger24.error("Primary currency not found", {
|
|
34849
35129
|
userId,
|
|
34850
35130
|
amount
|
|
34851
35131
|
});
|
|
@@ -34858,17 +35138,17 @@ class InventoryService {
|
|
|
34858
35138
|
updatedAt: new Date
|
|
34859
35139
|
}
|
|
34860
35140
|
});
|
|
34861
|
-
|
|
35141
|
+
logger24.debug("Added credits", { userId, amount });
|
|
34862
35142
|
}
|
|
34863
35143
|
}
|
|
34864
|
-
var
|
|
35144
|
+
var logger24;
|
|
34865
35145
|
var init_inventory_service = __esm(() => {
|
|
34866
35146
|
init_drizzle_orm();
|
|
34867
35147
|
init_src();
|
|
34868
35148
|
init_tables_index();
|
|
34869
35149
|
init_src2();
|
|
34870
35150
|
init_errors();
|
|
34871
|
-
|
|
35151
|
+
logger24 = log.scope("InventoryService");
|
|
34872
35152
|
});
|
|
34873
35153
|
|
|
34874
35154
|
// ../api-core/src/services/leaderboard.service.ts
|
|
@@ -34900,7 +35180,7 @@ class LeaderboardService {
|
|
|
34900
35180
|
sessionId
|
|
34901
35181
|
}).returning();
|
|
34902
35182
|
if (!newScore) {
|
|
34903
|
-
|
|
35183
|
+
logger25.error("Score insert returned no rows", { userId, gameId, score: input.score });
|
|
34904
35184
|
throw new InternalError("Failed to insert score");
|
|
34905
35185
|
}
|
|
34906
35186
|
const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
|
|
@@ -34928,7 +35208,7 @@ class LeaderboardService {
|
|
|
34928
35208
|
movedUpWithinTop3
|
|
34929
35209
|
});
|
|
34930
35210
|
}
|
|
34931
|
-
|
|
35211
|
+
logger25.info("Score submitted", {
|
|
34932
35212
|
gameId,
|
|
34933
35213
|
userId,
|
|
34934
35214
|
isAnonymousUser,
|
|
@@ -35005,7 +35285,7 @@ class LeaderboardService {
|
|
|
35005
35285
|
});
|
|
35006
35286
|
}
|
|
35007
35287
|
} catch (error) {
|
|
35008
|
-
|
|
35288
|
+
logger25.warn("Failed to publish notification", { error });
|
|
35009
35289
|
}
|
|
35010
35290
|
}
|
|
35011
35291
|
async getLeaderboard(gameId, query, isAnonymousUser) {
|
|
@@ -35124,7 +35404,7 @@ class LeaderboardService {
|
|
|
35124
35404
|
return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
|
|
35125
35405
|
}
|
|
35126
35406
|
}
|
|
35127
|
-
var
|
|
35407
|
+
var logger25;
|
|
35128
35408
|
var init_leaderboard_service = __esm(() => {
|
|
35129
35409
|
init_drizzle_orm();
|
|
35130
35410
|
init_src();
|
|
@@ -35134,7 +35414,7 @@ var init_leaderboard_service = __esm(() => {
|
|
|
35134
35414
|
init_notification();
|
|
35135
35415
|
init_errors();
|
|
35136
35416
|
init_leaderboard_util();
|
|
35137
|
-
|
|
35417
|
+
logger25 = log.scope("LeaderboardService");
|
|
35138
35418
|
});
|
|
35139
35419
|
|
|
35140
35420
|
// ../api-core/src/services/level.service.ts
|
|
@@ -35150,9 +35430,9 @@ class LevelService {
|
|
|
35150
35430
|
for (const config2 of configs) {
|
|
35151
35431
|
levelConfigCache.set(config2.level, config2);
|
|
35152
35432
|
}
|
|
35153
|
-
|
|
35433
|
+
logger26.info("Cache pre-warmed", { count: configs.length });
|
|
35154
35434
|
} catch (error) {
|
|
35155
|
-
|
|
35435
|
+
logger26.error("Cache pre-warm failed", { error });
|
|
35156
35436
|
}
|
|
35157
35437
|
}
|
|
35158
35438
|
async getConfig(level) {
|
|
@@ -35186,7 +35466,7 @@ class LevelService {
|
|
|
35186
35466
|
totalXP
|
|
35187
35467
|
}).returning();
|
|
35188
35468
|
if (!newUserLevel) {
|
|
35189
|
-
|
|
35469
|
+
logger26.error("User level insert returned no rows", { userId: user.id });
|
|
35190
35470
|
throw new InternalError("Failed to create user level cache record");
|
|
35191
35471
|
}
|
|
35192
35472
|
userLevel = newUserLevel;
|
|
@@ -35201,7 +35481,7 @@ class LevelService {
|
|
|
35201
35481
|
userLevel = updatedUserLevel;
|
|
35202
35482
|
}
|
|
35203
35483
|
}
|
|
35204
|
-
|
|
35484
|
+
logger26.debug("Retrieved user level", {
|
|
35205
35485
|
userId: user.id,
|
|
35206
35486
|
totalXP,
|
|
35207
35487
|
currentLevel,
|
|
@@ -35212,7 +35492,7 @@ class LevelService {
|
|
|
35212
35492
|
async getProgress(user) {
|
|
35213
35493
|
const userLevel = await this.getByUser(user);
|
|
35214
35494
|
const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
|
|
35215
|
-
|
|
35495
|
+
logger26.debug("Retrieved progress", { userId: user.id });
|
|
35216
35496
|
return {
|
|
35217
35497
|
level: userLevel.currentLevel,
|
|
35218
35498
|
currentXp: userLevel.currentXp,
|
|
@@ -35246,7 +35526,7 @@ class LevelService {
|
|
|
35246
35526
|
if (leveledUp && previousUserLevel) {
|
|
35247
35527
|
await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
|
|
35248
35528
|
}
|
|
35249
|
-
|
|
35529
|
+
logger26.info("Synced from Timeback", {
|
|
35250
35530
|
userId,
|
|
35251
35531
|
totalXP,
|
|
35252
35532
|
currentLevel,
|
|
@@ -35287,7 +35567,7 @@ class LevelService {
|
|
|
35287
35567
|
}
|
|
35288
35568
|
if (totalCredits > 0) {
|
|
35289
35569
|
await this.deps.addCredits(userId, totalCredits);
|
|
35290
|
-
|
|
35570
|
+
logger26.info("Awarded level-up credits", {
|
|
35291
35571
|
userId,
|
|
35292
35572
|
fromLevel,
|
|
35293
35573
|
toLevel,
|
|
@@ -35325,14 +35605,14 @@ class LevelService {
|
|
|
35325
35605
|
};
|
|
35326
35606
|
}
|
|
35327
35607
|
}
|
|
35328
|
-
var
|
|
35608
|
+
var logger26, levelConfigCache = null;
|
|
35329
35609
|
var init_level_service = __esm(() => {
|
|
35330
35610
|
init_drizzle_orm();
|
|
35331
35611
|
init_src();
|
|
35332
35612
|
init_tables_index();
|
|
35333
35613
|
init_src2();
|
|
35334
35614
|
init_errors();
|
|
35335
|
-
|
|
35615
|
+
logger26 = log.scope("LevelService");
|
|
35336
35616
|
});
|
|
35337
35617
|
|
|
35338
35618
|
// ../realtime/src/server/domain/events.ts
|
|
@@ -35353,13 +35633,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
|
|
|
35353
35633
|
});
|
|
35354
35634
|
if (!res.ok) {
|
|
35355
35635
|
const text3 = await res.text().catch(() => "");
|
|
35356
|
-
|
|
35636
|
+
logger27.warn("Failed to publish to user", {
|
|
35357
35637
|
status: res.status,
|
|
35358
35638
|
body: text3
|
|
35359
35639
|
});
|
|
35360
35640
|
}
|
|
35361
35641
|
} catch (error) {
|
|
35362
|
-
|
|
35642
|
+
logger27.error("Publish to user error", { error });
|
|
35363
35643
|
}
|
|
35364
35644
|
}
|
|
35365
35645
|
|
|
@@ -35381,7 +35661,7 @@ class NotificationService {
|
|
|
35381
35661
|
conditions2.push(eq(notifications.type, type));
|
|
35382
35662
|
}
|
|
35383
35663
|
const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
|
|
35384
|
-
|
|
35664
|
+
logger27.debug("Listed notifications", { userId: user.id, count: results.length });
|
|
35385
35665
|
return results;
|
|
35386
35666
|
}
|
|
35387
35667
|
async updateStatus(notificationId, status, method) {
|
|
@@ -35400,7 +35680,7 @@ class NotificationService {
|
|
|
35400
35680
|
if (!updated) {
|
|
35401
35681
|
throw new NotFoundError("Notification", notificationId);
|
|
35402
35682
|
}
|
|
35403
|
-
|
|
35683
|
+
logger27.debug("Updated status", { notificationId, status });
|
|
35404
35684
|
return updated;
|
|
35405
35685
|
}
|
|
35406
35686
|
async getStats(user, options) {
|
|
@@ -35426,7 +35706,7 @@ class NotificationService {
|
|
|
35426
35706
|
const clicked = statsMap.clicked || 0;
|
|
35427
35707
|
const dismissed = statsMap.dismissed || 0;
|
|
35428
35708
|
const expired = statsMap.expired || 0;
|
|
35429
|
-
|
|
35709
|
+
logger27.debug("Retrieved stats", { userId: user.id, total });
|
|
35430
35710
|
return {
|
|
35431
35711
|
total,
|
|
35432
35712
|
delivered,
|
|
@@ -35475,7 +35755,7 @@ class NotificationService {
|
|
|
35475
35755
|
options: { data, clickUrl, metadata: metadata2 }
|
|
35476
35756
|
});
|
|
35477
35757
|
}
|
|
35478
|
-
|
|
35758
|
+
logger27.debug("Created notification", {
|
|
35479
35759
|
userId,
|
|
35480
35760
|
type,
|
|
35481
35761
|
id: notificationId,
|
|
@@ -35483,7 +35763,7 @@ class NotificationService {
|
|
|
35483
35763
|
});
|
|
35484
35764
|
return notificationId;
|
|
35485
35765
|
} catch (error) {
|
|
35486
|
-
|
|
35766
|
+
logger27.error("Failed to create notification", { userId, type, error });
|
|
35487
35767
|
return null;
|
|
35488
35768
|
}
|
|
35489
35769
|
}
|
|
@@ -35497,7 +35777,7 @@ class NotificationService {
|
|
|
35497
35777
|
}) {
|
|
35498
35778
|
const realtimeConfig = this.deps.realtime;
|
|
35499
35779
|
if (!realtimeConfig) {
|
|
35500
|
-
|
|
35780
|
+
logger27.warn("No realtime config for publish");
|
|
35501
35781
|
return;
|
|
35502
35782
|
}
|
|
35503
35783
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -35539,13 +35819,13 @@ class NotificationService {
|
|
|
35539
35819
|
metadata: data.metadata || {}
|
|
35540
35820
|
}).returning();
|
|
35541
35821
|
if (!notification) {
|
|
35542
|
-
|
|
35822
|
+
logger27.error("Notification insert returned no rows", {
|
|
35543
35823
|
userId: data.userId,
|
|
35544
35824
|
type: data.type
|
|
35545
35825
|
});
|
|
35546
35826
|
throw new InternalError("Failed to create notification");
|
|
35547
35827
|
}
|
|
35548
|
-
|
|
35828
|
+
logger27.info("Inserted notification", {
|
|
35549
35829
|
notificationId: notification.id,
|
|
35550
35830
|
userId: notification.userId,
|
|
35551
35831
|
type: notification.type
|
|
@@ -35555,7 +35835,7 @@ class NotificationService {
|
|
|
35555
35835
|
async deliverPending(userId) {
|
|
35556
35836
|
const realtimeConfig = this.deps.realtime;
|
|
35557
35837
|
if (!realtimeConfig) {
|
|
35558
|
-
|
|
35838
|
+
logger27.warn("No realtime config for delivery");
|
|
35559
35839
|
return;
|
|
35560
35840
|
}
|
|
35561
35841
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -35582,13 +35862,13 @@ class NotificationService {
|
|
|
35582
35862
|
metadata: notification.metadata,
|
|
35583
35863
|
clickUrl: notification.clickUrl
|
|
35584
35864
|
});
|
|
35585
|
-
|
|
35865
|
+
logger27.info("Delivered notification", {
|
|
35586
35866
|
notificationId: notification.id,
|
|
35587
35867
|
userId,
|
|
35588
35868
|
type: notification.type
|
|
35589
35869
|
});
|
|
35590
35870
|
} catch (error) {
|
|
35591
|
-
|
|
35871
|
+
logger27.warn("Failed to deliver", {
|
|
35592
35872
|
notificationId: notification.id,
|
|
35593
35873
|
error
|
|
35594
35874
|
});
|
|
@@ -35596,7 +35876,7 @@ class NotificationService {
|
|
|
35596
35876
|
}
|
|
35597
35877
|
}
|
|
35598
35878
|
}
|
|
35599
|
-
var
|
|
35879
|
+
var logger27;
|
|
35600
35880
|
var init_notification_service = __esm(() => {
|
|
35601
35881
|
init_drizzle_orm();
|
|
35602
35882
|
init_src();
|
|
@@ -35605,7 +35885,7 @@ var init_notification_service = __esm(() => {
|
|
|
35605
35885
|
init_events();
|
|
35606
35886
|
init_notification();
|
|
35607
35887
|
init_errors();
|
|
35608
|
-
|
|
35888
|
+
logger27 = log.scope("NotificationService");
|
|
35609
35889
|
});
|
|
35610
35890
|
|
|
35611
35891
|
// ../api-core/src/services/factory/player.ts
|
|
@@ -35729,7 +36009,7 @@ class CharacterService {
|
|
|
35729
36009
|
createdAt: characterComponents.createdAt,
|
|
35730
36010
|
updatedAt: characterComponents.updatedAt
|
|
35731
36011
|
}).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
|
|
35732
|
-
|
|
36012
|
+
logger28.debug("Listed available components", {
|
|
35733
36013
|
level,
|
|
35734
36014
|
count: components.length
|
|
35735
36015
|
});
|
|
@@ -35747,7 +36027,7 @@ class CharacterService {
|
|
|
35747
36027
|
}
|
|
35748
36028
|
}
|
|
35749
36029
|
});
|
|
35750
|
-
|
|
36030
|
+
logger28.debug("Retrieved character", { userId: user.id, found: Boolean(pc) });
|
|
35751
36031
|
return pc ?? null;
|
|
35752
36032
|
}
|
|
35753
36033
|
async getByUserId(userId) {
|
|
@@ -35762,7 +36042,7 @@ class CharacterService {
|
|
|
35762
36042
|
}
|
|
35763
36043
|
}
|
|
35764
36044
|
});
|
|
35765
|
-
|
|
36045
|
+
logger28.debug("Retrieved character by ID", { userId, found: Boolean(pc) });
|
|
35766
36046
|
return pc ?? null;
|
|
35767
36047
|
}
|
|
35768
36048
|
async create(input, user) {
|
|
@@ -35777,13 +36057,13 @@ class CharacterService {
|
|
|
35777
36057
|
}
|
|
35778
36058
|
const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
|
|
35779
36059
|
if (!characterRow) {
|
|
35780
|
-
|
|
36060
|
+
logger28.error("Character insert returned no rows", { userId: user.id });
|
|
35781
36061
|
throw new InternalError("Failed to create character in database");
|
|
35782
36062
|
}
|
|
35783
36063
|
await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
|
|
35784
36064
|
return characterRow;
|
|
35785
36065
|
});
|
|
35786
|
-
|
|
36066
|
+
logger28.info("Created character", { userId: user.id, characterId: result.id });
|
|
35787
36067
|
return result;
|
|
35788
36068
|
}
|
|
35789
36069
|
async update(input, user) {
|
|
@@ -35795,7 +36075,7 @@ class CharacterService {
|
|
|
35795
36075
|
if (!row) {
|
|
35796
36076
|
throw new NotFoundError("Player character");
|
|
35797
36077
|
}
|
|
35798
|
-
|
|
36078
|
+
logger28.info("Updated character", {
|
|
35799
36079
|
userId: user.id,
|
|
35800
36080
|
characterId: row.id,
|
|
35801
36081
|
updatedFields: Object.keys(input)
|
|
@@ -35817,7 +36097,7 @@ class CharacterService {
|
|
|
35817
36097
|
const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
|
|
35818
36098
|
const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
|
|
35819
36099
|
if (!validation.isValid) {
|
|
35820
|
-
|
|
36100
|
+
logger28.warn("Accessory validation failed", {
|
|
35821
36101
|
userId: user.id,
|
|
35822
36102
|
slot,
|
|
35823
36103
|
accessoryComponentId,
|
|
@@ -35833,14 +36113,14 @@ class CharacterService {
|
|
|
35833
36113
|
slot
|
|
35834
36114
|
}).returning();
|
|
35835
36115
|
if (!result) {
|
|
35836
|
-
|
|
36116
|
+
logger28.error("Accessory insert returned no rows", {
|
|
35837
36117
|
userId: user.id,
|
|
35838
36118
|
slot,
|
|
35839
36119
|
accessoryComponentId
|
|
35840
36120
|
});
|
|
35841
36121
|
throw new InternalError("Failed to equip accessory");
|
|
35842
36122
|
}
|
|
35843
|
-
|
|
36123
|
+
logger28.info("Equipped accessory", {
|
|
35844
36124
|
userId: user.id,
|
|
35845
36125
|
slot,
|
|
35846
36126
|
accessoryComponentId
|
|
@@ -35861,7 +36141,7 @@ class CharacterService {
|
|
|
35861
36141
|
const playerLevel = userLevel?.currentLevel ?? 1;
|
|
35862
36142
|
const validation = validateAccessoryRemoval(slot, playerLevel);
|
|
35863
36143
|
if (!validation.isValid) {
|
|
35864
|
-
|
|
36144
|
+
logger28.warn("Accessory removal validation failed", {
|
|
35865
36145
|
userId: user.id,
|
|
35866
36146
|
slot,
|
|
35867
36147
|
playerLevel,
|
|
@@ -35870,17 +36150,17 @@ class CharacterService {
|
|
|
35870
36150
|
throw new ValidationError(validation.error ?? "Invalid accessory removal");
|
|
35871
36151
|
}
|
|
35872
36152
|
await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
|
|
35873
|
-
|
|
36153
|
+
logger28.info("Removed accessory", { userId: user.id, slot });
|
|
35874
36154
|
}
|
|
35875
36155
|
}
|
|
35876
|
-
var
|
|
36156
|
+
var logger28;
|
|
35877
36157
|
var init_character_service = __esm(() => {
|
|
35878
36158
|
init_drizzle_orm();
|
|
35879
36159
|
init_tables_index();
|
|
35880
36160
|
init_src2();
|
|
35881
36161
|
init_errors();
|
|
35882
36162
|
init_accessory_util();
|
|
35883
|
-
|
|
36163
|
+
logger28 = log.scope("CharacterService");
|
|
35884
36164
|
});
|
|
35885
36165
|
|
|
35886
36166
|
// ../api-core/src/services/currency.service.ts
|
|
@@ -35892,7 +36172,7 @@ class CurrencyService {
|
|
|
35892
36172
|
async list() {
|
|
35893
36173
|
const db2 = this.deps.db;
|
|
35894
36174
|
const allCurrencies = await db2.query.currencies.findMany();
|
|
35895
|
-
|
|
36175
|
+
logger29.debug("Listed currencies", { count: allCurrencies.length });
|
|
35896
36176
|
return allCurrencies;
|
|
35897
36177
|
}
|
|
35898
36178
|
async getById(currencyId) {
|
|
@@ -35903,7 +36183,7 @@ class CurrencyService {
|
|
|
35903
36183
|
if (!currency) {
|
|
35904
36184
|
throw new NotFoundError("Currency", currencyId);
|
|
35905
36185
|
}
|
|
35906
|
-
|
|
36186
|
+
logger29.debug("Retrieved currency", { currencyId });
|
|
35907
36187
|
return currency;
|
|
35908
36188
|
}
|
|
35909
36189
|
async create(data) {
|
|
@@ -35911,13 +36191,13 @@ class CurrencyService {
|
|
|
35911
36191
|
try {
|
|
35912
36192
|
const [newCurrency] = await db2.insert(currencies).values(data).returning();
|
|
35913
36193
|
if (!newCurrency) {
|
|
35914
|
-
|
|
36194
|
+
logger29.error("Currency insert returned no rows", {
|
|
35915
36195
|
itemId: data.itemId,
|
|
35916
36196
|
symbol: data.symbol
|
|
35917
36197
|
});
|
|
35918
36198
|
throw new InternalError("Failed to create currency");
|
|
35919
36199
|
}
|
|
35920
|
-
|
|
36200
|
+
logger29.info("Created currency", {
|
|
35921
36201
|
currencyId: newCurrency.id,
|
|
35922
36202
|
itemId: newCurrency.itemId,
|
|
35923
36203
|
symbol: newCurrency.symbol,
|
|
@@ -35946,7 +36226,7 @@ class CurrencyService {
|
|
|
35946
36226
|
if (!updatedCurrency) {
|
|
35947
36227
|
throw new NotFoundError("Currency", currencyId);
|
|
35948
36228
|
}
|
|
35949
|
-
|
|
36229
|
+
logger29.info("Updated currency", {
|
|
35950
36230
|
currencyId: updatedCurrency.id,
|
|
35951
36231
|
updatedFields: Object.keys(data)
|
|
35952
36232
|
});
|
|
@@ -35972,16 +36252,16 @@ class CurrencyService {
|
|
|
35972
36252
|
if (result.length === 0) {
|
|
35973
36253
|
throw new NotFoundError("Currency", currencyId);
|
|
35974
36254
|
}
|
|
35975
|
-
|
|
36255
|
+
logger29.info("Deleted currency", { currencyId });
|
|
35976
36256
|
}
|
|
35977
36257
|
}
|
|
35978
|
-
var
|
|
36258
|
+
var logger29;
|
|
35979
36259
|
var init_currency_service = __esm(() => {
|
|
35980
36260
|
init_drizzle_orm();
|
|
35981
36261
|
init_tables_index();
|
|
35982
36262
|
init_src2();
|
|
35983
36263
|
init_errors();
|
|
35984
|
-
|
|
36264
|
+
logger29 = log.scope("CurrencyService");
|
|
35985
36265
|
});
|
|
35986
36266
|
|
|
35987
36267
|
// ../api-core/src/services/logs.service.ts
|
|
@@ -36000,11 +36280,11 @@ class LogsService {
|
|
|
36000
36280
|
if (!game) {
|
|
36001
36281
|
throw new NotFoundError("Game", slug2);
|
|
36002
36282
|
}
|
|
36003
|
-
|
|
36283
|
+
logger30.info("Admin accessing game logs", { adminId: user.id, slug: slug2, sstStage });
|
|
36004
36284
|
} else {
|
|
36005
36285
|
const isApprovedDev = user.developerStatus === "approved";
|
|
36006
36286
|
if (!isApprovedDev) {
|
|
36007
|
-
|
|
36287
|
+
logger30.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
|
|
36008
36288
|
throw new AccessDeniedError("Must be an approved developer");
|
|
36009
36289
|
}
|
|
36010
36290
|
const game = await db2.query.games.findFirst({
|
|
@@ -36019,7 +36299,7 @@ class LogsService {
|
|
|
36019
36299
|
columns: { id: true }
|
|
36020
36300
|
});
|
|
36021
36301
|
if (!membership) {
|
|
36022
|
-
|
|
36302
|
+
logger30.warn("Developer attempted access to unowned game logs", {
|
|
36023
36303
|
userId: user.id,
|
|
36024
36304
|
slug: slug2
|
|
36025
36305
|
});
|
|
@@ -36028,7 +36308,7 @@ class LogsService {
|
|
|
36028
36308
|
}
|
|
36029
36309
|
const workerId = getDeploymentId(slug2, sstStage);
|
|
36030
36310
|
const token = await this.deps.mintLogStreamToken(user.id, workerId);
|
|
36031
|
-
|
|
36311
|
+
logger30.debug("Generated log stream token", {
|
|
36032
36312
|
userId: user.id,
|
|
36033
36313
|
slug: slug2,
|
|
36034
36314
|
workerId
|
|
@@ -36036,14 +36316,14 @@ class LogsService {
|
|
|
36036
36316
|
return { token, workerId };
|
|
36037
36317
|
}
|
|
36038
36318
|
}
|
|
36039
|
-
var
|
|
36319
|
+
var logger30;
|
|
36040
36320
|
var init_logs_service = __esm(() => {
|
|
36041
36321
|
init_drizzle_orm();
|
|
36042
36322
|
init_tables_index();
|
|
36043
36323
|
init_src2();
|
|
36044
36324
|
init_errors();
|
|
36045
36325
|
init_deployment_util();
|
|
36046
|
-
|
|
36326
|
+
logger30 = log.scope("LogsService");
|
|
36047
36327
|
});
|
|
36048
36328
|
|
|
36049
36329
|
// ../api-core/src/services/lti.service.ts
|
|
@@ -36096,7 +36376,7 @@ class MapService {
|
|
|
36096
36376
|
if (!mapDetails) {
|
|
36097
36377
|
throw new NotFoundError("Map", identifier);
|
|
36098
36378
|
}
|
|
36099
|
-
|
|
36379
|
+
logger31.debug("Retrieved map", { identifier });
|
|
36100
36380
|
return mapDetails;
|
|
36101
36381
|
}
|
|
36102
36382
|
async getElements(mapId) {
|
|
@@ -36112,7 +36392,7 @@ class MapService {
|
|
|
36112
36392
|
}
|
|
36113
36393
|
}
|
|
36114
36394
|
});
|
|
36115
|
-
|
|
36395
|
+
logger31.debug("Retrieved elements", { mapId, count: elements.length });
|
|
36116
36396
|
return elements;
|
|
36117
36397
|
}
|
|
36118
36398
|
async getObjects(mapId, userId) {
|
|
@@ -36133,7 +36413,7 @@ class MapService {
|
|
|
36133
36413
|
}
|
|
36134
36414
|
}
|
|
36135
36415
|
});
|
|
36136
|
-
|
|
36416
|
+
logger31.debug("Retrieved objects", { mapId, userId, count: objects.length });
|
|
36137
36417
|
return objects.map((object) => this.formatMapObjectWithItem(object));
|
|
36138
36418
|
}
|
|
36139
36419
|
async createObject(mapId, data, user) {
|
|
@@ -36160,7 +36440,7 @@ class MapService {
|
|
|
36160
36440
|
throw new NotFoundError("Item", data.itemId);
|
|
36161
36441
|
}
|
|
36162
36442
|
if (!item.isPlaceable) {
|
|
36163
|
-
|
|
36443
|
+
logger31.warn("Attempted to place non-placeable item", {
|
|
36164
36444
|
userId: user.id,
|
|
36165
36445
|
itemId: data.itemId,
|
|
36166
36446
|
mapId
|
|
@@ -36174,7 +36454,7 @@ class MapService {
|
|
|
36174
36454
|
};
|
|
36175
36455
|
const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
|
|
36176
36456
|
if (!createdObject) {
|
|
36177
|
-
|
|
36457
|
+
logger31.error("Map object insert returned no rows", {
|
|
36178
36458
|
userId: user.id,
|
|
36179
36459
|
mapId,
|
|
36180
36460
|
itemId: data.itemId
|
|
@@ -36198,12 +36478,12 @@ class MapService {
|
|
|
36198
36478
|
}
|
|
36199
36479
|
});
|
|
36200
36480
|
if (!objectWithItem) {
|
|
36201
|
-
|
|
36481
|
+
logger31.error("Map object query after insert returned no rows", {
|
|
36202
36482
|
objectId: createdObject.id
|
|
36203
36483
|
});
|
|
36204
36484
|
throw new InternalError("Failed to retrieve created object");
|
|
36205
36485
|
}
|
|
36206
|
-
|
|
36486
|
+
logger31.info("Created object", {
|
|
36207
36487
|
userId: user.id,
|
|
36208
36488
|
mapId,
|
|
36209
36489
|
objectId: createdObject.id,
|
|
@@ -36227,7 +36507,7 @@ class MapService {
|
|
|
36227
36507
|
if (result.length === 0) {
|
|
36228
36508
|
throw new NotFoundError("MapObject", objectId);
|
|
36229
36509
|
}
|
|
36230
|
-
|
|
36510
|
+
logger31.info("Deleted object", {
|
|
36231
36511
|
userId: user.id,
|
|
36232
36512
|
mapId,
|
|
36233
36513
|
objectId
|
|
@@ -36256,13 +36536,13 @@ class MapService {
|
|
|
36256
36536
|
};
|
|
36257
36537
|
}
|
|
36258
36538
|
}
|
|
36259
|
-
var
|
|
36539
|
+
var logger31;
|
|
36260
36540
|
var init_map_service = __esm(() => {
|
|
36261
36541
|
init_drizzle_orm();
|
|
36262
36542
|
init_tables_index();
|
|
36263
36543
|
init_src2();
|
|
36264
36544
|
init_errors();
|
|
36265
|
-
|
|
36545
|
+
logger31 = log.scope("MapService");
|
|
36266
36546
|
});
|
|
36267
36547
|
|
|
36268
36548
|
// ../api-core/src/services/realtime.service.ts
|
|
@@ -36297,20 +36577,20 @@ class RealtimeService {
|
|
|
36297
36577
|
}
|
|
36298
36578
|
const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
|
|
36299
36579
|
const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
|
|
36300
|
-
|
|
36580
|
+
logger32.info("Generated token", {
|
|
36301
36581
|
userId: user.id,
|
|
36302
36582
|
gameId: resolvedGameId || "global"
|
|
36303
36583
|
});
|
|
36304
36584
|
return { token };
|
|
36305
36585
|
}
|
|
36306
36586
|
}
|
|
36307
|
-
var
|
|
36587
|
+
var logger32;
|
|
36308
36588
|
var init_realtime_service = __esm(() => {
|
|
36309
36589
|
init_drizzle_orm();
|
|
36310
36590
|
init_tables_index();
|
|
36311
36591
|
init_src2();
|
|
36312
36592
|
init_errors();
|
|
36313
|
-
|
|
36593
|
+
logger32 = log.scope("RealtimeService");
|
|
36314
36594
|
});
|
|
36315
36595
|
|
|
36316
36596
|
// ../api-core/src/services/session.service.ts
|
|
@@ -36345,10 +36625,10 @@ class SessionService {
|
|
|
36345
36625
|
};
|
|
36346
36626
|
const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
|
|
36347
36627
|
if (!newSession?.sessionId) {
|
|
36348
|
-
|
|
36628
|
+
logger33.error("Game session insert returned no rows", { userId, gameId });
|
|
36349
36629
|
throw new InternalError("Failed to create game session");
|
|
36350
36630
|
}
|
|
36351
|
-
|
|
36631
|
+
logger33.info("Started new session", {
|
|
36352
36632
|
sessionId: newSession.sessionId,
|
|
36353
36633
|
gameId,
|
|
36354
36634
|
userId
|
|
@@ -36369,23 +36649,23 @@ class SessionService {
|
|
|
36369
36649
|
return { success: true, message: "Session already ended" };
|
|
36370
36650
|
}
|
|
36371
36651
|
await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
|
|
36372
|
-
|
|
36652
|
+
logger33.info("Ended session", { sessionId, gameId, userId });
|
|
36373
36653
|
return { success: true };
|
|
36374
36654
|
}
|
|
36375
36655
|
async mintToken(gameIdOrSlug, userId) {
|
|
36376
36656
|
const gameId = await this.resolveGameId(gameIdOrSlug);
|
|
36377
36657
|
const result = await this.deps.mintGameToken(gameId, userId);
|
|
36378
|
-
|
|
36658
|
+
logger33.debug("Minted game token", { gameId, userId });
|
|
36379
36659
|
return result;
|
|
36380
36660
|
}
|
|
36381
36661
|
}
|
|
36382
|
-
var
|
|
36662
|
+
var logger33;
|
|
36383
36663
|
var init_session_service = __esm(() => {
|
|
36384
36664
|
init_drizzle_orm();
|
|
36385
36665
|
init_tables_index();
|
|
36386
36666
|
init_src2();
|
|
36387
36667
|
init_errors();
|
|
36388
|
-
|
|
36668
|
+
logger33 = log.scope("SessionService");
|
|
36389
36669
|
});
|
|
36390
36670
|
|
|
36391
36671
|
// ../api-core/src/services/shop.service.ts
|
|
@@ -36431,7 +36711,7 @@ class ShopService {
|
|
|
36431
36711
|
const shopItems = [];
|
|
36432
36712
|
for (const listing of listingsWithRelations) {
|
|
36433
36713
|
if (!listing.item || !listing.currency) {
|
|
36434
|
-
|
|
36714
|
+
logger34.warn("Listing missing item or currency, skipping", {
|
|
36435
36715
|
listingId: listing.id
|
|
36436
36716
|
});
|
|
36437
36717
|
} else {
|
|
@@ -36448,7 +36728,7 @@ class ShopService {
|
|
|
36448
36728
|
});
|
|
36449
36729
|
}
|
|
36450
36730
|
}
|
|
36451
|
-
|
|
36731
|
+
logger34.debug("Retrieved shop view", {
|
|
36452
36732
|
userId: user.id,
|
|
36453
36733
|
itemCount: shopItems.length,
|
|
36454
36734
|
currencyCount: shopCurrencies.length
|
|
@@ -36459,12 +36739,12 @@ class ShopService {
|
|
|
36459
36739
|
};
|
|
36460
36740
|
}
|
|
36461
36741
|
}
|
|
36462
|
-
var
|
|
36742
|
+
var logger34;
|
|
36463
36743
|
var init_shop_service = __esm(() => {
|
|
36464
36744
|
init_drizzle_orm();
|
|
36465
36745
|
init_tables_index();
|
|
36466
36746
|
init_src2();
|
|
36467
|
-
|
|
36747
|
+
logger34 = log.scope("ShopService");
|
|
36468
36748
|
});
|
|
36469
36749
|
|
|
36470
36750
|
// ../api-core/src/services/sprite.service.ts
|
|
@@ -36481,17 +36761,17 @@ class SpriteService {
|
|
|
36481
36761
|
if (!template) {
|
|
36482
36762
|
throw new NotFoundError("SpriteTemplate", slug2);
|
|
36483
36763
|
}
|
|
36484
|
-
|
|
36764
|
+
logger35.debug("Retrieved sprite", { slug: slug2 });
|
|
36485
36765
|
return template;
|
|
36486
36766
|
}
|
|
36487
36767
|
}
|
|
36488
|
-
var
|
|
36768
|
+
var logger35;
|
|
36489
36769
|
var init_sprite_service = __esm(() => {
|
|
36490
36770
|
init_drizzle_orm();
|
|
36491
36771
|
init_tables_index();
|
|
36492
36772
|
init_src2();
|
|
36493
36773
|
init_errors();
|
|
36494
|
-
|
|
36774
|
+
logger35 = log.scope("SpriteService");
|
|
36495
36775
|
});
|
|
36496
36776
|
|
|
36497
36777
|
// ../api-core/src/services/user.service.ts
|
|
@@ -36506,12 +36786,12 @@ class UserService {
|
|
|
36506
36786
|
where: eq(users.id, user.id)
|
|
36507
36787
|
});
|
|
36508
36788
|
if (!userData) {
|
|
36509
|
-
|
|
36789
|
+
logger36.error("User not found", { userId: user.id });
|
|
36510
36790
|
throw new NotFoundError("User", user.id);
|
|
36511
36791
|
}
|
|
36512
36792
|
const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
|
|
36513
36793
|
if (gameId) {
|
|
36514
|
-
|
|
36794
|
+
logger36.debug("Fetched user profile (game context)", { userId: user.id, gameId });
|
|
36515
36795
|
return {
|
|
36516
36796
|
id: userData.id,
|
|
36517
36797
|
name: userData.name,
|
|
@@ -36524,7 +36804,7 @@ class UserService {
|
|
|
36524
36804
|
const timebackAccount = await db2.query.accounts.findFirst({
|
|
36525
36805
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
36526
36806
|
});
|
|
36527
|
-
|
|
36807
|
+
logger36.debug("Fetched user profile (platform context)", { userId: user.id });
|
|
36528
36808
|
return {
|
|
36529
36809
|
id: userData.id,
|
|
36530
36810
|
name: userData.name,
|
|
@@ -36547,7 +36827,7 @@ class UserService {
|
|
|
36547
36827
|
columns: { name: true }
|
|
36548
36828
|
});
|
|
36549
36829
|
if (!userData) {
|
|
36550
|
-
|
|
36830
|
+
logger36.error("Demo user not found", { userId });
|
|
36551
36831
|
throw new NotFoundError("User", userId);
|
|
36552
36832
|
}
|
|
36553
36833
|
return {
|
|
@@ -36561,10 +36841,10 @@ class UserService {
|
|
|
36561
36841
|
updatedAt: new Date
|
|
36562
36842
|
}).where(eq(users.id, userId)).returning({ name: users.name });
|
|
36563
36843
|
if (!updatedUser) {
|
|
36564
|
-
|
|
36844
|
+
logger36.error("Demo user not found for profile update", { userId });
|
|
36565
36845
|
throw new NotFoundError("User", userId);
|
|
36566
36846
|
}
|
|
36567
|
-
|
|
36847
|
+
logger36.debug("Updated demo profile", { userId, displayName });
|
|
36568
36848
|
return {
|
|
36569
36849
|
displayName: updatedUser.name,
|
|
36570
36850
|
isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
|
|
@@ -36577,7 +36857,7 @@ class UserService {
|
|
|
36577
36857
|
]);
|
|
36578
36858
|
const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
36579
36859
|
const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
36580
|
-
|
|
36860
|
+
logger36.debug("Fetched Timeback data", {
|
|
36581
36861
|
timebackId,
|
|
36582
36862
|
role,
|
|
36583
36863
|
enrollmentCount: enrollments.length,
|
|
@@ -36586,9 +36866,9 @@ class UserService {
|
|
|
36586
36866
|
return { id: timebackId, role, enrollments, organizations };
|
|
36587
36867
|
}
|
|
36588
36868
|
async fetchStudentProfile(timebackId) {
|
|
36589
|
-
|
|
36869
|
+
logger36.debug("Fetching student profile", { timebackId });
|
|
36590
36870
|
if (!this.deps.timeback) {
|
|
36591
|
-
|
|
36871
|
+
logger36.warn("Timeback client not available");
|
|
36592
36872
|
return { role: "student", organizations: [] };
|
|
36593
36873
|
}
|
|
36594
36874
|
try {
|
|
@@ -36616,14 +36896,14 @@ class UserService {
|
|
|
36616
36896
|
}
|
|
36617
36897
|
return { role, organizations: [...orgMap.values()] };
|
|
36618
36898
|
} catch (error) {
|
|
36619
|
-
|
|
36899
|
+
logger36.warn("Failed to fetch student profile", { error, timebackId });
|
|
36620
36900
|
return { role: "student", organizations: [] };
|
|
36621
36901
|
}
|
|
36622
36902
|
}
|
|
36623
36903
|
async fetchEnrollments(timebackId) {
|
|
36624
|
-
|
|
36904
|
+
logger36.debug("Fetching enrollments", { timebackId });
|
|
36625
36905
|
if (!this.deps.timeback) {
|
|
36626
|
-
|
|
36906
|
+
logger36.warn("Timeback client not available");
|
|
36627
36907
|
return [];
|
|
36628
36908
|
}
|
|
36629
36909
|
try {
|
|
@@ -36644,7 +36924,7 @@ class UserService {
|
|
|
36644
36924
|
orgId: courseToSchool.get(i2.courseId)
|
|
36645
36925
|
}));
|
|
36646
36926
|
} catch (error) {
|
|
36647
|
-
|
|
36927
|
+
logger36.warn("Failed to fetch enrollments", { error, timebackId });
|
|
36648
36928
|
return [];
|
|
36649
36929
|
}
|
|
36650
36930
|
}
|
|
@@ -36659,14 +36939,14 @@ class UserService {
|
|
|
36659
36939
|
return organizations.filter((o) => enrollmentOrgIds.has(o.id));
|
|
36660
36940
|
}
|
|
36661
36941
|
}
|
|
36662
|
-
var
|
|
36942
|
+
var logger36;
|
|
36663
36943
|
var init_user_service = __esm(() => {
|
|
36664
36944
|
init_drizzle_orm();
|
|
36665
36945
|
init_src();
|
|
36666
36946
|
init_tables_index();
|
|
36667
36947
|
init_src2();
|
|
36668
36948
|
init_errors();
|
|
36669
|
-
|
|
36949
|
+
logger36 = log.scope("UserService");
|
|
36670
36950
|
});
|
|
36671
36951
|
|
|
36672
36952
|
// ../api-core/src/services/verify.service.ts
|
|
@@ -36676,16 +36956,16 @@ class VerifyService {
|
|
|
36676
36956
|
this.deps = deps;
|
|
36677
36957
|
}
|
|
36678
36958
|
async verifyGameToken(token) {
|
|
36679
|
-
|
|
36959
|
+
logger37.debug("Verifying game token");
|
|
36680
36960
|
const payload = await this.deps.validateGameToken(token);
|
|
36681
36961
|
if (!payload) {
|
|
36682
|
-
|
|
36962
|
+
logger37.warn("Invalid or expired game token presented");
|
|
36683
36963
|
throw new ValidationError("Invalid or expired token");
|
|
36684
36964
|
}
|
|
36685
36965
|
const gameId = payload.sub;
|
|
36686
36966
|
const userId = payload.uid;
|
|
36687
36967
|
if (typeof gameId !== "string" || typeof userId !== "string") {
|
|
36688
|
-
|
|
36968
|
+
logger37.warn("Game token missing required claims", {
|
|
36689
36969
|
hasGameId: typeof gameId === "string",
|
|
36690
36970
|
hasUserId: typeof userId === "string"
|
|
36691
36971
|
});
|
|
@@ -36696,7 +36976,7 @@ class VerifyService {
|
|
|
36696
36976
|
where: eq(users.id, userId)
|
|
36697
36977
|
});
|
|
36698
36978
|
if (!userData) {
|
|
36699
|
-
|
|
36979
|
+
logger37.error("User not found for valid token", {
|
|
36700
36980
|
userId
|
|
36701
36981
|
});
|
|
36702
36982
|
throw new NotFoundError("User", userId);
|
|
@@ -36710,7 +36990,7 @@ class VerifyService {
|
|
|
36710
36990
|
family_name: undefined,
|
|
36711
36991
|
timeback_id: userData.timebackId || undefined
|
|
36712
36992
|
};
|
|
36713
|
-
|
|
36993
|
+
logger37.info("Token verified", { gameId, userId });
|
|
36714
36994
|
return {
|
|
36715
36995
|
claims: payload,
|
|
36716
36996
|
gameId,
|
|
@@ -36718,13 +36998,13 @@ class VerifyService {
|
|
|
36718
36998
|
};
|
|
36719
36999
|
}
|
|
36720
37000
|
}
|
|
36721
|
-
var
|
|
37001
|
+
var logger37;
|
|
36722
37002
|
var init_verify_service = __esm(() => {
|
|
36723
37003
|
init_drizzle_orm();
|
|
36724
37004
|
init_tables_index();
|
|
36725
37005
|
init_src2();
|
|
36726
37006
|
init_errors();
|
|
36727
|
-
|
|
37007
|
+
logger37 = log.scope("VerifyService");
|
|
36728
37008
|
});
|
|
36729
37009
|
|
|
36730
37010
|
// ../api-core/src/services/factory/standalone.ts
|
|
@@ -41842,7 +42122,7 @@ var humanize = (times) => {
|
|
|
41842
42122
|
}
|
|
41843
42123
|
}
|
|
41844
42124
|
return `${status}`;
|
|
41845
|
-
},
|
|
42125
|
+
}, logger38 = (fn = console.log) => {
|
|
41846
42126
|
return async function logger2(c, next) {
|
|
41847
42127
|
const { method, url: url2 } = c.req;
|
|
41848
42128
|
const path = url2.slice(url2.indexOf("/", 8));
|
|
@@ -42023,7 +42303,7 @@ function createApp(db2, options) {
|
|
|
42023
42303
|
const app = new Hono2;
|
|
42024
42304
|
app.use("*", cors({ origin: "*", credentials: true }));
|
|
42025
42305
|
if (options.verbose && !options.quiet) {
|
|
42026
|
-
app.use("*",
|
|
42306
|
+
app.use("*", logger38());
|
|
42027
42307
|
}
|
|
42028
42308
|
app.use("/api/*", async (c, next) => {
|
|
42029
42309
|
c.set("db", db2);
|
|
@@ -48456,12 +48736,12 @@ var init_session2 = __esm(() => {
|
|
|
48456
48736
|
init_utils();
|
|
48457
48737
|
init_dist5();
|
|
48458
48738
|
PglitePreparedQuery = class PglitePreparedQuery extends PgPreparedQuery {
|
|
48459
|
-
constructor(client, queryString, params,
|
|
48739
|
+
constructor(client, queryString, params, logger39, fields, name3, _isResponseInArrayMode, customResultMapper) {
|
|
48460
48740
|
super({ sql: queryString, params });
|
|
48461
48741
|
this.client = client;
|
|
48462
48742
|
this.queryString = queryString;
|
|
48463
48743
|
this.params = params;
|
|
48464
|
-
this.logger =
|
|
48744
|
+
this.logger = logger39;
|
|
48465
48745
|
this.fields = fields;
|
|
48466
48746
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
48467
48747
|
this.customResultMapper = customResultMapper;
|
|
@@ -48565,11 +48845,11 @@ var init_session2 = __esm(() => {
|
|
|
48565
48845
|
// ../../node_modules/.bun/drizzle-orm@0.42.0+f8aef3f54a4d48e2/node_modules/drizzle-orm/pglite/driver.js
|
|
48566
48846
|
function construct(client, config2 = {}) {
|
|
48567
48847
|
const dialect2 = new PgDialect({ casing: config2.casing });
|
|
48568
|
-
let
|
|
48848
|
+
let logger39;
|
|
48569
48849
|
if (config2.logger === true) {
|
|
48570
|
-
|
|
48850
|
+
logger39 = new DefaultLogger;
|
|
48571
48851
|
} else if (config2.logger !== false) {
|
|
48572
|
-
|
|
48852
|
+
logger39 = config2.logger;
|
|
48573
48853
|
}
|
|
48574
48854
|
let schema2;
|
|
48575
48855
|
if (config2.schema) {
|
|
@@ -48580,7 +48860,7 @@ function construct(client, config2 = {}) {
|
|
|
48580
48860
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
48581
48861
|
};
|
|
48582
48862
|
}
|
|
48583
|
-
const driver = new PgliteDriver(client, dialect2, { logger:
|
|
48863
|
+
const driver = new PgliteDriver(client, dialect2, { logger: logger39 });
|
|
48584
48864
|
const session2 = driver.createSession(schema2);
|
|
48585
48865
|
const db2 = new PgliteDatabase(dialect2, session2, schema2);
|
|
48586
48866
|
db2.$client = client;
|
|
@@ -94794,8 +95074,8 @@ var init_currencies = __esm(() => {
|
|
|
94794
95074
|
});
|
|
94795
95075
|
|
|
94796
95076
|
// src/lib/logging/adapter.ts
|
|
94797
|
-
function setLogger(
|
|
94798
|
-
customLogger =
|
|
95077
|
+
function setLogger(logger39) {
|
|
95078
|
+
customLogger = logger39;
|
|
94799
95079
|
}
|
|
94800
95080
|
function getLogger() {
|
|
94801
95081
|
if (customLogger) {
|
|
@@ -94807,10 +95087,10 @@ function getLogger() {
|
|
|
94807
95087
|
error: (msg) => console.error(msg)
|
|
94808
95088
|
};
|
|
94809
95089
|
}
|
|
94810
|
-
var customLogger,
|
|
95090
|
+
var customLogger, logger39;
|
|
94811
95091
|
var init_adapter = __esm(() => {
|
|
94812
95092
|
init_config();
|
|
94813
|
-
|
|
95093
|
+
logger39 = {
|
|
94814
95094
|
info: (msg) => {
|
|
94815
95095
|
if (customLogger || !config.embedded) {
|
|
94816
95096
|
getLogger().info(msg);
|
|
@@ -94900,7 +95180,7 @@ async function seedCoreGames(db2) {
|
|
|
94900
95180
|
role: "owner"
|
|
94901
95181
|
}).onConflictDoNothing();
|
|
94902
95182
|
} catch (error2) {
|
|
94903
|
-
|
|
95183
|
+
logger39.error(`Error seeding core game '${gameData.slug}': ${error2}`);
|
|
94904
95184
|
}
|
|
94905
95185
|
}
|
|
94906
95186
|
}
|
|
@@ -94950,7 +95230,7 @@ async function seedCurrentProjectGame(db2, project) {
|
|
|
94950
95230
|
}
|
|
94951
95231
|
return newGame;
|
|
94952
95232
|
} catch (error2) {
|
|
94953
|
-
|
|
95233
|
+
logger39.error(`❌ Error seeding project game: ${error2}`);
|
|
94954
95234
|
throw error2;
|
|
94955
95235
|
}
|
|
94956
95236
|
}
|
|
@@ -95743,7 +96023,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95743
96023
|
where: eq(users.id, existingAccount.userId)
|
|
95744
96024
|
});
|
|
95745
96025
|
if (user) {
|
|
95746
|
-
|
|
96026
|
+
logger40.info("Found user by LTI account", {
|
|
95747
96027
|
userId: user.id,
|
|
95748
96028
|
ltiTimebackId
|
|
95749
96029
|
});
|
|
@@ -95772,13 +96052,13 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95772
96052
|
updatedAt: new Date
|
|
95773
96053
|
}).returning({ id: accounts.id });
|
|
95774
96054
|
if (!account) {
|
|
95775
|
-
|
|
96055
|
+
logger40.error("LTI account link insert returned no rows", {
|
|
95776
96056
|
userId: existingUser.id,
|
|
95777
96057
|
ltiTimebackId
|
|
95778
96058
|
});
|
|
95779
96059
|
throw new InternalError("Failed to link LTI account");
|
|
95780
96060
|
}
|
|
95781
|
-
|
|
96061
|
+
logger40.info("Linked LTI account to existing user", {
|
|
95782
96062
|
userId: existingUser.id,
|
|
95783
96063
|
ltiTimebackId
|
|
95784
96064
|
});
|
|
@@ -95798,7 +96078,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95798
96078
|
updatedAt: new Date
|
|
95799
96079
|
}).returning();
|
|
95800
96080
|
if (!insertedUser) {
|
|
95801
|
-
|
|
96081
|
+
logger40.error("LTI user insert returned no rows", { email, ltiTimebackId });
|
|
95802
96082
|
throw new InternalError("Failed to create user");
|
|
95803
96083
|
}
|
|
95804
96084
|
await tx.insert(accounts).values({
|
|
@@ -95813,7 +96093,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95813
96093
|
createdAt: new Date,
|
|
95814
96094
|
updatedAt: new Date
|
|
95815
96095
|
});
|
|
95816
|
-
|
|
96096
|
+
logger40.info("Provisioned new user from LTI", {
|
|
95817
96097
|
userId: insertedUser.id,
|
|
95818
96098
|
ltiTimebackId
|
|
95819
96099
|
});
|
|
@@ -95821,7 +96101,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95821
96101
|
});
|
|
95822
96102
|
return createdUser;
|
|
95823
96103
|
}
|
|
95824
|
-
var
|
|
96104
|
+
var logger40;
|
|
95825
96105
|
var init_lti_provisioning = __esm(() => {
|
|
95826
96106
|
init_drizzle_orm();
|
|
95827
96107
|
init_src();
|
|
@@ -95829,7 +96109,7 @@ var init_lti_provisioning = __esm(() => {
|
|
|
95829
96109
|
init_src2();
|
|
95830
96110
|
init_errors();
|
|
95831
96111
|
init_lti_util();
|
|
95832
|
-
|
|
96112
|
+
logger40 = log.scope("LtiProvisioning");
|
|
95833
96113
|
});
|
|
95834
96114
|
|
|
95835
96115
|
// ../api-core/src/utils/validation.util.ts
|
|
@@ -95877,21 +96157,21 @@ var init_utils11 = __esm(() => {
|
|
|
95877
96157
|
});
|
|
95878
96158
|
|
|
95879
96159
|
// ../api-core/src/controllers/achievement.controller.ts
|
|
95880
|
-
var
|
|
96160
|
+
var logger41, listCurrent, listHistory, postProgress, achievements3;
|
|
95881
96161
|
var init_achievement_controller = __esm(() => {
|
|
95882
96162
|
init_esm();
|
|
95883
96163
|
init_schemas_index();
|
|
95884
96164
|
init_src2();
|
|
95885
96165
|
init_errors();
|
|
95886
96166
|
init_utils11();
|
|
95887
|
-
|
|
96167
|
+
logger41 = log.scope("AchievementController");
|
|
95888
96168
|
listCurrent = requireNonAnonymous(async (ctx) => {
|
|
95889
|
-
|
|
96169
|
+
logger41.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
95890
96170
|
return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
|
|
95891
96171
|
});
|
|
95892
96172
|
listHistory = requireNonAnonymous(async (ctx) => {
|
|
95893
96173
|
const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
|
|
95894
|
-
|
|
96174
|
+
logger41.debug("Listing achievement history", { userId: ctx.user.id, limit });
|
|
95895
96175
|
return ctx.services.achievement.listHistory(ctx.user, limit);
|
|
95896
96176
|
});
|
|
95897
96177
|
postProgress = requireNonAnonymous(async (ctx) => {
|
|
@@ -95902,12 +96182,12 @@ var init_achievement_controller = __esm(() => {
|
|
|
95902
96182
|
} catch (error2) {
|
|
95903
96183
|
if (error2 instanceof exports_external.ZodError) {
|
|
95904
96184
|
const details = formatZodError(error2);
|
|
95905
|
-
|
|
96185
|
+
logger41.warn("Submit achievement progress validation failed", { details });
|
|
95906
96186
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
95907
96187
|
}
|
|
95908
96188
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95909
96189
|
}
|
|
95910
|
-
|
|
96190
|
+
logger41.debug("Submitting progress", {
|
|
95911
96191
|
userId: ctx.user.id,
|
|
95912
96192
|
achievementId: body2.achievementId
|
|
95913
96193
|
});
|
|
@@ -95921,14 +96201,14 @@ var init_achievement_controller = __esm(() => {
|
|
|
95921
96201
|
});
|
|
95922
96202
|
|
|
95923
96203
|
// ../api-core/src/controllers/admin.controller.ts
|
|
95924
|
-
var
|
|
96204
|
+
var logger42, getAllowedOrigins;
|
|
95925
96205
|
var init_admin_controller = __esm(() => {
|
|
95926
96206
|
init_src2();
|
|
95927
96207
|
init_utils11();
|
|
95928
|
-
|
|
96208
|
+
logger42 = log.scope("AdminController");
|
|
95929
96209
|
getAllowedOrigins = requireAdmin(async (ctx) => {
|
|
95930
96210
|
const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
|
|
95931
|
-
|
|
96211
|
+
logger42.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
|
|
95932
96212
|
if (shouldRefresh) {
|
|
95933
96213
|
await ctx.providers.cache.refreshGameOrigins();
|
|
95934
96214
|
}
|
|
@@ -95943,14 +96223,14 @@ var init_admin_controller = __esm(() => {
|
|
|
95943
96223
|
});
|
|
95944
96224
|
|
|
95945
96225
|
// ../api-core/src/controllers/bucket.controller.ts
|
|
95946
|
-
var
|
|
96226
|
+
var logger43, listFiles, getFile, putFile, deleteFile, initiateUpload;
|
|
95947
96227
|
var init_bucket_controller = __esm(() => {
|
|
95948
96228
|
init_esm();
|
|
95949
96229
|
init_schemas_index();
|
|
95950
96230
|
init_src2();
|
|
95951
96231
|
init_errors();
|
|
95952
96232
|
init_utils11();
|
|
95953
|
-
|
|
96233
|
+
logger43 = log.scope("BucketController");
|
|
95954
96234
|
listFiles = requireDeveloper(async (ctx) => {
|
|
95955
96235
|
const slug2 = ctx.params.slug;
|
|
95956
96236
|
if (!slug2) {
|
|
@@ -95958,7 +96238,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95958
96238
|
}
|
|
95959
96239
|
const url2 = ctx.url;
|
|
95960
96240
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
95961
|
-
|
|
96241
|
+
logger43.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
95962
96242
|
const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
|
|
95963
96243
|
return { files };
|
|
95964
96244
|
});
|
|
@@ -95968,7 +96248,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95968
96248
|
if (!slug2 || !key) {
|
|
95969
96249
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
95970
96250
|
}
|
|
95971
|
-
|
|
96251
|
+
logger43.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
|
|
95972
96252
|
const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
|
|
95973
96253
|
return new Response(Buffer.from(object.body), {
|
|
95974
96254
|
status: 200,
|
|
@@ -95987,7 +96267,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95987
96267
|
const arrayBuffer = await ctx.request.arrayBuffer();
|
|
95988
96268
|
const body2 = new Uint8Array(arrayBuffer);
|
|
95989
96269
|
const contentType = ctx.request.headers.get("content-type") || undefined;
|
|
95990
|
-
|
|
96270
|
+
logger43.debug("Uploading file", {
|
|
95991
96271
|
userId: ctx.user.id,
|
|
95992
96272
|
slug: slug2,
|
|
95993
96273
|
key,
|
|
@@ -96003,7 +96283,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
96003
96283
|
if (!slug2 || !key) {
|
|
96004
96284
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
96005
96285
|
}
|
|
96006
|
-
|
|
96286
|
+
logger43.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
|
|
96007
96287
|
await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
|
|
96008
96288
|
return { success: true, key };
|
|
96009
96289
|
});
|
|
@@ -96015,12 +96295,12 @@ var init_bucket_controller = __esm(() => {
|
|
|
96015
96295
|
} catch (error2) {
|
|
96016
96296
|
if (error2 instanceof exports_external.ZodError) {
|
|
96017
96297
|
const details = formatZodError(error2);
|
|
96018
|
-
|
|
96298
|
+
logger43.warn("Initiate upload validation failed", { details });
|
|
96019
96299
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96020
96300
|
}
|
|
96021
96301
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96022
96302
|
}
|
|
96023
|
-
|
|
96303
|
+
logger43.debug("Initiating multipart upload", {
|
|
96024
96304
|
userId: ctx.user.id,
|
|
96025
96305
|
gameId: body2.gameId,
|
|
96026
96306
|
fileName: body2.fileName
|
|
@@ -96037,19 +96317,19 @@ async function listComponents(ctx) {
|
|
|
96037
96317
|
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
96038
96318
|
level = Math.floor(Math.max(0, parsed));
|
|
96039
96319
|
}
|
|
96040
|
-
|
|
96320
|
+
logger44.debug("Listing components", { level });
|
|
96041
96321
|
return ctx.services.character.listAvailableComponents(level);
|
|
96042
96322
|
}
|
|
96043
|
-
var
|
|
96323
|
+
var logger44, get, getByUserId, create, update2, equipAccessory, removeAccessory, character2;
|
|
96044
96324
|
var init_character_controller = __esm(() => {
|
|
96045
96325
|
init_esm();
|
|
96046
96326
|
init_schemas_index();
|
|
96047
96327
|
init_src2();
|
|
96048
96328
|
init_errors();
|
|
96049
96329
|
init_utils11();
|
|
96050
|
-
|
|
96330
|
+
logger44 = log.scope("CharacterController");
|
|
96051
96331
|
get = requireNonAnonymous(async (ctx) => {
|
|
96052
|
-
|
|
96332
|
+
logger44.debug("Getting character", { userId: ctx.user.id });
|
|
96053
96333
|
return ctx.services.character.getByUser(ctx.user);
|
|
96054
96334
|
});
|
|
96055
96335
|
getByUserId = requireNonAnonymous(async (ctx) => {
|
|
@@ -96057,7 +96337,7 @@ var init_character_controller = __esm(() => {
|
|
|
96057
96337
|
if (!userId) {
|
|
96058
96338
|
throw ApiError.badRequest("User ID is required in the URL path");
|
|
96059
96339
|
}
|
|
96060
|
-
|
|
96340
|
+
logger44.debug("Getting character by user ID", { requestedUserId: userId });
|
|
96061
96341
|
return ctx.services.character.getByUserId(userId);
|
|
96062
96342
|
});
|
|
96063
96343
|
create = requireNonAnonymous(async (ctx) => {
|
|
@@ -96068,12 +96348,12 @@ var init_character_controller = __esm(() => {
|
|
|
96068
96348
|
} catch (error2) {
|
|
96069
96349
|
if (error2 instanceof exports_external.ZodError) {
|
|
96070
96350
|
const details = formatZodError(error2);
|
|
96071
|
-
|
|
96351
|
+
logger44.warn("Create character validation failed", { details });
|
|
96072
96352
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96073
96353
|
}
|
|
96074
96354
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96075
96355
|
}
|
|
96076
|
-
|
|
96356
|
+
logger44.debug("Creating character", {
|
|
96077
96357
|
userId: ctx.user.id,
|
|
96078
96358
|
bodyComponentId: body2.bodyComponentId,
|
|
96079
96359
|
hairstyleComponentId: body2.hairstyleComponentId
|
|
@@ -96088,12 +96368,12 @@ var init_character_controller = __esm(() => {
|
|
|
96088
96368
|
} catch (error2) {
|
|
96089
96369
|
if (error2 instanceof exports_external.ZodError) {
|
|
96090
96370
|
const details = formatZodError(error2);
|
|
96091
|
-
|
|
96371
|
+
logger44.warn("Update character validation failed", { details });
|
|
96092
96372
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96093
96373
|
}
|
|
96094
96374
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96095
96375
|
}
|
|
96096
|
-
|
|
96376
|
+
logger44.debug("Updating character", {
|
|
96097
96377
|
userId: ctx.user.id,
|
|
96098
96378
|
bodyComponentId: body2.bodyComponentId,
|
|
96099
96379
|
hairstyleComponentId: body2.hairstyleComponentId,
|
|
@@ -96109,12 +96389,12 @@ var init_character_controller = __esm(() => {
|
|
|
96109
96389
|
} catch (error2) {
|
|
96110
96390
|
if (error2 instanceof exports_external.ZodError) {
|
|
96111
96391
|
const details = formatZodError(error2);
|
|
96112
|
-
|
|
96392
|
+
logger44.warn("Equip accessory validation failed", { details });
|
|
96113
96393
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96114
96394
|
}
|
|
96115
96395
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96116
96396
|
}
|
|
96117
|
-
|
|
96397
|
+
logger44.debug("Equipping accessory", {
|
|
96118
96398
|
userId: ctx.user.id,
|
|
96119
96399
|
slot: body2.slot,
|
|
96120
96400
|
accessoryComponentId: body2.accessoryComponentId
|
|
@@ -96126,7 +96406,7 @@ var init_character_controller = __esm(() => {
|
|
|
96126
96406
|
if (!slot) {
|
|
96127
96407
|
throw ApiError.badRequest("Slot is required in the URL path");
|
|
96128
96408
|
}
|
|
96129
|
-
|
|
96409
|
+
logger44.debug("Removing accessory", { userId: ctx.user.id, slot });
|
|
96130
96410
|
await ctx.services.character.removeAccessory(slot, ctx.user);
|
|
96131
96411
|
return { success: true };
|
|
96132
96412
|
});
|
|
@@ -96142,7 +96422,7 @@ var init_character_controller = __esm(() => {
|
|
|
96142
96422
|
});
|
|
96143
96423
|
|
|
96144
96424
|
// ../api-core/src/controllers/currency.controller.ts
|
|
96145
|
-
var
|
|
96425
|
+
var logger45, list, getById, create2, update3, remove, currencyController;
|
|
96146
96426
|
var init_currency_controller = __esm(() => {
|
|
96147
96427
|
init_esm();
|
|
96148
96428
|
init_schemas_index();
|
|
@@ -96150,9 +96430,9 @@ var init_currency_controller = __esm(() => {
|
|
|
96150
96430
|
init_src4();
|
|
96151
96431
|
init_errors();
|
|
96152
96432
|
init_utils11();
|
|
96153
|
-
|
|
96433
|
+
logger45 = log.scope("CurrencyController");
|
|
96154
96434
|
list = requireNonAnonymous(async (ctx) => {
|
|
96155
|
-
|
|
96435
|
+
logger45.debug("Listing currencies", { userId: ctx.user.id });
|
|
96156
96436
|
return ctx.services.currency.list();
|
|
96157
96437
|
});
|
|
96158
96438
|
getById = requireNonAnonymous(async (ctx) => {
|
|
@@ -96163,7 +96443,7 @@ var init_currency_controller = __esm(() => {
|
|
|
96163
96443
|
if (!isValidUUID(currencyId)) {
|
|
96164
96444
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
96165
96445
|
}
|
|
96166
|
-
|
|
96446
|
+
logger45.debug("Getting currency", { userId: ctx.user.id, currencyId });
|
|
96167
96447
|
return ctx.services.currency.getById(currencyId);
|
|
96168
96448
|
});
|
|
96169
96449
|
create2 = requireAdmin(async (ctx) => {
|
|
@@ -96174,12 +96454,12 @@ var init_currency_controller = __esm(() => {
|
|
|
96174
96454
|
} catch (error2) {
|
|
96175
96455
|
if (error2 instanceof exports_external.ZodError) {
|
|
96176
96456
|
const details = formatZodError(error2);
|
|
96177
|
-
|
|
96457
|
+
logger45.warn("Create currency validation failed", { details });
|
|
96178
96458
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96179
96459
|
}
|
|
96180
96460
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96181
96461
|
}
|
|
96182
|
-
|
|
96462
|
+
logger45.debug("Creating currency", {
|
|
96183
96463
|
userId: ctx.user.id,
|
|
96184
96464
|
symbol: body2.symbol,
|
|
96185
96465
|
itemId: body2.itemId,
|
|
@@ -96202,12 +96482,12 @@ var init_currency_controller = __esm(() => {
|
|
|
96202
96482
|
} catch (error2) {
|
|
96203
96483
|
if (error2 instanceof exports_external.ZodError) {
|
|
96204
96484
|
const details = formatZodError(error2);
|
|
96205
|
-
|
|
96485
|
+
logger45.warn("Update currency validation failed", { details });
|
|
96206
96486
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96207
96487
|
}
|
|
96208
96488
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96209
96489
|
}
|
|
96210
|
-
|
|
96490
|
+
logger45.debug("Updating currency", {
|
|
96211
96491
|
userId: ctx.user.id,
|
|
96212
96492
|
currencyId,
|
|
96213
96493
|
symbol: body2.symbol,
|
|
@@ -96224,7 +96504,7 @@ var init_currency_controller = __esm(() => {
|
|
|
96224
96504
|
if (!isValidUUID(currencyId)) {
|
|
96225
96505
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
96226
96506
|
}
|
|
96227
|
-
|
|
96507
|
+
logger45.debug("Deleting currency", { userId: ctx.user.id, currencyId });
|
|
96228
96508
|
await ctx.services.currency.delete(currencyId);
|
|
96229
96509
|
});
|
|
96230
96510
|
currencyController = {
|
|
@@ -96237,14 +96517,14 @@ var init_currency_controller = __esm(() => {
|
|
|
96237
96517
|
});
|
|
96238
96518
|
|
|
96239
96519
|
// ../api-core/src/controllers/database.controller.ts
|
|
96240
|
-
var
|
|
96520
|
+
var logger46, reset;
|
|
96241
96521
|
var init_database_controller = __esm(() => {
|
|
96242
96522
|
init_esm();
|
|
96243
96523
|
init_schemas_index();
|
|
96244
96524
|
init_src2();
|
|
96245
96525
|
init_errors();
|
|
96246
96526
|
init_utils11();
|
|
96247
|
-
|
|
96527
|
+
logger46 = log.scope("DatabaseController");
|
|
96248
96528
|
reset = requireDeveloper(async (ctx) => {
|
|
96249
96529
|
const slug2 = ctx.params.slug;
|
|
96250
96530
|
if (!slug2) {
|
|
@@ -96257,11 +96537,11 @@ var init_database_controller = __esm(() => {
|
|
|
96257
96537
|
} catch (error2) {
|
|
96258
96538
|
if (error2 instanceof exports_external.ZodError) {
|
|
96259
96539
|
const details = formatZodError(error2);
|
|
96260
|
-
|
|
96540
|
+
logger46.warn("Database reset validation failed", { details });
|
|
96261
96541
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96262
96542
|
}
|
|
96263
96543
|
}
|
|
96264
|
-
|
|
96544
|
+
logger46.debug("Resetting database", {
|
|
96265
96545
|
userId: ctx.user.id,
|
|
96266
96546
|
slug: slug2,
|
|
96267
96547
|
hasSchema: Boolean(body2.schema)
|
|
@@ -96279,7 +96559,7 @@ async function createJob(ctx) {
|
|
|
96279
96559
|
let body2;
|
|
96280
96560
|
try {
|
|
96281
96561
|
const json4 = await ctx.request.json();
|
|
96282
|
-
|
|
96562
|
+
logger47.debug("Deploy request body", {
|
|
96283
96563
|
keys: Object.keys(json4 || {}),
|
|
96284
96564
|
hasUploadToken: Boolean(json4?.uploadToken),
|
|
96285
96565
|
hasCode: Boolean(json4?.code),
|
|
@@ -96289,7 +96569,7 @@ async function createJob(ctx) {
|
|
|
96289
96569
|
} catch (error2) {
|
|
96290
96570
|
if (error2 instanceof exports_external.ZodError) {
|
|
96291
96571
|
const details = formatZodError(error2);
|
|
96292
|
-
|
|
96572
|
+
logger47.warn("Deploy validation failed", { details });
|
|
96293
96573
|
throw ApiError.unprocessableEntity("Invalid deploy request", details);
|
|
96294
96574
|
}
|
|
96295
96575
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96310,14 +96590,14 @@ async function getJob(ctx) {
|
|
|
96310
96590
|
}
|
|
96311
96591
|
return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
|
|
96312
96592
|
}
|
|
96313
|
-
var
|
|
96593
|
+
var logger47, deploy;
|
|
96314
96594
|
var init_deploy_controller = __esm(() => {
|
|
96315
96595
|
init_esm();
|
|
96316
96596
|
init_schemas_index();
|
|
96317
96597
|
init_src2();
|
|
96318
96598
|
init_errors();
|
|
96319
96599
|
init_utils11();
|
|
96320
|
-
|
|
96600
|
+
logger47 = log.scope("DeployController");
|
|
96321
96601
|
deploy = {
|
|
96322
96602
|
createJob: requireDeveloper(createJob),
|
|
96323
96603
|
getJob: requireDeveloper(getJob)
|
|
@@ -96325,17 +96605,17 @@ var init_deploy_controller = __esm(() => {
|
|
|
96325
96605
|
});
|
|
96326
96606
|
|
|
96327
96607
|
// ../api-core/src/controllers/developer.controller.ts
|
|
96328
|
-
var
|
|
96608
|
+
var logger48, apply, getStatus, developer;
|
|
96329
96609
|
var init_developer_controller = __esm(() => {
|
|
96330
96610
|
init_src2();
|
|
96331
96611
|
init_utils11();
|
|
96332
|
-
|
|
96612
|
+
logger48 = log.scope("DeveloperController");
|
|
96333
96613
|
apply = requireNonAnonymous(async (ctx) => {
|
|
96334
|
-
|
|
96614
|
+
logger48.debug("Applying for developer status", { userId: ctx.user.id });
|
|
96335
96615
|
await ctx.services.developer.apply(ctx.user);
|
|
96336
96616
|
});
|
|
96337
96617
|
getStatus = requireNonAnonymous(async (ctx) => {
|
|
96338
|
-
|
|
96618
|
+
logger48.debug("Getting developer status", { userId: ctx.user.id });
|
|
96339
96619
|
const status = await ctx.services.developer.getStatus(ctx.user.id);
|
|
96340
96620
|
return { status };
|
|
96341
96621
|
});
|
|
@@ -96346,7 +96626,7 @@ var init_developer_controller = __esm(() => {
|
|
|
96346
96626
|
});
|
|
96347
96627
|
|
|
96348
96628
|
// ../api-core/src/controllers/domain.controller.ts
|
|
96349
|
-
var
|
|
96629
|
+
var logger49, add, list2, getStatus2, remove2, domains2;
|
|
96350
96630
|
var init_domain_controller = __esm(() => {
|
|
96351
96631
|
init_esm();
|
|
96352
96632
|
init_schemas_index();
|
|
@@ -96354,7 +96634,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96354
96634
|
init_config2();
|
|
96355
96635
|
init_errors();
|
|
96356
96636
|
init_utils11();
|
|
96357
|
-
|
|
96637
|
+
logger49 = log.scope("DomainController");
|
|
96358
96638
|
add = requireDeveloper(async (ctx) => {
|
|
96359
96639
|
const slug2 = ctx.params.slug;
|
|
96360
96640
|
if (!slug2) {
|
|
@@ -96367,13 +96647,13 @@ var init_domain_controller = __esm(() => {
|
|
|
96367
96647
|
} catch (error2) {
|
|
96368
96648
|
if (error2 instanceof exports_external.ZodError) {
|
|
96369
96649
|
const details = formatZodError(error2);
|
|
96370
|
-
|
|
96650
|
+
logger49.warn("Add domain validation failed", { details });
|
|
96371
96651
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96372
96652
|
}
|
|
96373
96653
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96374
96654
|
}
|
|
96375
96655
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96376
|
-
|
|
96656
|
+
logger49.debug("Adding domain", {
|
|
96377
96657
|
userId: ctx.user.id,
|
|
96378
96658
|
slug: slug2,
|
|
96379
96659
|
hostname: body2.hostname,
|
|
@@ -96387,7 +96667,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96387
96667
|
throw ApiError.badRequest("Missing game slug");
|
|
96388
96668
|
}
|
|
96389
96669
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96390
|
-
|
|
96670
|
+
logger49.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
|
|
96391
96671
|
const domains2 = await ctx.services.domain.list(slug2, environment, ctx.user);
|
|
96392
96672
|
return { domains: domains2 };
|
|
96393
96673
|
});
|
|
@@ -96402,7 +96682,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96402
96682
|
}
|
|
96403
96683
|
const refresh = ctx.url.searchParams.get("refresh") === "true";
|
|
96404
96684
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96405
|
-
|
|
96685
|
+
logger49.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
|
|
96406
96686
|
return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
|
|
96407
96687
|
});
|
|
96408
96688
|
remove2 = requireDeveloper(async (ctx) => {
|
|
@@ -96415,7 +96695,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96415
96695
|
throw ApiError.badRequest("Missing hostname");
|
|
96416
96696
|
}
|
|
96417
96697
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96418
|
-
|
|
96698
|
+
logger49.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
|
|
96419
96699
|
await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
|
|
96420
96700
|
});
|
|
96421
96701
|
domains2 = {
|
|
@@ -96427,7 +96707,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96427
96707
|
});
|
|
96428
96708
|
|
|
96429
96709
|
// ../api-core/src/controllers/game.controller.ts
|
|
96430
|
-
var
|
|
96710
|
+
var logger50, list3, listAccessible, getSubjects, getById2, getBySlug, getManifest, upsertBySlug, remove3, games2;
|
|
96431
96711
|
var init_game_controller = __esm(() => {
|
|
96432
96712
|
init_esm();
|
|
96433
96713
|
init_schemas_index();
|
|
@@ -96435,17 +96715,17 @@ var init_game_controller = __esm(() => {
|
|
|
96435
96715
|
init_src4();
|
|
96436
96716
|
init_errors();
|
|
96437
96717
|
init_utils11();
|
|
96438
|
-
|
|
96718
|
+
logger50 = log.scope("GameController");
|
|
96439
96719
|
list3 = requireNonAnonymous(async (ctx) => {
|
|
96440
|
-
|
|
96720
|
+
logger50.debug("Listing games", { userId: ctx.user.id });
|
|
96441
96721
|
return ctx.services.game.list(ctx.user);
|
|
96442
96722
|
});
|
|
96443
96723
|
listAccessible = requireNonAnonymous(async (ctx) => {
|
|
96444
|
-
|
|
96724
|
+
logger50.debug("Listing accessible games", { userId: ctx.user.id });
|
|
96445
96725
|
return ctx.services.game.listAccessible(ctx.user);
|
|
96446
96726
|
});
|
|
96447
96727
|
getSubjects = requireNonAnonymous(async (ctx) => {
|
|
96448
|
-
|
|
96728
|
+
logger50.debug("Getting game subjects", { userId: ctx.user.id });
|
|
96449
96729
|
return ctx.services.game.getSubjects();
|
|
96450
96730
|
});
|
|
96451
96731
|
getById2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96456,7 +96736,7 @@ var init_game_controller = __esm(() => {
|
|
|
96456
96736
|
if (!isValidUUID(gameId)) {
|
|
96457
96737
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96458
96738
|
}
|
|
96459
|
-
|
|
96739
|
+
logger50.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
|
|
96460
96740
|
return ctx.services.game.getById(gameId, ctx.user);
|
|
96461
96741
|
});
|
|
96462
96742
|
getBySlug = requireNonAnonymous(async (ctx) => {
|
|
@@ -96464,7 +96744,7 @@ var init_game_controller = __esm(() => {
|
|
|
96464
96744
|
if (!slug2) {
|
|
96465
96745
|
throw ApiError.badRequest("Missing game slug");
|
|
96466
96746
|
}
|
|
96467
|
-
|
|
96747
|
+
logger50.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
|
|
96468
96748
|
return ctx.services.game.getBySlug(slug2, ctx.user);
|
|
96469
96749
|
});
|
|
96470
96750
|
getManifest = requireNonAnonymous(async (ctx) => {
|
|
@@ -96475,7 +96755,7 @@ var init_game_controller = __esm(() => {
|
|
|
96475
96755
|
if (!isValidUUID(gameId)) {
|
|
96476
96756
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96477
96757
|
}
|
|
96478
|
-
|
|
96758
|
+
logger50.debug("Getting game manifest by ID", {
|
|
96479
96759
|
userId: ctx.user.id,
|
|
96480
96760
|
gameId,
|
|
96481
96761
|
launchId: ctx.launchId
|
|
@@ -96494,12 +96774,12 @@ var init_game_controller = __esm(() => {
|
|
|
96494
96774
|
} catch (error2) {
|
|
96495
96775
|
if (error2 instanceof exports_external.ZodError) {
|
|
96496
96776
|
const details = formatZodError(error2);
|
|
96497
|
-
|
|
96777
|
+
logger50.warn("Upsert game validation failed", { details });
|
|
96498
96778
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96499
96779
|
}
|
|
96500
96780
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96501
96781
|
}
|
|
96502
|
-
|
|
96782
|
+
logger50.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
|
|
96503
96783
|
return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
|
|
96504
96784
|
});
|
|
96505
96785
|
remove3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96510,7 +96790,7 @@ var init_game_controller = __esm(() => {
|
|
|
96510
96790
|
if (!isValidUUID(gameId)) {
|
|
96511
96791
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96512
96792
|
}
|
|
96513
|
-
|
|
96793
|
+
logger50.debug("Deleting game", { userId: ctx.user.id, gameId });
|
|
96514
96794
|
await ctx.services.game.delete(gameId, ctx.user);
|
|
96515
96795
|
});
|
|
96516
96796
|
games2 = {
|
|
@@ -96526,16 +96806,16 @@ var init_game_controller = __esm(() => {
|
|
|
96526
96806
|
});
|
|
96527
96807
|
|
|
96528
96808
|
// ../api-core/src/controllers/inventory.controller.ts
|
|
96529
|
-
var
|
|
96809
|
+
var logger51, list4, addItem, removeItem, inventory;
|
|
96530
96810
|
var init_inventory_controller = __esm(() => {
|
|
96531
96811
|
init_esm();
|
|
96532
96812
|
init_schemas_index();
|
|
96533
96813
|
init_src2();
|
|
96534
96814
|
init_errors();
|
|
96535
96815
|
init_utils11();
|
|
96536
|
-
|
|
96816
|
+
logger51 = log.scope("InventoryController");
|
|
96537
96817
|
list4 = requireNonAnonymous(async (ctx) => {
|
|
96538
|
-
|
|
96818
|
+
logger51.debug("Listing inventory", { userId: ctx.user.id });
|
|
96539
96819
|
return ctx.services.inventory.list(ctx.user);
|
|
96540
96820
|
});
|
|
96541
96821
|
addItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -96546,12 +96826,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
96546
96826
|
} catch (error2) {
|
|
96547
96827
|
if (error2 instanceof exports_external.ZodError) {
|
|
96548
96828
|
const details = formatZodError(error2);
|
|
96549
|
-
|
|
96829
|
+
logger51.warn("Add inventory item validation failed", { details });
|
|
96550
96830
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96551
96831
|
}
|
|
96552
96832
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96553
96833
|
}
|
|
96554
|
-
|
|
96834
|
+
logger51.debug("Adding item", {
|
|
96555
96835
|
userId: ctx.user.id,
|
|
96556
96836
|
itemId: body2.itemId,
|
|
96557
96837
|
qty: body2.qty
|
|
@@ -96566,12 +96846,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
96566
96846
|
} catch (error2) {
|
|
96567
96847
|
if (error2 instanceof exports_external.ZodError) {
|
|
96568
96848
|
const details = formatZodError(error2);
|
|
96569
|
-
|
|
96849
|
+
logger51.warn("Remove inventory item validation failed", { details });
|
|
96570
96850
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96571
96851
|
}
|
|
96572
96852
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96573
96853
|
}
|
|
96574
|
-
|
|
96854
|
+
logger51.debug("Removing item", {
|
|
96575
96855
|
userId: ctx.user.id,
|
|
96576
96856
|
itemId: body2.itemId,
|
|
96577
96857
|
qty: body2.qty
|
|
@@ -96586,7 +96866,7 @@ var init_inventory_controller = __esm(() => {
|
|
|
96586
96866
|
});
|
|
96587
96867
|
|
|
96588
96868
|
// ../api-core/src/controllers/item.controller.ts
|
|
96589
|
-
var
|
|
96869
|
+
var logger52, list5, getById3, resolve2, create3, update4, remove4, listByGame, createForGame, updateForGame, deleteForGame, items2;
|
|
96590
96870
|
var init_item_controller = __esm(() => {
|
|
96591
96871
|
init_esm();
|
|
96592
96872
|
init_schemas_index();
|
|
@@ -96594,10 +96874,10 @@ var init_item_controller = __esm(() => {
|
|
|
96594
96874
|
init_src4();
|
|
96595
96875
|
init_errors();
|
|
96596
96876
|
init_utils11();
|
|
96597
|
-
|
|
96877
|
+
logger52 = log.scope("ItemController");
|
|
96598
96878
|
list5 = requireNonAnonymous(async (ctx) => {
|
|
96599
96879
|
const gameId = ctx.url.searchParams.get("gameId") || undefined;
|
|
96600
|
-
|
|
96880
|
+
logger52.debug("Listing items", { userId: ctx.user.id, gameId });
|
|
96601
96881
|
return ctx.services.item.list(gameId);
|
|
96602
96882
|
});
|
|
96603
96883
|
getById3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96608,7 +96888,7 @@ var init_item_controller = __esm(() => {
|
|
|
96608
96888
|
if (!isValidUUID(itemId)) {
|
|
96609
96889
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96610
96890
|
}
|
|
96611
|
-
|
|
96891
|
+
logger52.debug("Getting item", { userId: ctx.user.id, itemId });
|
|
96612
96892
|
return ctx.services.item.getById(itemId);
|
|
96613
96893
|
});
|
|
96614
96894
|
resolve2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96620,7 +96900,7 @@ var init_item_controller = __esm(() => {
|
|
|
96620
96900
|
if (gameId && !isValidUUID(gameId)) {
|
|
96621
96901
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96622
96902
|
}
|
|
96623
|
-
|
|
96903
|
+
logger52.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
|
|
96624
96904
|
return ctx.services.item.resolveBySlug(slug2, gameId);
|
|
96625
96905
|
});
|
|
96626
96906
|
create3 = requireRole(["admin"], async (ctx) => {
|
|
@@ -96631,12 +96911,12 @@ var init_item_controller = __esm(() => {
|
|
|
96631
96911
|
} catch (error2) {
|
|
96632
96912
|
if (error2 instanceof exports_external.ZodError) {
|
|
96633
96913
|
const details = formatZodError(error2);
|
|
96634
|
-
|
|
96914
|
+
logger52.warn("Create item validation failed", { details });
|
|
96635
96915
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96636
96916
|
}
|
|
96637
96917
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96638
96918
|
}
|
|
96639
|
-
|
|
96919
|
+
logger52.debug("Creating item", {
|
|
96640
96920
|
userId: ctx.user.id,
|
|
96641
96921
|
slug: body2.slug,
|
|
96642
96922
|
displayName: body2.displayName
|
|
@@ -96658,7 +96938,7 @@ var init_item_controller = __esm(() => {
|
|
|
96658
96938
|
} catch (error2) {
|
|
96659
96939
|
if (error2 instanceof exports_external.ZodError) {
|
|
96660
96940
|
const details = formatZodError(error2);
|
|
96661
|
-
|
|
96941
|
+
logger52.warn("Update item validation failed", { details });
|
|
96662
96942
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96663
96943
|
}
|
|
96664
96944
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96666,7 +96946,7 @@ var init_item_controller = __esm(() => {
|
|
|
96666
96946
|
if (Object.keys(body2).length === 0) {
|
|
96667
96947
|
throw ApiError.badRequest("No update data provided");
|
|
96668
96948
|
}
|
|
96669
|
-
|
|
96949
|
+
logger52.debug("Updating item", {
|
|
96670
96950
|
userId: ctx.user.id,
|
|
96671
96951
|
itemId,
|
|
96672
96952
|
slug: body2.slug,
|
|
@@ -96683,7 +96963,7 @@ var init_item_controller = __esm(() => {
|
|
|
96683
96963
|
if (!isValidUUID(itemId)) {
|
|
96684
96964
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96685
96965
|
}
|
|
96686
|
-
|
|
96966
|
+
logger52.debug("Deleting item", { userId: ctx.user.id, itemId });
|
|
96687
96967
|
await ctx.services.item.delete(itemId);
|
|
96688
96968
|
});
|
|
96689
96969
|
listByGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -96694,7 +96974,7 @@ var init_item_controller = __esm(() => {
|
|
|
96694
96974
|
if (!isValidUUID(gameId)) {
|
|
96695
96975
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96696
96976
|
}
|
|
96697
|
-
|
|
96977
|
+
logger52.debug("Listing game items", { userId: ctx.user.id, gameId });
|
|
96698
96978
|
return ctx.services.item.listByGame(gameId);
|
|
96699
96979
|
});
|
|
96700
96980
|
createForGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -96712,12 +96992,12 @@ var init_item_controller = __esm(() => {
|
|
|
96712
96992
|
} catch (error2) {
|
|
96713
96993
|
if (error2 instanceof exports_external.ZodError) {
|
|
96714
96994
|
const details = formatZodError(error2);
|
|
96715
|
-
|
|
96995
|
+
logger52.warn("Create game item validation failed", { details });
|
|
96716
96996
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96717
96997
|
}
|
|
96718
96998
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96719
96999
|
}
|
|
96720
|
-
|
|
97000
|
+
logger52.debug("Creating game item", {
|
|
96721
97001
|
userId: ctx.user.id,
|
|
96722
97002
|
gameId,
|
|
96723
97003
|
slug: body2.slug,
|
|
@@ -96744,7 +97024,7 @@ var init_item_controller = __esm(() => {
|
|
|
96744
97024
|
} catch (error2) {
|
|
96745
97025
|
if (error2 instanceof exports_external.ZodError) {
|
|
96746
97026
|
const details = formatZodError(error2);
|
|
96747
|
-
|
|
97027
|
+
logger52.warn("Update game item validation failed", { details });
|
|
96748
97028
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96749
97029
|
}
|
|
96750
97030
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96752,7 +97032,7 @@ var init_item_controller = __esm(() => {
|
|
|
96752
97032
|
if (Object.keys(body2).length === 0) {
|
|
96753
97033
|
throw ApiError.badRequest("No update data provided");
|
|
96754
97034
|
}
|
|
96755
|
-
|
|
97035
|
+
logger52.debug("Updating game item", {
|
|
96756
97036
|
userId: ctx.user.id,
|
|
96757
97037
|
gameId,
|
|
96758
97038
|
itemId,
|
|
@@ -96774,7 +97054,7 @@ var init_item_controller = __esm(() => {
|
|
|
96774
97054
|
if (!isValidUUID(itemId)) {
|
|
96775
97055
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96776
97056
|
}
|
|
96777
|
-
|
|
97057
|
+
logger52.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
|
|
96778
97058
|
await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
|
|
96779
97059
|
});
|
|
96780
97060
|
items2 = {
|
|
@@ -96792,14 +97072,14 @@ var init_item_controller = __esm(() => {
|
|
|
96792
97072
|
});
|
|
96793
97073
|
|
|
96794
97074
|
// ../api-core/src/controllers/kv.controller.ts
|
|
96795
|
-
var
|
|
97075
|
+
var logger53, listKeys, getStats, seed, getValue2, setValue2, deleteValue, getMetadata, clear;
|
|
96796
97076
|
var init_kv_controller = __esm(() => {
|
|
96797
97077
|
init_esm();
|
|
96798
97078
|
init_schemas_index();
|
|
96799
97079
|
init_src2();
|
|
96800
97080
|
init_errors();
|
|
96801
97081
|
init_utils11();
|
|
96802
|
-
|
|
97082
|
+
logger53 = log.scope("KVController");
|
|
96803
97083
|
listKeys = requireDeveloper(async (ctx) => {
|
|
96804
97084
|
const slug2 = ctx.params.slug;
|
|
96805
97085
|
if (!slug2) {
|
|
@@ -96807,7 +97087,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96807
97087
|
}
|
|
96808
97088
|
const url2 = ctx.url;
|
|
96809
97089
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
96810
|
-
|
|
97090
|
+
logger53.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
96811
97091
|
const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
|
|
96812
97092
|
return { keys };
|
|
96813
97093
|
});
|
|
@@ -96816,7 +97096,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96816
97096
|
if (!slug2) {
|
|
96817
97097
|
throw ApiError.badRequest("Missing game slug");
|
|
96818
97098
|
}
|
|
96819
|
-
|
|
97099
|
+
logger53.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
|
|
96820
97100
|
return ctx.services.kv.getStats(slug2, ctx.user);
|
|
96821
97101
|
});
|
|
96822
97102
|
seed = requireDeveloper(async (ctx) => {
|
|
@@ -96831,12 +97111,12 @@ var init_kv_controller = __esm(() => {
|
|
|
96831
97111
|
} catch (error2) {
|
|
96832
97112
|
if (error2 instanceof exports_external.ZodError) {
|
|
96833
97113
|
const details = formatZodError(error2);
|
|
96834
|
-
|
|
97114
|
+
logger53.warn("Seed validation failed", { details });
|
|
96835
97115
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96836
97116
|
}
|
|
96837
97117
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96838
97118
|
}
|
|
96839
|
-
|
|
97119
|
+
logger53.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
|
|
96840
97120
|
await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
|
|
96841
97121
|
return { success: true, count: body2.entries.length };
|
|
96842
97122
|
});
|
|
@@ -96846,7 +97126,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96846
97126
|
if (!slug2 || !key) {
|
|
96847
97127
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96848
97128
|
}
|
|
96849
|
-
|
|
97129
|
+
logger53.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
|
|
96850
97130
|
const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
|
|
96851
97131
|
return { key, value };
|
|
96852
97132
|
});
|
|
@@ -96860,7 +97140,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96860
97140
|
if (!value) {
|
|
96861
97141
|
throw ApiError.badRequest("Missing value in request body");
|
|
96862
97142
|
}
|
|
96863
|
-
|
|
97143
|
+
logger53.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
|
|
96864
97144
|
await ctx.services.kv.setValue(slug2, key, value, ctx.user);
|
|
96865
97145
|
return { success: true, key };
|
|
96866
97146
|
});
|
|
@@ -96870,7 +97150,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96870
97150
|
if (!slug2 || !key) {
|
|
96871
97151
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96872
97152
|
}
|
|
96873
|
-
|
|
97153
|
+
logger53.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
|
|
96874
97154
|
await ctx.services.kv.deleteValue(slug2, key, ctx.user);
|
|
96875
97155
|
return { success: true, key };
|
|
96876
97156
|
});
|
|
@@ -96880,7 +97160,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96880
97160
|
if (!slug2 || !key) {
|
|
96881
97161
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96882
97162
|
}
|
|
96883
|
-
|
|
97163
|
+
logger53.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
|
|
96884
97164
|
const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
|
|
96885
97165
|
return { key, metadata: metadata2 };
|
|
96886
97166
|
});
|
|
@@ -96889,21 +97169,21 @@ var init_kv_controller = __esm(() => {
|
|
|
96889
97169
|
if (!slug2) {
|
|
96890
97170
|
throw ApiError.badRequest("Missing game slug");
|
|
96891
97171
|
}
|
|
96892
|
-
|
|
97172
|
+
logger53.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
|
|
96893
97173
|
const deleted = await ctx.services.kv.clear(slug2, ctx.user);
|
|
96894
97174
|
return { success: true, deleted };
|
|
96895
97175
|
});
|
|
96896
97176
|
});
|
|
96897
97177
|
|
|
96898
97178
|
// ../api-core/src/controllers/leaderboard.controller.ts
|
|
96899
|
-
var
|
|
97179
|
+
var logger54, submitScore, getGlobalLeaderboard, getLeaderboard, getUserRank, getUserAllScores, getUserScores, leaderboard;
|
|
96900
97180
|
var init_leaderboard_controller = __esm(() => {
|
|
96901
97181
|
init_esm();
|
|
96902
97182
|
init_schemas_index();
|
|
96903
97183
|
init_src2();
|
|
96904
97184
|
init_errors();
|
|
96905
97185
|
init_utils11();
|
|
96906
|
-
|
|
97186
|
+
logger54 = log.scope("LeaderboardController");
|
|
96907
97187
|
submitScore = requireAuth(async (ctx) => {
|
|
96908
97188
|
const gameId = ctx.params.gameId;
|
|
96909
97189
|
if (!gameId) {
|
|
@@ -96916,12 +97196,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96916
97196
|
} catch (error2) {
|
|
96917
97197
|
if (error2 instanceof exports_external.ZodError) {
|
|
96918
97198
|
const details = formatZodError(error2);
|
|
96919
|
-
|
|
97199
|
+
logger54.warn("Submit score validation failed", { details });
|
|
96920
97200
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96921
97201
|
}
|
|
96922
97202
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96923
97203
|
}
|
|
96924
|
-
|
|
97204
|
+
logger54.debug("Submitting score", {
|
|
96925
97205
|
userId: ctx.user.id,
|
|
96926
97206
|
gameId,
|
|
96927
97207
|
score: body2.score
|
|
@@ -96944,12 +97224,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96944
97224
|
} catch (error2) {
|
|
96945
97225
|
if (error2 instanceof exports_external.ZodError) {
|
|
96946
97226
|
const details = formatZodError(error2);
|
|
96947
|
-
|
|
97227
|
+
logger54.warn("Get global leaderboard query validation failed", { details });
|
|
96948
97228
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
96949
97229
|
}
|
|
96950
97230
|
throw ApiError.badRequest("Invalid query parameters");
|
|
96951
97231
|
}
|
|
96952
|
-
|
|
97232
|
+
logger54.debug("Getting global leaderboard", {
|
|
96953
97233
|
userId: ctx.user.id,
|
|
96954
97234
|
gameId,
|
|
96955
97235
|
...query
|
|
@@ -96972,12 +97252,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96972
97252
|
} catch (error2) {
|
|
96973
97253
|
if (error2 instanceof exports_external.ZodError) {
|
|
96974
97254
|
const details = formatZodError(error2);
|
|
96975
|
-
|
|
97255
|
+
logger54.warn("Get leaderboard query validation failed", { details });
|
|
96976
97256
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
96977
97257
|
}
|
|
96978
97258
|
throw ApiError.badRequest("Invalid query parameters");
|
|
96979
97259
|
}
|
|
96980
|
-
|
|
97260
|
+
logger54.debug("Getting leaderboard", {
|
|
96981
97261
|
userId: ctx.user.id,
|
|
96982
97262
|
gameId,
|
|
96983
97263
|
...query
|
|
@@ -96989,7 +97269,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96989
97269
|
if (!gameId || !userId) {
|
|
96990
97270
|
throw ApiError.badRequest("Game ID and User ID are required");
|
|
96991
97271
|
}
|
|
96992
|
-
|
|
97272
|
+
logger54.debug("Getting user rank", {
|
|
96993
97273
|
requesterId: ctx.user.id,
|
|
96994
97274
|
gameId,
|
|
96995
97275
|
targetUserId: userId
|
|
@@ -97004,7 +97284,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
97004
97284
|
const url2 = ctx.url;
|
|
97005
97285
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "50"), 100);
|
|
97006
97286
|
const gameId = url2.searchParams.get("gameId") || undefined;
|
|
97007
|
-
|
|
97287
|
+
logger54.debug("Getting user all scores", {
|
|
97008
97288
|
requesterId: ctx.user.id,
|
|
97009
97289
|
targetUserId: userId,
|
|
97010
97290
|
gameId,
|
|
@@ -97019,7 +97299,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
97019
97299
|
}
|
|
97020
97300
|
const url2 = ctx.url;
|
|
97021
97301
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "10"), 100);
|
|
97022
|
-
|
|
97302
|
+
logger54.debug("Getting user scores", {
|
|
97023
97303
|
requesterId: ctx.user.id,
|
|
97024
97304
|
gameId,
|
|
97025
97305
|
targetUserId: userId,
|
|
@@ -97039,7 +97319,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
97039
97319
|
|
|
97040
97320
|
// ../api-core/src/controllers/level.controller.ts
|
|
97041
97321
|
async function listConfigs(ctx) {
|
|
97042
|
-
|
|
97322
|
+
logger55.debug("Listing level configs");
|
|
97043
97323
|
return ctx.services.level.listConfigs();
|
|
97044
97324
|
}
|
|
97045
97325
|
async function getConfig(ctx) {
|
|
@@ -97051,21 +97331,21 @@ async function getConfig(ctx) {
|
|
|
97051
97331
|
if (isNaN(level) || level < 1) {
|
|
97052
97332
|
throw ApiError.badRequest("Level must be a positive integer");
|
|
97053
97333
|
}
|
|
97054
|
-
|
|
97334
|
+
logger55.debug("Getting level config", { level });
|
|
97055
97335
|
return ctx.services.level.getConfig(level);
|
|
97056
97336
|
}
|
|
97057
|
-
var
|
|
97337
|
+
var logger55, getByUser, getProgress, levels;
|
|
97058
97338
|
var init_level_controller = __esm(() => {
|
|
97059
97339
|
init_src2();
|
|
97060
97340
|
init_errors();
|
|
97061
97341
|
init_utils11();
|
|
97062
|
-
|
|
97342
|
+
logger55 = log.scope("LevelController");
|
|
97063
97343
|
getByUser = requireNonAnonymous(async (ctx) => {
|
|
97064
|
-
|
|
97344
|
+
logger55.debug("Getting user level", { userId: ctx.user.id });
|
|
97065
97345
|
return ctx.services.level.getByUser(ctx.user);
|
|
97066
97346
|
});
|
|
97067
97347
|
getProgress = requireNonAnonymous(async (ctx) => {
|
|
97068
|
-
|
|
97348
|
+
logger55.debug("Getting level progress", { userId: ctx.user.id });
|
|
97069
97349
|
return ctx.services.level.getProgress(ctx.user);
|
|
97070
97350
|
});
|
|
97071
97351
|
levels = {
|
|
@@ -97077,12 +97357,12 @@ var init_level_controller = __esm(() => {
|
|
|
97077
97357
|
});
|
|
97078
97358
|
|
|
97079
97359
|
// ../api-core/src/controllers/logs.controller.ts
|
|
97080
|
-
var
|
|
97360
|
+
var logger56, generateToken, logs;
|
|
97081
97361
|
var init_logs_controller = __esm(() => {
|
|
97082
97362
|
init_src2();
|
|
97083
97363
|
init_errors();
|
|
97084
97364
|
init_utils11();
|
|
97085
|
-
|
|
97365
|
+
logger56 = log.scope("LogsController");
|
|
97086
97366
|
generateToken = requireDeveloper(async (ctx) => {
|
|
97087
97367
|
const slug2 = ctx.params.slug;
|
|
97088
97368
|
if (!slug2) {
|
|
@@ -97101,7 +97381,7 @@ var init_logs_controller = __esm(() => {
|
|
|
97101
97381
|
}
|
|
97102
97382
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97103
97383
|
}
|
|
97104
|
-
|
|
97384
|
+
logger56.debug("Generating log stream token", {
|
|
97105
97385
|
userId: ctx.user.id,
|
|
97106
97386
|
slug: slug2,
|
|
97107
97387
|
environment: body2.environment
|
|
@@ -97120,13 +97400,13 @@ var init_logs_controller = __esm(() => {
|
|
|
97120
97400
|
});
|
|
97121
97401
|
|
|
97122
97402
|
// ../api-core/src/controllers/lti.controller.ts
|
|
97123
|
-
var
|
|
97403
|
+
var logger57, getStatus3, lti;
|
|
97124
97404
|
var init_lti_controller = __esm(() => {
|
|
97125
97405
|
init_src2();
|
|
97126
97406
|
init_utils11();
|
|
97127
|
-
|
|
97407
|
+
logger57 = log.scope("LtiController");
|
|
97128
97408
|
getStatus3 = requireNonAnonymous(async (ctx) => {
|
|
97129
|
-
|
|
97409
|
+
logger57.debug("Getting status", { userId: ctx.user.id });
|
|
97130
97410
|
return ctx.services.lti.getStatus(ctx.user);
|
|
97131
97411
|
});
|
|
97132
97412
|
lti = {
|
|
@@ -97135,7 +97415,7 @@ var init_lti_controller = __esm(() => {
|
|
|
97135
97415
|
});
|
|
97136
97416
|
|
|
97137
97417
|
// ../api-core/src/controllers/map.controller.ts
|
|
97138
|
-
var
|
|
97418
|
+
var logger58, getByIdentifier, getElements, getObjects, createObject, deleteObject, maps2;
|
|
97139
97419
|
var init_map_controller = __esm(() => {
|
|
97140
97420
|
init_esm();
|
|
97141
97421
|
init_schemas_index();
|
|
@@ -97143,13 +97423,13 @@ var init_map_controller = __esm(() => {
|
|
|
97143
97423
|
init_src4();
|
|
97144
97424
|
init_errors();
|
|
97145
97425
|
init_utils11();
|
|
97146
|
-
|
|
97426
|
+
logger58 = log.scope("MapController");
|
|
97147
97427
|
getByIdentifier = requireNonAnonymous(async (ctx) => {
|
|
97148
97428
|
const identifier = ctx.params.identifier;
|
|
97149
97429
|
if (!identifier) {
|
|
97150
97430
|
throw ApiError.badRequest("Missing map identifier");
|
|
97151
97431
|
}
|
|
97152
|
-
|
|
97432
|
+
logger58.debug("Getting map", { userId: ctx.user.id, identifier });
|
|
97153
97433
|
return ctx.services.map.getByIdentifier(identifier);
|
|
97154
97434
|
});
|
|
97155
97435
|
getElements = requireNonAnonymous(async (ctx) => {
|
|
@@ -97160,7 +97440,7 @@ var init_map_controller = __esm(() => {
|
|
|
97160
97440
|
if (!isValidUUID(mapId)) {
|
|
97161
97441
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
97162
97442
|
}
|
|
97163
|
-
|
|
97443
|
+
logger58.debug("Getting map elements", { userId: ctx.user.id, mapId });
|
|
97164
97444
|
return ctx.services.map.getElements(mapId);
|
|
97165
97445
|
});
|
|
97166
97446
|
getObjects = requireNonAnonymous(async (ctx) => {
|
|
@@ -97171,7 +97451,7 @@ var init_map_controller = __esm(() => {
|
|
|
97171
97451
|
if (!isValidUUID(mapId)) {
|
|
97172
97452
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
97173
97453
|
}
|
|
97174
|
-
|
|
97454
|
+
logger58.debug("Getting map objects", { userId: ctx.user.id, mapId });
|
|
97175
97455
|
return ctx.services.map.getObjects(mapId, ctx.user.id);
|
|
97176
97456
|
});
|
|
97177
97457
|
createObject = requireNonAnonymous(async (ctx) => {
|
|
@@ -97193,12 +97473,12 @@ var init_map_controller = __esm(() => {
|
|
|
97193
97473
|
} catch (error2) {
|
|
97194
97474
|
if (error2 instanceof exports_external.ZodError) {
|
|
97195
97475
|
const details = formatZodError(error2);
|
|
97196
|
-
|
|
97476
|
+
logger58.warn("Create map object validation failed", { details });
|
|
97197
97477
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97198
97478
|
}
|
|
97199
97479
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97200
97480
|
}
|
|
97201
|
-
|
|
97481
|
+
logger58.debug("Creating map object", {
|
|
97202
97482
|
userId: ctx.user.id,
|
|
97203
97483
|
mapId,
|
|
97204
97484
|
itemId: body2.itemId,
|
|
@@ -97222,7 +97502,7 @@ var init_map_controller = __esm(() => {
|
|
|
97222
97502
|
if (!isValidUUID(objectId)) {
|
|
97223
97503
|
throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
|
|
97224
97504
|
}
|
|
97225
|
-
|
|
97505
|
+
logger58.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
|
|
97226
97506
|
await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
|
|
97227
97507
|
});
|
|
97228
97508
|
maps2 = {
|
|
@@ -97235,14 +97515,14 @@ var init_map_controller = __esm(() => {
|
|
|
97235
97515
|
});
|
|
97236
97516
|
|
|
97237
97517
|
// ../api-core/src/controllers/notification.controller.ts
|
|
97238
|
-
var
|
|
97518
|
+
var logger59, list6, updateStatus, getStats2, create4, deliver, notifications2;
|
|
97239
97519
|
var init_notification_controller = __esm(() => {
|
|
97240
97520
|
init_esm();
|
|
97241
97521
|
init_schemas_index();
|
|
97242
97522
|
init_src2();
|
|
97243
97523
|
init_errors();
|
|
97244
97524
|
init_utils11();
|
|
97245
|
-
|
|
97525
|
+
logger59 = log.scope("NotificationController");
|
|
97246
97526
|
list6 = requireNonAnonymous(async (ctx) => {
|
|
97247
97527
|
const query = {
|
|
97248
97528
|
status: ctx.url.searchParams.get("status") || undefined,
|
|
@@ -97253,10 +97533,10 @@ var init_notification_controller = __esm(() => {
|
|
|
97253
97533
|
const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
|
|
97254
97534
|
if (!result.success) {
|
|
97255
97535
|
const details = formatZodError(result.error);
|
|
97256
|
-
|
|
97536
|
+
logger59.warn("List notifications query validation failed", { details });
|
|
97257
97537
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
97258
97538
|
}
|
|
97259
|
-
|
|
97539
|
+
logger59.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
|
|
97260
97540
|
return ctx.services.notification.list(ctx.user, result.data);
|
|
97261
97541
|
});
|
|
97262
97542
|
updateStatus = requireNonAnonymous(async (ctx) => {
|
|
@@ -97271,12 +97551,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97271
97551
|
} catch (error2) {
|
|
97272
97552
|
if (error2 instanceof exports_external.ZodError) {
|
|
97273
97553
|
const details = formatZodError(error2);
|
|
97274
|
-
|
|
97554
|
+
logger59.warn("Update notification status validation failed", { details });
|
|
97275
97555
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
97276
97556
|
}
|
|
97277
97557
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97278
97558
|
}
|
|
97279
|
-
|
|
97559
|
+
logger59.debug("Updating status", {
|
|
97280
97560
|
userId: ctx.user.id,
|
|
97281
97561
|
notificationId,
|
|
97282
97562
|
status: body2.status
|
|
@@ -97286,7 +97566,7 @@ var init_notification_controller = __esm(() => {
|
|
|
97286
97566
|
getStats2 = requireNonAnonymous(async (ctx) => {
|
|
97287
97567
|
const startDate = ctx.url.searchParams.get("startDate");
|
|
97288
97568
|
const endDate = ctx.url.searchParams.get("endDate");
|
|
97289
|
-
|
|
97569
|
+
logger59.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
|
|
97290
97570
|
return ctx.services.notification.getStats(ctx.user, {
|
|
97291
97571
|
startDate: startDate ? new Date(startDate) : undefined,
|
|
97292
97572
|
endDate: endDate ? new Date(endDate) : undefined
|
|
@@ -97300,12 +97580,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97300
97580
|
} catch (error2) {
|
|
97301
97581
|
if (error2 instanceof exports_external.ZodError) {
|
|
97302
97582
|
const details = formatZodError(error2);
|
|
97303
|
-
|
|
97583
|
+
logger59.warn("Create notification validation failed", { details });
|
|
97304
97584
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
97305
97585
|
}
|
|
97306
97586
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97307
97587
|
}
|
|
97308
|
-
|
|
97588
|
+
logger59.debug("Creating notification", {
|
|
97309
97589
|
userId: ctx.user.id,
|
|
97310
97590
|
targetUserId: body2.userId,
|
|
97311
97591
|
type: body2.type
|
|
@@ -97323,12 +97603,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97323
97603
|
});
|
|
97324
97604
|
});
|
|
97325
97605
|
deliver = requireNonAnonymous(async (ctx) => {
|
|
97326
|
-
|
|
97606
|
+
logger59.debug("Delivering notifications", { userId: ctx.user.id });
|
|
97327
97607
|
try {
|
|
97328
97608
|
await ctx.services.notification.deliverPending(ctx.user.id);
|
|
97329
97609
|
return { success: true };
|
|
97330
97610
|
} catch (error2) {
|
|
97331
|
-
|
|
97611
|
+
logger59.error("Failed to deliver notifications", { error: error2 });
|
|
97332
97612
|
throw ApiError.internal("Failed to deliver notifications");
|
|
97333
97613
|
}
|
|
97334
97614
|
});
|
|
@@ -97342,14 +97622,14 @@ var init_notification_controller = __esm(() => {
|
|
|
97342
97622
|
});
|
|
97343
97623
|
|
|
97344
97624
|
// ../api-core/src/controllers/realtime.controller.ts
|
|
97345
|
-
var
|
|
97625
|
+
var logger60, generateToken2, realtime;
|
|
97346
97626
|
var init_realtime_controller = __esm(() => {
|
|
97347
97627
|
init_src2();
|
|
97348
97628
|
init_utils11();
|
|
97349
|
-
|
|
97629
|
+
logger60 = log.scope("RealtimeController");
|
|
97350
97630
|
generateToken2 = requireNonAnonymous(async (ctx) => {
|
|
97351
97631
|
const gameIdOrSlug = ctx.params.gameId;
|
|
97352
|
-
|
|
97632
|
+
logger60.debug("Generating token", {
|
|
97353
97633
|
userId: ctx.user.id,
|
|
97354
97634
|
gameId: gameIdOrSlug || "global",
|
|
97355
97635
|
launchId: ctx.launchId
|
|
@@ -97362,20 +97642,20 @@ var init_realtime_controller = __esm(() => {
|
|
|
97362
97642
|
});
|
|
97363
97643
|
|
|
97364
97644
|
// ../api-core/src/controllers/secrets.controller.ts
|
|
97365
|
-
var
|
|
97645
|
+
var logger61, listKeys2, setSecrets, deleteSecret, secrets;
|
|
97366
97646
|
var init_secrets_controller = __esm(() => {
|
|
97367
97647
|
init_esm();
|
|
97368
97648
|
init_schemas_index();
|
|
97369
97649
|
init_src2();
|
|
97370
97650
|
init_errors();
|
|
97371
97651
|
init_utils11();
|
|
97372
|
-
|
|
97652
|
+
logger61 = log.scope("SecretsController");
|
|
97373
97653
|
listKeys2 = requireDeveloper(async (ctx) => {
|
|
97374
97654
|
const slug2 = ctx.params.slug;
|
|
97375
97655
|
if (!slug2) {
|
|
97376
97656
|
throw ApiError.badRequest("Missing game slug");
|
|
97377
97657
|
}
|
|
97378
|
-
|
|
97658
|
+
logger61.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
|
|
97379
97659
|
const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
|
|
97380
97660
|
return { keys };
|
|
97381
97661
|
});
|
|
@@ -97391,12 +97671,12 @@ var init_secrets_controller = __esm(() => {
|
|
|
97391
97671
|
} catch (error2) {
|
|
97392
97672
|
if (error2 instanceof exports_external.ZodError) {
|
|
97393
97673
|
const details = formatZodError(error2);
|
|
97394
|
-
|
|
97674
|
+
logger61.warn("Set secrets validation failed", { details });
|
|
97395
97675
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97396
97676
|
}
|
|
97397
97677
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97398
97678
|
}
|
|
97399
|
-
|
|
97679
|
+
logger61.debug("Setting secrets", {
|
|
97400
97680
|
userId: ctx.user.id,
|
|
97401
97681
|
slug: slug2,
|
|
97402
97682
|
keyCount: Object.keys(body2).length
|
|
@@ -97413,7 +97693,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
97413
97693
|
if (!key) {
|
|
97414
97694
|
throw ApiError.badRequest("Missing secret key");
|
|
97415
97695
|
}
|
|
97416
|
-
|
|
97696
|
+
logger61.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
|
|
97417
97697
|
await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
|
|
97418
97698
|
return { success: true };
|
|
97419
97699
|
});
|
|
@@ -97425,14 +97705,14 @@ var init_secrets_controller = __esm(() => {
|
|
|
97425
97705
|
});
|
|
97426
97706
|
|
|
97427
97707
|
// ../api-core/src/controllers/seed.controller.ts
|
|
97428
|
-
var
|
|
97708
|
+
var logger62, seed2;
|
|
97429
97709
|
var init_seed_controller = __esm(() => {
|
|
97430
97710
|
init_esm();
|
|
97431
97711
|
init_schemas_index();
|
|
97432
97712
|
init_src2();
|
|
97433
97713
|
init_errors();
|
|
97434
97714
|
init_utils11();
|
|
97435
|
-
|
|
97715
|
+
logger62 = log.scope("SeedController");
|
|
97436
97716
|
seed2 = requireDeveloper(async (ctx) => {
|
|
97437
97717
|
const slug2 = ctx.params.slug;
|
|
97438
97718
|
if (!slug2) {
|
|
@@ -97445,12 +97725,12 @@ var init_seed_controller = __esm(() => {
|
|
|
97445
97725
|
} catch (error2) {
|
|
97446
97726
|
if (error2 instanceof exports_external.ZodError) {
|
|
97447
97727
|
const details = formatZodError(error2);
|
|
97448
|
-
|
|
97728
|
+
logger62.warn("Seed database validation failed", { details });
|
|
97449
97729
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97450
97730
|
}
|
|
97451
97731
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97452
97732
|
}
|
|
97453
|
-
|
|
97733
|
+
logger62.debug("Seeding database", {
|
|
97454
97734
|
userId: ctx.user.id,
|
|
97455
97735
|
slug: slug2,
|
|
97456
97736
|
codeLength: body2.code.length,
|
|
@@ -97461,19 +97741,19 @@ var init_seed_controller = __esm(() => {
|
|
|
97461
97741
|
});
|
|
97462
97742
|
|
|
97463
97743
|
// ../api-core/src/controllers/session.controller.ts
|
|
97464
|
-
var
|
|
97744
|
+
var logger63, start2, end, mintToken, sessions2;
|
|
97465
97745
|
var init_session_controller = __esm(() => {
|
|
97466
97746
|
init_src2();
|
|
97467
97747
|
init_tunnel();
|
|
97468
97748
|
init_errors();
|
|
97469
97749
|
init_utils11();
|
|
97470
|
-
|
|
97750
|
+
logger63 = log.scope("SessionController");
|
|
97471
97751
|
start2 = requireAuth(async (ctx) => {
|
|
97472
97752
|
const gameIdOrSlug = ctx.params.gameId;
|
|
97473
97753
|
if (!gameIdOrSlug) {
|
|
97474
97754
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
97475
97755
|
}
|
|
97476
|
-
|
|
97756
|
+
logger63.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
97477
97757
|
return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
|
|
97478
97758
|
});
|
|
97479
97759
|
end = requireAuth(async (ctx) => {
|
|
@@ -97485,7 +97765,7 @@ var init_session_controller = __esm(() => {
|
|
|
97485
97765
|
if (!sessionId) {
|
|
97486
97766
|
throw ApiError.badRequest("Missing session ID");
|
|
97487
97767
|
}
|
|
97488
|
-
|
|
97768
|
+
logger63.debug("Ending session", {
|
|
97489
97769
|
userId: ctx.user.id,
|
|
97490
97770
|
gameIdOrSlug,
|
|
97491
97771
|
sessionId,
|
|
@@ -97498,7 +97778,7 @@ var init_session_controller = __esm(() => {
|
|
|
97498
97778
|
if (!gameIdOrSlug) {
|
|
97499
97779
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
97500
97780
|
}
|
|
97501
|
-
|
|
97781
|
+
logger63.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
97502
97782
|
const { token, exp } = await ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
|
|
97503
97783
|
let baseUrl;
|
|
97504
97784
|
if (ctx.config.isLocal) {
|
|
@@ -97516,13 +97796,13 @@ var init_session_controller = __esm(() => {
|
|
|
97516
97796
|
});
|
|
97517
97797
|
|
|
97518
97798
|
// ../api-core/src/controllers/shop.controller.ts
|
|
97519
|
-
var
|
|
97799
|
+
var logger64, getShopView, shop;
|
|
97520
97800
|
var init_shop_controller = __esm(() => {
|
|
97521
97801
|
init_src2();
|
|
97522
97802
|
init_utils11();
|
|
97523
|
-
|
|
97803
|
+
logger64 = log.scope("ShopController");
|
|
97524
97804
|
getShopView = requireNonAnonymous(async (ctx) => {
|
|
97525
|
-
|
|
97805
|
+
logger64.debug("Getting shop view", { userId: ctx.user.id });
|
|
97526
97806
|
return ctx.services.shop.getShopView(ctx.user);
|
|
97527
97807
|
});
|
|
97528
97808
|
shop = {
|
|
@@ -97531,7 +97811,7 @@ var init_shop_controller = __esm(() => {
|
|
|
97531
97811
|
});
|
|
97532
97812
|
|
|
97533
97813
|
// ../api-core/src/controllers/shop-listing.controller.ts
|
|
97534
|
-
var
|
|
97814
|
+
var logger65, list7, getById4, create5, update5, remove5, listByGame2, getByGameItem, createForGameItem, updateForGameItem, deleteForGameItem, shopListings2;
|
|
97535
97815
|
var init_shop_listing_controller = __esm(() => {
|
|
97536
97816
|
init_esm();
|
|
97537
97817
|
init_schemas_index();
|
|
@@ -97539,9 +97819,9 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97539
97819
|
init_src4();
|
|
97540
97820
|
init_errors();
|
|
97541
97821
|
init_utils11();
|
|
97542
|
-
|
|
97822
|
+
logger65 = log.scope("ShopListingController");
|
|
97543
97823
|
list7 = requireAdmin(async (ctx) => {
|
|
97544
|
-
|
|
97824
|
+
logger65.debug("Listing shop listings", { userId: ctx.user.id });
|
|
97545
97825
|
return ctx.services.shopListing.list();
|
|
97546
97826
|
});
|
|
97547
97827
|
getById4 = requireAdmin(async (ctx) => {
|
|
@@ -97552,7 +97832,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97552
97832
|
if (!isValidUUID(listingId)) {
|
|
97553
97833
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
97554
97834
|
}
|
|
97555
|
-
|
|
97835
|
+
logger65.debug("Getting listing", { userId: ctx.user.id, listingId });
|
|
97556
97836
|
return ctx.services.shopListing.getById(listingId);
|
|
97557
97837
|
});
|
|
97558
97838
|
create5 = requireAdmin(async (ctx) => {
|
|
@@ -97563,12 +97843,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97563
97843
|
} catch (error2) {
|
|
97564
97844
|
if (error2 instanceof exports_external.ZodError) {
|
|
97565
97845
|
const details = formatZodError(error2);
|
|
97566
|
-
|
|
97846
|
+
logger65.warn("Create shop listing validation failed", { details });
|
|
97567
97847
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97568
97848
|
}
|
|
97569
97849
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97570
97850
|
}
|
|
97571
|
-
|
|
97851
|
+
logger65.debug("Creating listing", {
|
|
97572
97852
|
userId: ctx.user.id,
|
|
97573
97853
|
itemId: body2.itemId,
|
|
97574
97854
|
currencyId: body2.currencyId,
|
|
@@ -97591,12 +97871,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97591
97871
|
} catch (error2) {
|
|
97592
97872
|
if (error2 instanceof exports_external.ZodError) {
|
|
97593
97873
|
const details = formatZodError(error2);
|
|
97594
|
-
|
|
97874
|
+
logger65.warn("Update shop listing validation failed", { details });
|
|
97595
97875
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97596
97876
|
}
|
|
97597
97877
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97598
97878
|
}
|
|
97599
|
-
|
|
97879
|
+
logger65.debug("Updating listing", {
|
|
97600
97880
|
userId: ctx.user.id,
|
|
97601
97881
|
listingId,
|
|
97602
97882
|
price: body2.price,
|
|
@@ -97613,7 +97893,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97613
97893
|
if (!isValidUUID(listingId)) {
|
|
97614
97894
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
97615
97895
|
}
|
|
97616
|
-
|
|
97896
|
+
logger65.debug("Deleting listing", { userId: ctx.user.id, listingId });
|
|
97617
97897
|
await ctx.services.shopListing.delete(listingId);
|
|
97618
97898
|
});
|
|
97619
97899
|
listByGame2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -97624,7 +97904,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97624
97904
|
if (!isValidUUID(gameId)) {
|
|
97625
97905
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
97626
97906
|
}
|
|
97627
|
-
|
|
97907
|
+
logger65.debug("Listing game listings", { userId: ctx.user.id, gameId });
|
|
97628
97908
|
return ctx.services.shopListing.listByGame(gameId, ctx.user);
|
|
97629
97909
|
});
|
|
97630
97910
|
getByGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -97639,7 +97919,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97639
97919
|
if (!isValidUUID(itemId)) {
|
|
97640
97920
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
97641
97921
|
}
|
|
97642
|
-
|
|
97922
|
+
logger65.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
|
|
97643
97923
|
return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
|
|
97644
97924
|
});
|
|
97645
97925
|
createForGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -97661,12 +97941,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97661
97941
|
} catch (error2) {
|
|
97662
97942
|
if (error2 instanceof exports_external.ZodError) {
|
|
97663
97943
|
const details = formatZodError(error2);
|
|
97664
|
-
|
|
97944
|
+
logger65.warn("Create game item listing validation failed", { details });
|
|
97665
97945
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97666
97946
|
}
|
|
97667
97947
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97668
97948
|
}
|
|
97669
|
-
|
|
97949
|
+
logger65.debug("Creating game item listing", {
|
|
97670
97950
|
userId: ctx.user.id,
|
|
97671
97951
|
gameId,
|
|
97672
97952
|
itemId,
|
|
@@ -97694,12 +97974,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97694
97974
|
} catch (error2) {
|
|
97695
97975
|
if (error2 instanceof exports_external.ZodError) {
|
|
97696
97976
|
const details = formatZodError(error2);
|
|
97697
|
-
|
|
97977
|
+
logger65.warn("Update game item listing validation failed", { details });
|
|
97698
97978
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97699
97979
|
}
|
|
97700
97980
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97701
97981
|
}
|
|
97702
|
-
|
|
97982
|
+
logger65.debug("Updating game item listing", {
|
|
97703
97983
|
userId: ctx.user.id,
|
|
97704
97984
|
gameId,
|
|
97705
97985
|
itemId,
|
|
@@ -97721,7 +98001,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97721
98001
|
if (!isValidUUID(itemId)) {
|
|
97722
98002
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
97723
98003
|
}
|
|
97724
|
-
|
|
98004
|
+
logger65.debug("Deleting game item listing", {
|
|
97725
98005
|
userId: ctx.user.id,
|
|
97726
98006
|
gameId,
|
|
97727
98007
|
itemId
|
|
@@ -97748,21 +98028,21 @@ async function getBySlug2(ctx) {
|
|
|
97748
98028
|
if (!slug2) {
|
|
97749
98029
|
throw ApiError.badRequest("Template slug is required");
|
|
97750
98030
|
}
|
|
97751
|
-
|
|
98031
|
+
logger66.debug("Getting sprite by slug", { slug: slug2 });
|
|
97752
98032
|
return ctx.services.sprite.getBySlug(slug2);
|
|
97753
98033
|
}
|
|
97754
|
-
var
|
|
98034
|
+
var logger66, sprites;
|
|
97755
98035
|
var init_sprite_controller = __esm(() => {
|
|
97756
98036
|
init_src2();
|
|
97757
98037
|
init_errors();
|
|
97758
|
-
|
|
98038
|
+
logger66 = log.scope("SpriteController");
|
|
97759
98039
|
sprites = {
|
|
97760
98040
|
getBySlug: getBySlug2
|
|
97761
98041
|
};
|
|
97762
98042
|
});
|
|
97763
98043
|
|
|
97764
98044
|
// ../api-core/src/controllers/timeback.controller.ts
|
|
97765
|
-
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;
|
|
97766
98046
|
var init_timeback_controller = __esm(() => {
|
|
97767
98047
|
init_esm();
|
|
97768
98048
|
init_schemas_index();
|
|
@@ -97770,15 +98050,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
97770
98050
|
init_src4();
|
|
97771
98051
|
init_errors();
|
|
97772
98052
|
init_utils11();
|
|
97773
|
-
|
|
98053
|
+
logger67 = log.scope("TimebackController");
|
|
97774
98054
|
getTodayXp = requireNonAnonymous(async (ctx) => {
|
|
97775
98055
|
const date4 = ctx.url.searchParams.get("date") || undefined;
|
|
97776
98056
|
const tz = ctx.url.searchParams.get("tz") || undefined;
|
|
97777
|
-
|
|
98057
|
+
logger67.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
|
|
97778
98058
|
return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
|
|
97779
98059
|
});
|
|
97780
98060
|
getTotalXp = requireNonAnonymous(async (ctx) => {
|
|
97781
|
-
|
|
98061
|
+
logger67.debug("Getting total XP", { userId: ctx.user.id });
|
|
97782
98062
|
return ctx.services.timeback.getTotalXp(ctx.user.id);
|
|
97783
98063
|
});
|
|
97784
98064
|
updateTodayXp = requireNonAnonymous(async (ctx) => {
|
|
@@ -97789,18 +98069,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
97789
98069
|
} catch (error2) {
|
|
97790
98070
|
if (error2 instanceof exports_external.ZodError) {
|
|
97791
98071
|
const details = formatZodError(error2);
|
|
97792
|
-
|
|
98072
|
+
logger67.warn("Update today XP validation failed", { details });
|
|
97793
98073
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97794
98074
|
}
|
|
97795
98075
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97796
98076
|
}
|
|
97797
|
-
|
|
98077
|
+
logger67.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
|
|
97798
98078
|
return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
|
|
97799
98079
|
});
|
|
97800
98080
|
getXpHistory = requireNonAnonymous(async (ctx) => {
|
|
97801
98081
|
const startDate = ctx.url.searchParams.get("startDate") || undefined;
|
|
97802
98082
|
const endDate = ctx.url.searchParams.get("endDate") || undefined;
|
|
97803
|
-
|
|
98083
|
+
logger67.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
|
|
97804
98084
|
return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
|
|
97805
98085
|
});
|
|
97806
98086
|
populateStudent = requireNonAnonymous(async (ctx) => {
|
|
@@ -97811,18 +98091,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
97811
98091
|
} catch (error2) {
|
|
97812
98092
|
if (error2 instanceof exports_external.ZodError) {
|
|
97813
98093
|
const details = formatZodError(error2);
|
|
97814
|
-
|
|
98094
|
+
logger67.warn("Populate student validation failed", { details });
|
|
97815
98095
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97816
98096
|
}
|
|
97817
98097
|
}
|
|
97818
|
-
|
|
98098
|
+
logger67.debug("Populating student", {
|
|
97819
98099
|
userId: ctx.user.id,
|
|
97820
98100
|
hasProvidedNames: Boolean(providedNames)
|
|
97821
98101
|
});
|
|
97822
98102
|
return ctx.services.timeback.populateStudent(ctx.user, providedNames);
|
|
97823
98103
|
});
|
|
97824
98104
|
getUser = requireNonAnonymous(async (ctx) => {
|
|
97825
|
-
|
|
98105
|
+
logger67.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
97826
98106
|
return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
|
|
97827
98107
|
});
|
|
97828
98108
|
getUserById = requireNonAnonymous(async (ctx) => {
|
|
@@ -97830,7 +98110,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97830
98110
|
if (!timebackId) {
|
|
97831
98111
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
97832
98112
|
}
|
|
97833
|
-
|
|
98113
|
+
logger67.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
|
|
97834
98114
|
return ctx.services.timeback.getUserDataByTimebackId(timebackId);
|
|
97835
98115
|
});
|
|
97836
98116
|
setupIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -97841,12 +98121,12 @@ var init_timeback_controller = __esm(() => {
|
|
|
97841
98121
|
} catch (error2) {
|
|
97842
98122
|
if (error2 instanceof exports_external.ZodError) {
|
|
97843
98123
|
const details = formatZodError(error2);
|
|
97844
|
-
|
|
98124
|
+
logger67.warn("Setup integration validation failed", { details });
|
|
97845
98125
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97846
98126
|
}
|
|
97847
98127
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97848
98128
|
}
|
|
97849
|
-
|
|
98129
|
+
logger67.debug("Setting up integration", {
|
|
97850
98130
|
userId: ctx.user.id,
|
|
97851
98131
|
gameId: body2.gameId
|
|
97852
98132
|
});
|
|
@@ -97860,9 +98140,37 @@ var init_timeback_controller = __esm(() => {
|
|
|
97860
98140
|
if (!isValidUUID(gameId)) {
|
|
97861
98141
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97862
98142
|
}
|
|
97863
|
-
|
|
98143
|
+
logger67.debug("Getting integrations", { userId: ctx.user.id, gameId });
|
|
97864
98144
|
return ctx.services.timeback.getIntegrations(gameId, ctx.user);
|
|
97865
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
|
+
});
|
|
97866
98174
|
verifyIntegration = requireDeveloper(async (ctx) => {
|
|
97867
98175
|
const gameId = ctx.params.gameId;
|
|
97868
98176
|
if (!gameId) {
|
|
@@ -97871,7 +98179,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97871
98179
|
if (!isValidUUID(gameId)) {
|
|
97872
98180
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97873
98181
|
}
|
|
97874
|
-
|
|
98182
|
+
logger67.debug("Verifying integration", { userId: ctx.user.id, gameId });
|
|
97875
98183
|
return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
|
|
97876
98184
|
});
|
|
97877
98185
|
getConfig2 = requireDeveloper(async (ctx) => {
|
|
@@ -97882,7 +98190,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97882
98190
|
if (!isValidUUID(gameId)) {
|
|
97883
98191
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97884
98192
|
}
|
|
97885
|
-
|
|
98193
|
+
logger67.debug("Getting config", { userId: ctx.user.id, gameId });
|
|
97886
98194
|
return ctx.services.timeback.getConfig(gameId, ctx.user);
|
|
97887
98195
|
});
|
|
97888
98196
|
deleteIntegrations = requireDeveloper(async (ctx) => {
|
|
@@ -97893,7 +98201,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97893
98201
|
if (!isValidUUID(gameId)) {
|
|
97894
98202
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97895
98203
|
}
|
|
97896
|
-
|
|
98204
|
+
logger67.debug("Deleting integrations", { userId: ctx.user.id, gameId });
|
|
97897
98205
|
await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
|
|
97898
98206
|
});
|
|
97899
98207
|
endActivity = requireDeveloper(async (ctx) => {
|
|
@@ -97904,7 +98212,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97904
98212
|
} catch (error2) {
|
|
97905
98213
|
if (error2 instanceof exports_external.ZodError) {
|
|
97906
98214
|
const details = formatZodError(error2);
|
|
97907
|
-
|
|
98215
|
+
logger67.warn("End activity validation failed", { details });
|
|
97908
98216
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97909
98217
|
}
|
|
97910
98218
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -97922,7 +98230,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97922
98230
|
masteredUnits,
|
|
97923
98231
|
extensions
|
|
97924
98232
|
} = body2;
|
|
97925
|
-
|
|
98233
|
+
logger67.debug("Ending activity", { userId: ctx.user.id, gameId });
|
|
97926
98234
|
return ctx.services.timeback.endActivity({
|
|
97927
98235
|
gameId,
|
|
97928
98236
|
studentId,
|
|
@@ -97946,7 +98254,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97946
98254
|
} catch (error2) {
|
|
97947
98255
|
if (error2 instanceof exports_external.ZodError) {
|
|
97948
98256
|
const details = formatZodError(error2);
|
|
97949
|
-
|
|
98257
|
+
logger67.warn("Heartbeat validation failed", { details });
|
|
97950
98258
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97951
98259
|
}
|
|
97952
98260
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -97962,7 +98270,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97962
98270
|
windowSequence,
|
|
97963
98271
|
isFinal
|
|
97964
98272
|
} = body2;
|
|
97965
|
-
|
|
98273
|
+
logger67.debug("Recording heartbeat", {
|
|
97966
98274
|
userId: ctx.user.id,
|
|
97967
98275
|
gameId,
|
|
97968
98276
|
runId,
|
|
@@ -97987,7 +98295,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97987
98295
|
});
|
|
97988
98296
|
advanceCourse = requireDeveloper(async (ctx) => {
|
|
97989
98297
|
const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
|
|
97990
|
-
|
|
98298
|
+
logger67.debug("Advancing student manually", {
|
|
97991
98299
|
userId: ctx.user.id,
|
|
97992
98300
|
gameId: body2.gameId,
|
|
97993
98301
|
studentId: body2.studentId,
|
|
@@ -98028,7 +98336,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98028
98336
|
perCourse: includeOptions.includes("percourse"),
|
|
98029
98337
|
today: includeOptions.includes("today")
|
|
98030
98338
|
};
|
|
98031
|
-
|
|
98339
|
+
logger67.debug("Getting student XP", {
|
|
98032
98340
|
requesterId: ctx.user.id,
|
|
98033
98341
|
timebackId,
|
|
98034
98342
|
gameId,
|
|
@@ -98050,7 +98358,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98050
98358
|
if (!gameId || !courseId) {
|
|
98051
98359
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98052
98360
|
}
|
|
98053
|
-
|
|
98361
|
+
logger67.debug("Getting course roster", {
|
|
98054
98362
|
requesterId: ctx.user.id,
|
|
98055
98363
|
gameId,
|
|
98056
98364
|
courseId,
|
|
@@ -98067,7 +98375,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98067
98375
|
if (!timebackId || !gameId) {
|
|
98068
98376
|
throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
|
|
98069
98377
|
}
|
|
98070
|
-
|
|
98378
|
+
logger67.debug("Getting student overview", {
|
|
98071
98379
|
requesterId: ctx.user.id,
|
|
98072
98380
|
timebackId,
|
|
98073
98381
|
gameId,
|
|
@@ -98081,7 +98389,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98081
98389
|
if (!gameId || !timebackId) {
|
|
98082
98390
|
throw ApiError.badRequest("Missing gameId or timebackId path parameter");
|
|
98083
98391
|
}
|
|
98084
|
-
|
|
98392
|
+
logger67.debug("Getting game metrics", {
|
|
98085
98393
|
requesterId: ctx.user.id,
|
|
98086
98394
|
gameId,
|
|
98087
98395
|
timebackId
|
|
@@ -98099,7 +98407,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98099
98407
|
if (!timebackId || !courseId || !gameId) {
|
|
98100
98408
|
throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
|
|
98101
98409
|
}
|
|
98102
|
-
|
|
98410
|
+
logger67.debug("Getting student activity", {
|
|
98103
98411
|
requesterId: ctx.user.id,
|
|
98104
98412
|
timebackId,
|
|
98105
98413
|
courseId,
|
|
@@ -98124,7 +98432,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98124
98432
|
if (!timebackId || !courseId || !activityId || !gameId) {
|
|
98125
98433
|
throw ApiError.badRequest("Missing timebackId, courseId, or activityId path parameter, or gameId query parameter");
|
|
98126
98434
|
}
|
|
98127
|
-
|
|
98435
|
+
logger67.debug("Getting activity detail", {
|
|
98128
98436
|
requesterId: ctx.user.id,
|
|
98129
98437
|
timebackId,
|
|
98130
98438
|
courseId,
|
|
@@ -98142,7 +98450,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98142
98450
|
});
|
|
98143
98451
|
grantXp = requireDeveloper(async (ctx) => {
|
|
98144
98452
|
const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
|
|
98145
|
-
|
|
98453
|
+
logger67.debug("Granting manual XP", {
|
|
98146
98454
|
requesterId: ctx.user.id,
|
|
98147
98455
|
gameId: body2.gameId,
|
|
98148
98456
|
courseId: body2.courseId,
|
|
@@ -98154,7 +98462,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98154
98462
|
});
|
|
98155
98463
|
adjustTime = requireDeveloper(async (ctx) => {
|
|
98156
98464
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
|
|
98157
|
-
|
|
98465
|
+
logger67.debug("Adjusting time spent", {
|
|
98158
98466
|
requesterId: ctx.user.id,
|
|
98159
98467
|
gameId: body2.gameId,
|
|
98160
98468
|
courseId: body2.courseId,
|
|
@@ -98166,7 +98474,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98166
98474
|
});
|
|
98167
98475
|
adjustMastery = requireDeveloper(async (ctx) => {
|
|
98168
98476
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
|
|
98169
|
-
|
|
98477
|
+
logger67.debug("Adjusting mastered units", {
|
|
98170
98478
|
requesterId: ctx.user.id,
|
|
98171
98479
|
gameId: body2.gameId,
|
|
98172
98480
|
courseId: body2.courseId,
|
|
@@ -98176,6 +98484,22 @@ var init_timeback_controller = __esm(() => {
|
|
|
98176
98484
|
});
|
|
98177
98485
|
return ctx.services.timebackAdmin.adjustMasteredUnits(body2, ctx.user);
|
|
98178
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
|
+
});
|
|
98179
98503
|
searchStudents = requireGameManagementAccess(async (ctx) => {
|
|
98180
98504
|
const gameId = ctx.params.gameId;
|
|
98181
98505
|
const courseId = ctx.params.courseId;
|
|
@@ -98183,7 +98507,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98183
98507
|
if (!gameId || !courseId) {
|
|
98184
98508
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98185
98509
|
}
|
|
98186
|
-
|
|
98510
|
+
logger67.debug("Searching students for enrollment", {
|
|
98187
98511
|
requesterId: ctx.user.id,
|
|
98188
98512
|
gameId,
|
|
98189
98513
|
courseId,
|
|
@@ -98193,7 +98517,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98193
98517
|
});
|
|
98194
98518
|
enrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
98195
98519
|
const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
|
|
98196
|
-
|
|
98520
|
+
logger67.debug("Enrolling student", {
|
|
98197
98521
|
requesterId: ctx.user.id,
|
|
98198
98522
|
gameId: body2.gameId,
|
|
98199
98523
|
courseId: body2.courseId,
|
|
@@ -98203,7 +98527,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98203
98527
|
});
|
|
98204
98528
|
unenrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
98205
98529
|
const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
|
|
98206
|
-
|
|
98530
|
+
logger67.debug("Unenrolling student", {
|
|
98207
98531
|
requesterId: ctx.user.id,
|
|
98208
98532
|
gameId: body2.gameId,
|
|
98209
98533
|
courseId: body2.courseId,
|
|
@@ -98213,7 +98537,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98213
98537
|
});
|
|
98214
98538
|
reactivateEnrollment = requireGameManagementAccess(async (ctx) => {
|
|
98215
98539
|
const body2 = await parseRequestBody(ctx.request, ReactivateEnrollmentRequestSchema);
|
|
98216
|
-
|
|
98540
|
+
logger67.debug("Reactivating enrollment", {
|
|
98217
98541
|
requesterId: ctx.user.id,
|
|
98218
98542
|
gameId: body2.gameId,
|
|
98219
98543
|
courseId: body2.courseId,
|
|
@@ -98353,6 +98677,8 @@ var init_timeback_controller = __esm(() => {
|
|
|
98353
98677
|
getUserById,
|
|
98354
98678
|
setupIntegration,
|
|
98355
98679
|
getIntegrations,
|
|
98680
|
+
updateIntegration,
|
|
98681
|
+
getIntegrationConfig,
|
|
98356
98682
|
verifyIntegration,
|
|
98357
98683
|
getConfig: getConfig2,
|
|
98358
98684
|
deleteIntegrations,
|
|
@@ -98368,6 +98694,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98368
98694
|
grantXp,
|
|
98369
98695
|
adjustTime,
|
|
98370
98696
|
adjustMastery,
|
|
98697
|
+
reconcileMasteryForConfigChange,
|
|
98371
98698
|
searchStudents,
|
|
98372
98699
|
enrollStudent,
|
|
98373
98700
|
unenrollStudent,
|
|
@@ -98389,14 +98716,14 @@ var init_timeback_controller = __esm(() => {
|
|
|
98389
98716
|
});
|
|
98390
98717
|
|
|
98391
98718
|
// ../api-core/src/controllers/upload.controller.ts
|
|
98392
|
-
var
|
|
98719
|
+
var logger68, initiate;
|
|
98393
98720
|
var init_upload_controller = __esm(() => {
|
|
98394
98721
|
init_esm();
|
|
98395
98722
|
init_schemas_index();
|
|
98396
98723
|
init_src2();
|
|
98397
98724
|
init_errors();
|
|
98398
98725
|
init_utils11();
|
|
98399
|
-
|
|
98726
|
+
logger68 = log.scope("UploadController");
|
|
98400
98727
|
initiate = requireDeveloper(async (ctx) => {
|
|
98401
98728
|
let body2;
|
|
98402
98729
|
try {
|
|
@@ -98405,34 +98732,34 @@ var init_upload_controller = __esm(() => {
|
|
|
98405
98732
|
} catch (error2) {
|
|
98406
98733
|
if (error2 instanceof exports_external.ZodError) {
|
|
98407
98734
|
const details = formatZodError(error2);
|
|
98408
|
-
|
|
98735
|
+
logger68.warn("Initiate upload validation failed", { details });
|
|
98409
98736
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
98410
98737
|
}
|
|
98411
98738
|
throw ApiError.badRequest("Invalid JSON body");
|
|
98412
98739
|
}
|
|
98413
|
-
|
|
98740
|
+
logger68.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
|
|
98414
98741
|
return ctx.services.upload.initiate(body2, ctx.user);
|
|
98415
98742
|
});
|
|
98416
98743
|
});
|
|
98417
98744
|
|
|
98418
98745
|
// ../api-core/src/controllers/user.controller.ts
|
|
98419
|
-
var
|
|
98746
|
+
var logger69, getMe, getDemoProfile, updateDemoProfile, users2;
|
|
98420
98747
|
var init_user_controller = __esm(() => {
|
|
98421
98748
|
init_schemas_index();
|
|
98422
98749
|
init_src2();
|
|
98423
98750
|
init_utils11();
|
|
98424
|
-
|
|
98751
|
+
logger69 = log.scope("UserController");
|
|
98425
98752
|
getMe = requireNonAnonymous(async (ctx) => {
|
|
98426
|
-
|
|
98753
|
+
logger69.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
98427
98754
|
return ctx.services.user.getMe(ctx.user, ctx.gameId);
|
|
98428
98755
|
});
|
|
98429
98756
|
getDemoProfile = requireAnonymous(async (ctx) => {
|
|
98430
|
-
|
|
98757
|
+
logger69.debug("Getting demo profile", { userId: ctx.user.id });
|
|
98431
98758
|
return ctx.services.user.getDemoProfile(ctx.user.id);
|
|
98432
98759
|
});
|
|
98433
98760
|
updateDemoProfile = requireAnonymous(async (ctx) => {
|
|
98434
98761
|
const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
|
|
98435
|
-
|
|
98762
|
+
logger69.debug("Updating demo profile", {
|
|
98436
98763
|
userId: ctx.user.id,
|
|
98437
98764
|
displayName: body2.displayName
|
|
98438
98765
|
});
|
|
@@ -98446,13 +98773,13 @@ var init_user_controller = __esm(() => {
|
|
|
98446
98773
|
});
|
|
98447
98774
|
|
|
98448
98775
|
// ../api-core/src/controllers/verify.controller.ts
|
|
98449
|
-
var
|
|
98776
|
+
var logger70;
|
|
98450
98777
|
var init_verify_controller = __esm(() => {
|
|
98451
98778
|
init_schemas_index();
|
|
98452
98779
|
init_src2();
|
|
98453
98780
|
init_errors();
|
|
98454
98781
|
init_utils11();
|
|
98455
|
-
|
|
98782
|
+
logger70 = log.scope("VerifyController");
|
|
98456
98783
|
});
|
|
98457
98784
|
|
|
98458
98785
|
// ../api-core/src/controllers/index.ts
|
|
@@ -98766,7 +99093,7 @@ var init_uploads = __esm(() => {
|
|
|
98766
99093
|
});
|
|
98767
99094
|
|
|
98768
99095
|
// src/routes/platform/games/deploy.ts
|
|
98769
|
-
var
|
|
99096
|
+
var logger71, gameDeployRouter;
|
|
98770
99097
|
var init_deploy = __esm(() => {
|
|
98771
99098
|
init_drizzle_orm();
|
|
98772
99099
|
init_dist4();
|
|
@@ -98776,7 +99103,7 @@ var init_deploy = __esm(() => {
|
|
|
98776
99103
|
init_src2();
|
|
98777
99104
|
init_api();
|
|
98778
99105
|
init_uploads();
|
|
98779
|
-
|
|
99106
|
+
logger71 = log.scope("SandboxDeploy");
|
|
98780
99107
|
gameDeployRouter = new Hono2;
|
|
98781
99108
|
gameDeployRouter.post("/:slug/deploy", async (c2) => {
|
|
98782
99109
|
const user = c2.get("user");
|
|
@@ -98902,7 +99229,7 @@ var init_deploy = __esm(() => {
|
|
|
98902
99229
|
completedAt: now2
|
|
98903
99230
|
};
|
|
98904
99231
|
const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
|
|
98905
|
-
|
|
99232
|
+
logger71.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
|
|
98906
99233
|
return c2.json({
|
|
98907
99234
|
id: insertedJob.id,
|
|
98908
99235
|
status: "succeeded",
|
|
@@ -99549,7 +99876,7 @@ function verifyMockToken(idToken) {
|
|
|
99549
99876
|
throw new Error("Invalid LTI token format");
|
|
99550
99877
|
}
|
|
99551
99878
|
}
|
|
99552
|
-
var
|
|
99879
|
+
var logger72, ltiRouter;
|
|
99553
99880
|
var init_lti = __esm(() => {
|
|
99554
99881
|
init_drizzle_orm();
|
|
99555
99882
|
init_dist4();
|
|
@@ -99559,7 +99886,7 @@ var init_lti = __esm(() => {
|
|
|
99559
99886
|
init_src2();
|
|
99560
99887
|
init_constants();
|
|
99561
99888
|
init_api();
|
|
99562
|
-
|
|
99889
|
+
logger72 = log.scope("SandboxLti");
|
|
99563
99890
|
ltiRouter = new Hono2;
|
|
99564
99891
|
ltiRouter.post("/launch", async (c2) => {
|
|
99565
99892
|
const db2 = c2.get("db");
|
|
@@ -99577,7 +99904,7 @@ var init_lti = __esm(() => {
|
|
|
99577
99904
|
claims = verifyMockToken(idToken);
|
|
99578
99905
|
} catch (error2) {
|
|
99579
99906
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
99580
|
-
|
|
99907
|
+
logger72.error("LTI token verification failed", { error: errorMessage });
|
|
99581
99908
|
return c2.json({
|
|
99582
99909
|
error: "invalid_token",
|
|
99583
99910
|
message: errorMessage
|
|
@@ -99585,7 +99912,7 @@ var init_lti = __esm(() => {
|
|
|
99585
99912
|
}
|
|
99586
99913
|
const validationError = validateLtiClaims(claims);
|
|
99587
99914
|
if (validationError) {
|
|
99588
|
-
|
|
99915
|
+
logger72.warn("LTI claims validation failed", {
|
|
99589
99916
|
error: validationError,
|
|
99590
99917
|
sub: claims.sub
|
|
99591
99918
|
});
|
|
@@ -99605,7 +99932,7 @@ var init_lti = __esm(() => {
|
|
|
99605
99932
|
createdAt: new Date,
|
|
99606
99933
|
updatedAt: new Date
|
|
99607
99934
|
});
|
|
99608
|
-
|
|
99935
|
+
logger72.info("LTI launch successful", { userId: user.id });
|
|
99609
99936
|
const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
|
|
99610
99937
|
const currentHost = new URL(c2.req.url).hostname;
|
|
99611
99938
|
const redirectPath = extractRedirectPath(targetUri, currentHost);
|
|
@@ -99613,7 +99940,7 @@ var init_lti = __esm(() => {
|
|
|
99613
99940
|
return c2.redirect(redirectPath);
|
|
99614
99941
|
} catch (error2) {
|
|
99615
99942
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
99616
|
-
|
|
99943
|
+
logger72.error("Unexpected error during LTI launch", { error: errorMessage });
|
|
99617
99944
|
return c2.json({
|
|
99618
99945
|
error: "unexpected_error",
|
|
99619
99946
|
message: "An unexpected error occurred during LTI launch"
|