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