@playcademy/vite-plugin 0.2.34 → 0.2.35-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/index.js +830 -499
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25353,7 +25353,7 @@ var package_default;
|
|
|
25353
25353
|
var init_package = __esm(() => {
|
|
25354
25354
|
package_default = {
|
|
25355
25355
|
name: "@playcademy/sandbox",
|
|
25356
|
-
version: "0.3.
|
|
25356
|
+
version: "0.3.19-beta.1",
|
|
25357
25357
|
description: "Local development server for Playcademy game development",
|
|
25358
25358
|
type: "module",
|
|
25359
25359
|
exports: {
|
|
@@ -55125,6 +55125,8 @@ var TIMEBACK_SUBJECTS4;
|
|
|
55125
55125
|
var TimebackGradeSchema;
|
|
55126
55126
|
var TimebackSubjectSchema;
|
|
55127
55127
|
var UpdateTimebackXpRequestSchema;
|
|
55128
|
+
var CourseGoalsSchema;
|
|
55129
|
+
var UpdateGameTimebackIntegrationRequestSchema;
|
|
55128
55130
|
var TimebackActivityDataSchema;
|
|
55129
55131
|
var EndActivityRequestSchema;
|
|
55130
55132
|
var GameActivityMetricsSchema;
|
|
@@ -55144,6 +55146,7 @@ var ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE;
|
|
|
55144
55146
|
var GrantTimebackXpRequestSchema;
|
|
55145
55147
|
var AdjustTimebackTimeRequestSchema;
|
|
55146
55148
|
var AdjustTimebackMasteryRequestSchema;
|
|
55149
|
+
var ReconcileMasteryForConfigChangeSchema;
|
|
55147
55150
|
var EnrollStudentRequestSchema;
|
|
55148
55151
|
var UnenrollStudentRequestSchema;
|
|
55149
55152
|
var ReactivateEnrollmentRequestSchema;
|
|
@@ -55175,6 +55178,24 @@ var init_schemas11 = __esm(() => {
|
|
|
55175
55178
|
xp: exports_external.number().min(0, "XP must be a non-negative number"),
|
|
55176
55179
|
userTimestamp: exports_external.string().datetime().optional()
|
|
55177
55180
|
});
|
|
55181
|
+
CourseGoalsSchema = exports_external.object({
|
|
55182
|
+
dailyXp: exports_external.number().int().nonnegative().nullable().optional(),
|
|
55183
|
+
dailyLessons: exports_external.number().int().nonnegative().nullable().optional(),
|
|
55184
|
+
dailyActiveMinutes: exports_external.number().int().nonnegative().nullable().optional(),
|
|
55185
|
+
dailyAccuracy: exports_external.number().int().min(0).max(100).nullable().optional(),
|
|
55186
|
+
dailyMasteredUnits: exports_external.number().int().nonnegative().nullable().optional()
|
|
55187
|
+
});
|
|
55188
|
+
UpdateGameTimebackIntegrationRequestSchema = exports_external.object({
|
|
55189
|
+
title: exports_external.string().trim().min(1).optional(),
|
|
55190
|
+
courseCode: exports_external.string().trim().min(1).optional(),
|
|
55191
|
+
subject: TimebackSubjectSchema.optional(),
|
|
55192
|
+
totalXp: exports_external.number().int().nonnegative().nullable().optional(),
|
|
55193
|
+
masterableUnits: exports_external.number().int().nonnegative().nullable().optional(),
|
|
55194
|
+
goals: CourseGoalsSchema.optional(),
|
|
55195
|
+
publishStatus: exports_external.enum(["draft", "testing", "published", "deactivated"]).nullable().optional(),
|
|
55196
|
+
isSupplemental: exports_external.boolean().optional(),
|
|
55197
|
+
timebackVisible: exports_external.boolean().nullable().optional()
|
|
55198
|
+
});
|
|
55178
55199
|
TimebackActivityDataSchema = exports_external.object({
|
|
55179
55200
|
activityId: exports_external.string().min(1),
|
|
55180
55201
|
activityName: exports_external.string().optional(),
|
|
@@ -55344,6 +55365,13 @@ var init_schemas11 = __esm(() => {
|
|
|
55344
55365
|
date: AdminAttributionDateSchema.optional(),
|
|
55345
55366
|
useCurrentTime: exports_external.boolean().optional()
|
|
55346
55367
|
});
|
|
55368
|
+
ReconcileMasteryForConfigChangeSchema = exports_external.object({
|
|
55369
|
+
gameId: exports_external.string().uuid(),
|
|
55370
|
+
courseId: exports_external.string().min(1),
|
|
55371
|
+
oldMasterableUnits: exports_external.number().int().positive(),
|
|
55372
|
+
newMasterableUnits: exports_external.number().int().positive(),
|
|
55373
|
+
affectedStudentIds: exports_external.array(exports_external.string().min(1)).min(1).max(500)
|
|
55374
|
+
});
|
|
55347
55375
|
EnrollStudentRequestSchema = exports_external.object({
|
|
55348
55376
|
gameId: exports_external.string().uuid(),
|
|
55349
55377
|
courseId: exports_external.string().min(1),
|
|
@@ -55492,6 +55520,63 @@ function compareEnrollmentsByRecency(a, b) {
|
|
|
55492
55520
|
var init_timeback_admin_util = __esm(() => {
|
|
55493
55521
|
init_errors();
|
|
55494
55522
|
});
|
|
55523
|
+
async function upsertMasteryCompletionEntry(params) {
|
|
55524
|
+
const { client, courseId, studentId, appName, action } = params;
|
|
55525
|
+
const ids = deriveSourcedIds(courseId);
|
|
55526
|
+
const lineItemId = `${ids.course}-mastery-completion-assessment`;
|
|
55527
|
+
const resultId = `${lineItemId}:${studentId}:completion`;
|
|
55528
|
+
if (action === "complete") {
|
|
55529
|
+
await client.oneroster.assessmentLineItems.findOrCreate(lineItemId, {
|
|
55530
|
+
sourcedId: lineItemId,
|
|
55531
|
+
title: "Mastery Completion",
|
|
55532
|
+
status: ONEROSTER_STATUS.active,
|
|
55533
|
+
course: { sourcedId: ids.course },
|
|
55534
|
+
...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
|
|
55535
|
+
});
|
|
55536
|
+
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
55537
|
+
sourcedId: resultId,
|
|
55538
|
+
status: ONEROSTER_STATUS.active,
|
|
55539
|
+
assessmentLineItem: { sourcedId: lineItemId },
|
|
55540
|
+
student: { sourcedId: studentId },
|
|
55541
|
+
score: 100,
|
|
55542
|
+
scoreDate: new Date().toISOString(),
|
|
55543
|
+
scoreStatus: SCORE_STATUS.fullyGraded,
|
|
55544
|
+
inProgress: "false",
|
|
55545
|
+
metadata: {
|
|
55546
|
+
isMasteryCompletion: true,
|
|
55547
|
+
adminAction: true,
|
|
55548
|
+
appName
|
|
55549
|
+
}
|
|
55550
|
+
});
|
|
55551
|
+
} else {
|
|
55552
|
+
try {
|
|
55553
|
+
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
55554
|
+
sourcedId: resultId,
|
|
55555
|
+
status: ONEROSTER_STATUS.active,
|
|
55556
|
+
assessmentLineItem: { sourcedId: lineItemId },
|
|
55557
|
+
student: { sourcedId: studentId },
|
|
55558
|
+
score: 0,
|
|
55559
|
+
scoreDate: new Date().toISOString(),
|
|
55560
|
+
scoreStatus: SCORE_STATUS.notSubmitted,
|
|
55561
|
+
inProgress: "true",
|
|
55562
|
+
metadata: {
|
|
55563
|
+
isMasteryCompletion: true,
|
|
55564
|
+
adminAction: true,
|
|
55565
|
+
appName
|
|
55566
|
+
}
|
|
55567
|
+
});
|
|
55568
|
+
} catch {
|
|
55569
|
+
logger17.debug("No completion entry to revoke", { studentId, courseId });
|
|
55570
|
+
}
|
|
55571
|
+
}
|
|
55572
|
+
}
|
|
55573
|
+
var logger17;
|
|
55574
|
+
var init_timeback_mastery_completion_util = __esm(() => {
|
|
55575
|
+
init_src2();
|
|
55576
|
+
init_constants4();
|
|
55577
|
+
init_utils6();
|
|
55578
|
+
logger17 = log.scope("timeback-mastery-completion");
|
|
55579
|
+
});
|
|
55495
55580
|
function isRecord2(value) {
|
|
55496
55581
|
return typeof value === "object" && value !== null;
|
|
55497
55582
|
}
|
|
@@ -55847,7 +55932,7 @@ class TimebackAdminService {
|
|
|
55847
55932
|
}
|
|
55848
55933
|
requireClient() {
|
|
55849
55934
|
if (!this.deps.timeback) {
|
|
55850
|
-
|
|
55935
|
+
logger18.error("Timeback client not available in context");
|
|
55851
55936
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
55852
55937
|
}
|
|
55853
55938
|
return this.deps.timeback;
|
|
@@ -56067,7 +56152,7 @@ class TimebackAdminService {
|
|
|
56067
56152
|
});
|
|
56068
56153
|
return [enrollmentId, this.summarizeAnalyticsFacts(analytics.facts)];
|
|
56069
56154
|
} catch (error) {
|
|
56070
|
-
|
|
56155
|
+
logger18.warn("Failed to load enrollment analytics summary", {
|
|
56071
56156
|
enrollmentId,
|
|
56072
56157
|
error: error instanceof Error ? error.message : String(error)
|
|
56073
56158
|
});
|
|
@@ -56097,7 +56182,7 @@ class TimebackAdminService {
|
|
|
56097
56182
|
const events = await this.fetchCaliperEventsForStudent(client, studentId, source, eventLimit);
|
|
56098
56183
|
return TimebackAdminService.mapRecentActivityItems(events, relevantCourseIds).slice(0, maxResults);
|
|
56099
56184
|
} catch (error) {
|
|
56100
|
-
|
|
56185
|
+
logger18.warn("Failed to load recent Caliper activity", {
|
|
56101
56186
|
studentId,
|
|
56102
56187
|
gameId: source.gameId,
|
|
56103
56188
|
sourceMode: source.sourceMode,
|
|
@@ -56423,60 +56508,44 @@ class TimebackAdminService {
|
|
|
56423
56508
|
const wasMastered = currentMastered >= masterableUnits;
|
|
56424
56509
|
const willBeMastered = currentMastered + data.units >= masterableUnits;
|
|
56425
56510
|
if (wasMastered !== willBeMastered) {
|
|
56426
|
-
|
|
56427
|
-
|
|
56428
|
-
|
|
56429
|
-
|
|
56430
|
-
|
|
56431
|
-
|
|
56432
|
-
|
|
56433
|
-
status: ONEROSTER_STATUS.active,
|
|
56434
|
-
course: { sourcedId: ids.course },
|
|
56435
|
-
...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
|
|
56436
|
-
});
|
|
56437
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
56438
|
-
sourcedId: resultId,
|
|
56439
|
-
status: ONEROSTER_STATUS.active,
|
|
56440
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
56441
|
-
student: { sourcedId: data.studentId },
|
|
56442
|
-
score: 100,
|
|
56443
|
-
scoreDate: new Date().toISOString(),
|
|
56444
|
-
scoreStatus: SCORE_STATUS.fullyGraded,
|
|
56445
|
-
inProgress: "false",
|
|
56446
|
-
metadata: {
|
|
56447
|
-
isMasteryCompletion: true,
|
|
56448
|
-
adminAction: true,
|
|
56449
|
-
appName
|
|
56450
|
-
}
|
|
56451
|
-
});
|
|
56452
|
-
} else {
|
|
56453
|
-
try {
|
|
56454
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
56455
|
-
sourcedId: resultId,
|
|
56456
|
-
status: ONEROSTER_STATUS.active,
|
|
56457
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
56458
|
-
student: { sourcedId: data.studentId },
|
|
56459
|
-
score: 0,
|
|
56460
|
-
scoreDate: new Date().toISOString(),
|
|
56461
|
-
scoreStatus: SCORE_STATUS.notSubmitted,
|
|
56462
|
-
inProgress: "true",
|
|
56463
|
-
metadata: {
|
|
56464
|
-
isMasteryCompletion: true,
|
|
56465
|
-
adminAction: true,
|
|
56466
|
-
appName
|
|
56467
|
-
}
|
|
56468
|
-
});
|
|
56469
|
-
} catch {
|
|
56470
|
-
logger17.debug("No completion entry to revoke", {
|
|
56471
|
-
studentId: data.studentId,
|
|
56472
|
-
courseId: data.courseId
|
|
56473
|
-
});
|
|
56474
|
-
}
|
|
56475
|
-
}
|
|
56511
|
+
await upsertMasteryCompletionEntry({
|
|
56512
|
+
client,
|
|
56513
|
+
courseId: data.courseId,
|
|
56514
|
+
studentId: data.studentId,
|
|
56515
|
+
appName,
|
|
56516
|
+
action: willBeMastered ? "complete" : "revoke"
|
|
56517
|
+
});
|
|
56476
56518
|
}
|
|
56477
56519
|
}
|
|
56478
56520
|
return { status: "ok" };
|
|
56479
56521
|
}
|
|
56522
|
+
async reconcileMasteryForConfigChange(gameId, courseId, user, context) {
|
|
56523
|
+
const { client, appName } = await this.resolveAdminMutationContext(gameId, courseId, user);
|
|
56524
|
+
const action = context.newMasterableUnits < context.oldMasterableUnits ? "complete" : "revoke";
|
|
56525
|
+
const failed = [];
|
|
56526
|
+
let processed = 0;
|
|
56527
|
+
await TimebackAdminService.runWithConcurrency(context.affectedStudentIds, 8, async (studentId) => {
|
|
56528
|
+
try {
|
|
56529
|
+
await upsertMasteryCompletionEntry({
|
|
56530
|
+
client,
|
|
56531
|
+
courseId,
|
|
56532
|
+
studentId,
|
|
56533
|
+
appName,
|
|
56534
|
+
action
|
|
56535
|
+
});
|
|
56536
|
+
processed++;
|
|
56537
|
+
} catch (error) {
|
|
56538
|
+
logger18.warn("Failed to reconcile mastery completion for student", {
|
|
56539
|
+
studentId,
|
|
56540
|
+
courseId,
|
|
56541
|
+
action,
|
|
56542
|
+
error: error instanceof Error ? error.message : String(error)
|
|
56543
|
+
});
|
|
56544
|
+
failed.push(studentId);
|
|
56545
|
+
}
|
|
56546
|
+
});
|
|
56547
|
+
return { processed, failed };
|
|
56548
|
+
}
|
|
56480
56549
|
async searchStudentsForEnrollment(gameId, courseId, query, user) {
|
|
56481
56550
|
const client = this.requireClient();
|
|
56482
56551
|
await this.deps.validateGameManagementAccess(user, gameId);
|
|
@@ -56503,7 +56572,7 @@ class TimebackAdminService {
|
|
|
56503
56572
|
const response = await client["request"](endpoint, "GET");
|
|
56504
56573
|
allUsers = response.users || [];
|
|
56505
56574
|
} catch (error) {
|
|
56506
|
-
|
|
56575
|
+
logger18.warn("Failed to search OneRoster users", {
|
|
56507
56576
|
query: trimmedQuery,
|
|
56508
56577
|
error: error instanceof Error ? error.message : String(error)
|
|
56509
56578
|
});
|
|
@@ -56648,7 +56717,7 @@ class TimebackAdminService {
|
|
|
56648
56717
|
return results;
|
|
56649
56718
|
}
|
|
56650
56719
|
}
|
|
56651
|
-
var
|
|
56720
|
+
var logger18;
|
|
56652
56721
|
var init_timeback_admin_service = __esm(() => {
|
|
56653
56722
|
init_drizzle_orm();
|
|
56654
56723
|
init_src();
|
|
@@ -56661,8 +56730,9 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
56661
56730
|
init_errors();
|
|
56662
56731
|
init_timeback_admin_metrics_util();
|
|
56663
56732
|
init_timeback_admin_util();
|
|
56733
|
+
init_timeback_mastery_completion_util();
|
|
56664
56734
|
init_timeback_util();
|
|
56665
|
-
|
|
56735
|
+
logger18 = log.scope("TimebackAdminService");
|
|
56666
56736
|
});
|
|
56667
56737
|
var __esm5 = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
56668
56738
|
var TIMEBACK_API_URLS4;
|
|
@@ -56935,7 +57005,7 @@ class TimebackAssessmentsService {
|
|
|
56935
57005
|
isActive: row.bankActive
|
|
56936
57006
|
};
|
|
56937
57007
|
} catch {
|
|
56938
|
-
|
|
57008
|
+
logger19.warn("Failed to fetch QTI test metadata", {
|
|
56939
57009
|
identifier: row.qtiTestIdentifier
|
|
56940
57010
|
});
|
|
56941
57011
|
return {
|
|
@@ -56989,7 +57059,7 @@ class TimebackAssessmentsService {
|
|
|
56989
57059
|
});
|
|
56990
57060
|
} catch (error) {
|
|
56991
57061
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
56992
|
-
|
|
57062
|
+
logger19.info("QTI test already exists (idempotent retry)", {
|
|
56993
57063
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
56994
57064
|
});
|
|
56995
57065
|
} else {
|
|
@@ -57002,7 +57072,7 @@ class TimebackAssessmentsService {
|
|
|
57002
57072
|
qtiTestIdentifier: input.qtiTestIdentifier,
|
|
57003
57073
|
sortOrder: maxSortOrder + 1
|
|
57004
57074
|
}).returning();
|
|
57005
|
-
|
|
57075
|
+
logger19.info("Assessment created", {
|
|
57006
57076
|
integrationId,
|
|
57007
57077
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
57008
57078
|
});
|
|
@@ -57024,13 +57094,13 @@ class TimebackAssessmentsService {
|
|
|
57024
57094
|
}
|
|
57025
57095
|
await client.qti.tests.delete(qtiTestIdentifier);
|
|
57026
57096
|
} catch (error) {
|
|
57027
|
-
|
|
57097
|
+
logger19.warn("Partial QTI cleanup during assessment deletion", {
|
|
57028
57098
|
qtiTestIdentifier,
|
|
57029
57099
|
error: error instanceof Error ? error.message : String(error)
|
|
57030
57100
|
});
|
|
57031
57101
|
}
|
|
57032
57102
|
await this.deps.db.delete(gameTimebackAssessmentTests).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
57033
|
-
|
|
57103
|
+
logger19.info("Assessment deleted", { integrationId, qtiTestIdentifier });
|
|
57034
57104
|
}
|
|
57035
57105
|
async reorderAssessments(integrationId, identifiers) {
|
|
57036
57106
|
await this.requireIntegration(integrationId);
|
|
@@ -57075,7 +57145,7 @@ class TimebackAssessmentsService {
|
|
|
57075
57145
|
return client.qti.tests.reorderItems(qtiTestIdentifier, partId, sectionId, items2);
|
|
57076
57146
|
}
|
|
57077
57147
|
async activateAssessment(integrationId, qtiTestIdentifier) {
|
|
57078
|
-
|
|
57148
|
+
logger19.debug("Activating assessment", { integrationId, qtiTestIdentifier });
|
|
57079
57149
|
const client = this.requireClient();
|
|
57080
57150
|
const integration = await this.requireIntegration(integrationId);
|
|
57081
57151
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -57113,7 +57183,7 @@ class TimebackAssessmentsService {
|
|
|
57113
57183
|
});
|
|
57114
57184
|
}
|
|
57115
57185
|
} catch {
|
|
57116
|
-
|
|
57186
|
+
logger19.warn("Failed to reactivate existing child resource, will create new", {
|
|
57117
57187
|
childResourceId
|
|
57118
57188
|
});
|
|
57119
57189
|
childResourceId = null;
|
|
@@ -57126,7 +57196,7 @@ class TimebackAssessmentsService {
|
|
|
57126
57196
|
const resourceUrl = resource.metadata?.url;
|
|
57127
57197
|
if (resourceUrl === qtiTestUrl) {
|
|
57128
57198
|
childResourceId = resourceId;
|
|
57129
|
-
|
|
57199
|
+
logger19.info("Found existing child Resource for QTI test (idempotent retry)", {
|
|
57130
57200
|
qtiTestIdentifier,
|
|
57131
57201
|
childResourceId
|
|
57132
57202
|
});
|
|
@@ -57135,7 +57205,7 @@ class TimebackAssessmentsService {
|
|
|
57135
57205
|
} catch {}
|
|
57136
57206
|
}
|
|
57137
57207
|
if (!childResourceId) {
|
|
57138
|
-
|
|
57208
|
+
logger19.debug("Creating child resource", { qtiTestIdentifier, qtiTestUrl });
|
|
57139
57209
|
const childResult = await client.oneroster.resources.create({
|
|
57140
57210
|
resource: {
|
|
57141
57211
|
status: "active",
|
|
@@ -57163,10 +57233,10 @@ class TimebackAssessmentsService {
|
|
|
57163
57233
|
}
|
|
57164
57234
|
}
|
|
57165
57235
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: childResourceId, bankActive: true }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
57166
|
-
|
|
57236
|
+
logger19.info("Assessment activated", { integrationId, qtiTestIdentifier, childResourceId });
|
|
57167
57237
|
}
|
|
57168
57238
|
async deactivateAssessment(integrationId, qtiTestIdentifier) {
|
|
57169
|
-
|
|
57239
|
+
logger19.debug("Deactivating assessment", { integrationId, qtiTestIdentifier });
|
|
57170
57240
|
const client = this.requireClient();
|
|
57171
57241
|
const integration = await this.requireIntegration(integrationId);
|
|
57172
57242
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -57179,7 +57249,7 @@ class TimebackAssessmentsService {
|
|
|
57179
57249
|
const childResourceId = row.bankResourceId;
|
|
57180
57250
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
57181
57251
|
try {
|
|
57182
|
-
|
|
57252
|
+
logger19.debug("Reading parent resource for deactivation", {
|
|
57183
57253
|
resourceId: bankIds.resource
|
|
57184
57254
|
});
|
|
57185
57255
|
const parentResource = await client.oneroster.resources.get(bankIds.resource);
|
|
@@ -57198,22 +57268,22 @@ class TimebackAssessmentsService {
|
|
|
57198
57268
|
});
|
|
57199
57269
|
}
|
|
57200
57270
|
} catch (error) {
|
|
57201
|
-
|
|
57271
|
+
logger19.warn("Failed to update parent resource during deactivation", {
|
|
57202
57272
|
bankResourceId: bankIds.resource,
|
|
57203
57273
|
error: error instanceof Error ? error.message : String(error)
|
|
57204
57274
|
});
|
|
57205
57275
|
}
|
|
57206
57276
|
try {
|
|
57207
|
-
|
|
57277
|
+
logger19.debug("Deleting child resource", { childResourceId });
|
|
57208
57278
|
await client.oneroster.resources.delete(childResourceId);
|
|
57209
57279
|
} catch (error) {
|
|
57210
|
-
|
|
57280
|
+
logger19.warn("Failed to delete child resource (may already be deleted)", {
|
|
57211
57281
|
childResourceId,
|
|
57212
57282
|
error: error instanceof Error ? error.message : String(error)
|
|
57213
57283
|
});
|
|
57214
57284
|
}
|
|
57215
57285
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankActive: false }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
57216
|
-
|
|
57286
|
+
logger19.info("Assessment deactivated", { integrationId, qtiTestIdentifier });
|
|
57217
57287
|
}
|
|
57218
57288
|
isAssessmentActive(row) {
|
|
57219
57289
|
return row.bankActive;
|
|
@@ -57244,14 +57314,14 @@ class TimebackAssessmentsService {
|
|
|
57244
57314
|
status: "tobedeleted"
|
|
57245
57315
|
});
|
|
57246
57316
|
} catch (error) {
|
|
57247
|
-
|
|
57317
|
+
logger19.warn("Failed to delete component resource", { error });
|
|
57248
57318
|
}
|
|
57249
57319
|
for (const row of activeRows) {
|
|
57250
57320
|
if (row.bankResourceId) {
|
|
57251
57321
|
try {
|
|
57252
57322
|
await client.oneroster.resources.delete(row.bankResourceId);
|
|
57253
57323
|
} catch (error) {
|
|
57254
|
-
|
|
57324
|
+
logger19.warn("Failed to delete child resource", {
|
|
57255
57325
|
childResourceId: row.bankResourceId,
|
|
57256
57326
|
error
|
|
57257
57327
|
});
|
|
@@ -57261,17 +57331,17 @@ class TimebackAssessmentsService {
|
|
|
57261
57331
|
try {
|
|
57262
57332
|
await client.oneroster.resources.delete(bankIds.resource);
|
|
57263
57333
|
} catch (error) {
|
|
57264
|
-
|
|
57334
|
+
logger19.warn("Failed to delete parent resource", { error });
|
|
57265
57335
|
}
|
|
57266
57336
|
try {
|
|
57267
57337
|
await client.oneroster.courseComponents.update(bankIds.component, {
|
|
57268
57338
|
status: "tobedeleted"
|
|
57269
57339
|
});
|
|
57270
57340
|
} catch (error) {
|
|
57271
|
-
|
|
57341
|
+
logger19.warn("Failed to delete course component", { error });
|
|
57272
57342
|
}
|
|
57273
57343
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: null, bankActive: false }).where(eq(gameTimebackAssessmentTests.integrationId, integrationId));
|
|
57274
|
-
|
|
57344
|
+
logger19.info("Bank destroyed", { integrationId });
|
|
57275
57345
|
}
|
|
57276
57346
|
requireClient() {
|
|
57277
57347
|
if (!this.deps.timeback) {
|
|
@@ -57300,7 +57370,7 @@ class TimebackAssessmentsService {
|
|
|
57300
57370
|
async ensureBank(integration) {
|
|
57301
57371
|
const client = this.requireClient();
|
|
57302
57372
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
57303
|
-
|
|
57373
|
+
logger19.debug("Ensuring assessment bank hierarchy", {
|
|
57304
57374
|
courseId: integration.courseId,
|
|
57305
57375
|
bankIds
|
|
57306
57376
|
});
|
|
@@ -57317,7 +57387,7 @@ class TimebackAssessmentsService {
|
|
|
57317
57387
|
});
|
|
57318
57388
|
} catch (error) {
|
|
57319
57389
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
57320
|
-
|
|
57390
|
+
logger19.debug("Course component already exists", { sourcedId: bankIds.component });
|
|
57321
57391
|
} else {
|
|
57322
57392
|
throw error;
|
|
57323
57393
|
}
|
|
@@ -57341,7 +57411,7 @@ class TimebackAssessmentsService {
|
|
|
57341
57411
|
});
|
|
57342
57412
|
} catch (error) {
|
|
57343
57413
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
57344
|
-
|
|
57414
|
+
logger19.debug("Parent resource already exists", { sourcedId: bankIds.resource });
|
|
57345
57415
|
} else {
|
|
57346
57416
|
throw error;
|
|
57347
57417
|
}
|
|
@@ -57361,14 +57431,14 @@ class TimebackAssessmentsService {
|
|
|
57361
57431
|
});
|
|
57362
57432
|
} catch (error) {
|
|
57363
57433
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
57364
|
-
|
|
57434
|
+
logger19.debug("Component resource already exists", {
|
|
57365
57435
|
sourcedId: bankIds.componentResource
|
|
57366
57436
|
});
|
|
57367
57437
|
} else {
|
|
57368
57438
|
throw error;
|
|
57369
57439
|
}
|
|
57370
57440
|
}
|
|
57371
|
-
|
|
57441
|
+
logger19.info("Assessment bank hierarchy created", {
|
|
57372
57442
|
courseId: integration.courseId
|
|
57373
57443
|
});
|
|
57374
57444
|
}
|
|
@@ -57383,7 +57453,7 @@ class TimebackAssessmentsService {
|
|
|
57383
57453
|
return Math.max(...rows.map((r) => r.sortOrder));
|
|
57384
57454
|
}
|
|
57385
57455
|
}
|
|
57386
|
-
var
|
|
57456
|
+
var logger19;
|
|
57387
57457
|
var init_timeback_assessments_service = __esm(() => {
|
|
57388
57458
|
init_drizzle_orm();
|
|
57389
57459
|
init_tables_index();
|
|
@@ -57392,7 +57462,7 @@ var init_timeback_assessments_service = __esm(() => {
|
|
|
57392
57462
|
init_errors4();
|
|
57393
57463
|
init_utils6();
|
|
57394
57464
|
init_errors();
|
|
57395
|
-
|
|
57465
|
+
logger19 = log.scope("TimebackAssessmentsService");
|
|
57396
57466
|
});
|
|
57397
57467
|
async function promoteCompletedCourse({
|
|
57398
57468
|
db: db2,
|
|
@@ -57406,7 +57476,7 @@ async function promoteCompletedCourse({
|
|
|
57406
57476
|
});
|
|
57407
57477
|
const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
|
|
57408
57478
|
if (!nextIntegration) {
|
|
57409
|
-
|
|
57479
|
+
logger20.debug("Skipping promotion because no next course is configured", {
|
|
57410
57480
|
gameId: currentIntegration.gameId,
|
|
57411
57481
|
studentId,
|
|
57412
57482
|
grade: currentIntegration.grade,
|
|
@@ -57423,7 +57493,7 @@ async function promoteCompletedCourse({
|
|
|
57423
57493
|
const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
|
|
57424
57494
|
if (!currentEnrollment) {
|
|
57425
57495
|
if (nextEnrollment) {
|
|
57426
|
-
|
|
57496
|
+
logger20.debug("Skipping promotion because student is already on the next course", {
|
|
57427
57497
|
gameId: currentIntegration.gameId,
|
|
57428
57498
|
studentId,
|
|
57429
57499
|
grade: currentIntegration.grade,
|
|
@@ -57437,7 +57507,7 @@ async function promoteCompletedCourse({
|
|
|
57437
57507
|
nextCourseId: nextIntegration.courseId
|
|
57438
57508
|
};
|
|
57439
57509
|
}
|
|
57440
|
-
|
|
57510
|
+
logger20.debug("Skipping promotion because student is not enrolled in the current course", {
|
|
57441
57511
|
gameId: currentIntegration.gameId,
|
|
57442
57512
|
studentId,
|
|
57443
57513
|
grade: currentIntegration.grade,
|
|
@@ -57468,7 +57538,7 @@ async function promoteCompletedCourse({
|
|
|
57468
57538
|
client.invalidateEnrollments(studentId);
|
|
57469
57539
|
}
|
|
57470
57540
|
}
|
|
57471
|
-
|
|
57541
|
+
logger20.info("Promoted student to next course", {
|
|
57472
57542
|
gameId: currentIntegration.gameId,
|
|
57473
57543
|
studentId,
|
|
57474
57544
|
subject: currentIntegration.subject,
|
|
@@ -57483,14 +57553,14 @@ async function promoteCompletedCourse({
|
|
|
57483
57553
|
nextCourseId: nextIntegration.courseId
|
|
57484
57554
|
};
|
|
57485
57555
|
}
|
|
57486
|
-
var
|
|
57556
|
+
var logger20;
|
|
57487
57557
|
var init_timeback_promotion_util = __esm(() => {
|
|
57488
57558
|
init_drizzle_orm();
|
|
57489
57559
|
init_tables_index();
|
|
57490
57560
|
init_src2();
|
|
57491
|
-
|
|
57561
|
+
logger20 = log.scope("TimebackPromotion");
|
|
57492
57562
|
});
|
|
57493
|
-
var
|
|
57563
|
+
var logger21;
|
|
57494
57564
|
var TimebackService;
|
|
57495
57565
|
var init_timeback_service = __esm(() => {
|
|
57496
57566
|
init_drizzle_orm();
|
|
@@ -57502,7 +57572,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57502
57572
|
init_errors();
|
|
57503
57573
|
init_timeback_promotion_util();
|
|
57504
57574
|
init_timeback_util();
|
|
57505
|
-
|
|
57575
|
+
logger21 = log.scope("TimebackService");
|
|
57506
57576
|
TimebackService = class TimebackService2 {
|
|
57507
57577
|
static HEARTBEAT_DEDUPE_TTL_MS = 300000;
|
|
57508
57578
|
static processedHeartbeatWindows = new Map;
|
|
@@ -57548,7 +57618,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57548
57618
|
}
|
|
57549
57619
|
requireClient() {
|
|
57550
57620
|
if (!this.deps.timeback) {
|
|
57551
|
-
|
|
57621
|
+
logger21.error("Timeback client not available in context");
|
|
57552
57622
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
57553
57623
|
}
|
|
57554
57624
|
return this.deps.timeback;
|
|
@@ -57601,7 +57671,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57601
57671
|
set: { xp: sql`excluded.xp`, updatedAt: new Date }
|
|
57602
57672
|
}).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
|
|
57603
57673
|
if (!result) {
|
|
57604
|
-
|
|
57674
|
+
logger21.error("Daily XP upsert returned no rows", { userId, date: targetDate });
|
|
57605
57675
|
throw new InternalError("Failed to update daily XP record");
|
|
57606
57676
|
}
|
|
57607
57677
|
return { xp: result.xp, date: result.date.toISOString() };
|
|
@@ -57632,7 +57702,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57632
57702
|
columns: { id: true, timebackId: true }
|
|
57633
57703
|
});
|
|
57634
57704
|
if (dbUser?.timebackId) {
|
|
57635
|
-
|
|
57705
|
+
logger21.info("Student already onboarded", { userId: user.id });
|
|
57636
57706
|
return { status: "already_populated" };
|
|
57637
57707
|
}
|
|
57638
57708
|
let timebackId;
|
|
@@ -57641,7 +57711,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57641
57711
|
const existingUser = await client.oneroster.users.findByEmail(user.email);
|
|
57642
57712
|
timebackId = existingUser.sourcedId;
|
|
57643
57713
|
name3 = `${existingUser.givenName} ${existingUser.familyName}`;
|
|
57644
|
-
|
|
57714
|
+
logger21.info("Found existing student in OneRoster", {
|
|
57645
57715
|
userId: user.id,
|
|
57646
57716
|
timebackId
|
|
57647
57717
|
});
|
|
@@ -57670,7 +57740,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57670
57740
|
}
|
|
57671
57741
|
timebackId = response.sourcedIdPairs.allocatedSourcedId;
|
|
57672
57742
|
name3 = `${providedNames.firstName} ${providedNames.lastName}`;
|
|
57673
|
-
|
|
57743
|
+
logger21.info("Created student in OneRoster", { userId: user.id, timebackId });
|
|
57674
57744
|
}
|
|
57675
57745
|
const assessments = await this.fetchAssessments(timebackId);
|
|
57676
57746
|
await db2.transaction(async (tx) => {
|
|
@@ -57704,7 +57774,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57704
57774
|
}
|
|
57705
57775
|
const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
|
|
57706
57776
|
if (!updated) {
|
|
57707
|
-
|
|
57777
|
+
logger21.error("User Timeback ID update returned no rows", {
|
|
57708
57778
|
userId: user.id,
|
|
57709
57779
|
timebackId
|
|
57710
57780
|
});
|
|
@@ -57728,13 +57798,13 @@ var init_timeback_service = __esm(() => {
|
|
|
57728
57798
|
}
|
|
57729
57799
|
offset += limit;
|
|
57730
57800
|
}
|
|
57731
|
-
|
|
57801
|
+
logger21.debug("Fetched assessments", {
|
|
57732
57802
|
studentSourcedId,
|
|
57733
57803
|
totalCount: allAssessments.length
|
|
57734
57804
|
});
|
|
57735
57805
|
return allAssessments;
|
|
57736
57806
|
} catch (error) {
|
|
57737
|
-
|
|
57807
|
+
logger21.warn("Failed to fetch assessments", { studentSourcedId, error });
|
|
57738
57808
|
return [];
|
|
57739
57809
|
}
|
|
57740
57810
|
}
|
|
@@ -57847,7 +57917,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57847
57917
|
masterableUnits: derivedMasterableUnits
|
|
57848
57918
|
} = courseConfig;
|
|
57849
57919
|
if (!isTimebackSubject(subjectInput)) {
|
|
57850
|
-
|
|
57920
|
+
logger21.warn("Invalid Timeback subject in course config", {
|
|
57851
57921
|
subject: subjectInput,
|
|
57852
57922
|
courseCode,
|
|
57853
57923
|
title
|
|
@@ -57855,7 +57925,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57855
57925
|
throw new ValidationError(`Invalid subject "${subjectInput}"`);
|
|
57856
57926
|
}
|
|
57857
57927
|
if (!isTimebackGrade(grade)) {
|
|
57858
|
-
|
|
57928
|
+
logger21.warn("Invalid Timeback grade in course config", {
|
|
57859
57929
|
grade,
|
|
57860
57930
|
courseCode,
|
|
57861
57931
|
title
|
|
@@ -57867,7 +57937,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57867
57937
|
const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
|
|
57868
57938
|
const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
|
|
57869
57939
|
if (typeof totalXp !== "number") {
|
|
57870
|
-
|
|
57940
|
+
logger21.warn("Course missing totalXp in Timeback config", {
|
|
57871
57941
|
courseCode,
|
|
57872
57942
|
title
|
|
57873
57943
|
});
|
|
@@ -57883,7 +57953,9 @@ var init_timeback_service = __esm(() => {
|
|
|
57883
57953
|
courseCode,
|
|
57884
57954
|
level,
|
|
57885
57955
|
gradingScheme: "STANDARD",
|
|
57886
|
-
metadata: metadata2
|
|
57956
|
+
metadata: TimebackService2.patchCourseMetadata(metadata2, totalXp, {
|
|
57957
|
+
masterableUnits: masterableUnits ?? null
|
|
57958
|
+
})
|
|
57887
57959
|
},
|
|
57888
57960
|
component: {
|
|
57889
57961
|
...baseConfig.component,
|
|
@@ -57908,7 +57980,7 @@ var init_timeback_service = __esm(() => {
|
|
|
57908
57980
|
const existingIntegration = existing.find((i2) => i2.grade === grade && i2.subject === subject);
|
|
57909
57981
|
if (existingIntegration) {
|
|
57910
57982
|
await client.update(existingIntegration.courseId, fullConfig);
|
|
57911
|
-
const [updated] = await db2.update(gameTimebackIntegrations).set({ totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
|
|
57983
|
+
const [updated] = await db2.update(gameTimebackIntegrations).set({ subject, totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
|
|
57912
57984
|
if (updated) {
|
|
57913
57985
|
integrations.push(this.toGameTimebackIntegration(updated));
|
|
57914
57986
|
}
|
|
@@ -57933,6 +58005,60 @@ var init_timeback_service = __esm(() => {
|
|
|
57933
58005
|
});
|
|
57934
58006
|
return rows.map((row) => this.toGameTimebackIntegration(row));
|
|
57935
58007
|
}
|
|
58008
|
+
async getIntegrationConfig(gameId, courseId, user) {
|
|
58009
|
+
const client = this.requireClient();
|
|
58010
|
+
await this.deps.validateGameManagementAccess(user, gameId);
|
|
58011
|
+
const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
58012
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
|
|
58013
|
+
});
|
|
58014
|
+
if (!integration) {
|
|
58015
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
58016
|
+
}
|
|
58017
|
+
const config2 = await client.getConfig(courseId);
|
|
58018
|
+
return this.toGameTimebackIntegrationConfig(integration, config2);
|
|
58019
|
+
}
|
|
58020
|
+
async updateIntegration(gameId, courseId, user, patch) {
|
|
58021
|
+
const client = this.requireClient();
|
|
58022
|
+
await this.deps.validateDeveloperAccess(user, gameId);
|
|
58023
|
+
const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
58024
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
|
|
58025
|
+
});
|
|
58026
|
+
if (!integration) {
|
|
58027
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
58028
|
+
}
|
|
58029
|
+
const timebackConfig = await client.getConfig(courseId);
|
|
58030
|
+
const liveSubject = timebackConfig.course.subjects[0];
|
|
58031
|
+
const subject = patch.subject ?? (isTimebackSubject(liveSubject) ? liveSubject : integration.subject);
|
|
58032
|
+
if (!isTimebackSubject(subject)) {
|
|
58033
|
+
throw new ValidationError(`Invalid subject "${subject}"`);
|
|
58034
|
+
}
|
|
58035
|
+
if (subject !== integration.subject) {
|
|
58036
|
+
const subjectConflict = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
58037
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.grade, integration.grade), eq(gameTimebackIntegrations.subject, subject))
|
|
58038
|
+
});
|
|
58039
|
+
if (subjectConflict && subjectConflict.id !== integration.id) {
|
|
58040
|
+
throw new ValidationError(`A TimeBack integration already exists for ${subject} Grade ${integration.grade}`);
|
|
58041
|
+
}
|
|
58042
|
+
}
|
|
58043
|
+
const totalXp = "totalXp" in patch ? patch.totalXp ?? null : TimebackService2.getTotalXpFromConfig(timebackConfig) ?? integration.totalXp ?? null;
|
|
58044
|
+
const masterableUnits = "masterableUnits" in patch ? patch.masterableUnits ?? null : TimebackService2.getMasterableUnitsFromConfig(timebackConfig);
|
|
58045
|
+
await client.update(courseId, TimebackService2.patchTimebackConfig(timebackConfig, {
|
|
58046
|
+
...patch,
|
|
58047
|
+
subject,
|
|
58048
|
+
totalXp,
|
|
58049
|
+
masterableUnits,
|
|
58050
|
+
grade: integration.grade
|
|
58051
|
+
}));
|
|
58052
|
+
const [updated] = await this.deps.db.update(gameTimebackIntegrations).set({
|
|
58053
|
+
subject,
|
|
58054
|
+
totalXp,
|
|
58055
|
+
updatedAt: new Date
|
|
58056
|
+
}).where(eq(gameTimebackIntegrations.id, integration.id)).returning();
|
|
58057
|
+
if (!updated) {
|
|
58058
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
58059
|
+
}
|
|
58060
|
+
return this.toGameTimebackIntegration(updated);
|
|
58061
|
+
}
|
|
57936
58062
|
async verifyIntegration(gameId, user) {
|
|
57937
58063
|
const client = this.requireClient();
|
|
57938
58064
|
const db2 = this.deps.db;
|
|
@@ -57990,6 +58116,146 @@ var init_timeback_service = __esm(() => {
|
|
|
57990
58116
|
}
|
|
57991
58117
|
await db2.delete(gameTimebackIntegrations).where(eq(gameTimebackIntegrations.gameId, gameId));
|
|
57992
58118
|
}
|
|
58119
|
+
static getMasterableUnitsFromConfig(config2) {
|
|
58120
|
+
const playcademyMetadata = config2.resource.metadata?.playcademy;
|
|
58121
|
+
if (!isPlaycademyResourceMetadata(playcademyMetadata)) {
|
|
58122
|
+
return null;
|
|
58123
|
+
}
|
|
58124
|
+
return playcademyMetadata?.mastery?.masterableUnits ?? null;
|
|
58125
|
+
}
|
|
58126
|
+
static getTotalXpFromConfig(config2) {
|
|
58127
|
+
const courseMetadata = isCourseMetadata(config2.course.metadata) ? config2.course.metadata : undefined;
|
|
58128
|
+
if (typeof courseMetadata?.metrics?.totalXp === "number") {
|
|
58129
|
+
return courseMetadata.metrics.totalXp;
|
|
58130
|
+
}
|
|
58131
|
+
const resourceMetadata = config2.resource.metadata;
|
|
58132
|
+
if (isRecord2(resourceMetadata) && typeof resourceMetadata.xp === "number") {
|
|
58133
|
+
return resourceMetadata.xp;
|
|
58134
|
+
}
|
|
58135
|
+
return null;
|
|
58136
|
+
}
|
|
58137
|
+
static patchCourseMetadata(metadata2, totalXp, options) {
|
|
58138
|
+
const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
|
|
58139
|
+
const currentMetrics = isRecord2(nextMetadata.metrics) ? nextMetadata.metrics : {};
|
|
58140
|
+
const metrics = { ...currentMetrics };
|
|
58141
|
+
if (totalXp === null) {
|
|
58142
|
+
delete metrics.totalXp;
|
|
58143
|
+
} else {
|
|
58144
|
+
metrics.totalXp = totalXp;
|
|
58145
|
+
}
|
|
58146
|
+
if (options?.masterableUnits !== undefined) {
|
|
58147
|
+
if (options.masterableUnits === null) {
|
|
58148
|
+
delete metrics.totalLessons;
|
|
58149
|
+
} else {
|
|
58150
|
+
metrics.totalLessons = options.masterableUnits;
|
|
58151
|
+
}
|
|
58152
|
+
}
|
|
58153
|
+
metrics.totalGrades = 1;
|
|
58154
|
+
if (Object.keys(metrics).length > 0) {
|
|
58155
|
+
nextMetadata.metrics = metrics;
|
|
58156
|
+
} else {
|
|
58157
|
+
delete nextMetadata.metrics;
|
|
58158
|
+
}
|
|
58159
|
+
const goals = options?.goals;
|
|
58160
|
+
if (goals !== undefined) {
|
|
58161
|
+
if (goals === null) {
|
|
58162
|
+
delete nextMetadata.goals;
|
|
58163
|
+
} else {
|
|
58164
|
+
const currentGoals = isRecord2(nextMetadata.goals) ? nextMetadata.goals : {};
|
|
58165
|
+
const nextGoals = { ...currentGoals };
|
|
58166
|
+
for (const [key, value] of Object.entries(goals)) {
|
|
58167
|
+
if (value === null) {
|
|
58168
|
+
delete nextGoals[key];
|
|
58169
|
+
} else if (value !== undefined) {
|
|
58170
|
+
nextGoals[key] = value;
|
|
58171
|
+
}
|
|
58172
|
+
}
|
|
58173
|
+
if (Object.keys(nextGoals).length > 0) {
|
|
58174
|
+
nextMetadata.goals = nextGoals;
|
|
58175
|
+
} else {
|
|
58176
|
+
delete nextMetadata.goals;
|
|
58177
|
+
}
|
|
58178
|
+
}
|
|
58179
|
+
}
|
|
58180
|
+
if (options?.publishStatus !== undefined) {
|
|
58181
|
+
if (options.publishStatus === null) {
|
|
58182
|
+
delete nextMetadata.publishStatus;
|
|
58183
|
+
const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
|
|
58184
|
+
delete alphaLearn.publishStatus;
|
|
58185
|
+
if (Object.keys(alphaLearn).length > 0) {
|
|
58186
|
+
nextMetadata.AlphaLearn = alphaLearn;
|
|
58187
|
+
} else {
|
|
58188
|
+
delete nextMetadata.AlphaLearn;
|
|
58189
|
+
}
|
|
58190
|
+
} else {
|
|
58191
|
+
nextMetadata.publishStatus = options.publishStatus;
|
|
58192
|
+
const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
|
|
58193
|
+
alphaLearn.publishStatus = options.publishStatus === "published" ? "active" : options.publishStatus;
|
|
58194
|
+
nextMetadata.AlphaLearn = alphaLearn;
|
|
58195
|
+
}
|
|
58196
|
+
}
|
|
58197
|
+
if (options?.isSupplemental !== undefined) {
|
|
58198
|
+
nextMetadata.isSupplemental = options.isSupplemental;
|
|
58199
|
+
}
|
|
58200
|
+
if (options?.timebackVisible !== undefined) {
|
|
58201
|
+
if (options.timebackVisible === null) {
|
|
58202
|
+
delete nextMetadata.timebackVisible;
|
|
58203
|
+
} else {
|
|
58204
|
+
nextMetadata.timebackVisible = options.timebackVisible;
|
|
58205
|
+
}
|
|
58206
|
+
}
|
|
58207
|
+
return Object.keys(nextMetadata).length > 0 ? nextMetadata : undefined;
|
|
58208
|
+
}
|
|
58209
|
+
static patchResourceMetadata(metadata2, options) {
|
|
58210
|
+
const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
|
|
58211
|
+
const playcademyMetadata = isRecord2(nextMetadata.playcademy) ? { ...nextMetadata.playcademy } : {};
|
|
58212
|
+
const masteryMetadata = isRecord2(playcademyMetadata.mastery) ? { ...playcademyMetadata.mastery } : {};
|
|
58213
|
+
nextMetadata.subject = options.subject;
|
|
58214
|
+
nextMetadata.grades = [options.grade];
|
|
58215
|
+
if (options.totalXp === null) {
|
|
58216
|
+
delete nextMetadata.xp;
|
|
58217
|
+
} else {
|
|
58218
|
+
nextMetadata.xp = options.totalXp;
|
|
58219
|
+
}
|
|
58220
|
+
if (options.masterableUnits === null) {
|
|
58221
|
+
delete masteryMetadata.masterableUnits;
|
|
58222
|
+
} else {
|
|
58223
|
+
masteryMetadata.masterableUnits = options.masterableUnits;
|
|
58224
|
+
}
|
|
58225
|
+
if (Object.keys(masteryMetadata).length > 0) {
|
|
58226
|
+
playcademyMetadata.mastery = masteryMetadata;
|
|
58227
|
+
} else {
|
|
58228
|
+
delete playcademyMetadata.mastery;
|
|
58229
|
+
}
|
|
58230
|
+
if (Object.keys(playcademyMetadata).length > 0) {
|
|
58231
|
+
nextMetadata.playcademy = playcademyMetadata;
|
|
58232
|
+
} else {
|
|
58233
|
+
delete nextMetadata.playcademy;
|
|
58234
|
+
}
|
|
58235
|
+
return nextMetadata;
|
|
58236
|
+
}
|
|
58237
|
+
static patchTimebackConfig(config2, patch) {
|
|
58238
|
+
return {
|
|
58239
|
+
...config2,
|
|
58240
|
+
course: {
|
|
58241
|
+
...config2.course,
|
|
58242
|
+
title: patch.title ?? config2.course.title,
|
|
58243
|
+
courseCode: patch.courseCode ?? config2.course.courseCode,
|
|
58244
|
+
subjects: [patch.subject],
|
|
58245
|
+
metadata: TimebackService2.patchCourseMetadata(config2.course.metadata, patch.totalXp, {
|
|
58246
|
+
masterableUnits: patch.masterableUnits,
|
|
58247
|
+
goals: patch.goals,
|
|
58248
|
+
publishStatus: patch.publishStatus,
|
|
58249
|
+
isSupplemental: patch.isSupplemental,
|
|
58250
|
+
timebackVisible: patch.timebackVisible
|
|
58251
|
+
})
|
|
58252
|
+
},
|
|
58253
|
+
resource: {
|
|
58254
|
+
...config2.resource,
|
|
58255
|
+
metadata: TimebackService2.patchResourceMetadata(config2.resource.metadata, patch)
|
|
58256
|
+
}
|
|
58257
|
+
};
|
|
58258
|
+
}
|
|
57993
58259
|
toGameTimebackIntegration(integration) {
|
|
57994
58260
|
return {
|
|
57995
58261
|
id: integration.id,
|
|
@@ -58003,6 +58269,21 @@ var init_timeback_service = __esm(() => {
|
|
|
58003
58269
|
lastVerifiedAt: integration.lastVerifiedAt ?? null
|
|
58004
58270
|
};
|
|
58005
58271
|
}
|
|
58272
|
+
toGameTimebackIntegrationConfig(integration, config2) {
|
|
58273
|
+
const subject = config2.course.subjects[0] ?? integration.subject;
|
|
58274
|
+
if (!isTimebackSubject(subject)) {
|
|
58275
|
+
throw new ValidationError(`Invalid subject "${subject}"`);
|
|
58276
|
+
}
|
|
58277
|
+
return {
|
|
58278
|
+
integration: this.toGameTimebackIntegration(integration),
|
|
58279
|
+
title: config2.course.title,
|
|
58280
|
+
courseCode: config2.course.courseCode,
|
|
58281
|
+
subject,
|
|
58282
|
+
totalXp: TimebackService2.getTotalXpFromConfig(config2) ?? integration.totalXp ?? null,
|
|
58283
|
+
masterableUnits: TimebackService2.getMasterableUnitsFromConfig(config2),
|
|
58284
|
+
metadata: isCourseMetadata(config2.course.metadata) ? config2.course.metadata : null
|
|
58285
|
+
};
|
|
58286
|
+
}
|
|
58006
58287
|
async endActivity({
|
|
58007
58288
|
gameId,
|
|
58008
58289
|
studentId,
|
|
@@ -58068,7 +58349,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58068
58349
|
...runId ? { runId } : {}
|
|
58069
58350
|
});
|
|
58070
58351
|
}
|
|
58071
|
-
|
|
58352
|
+
logger21.info("Recorded activity completion", {
|
|
58072
58353
|
gameId,
|
|
58073
58354
|
courseId: integration.courseId,
|
|
58074
58355
|
studentId,
|
|
@@ -58122,7 +58403,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58122
58403
|
masteredUnits: masteryStatus.masteredUnits,
|
|
58123
58404
|
masterableUnits: masteryStatus.masterableUnits
|
|
58124
58405
|
};
|
|
58125
|
-
|
|
58406
|
+
logger21.debug("Skipping course advancement because mastery is incomplete", {
|
|
58126
58407
|
gameId,
|
|
58127
58408
|
studentId,
|
|
58128
58409
|
subject: currentIntegration.subject,
|
|
@@ -58140,7 +58421,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58140
58421
|
studentId,
|
|
58141
58422
|
enrollments
|
|
58142
58423
|
});
|
|
58143
|
-
|
|
58424
|
+
logger21.info("Manually advanced student", {
|
|
58144
58425
|
gameId,
|
|
58145
58426
|
studentId,
|
|
58146
58427
|
subject: currentIntegration.subject,
|
|
@@ -58173,7 +58454,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58173
58454
|
const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
|
|
58174
58455
|
const effectiveResumeId = resumeId ?? runId;
|
|
58175
58456
|
if (TimebackService2.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
|
|
58176
|
-
|
|
58457
|
+
logger21.debug("Skipping duplicate heartbeat window", {
|
|
58177
58458
|
gameId,
|
|
58178
58459
|
studentId,
|
|
58179
58460
|
runId,
|
|
@@ -58186,7 +58467,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58186
58467
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
58187
58468
|
const inFlightHeartbeat = TimebackService2.getInFlightHeartbeatWindow(heartbeatWindowKey);
|
|
58188
58469
|
if (inFlightHeartbeat) {
|
|
58189
|
-
|
|
58470
|
+
logger21.debug("Joining in-flight heartbeat window", {
|
|
58190
58471
|
gameId,
|
|
58191
58472
|
studentId,
|
|
58192
58473
|
runId,
|
|
@@ -58223,7 +58504,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58223
58504
|
});
|
|
58224
58505
|
}
|
|
58225
58506
|
TimebackService2.markHeartbeatWindowProcessed(heartbeatWindowKey);
|
|
58226
|
-
|
|
58507
|
+
logger21.debug("Recorded heartbeat", {
|
|
58227
58508
|
gameId,
|
|
58228
58509
|
courseId: integration.courseId,
|
|
58229
58510
|
studentId,
|
|
@@ -58258,7 +58539,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58258
58539
|
});
|
|
58259
58540
|
courseIds = integrations.map((i2) => i2.courseId);
|
|
58260
58541
|
if (courseIds.length === 0) {
|
|
58261
|
-
|
|
58542
|
+
logger21.debug("No integrations found for game, returning 0 XP", {
|
|
58262
58543
|
timebackId,
|
|
58263
58544
|
gameId: options.gameId,
|
|
58264
58545
|
grade: options.grade,
|
|
@@ -58275,7 +58556,7 @@ var init_timeback_service = __esm(() => {
|
|
|
58275
58556
|
courseIds: courseIds.length > 0 ? courseIds : undefined,
|
|
58276
58557
|
include: options?.include
|
|
58277
58558
|
});
|
|
58278
|
-
|
|
58559
|
+
logger21.debug("Retrieved student XP", {
|
|
58279
58560
|
timebackId,
|
|
58280
58561
|
gameId: options?.gameId,
|
|
58281
58562
|
grade: options?.grade,
|
|
@@ -58303,15 +58584,15 @@ class UploadService {
|
|
|
58303
58584
|
const { fileName, gameId } = request;
|
|
58304
58585
|
const bucketName = this.deps.uploadBucket;
|
|
58305
58586
|
if (!bucketName) {
|
|
58306
|
-
|
|
58587
|
+
logger22.error("Upload bucket not configured in environment");
|
|
58307
58588
|
throw new ValidationError("Upload bucket not configured");
|
|
58308
58589
|
}
|
|
58309
58590
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
58310
58591
|
const version2 = ulid();
|
|
58311
58592
|
const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
|
|
58312
|
-
|
|
58593
|
+
logger22.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
|
|
58313
58594
|
const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
|
|
58314
|
-
|
|
58595
|
+
logger22.info("Presigned URL generated", {
|
|
58315
58596
|
userId: user.id,
|
|
58316
58597
|
gameId,
|
|
58317
58598
|
version: version2
|
|
@@ -58324,12 +58605,12 @@ class UploadService {
|
|
|
58324
58605
|
};
|
|
58325
58606
|
}
|
|
58326
58607
|
}
|
|
58327
|
-
var
|
|
58608
|
+
var logger22;
|
|
58328
58609
|
var init_upload_service = __esm(() => {
|
|
58329
58610
|
init_node();
|
|
58330
58611
|
init_src2();
|
|
58331
58612
|
init_errors();
|
|
58332
|
-
|
|
58613
|
+
logger22 = log.scope("UploadService");
|
|
58333
58614
|
});
|
|
58334
58615
|
function createPlatformServices(deps) {
|
|
58335
58616
|
const {
|
|
@@ -58630,7 +58911,7 @@ class AchievementService {
|
|
|
58630
58911
|
results.push(result);
|
|
58631
58912
|
}
|
|
58632
58913
|
}
|
|
58633
|
-
|
|
58914
|
+
logger23.debug("Listed current achievements", { userId: user.id, count: results.length });
|
|
58634
58915
|
return results;
|
|
58635
58916
|
}
|
|
58636
58917
|
async listHistory(user, limit) {
|
|
@@ -58648,14 +58929,14 @@ class AchievementService {
|
|
|
58648
58929
|
createdAt: c.createdAt,
|
|
58649
58930
|
scopeKey: c.scopeKey
|
|
58650
58931
|
}));
|
|
58651
|
-
|
|
58932
|
+
logger23.debug("Listed achievement history", { userId: user.id, count: results.length });
|
|
58652
58933
|
return results;
|
|
58653
58934
|
}
|
|
58654
58935
|
async submitProgress(achievementId, user) {
|
|
58655
58936
|
const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
|
|
58656
58937
|
broadcast: false
|
|
58657
58938
|
});
|
|
58658
|
-
|
|
58939
|
+
logger23.debug("Submitted progress", {
|
|
58659
58940
|
userId: user.id,
|
|
58660
58941
|
achievementId,
|
|
58661
58942
|
wasNewClaim
|
|
@@ -58687,7 +58968,7 @@ class AchievementService {
|
|
|
58687
58968
|
rewardCredits
|
|
58688
58969
|
}).returning();
|
|
58689
58970
|
if (!newClaim) {
|
|
58690
|
-
|
|
58971
|
+
logger23.error("Achievement claim insert returned no rows", {
|
|
58691
58972
|
userId,
|
|
58692
58973
|
achievementId,
|
|
58693
58974
|
scopeKey
|
|
@@ -58696,7 +58977,7 @@ class AchievementService {
|
|
|
58696
58977
|
}
|
|
58697
58978
|
await this.deps.addCredits(userId, rewardCredits);
|
|
58698
58979
|
await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
|
|
58699
|
-
|
|
58980
|
+
logger23.info("Awarded achievement", {
|
|
58700
58981
|
userId,
|
|
58701
58982
|
achievementId,
|
|
58702
58983
|
scopeKey,
|
|
@@ -58733,7 +59014,7 @@ class AchievementService {
|
|
|
58733
59014
|
return { title, body: body2 };
|
|
58734
59015
|
}
|
|
58735
59016
|
}
|
|
58736
|
-
var
|
|
59017
|
+
var logger23;
|
|
58737
59018
|
var init_achievement_service = __esm(() => {
|
|
58738
59019
|
init_drizzle_orm();
|
|
58739
59020
|
init_tables_index();
|
|
@@ -58742,7 +59023,7 @@ var init_achievement_service = __esm(() => {
|
|
|
58742
59023
|
init_errors();
|
|
58743
59024
|
init_leaderboard_util();
|
|
58744
59025
|
init_scope_util();
|
|
58745
|
-
|
|
59026
|
+
logger23 = log.scope("AchievementService");
|
|
58746
59027
|
});
|
|
58747
59028
|
|
|
58748
59029
|
class InventoryService {
|
|
@@ -58769,7 +59050,7 @@ class InventoryService {
|
|
|
58769
59050
|
},
|
|
58770
59051
|
updatedAt: inventoryItems.updatedAt
|
|
58771
59052
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
58772
|
-
|
|
59053
|
+
logger24.debug("Listed inventory", { userId: user.id, count: inventory.length });
|
|
58773
59054
|
return inventory;
|
|
58774
59055
|
}
|
|
58775
59056
|
async addItem(itemId, quantity, user) {
|
|
@@ -58786,7 +59067,7 @@ class InventoryService {
|
|
|
58786
59067
|
const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
|
|
58787
59068
|
return inserted?.quantity ?? 0;
|
|
58788
59069
|
});
|
|
58789
|
-
|
|
59070
|
+
logger24.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
|
|
58790
59071
|
return { newTotal };
|
|
58791
59072
|
}
|
|
58792
59073
|
async removeItem(itemId, quantity, user) {
|
|
@@ -58797,7 +59078,7 @@ class InventoryService {
|
|
|
58797
59078
|
}
|
|
58798
59079
|
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);
|
|
58799
59080
|
if (!currentItem) {
|
|
58800
|
-
|
|
59081
|
+
logger24.warn("Insufficient inventory for removal", {
|
|
58801
59082
|
userId: user.id,
|
|
58802
59083
|
itemId,
|
|
58803
59084
|
requestedQuantity: quantity
|
|
@@ -58807,13 +59088,13 @@ class InventoryService {
|
|
|
58807
59088
|
const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
|
|
58808
59089
|
return updated?.quantity ?? 0;
|
|
58809
59090
|
});
|
|
58810
|
-
|
|
59091
|
+
logger24.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
|
|
58811
59092
|
return { newTotal };
|
|
58812
59093
|
}
|
|
58813
59094
|
async addCredits(userId, amount) {
|
|
58814
59095
|
const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
58815
59096
|
if (!creditsItem) {
|
|
58816
|
-
|
|
59097
|
+
logger24.error("Primary currency not found", {
|
|
58817
59098
|
userId,
|
|
58818
59099
|
amount
|
|
58819
59100
|
});
|
|
@@ -58826,17 +59107,17 @@ class InventoryService {
|
|
|
58826
59107
|
updatedAt: new Date
|
|
58827
59108
|
}
|
|
58828
59109
|
});
|
|
58829
|
-
|
|
59110
|
+
logger24.debug("Added credits", { userId, amount });
|
|
58830
59111
|
}
|
|
58831
59112
|
}
|
|
58832
|
-
var
|
|
59113
|
+
var logger24;
|
|
58833
59114
|
var init_inventory_service = __esm(() => {
|
|
58834
59115
|
init_drizzle_orm();
|
|
58835
59116
|
init_src();
|
|
58836
59117
|
init_tables_index();
|
|
58837
59118
|
init_src2();
|
|
58838
59119
|
init_errors();
|
|
58839
|
-
|
|
59120
|
+
logger24 = log.scope("InventoryService");
|
|
58840
59121
|
});
|
|
58841
59122
|
|
|
58842
59123
|
class LeaderboardService {
|
|
@@ -58867,7 +59148,7 @@ class LeaderboardService {
|
|
|
58867
59148
|
sessionId
|
|
58868
59149
|
}).returning();
|
|
58869
59150
|
if (!newScore) {
|
|
58870
|
-
|
|
59151
|
+
logger25.error("Score insert returned no rows", { userId, gameId, score: input.score });
|
|
58871
59152
|
throw new InternalError("Failed to insert score");
|
|
58872
59153
|
}
|
|
58873
59154
|
const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
|
|
@@ -58895,7 +59176,7 @@ class LeaderboardService {
|
|
|
58895
59176
|
movedUpWithinTop3
|
|
58896
59177
|
});
|
|
58897
59178
|
}
|
|
58898
|
-
|
|
59179
|
+
logger25.info("Score submitted", {
|
|
58899
59180
|
gameId,
|
|
58900
59181
|
userId,
|
|
58901
59182
|
isAnonymousUser,
|
|
@@ -58972,7 +59253,7 @@ class LeaderboardService {
|
|
|
58972
59253
|
});
|
|
58973
59254
|
}
|
|
58974
59255
|
} catch (error) {
|
|
58975
|
-
|
|
59256
|
+
logger25.warn("Failed to publish notification", { error });
|
|
58976
59257
|
}
|
|
58977
59258
|
}
|
|
58978
59259
|
async getLeaderboard(gameId, query, isAnonymousUser) {
|
|
@@ -59091,7 +59372,7 @@ class LeaderboardService {
|
|
|
59091
59372
|
return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
|
|
59092
59373
|
}
|
|
59093
59374
|
}
|
|
59094
|
-
var
|
|
59375
|
+
var logger25;
|
|
59095
59376
|
var init_leaderboard_service = __esm(() => {
|
|
59096
59377
|
init_drizzle_orm();
|
|
59097
59378
|
init_src();
|
|
@@ -59101,7 +59382,7 @@ var init_leaderboard_service = __esm(() => {
|
|
|
59101
59382
|
init_notification();
|
|
59102
59383
|
init_errors();
|
|
59103
59384
|
init_leaderboard_util();
|
|
59104
|
-
|
|
59385
|
+
logger25 = log.scope("LeaderboardService");
|
|
59105
59386
|
});
|
|
59106
59387
|
|
|
59107
59388
|
class LevelService {
|
|
@@ -59116,9 +59397,9 @@ class LevelService {
|
|
|
59116
59397
|
for (const config2 of configs) {
|
|
59117
59398
|
levelConfigCache.set(config2.level, config2);
|
|
59118
59399
|
}
|
|
59119
|
-
|
|
59400
|
+
logger26.info("Cache pre-warmed", { count: configs.length });
|
|
59120
59401
|
} catch (error) {
|
|
59121
|
-
|
|
59402
|
+
logger26.error("Cache pre-warm failed", { error });
|
|
59122
59403
|
}
|
|
59123
59404
|
}
|
|
59124
59405
|
async getConfig(level) {
|
|
@@ -59152,7 +59433,7 @@ class LevelService {
|
|
|
59152
59433
|
totalXP
|
|
59153
59434
|
}).returning();
|
|
59154
59435
|
if (!newUserLevel) {
|
|
59155
|
-
|
|
59436
|
+
logger26.error("User level insert returned no rows", { userId: user.id });
|
|
59156
59437
|
throw new InternalError("Failed to create user level cache record");
|
|
59157
59438
|
}
|
|
59158
59439
|
userLevel = newUserLevel;
|
|
@@ -59167,7 +59448,7 @@ class LevelService {
|
|
|
59167
59448
|
userLevel = updatedUserLevel;
|
|
59168
59449
|
}
|
|
59169
59450
|
}
|
|
59170
|
-
|
|
59451
|
+
logger26.debug("Retrieved user level", {
|
|
59171
59452
|
userId: user.id,
|
|
59172
59453
|
totalXP,
|
|
59173
59454
|
currentLevel,
|
|
@@ -59178,7 +59459,7 @@ class LevelService {
|
|
|
59178
59459
|
async getProgress(user) {
|
|
59179
59460
|
const userLevel = await this.getByUser(user);
|
|
59180
59461
|
const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
|
|
59181
|
-
|
|
59462
|
+
logger26.debug("Retrieved progress", { userId: user.id });
|
|
59182
59463
|
return {
|
|
59183
59464
|
level: userLevel.currentLevel,
|
|
59184
59465
|
currentXp: userLevel.currentXp,
|
|
@@ -59212,7 +59493,7 @@ class LevelService {
|
|
|
59212
59493
|
if (leveledUp && previousUserLevel) {
|
|
59213
59494
|
await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
|
|
59214
59495
|
}
|
|
59215
|
-
|
|
59496
|
+
logger26.info("Synced from Timeback", {
|
|
59216
59497
|
userId,
|
|
59217
59498
|
totalXP,
|
|
59218
59499
|
currentLevel,
|
|
@@ -59253,7 +59534,7 @@ class LevelService {
|
|
|
59253
59534
|
}
|
|
59254
59535
|
if (totalCredits > 0) {
|
|
59255
59536
|
await this.deps.addCredits(userId, totalCredits);
|
|
59256
|
-
|
|
59537
|
+
logger26.info("Awarded level-up credits", {
|
|
59257
59538
|
userId,
|
|
59258
59539
|
fromLevel,
|
|
59259
59540
|
toLevel,
|
|
@@ -59291,7 +59572,7 @@ class LevelService {
|
|
|
59291
59572
|
};
|
|
59292
59573
|
}
|
|
59293
59574
|
}
|
|
59294
|
-
var
|
|
59575
|
+
var logger26;
|
|
59295
59576
|
var levelConfigCache = null;
|
|
59296
59577
|
var init_level_service = __esm(() => {
|
|
59297
59578
|
init_drizzle_orm();
|
|
@@ -59299,7 +59580,7 @@ var init_level_service = __esm(() => {
|
|
|
59299
59580
|
init_tables_index();
|
|
59300
59581
|
init_src2();
|
|
59301
59582
|
init_errors();
|
|
59302
|
-
|
|
59583
|
+
logger26 = log.scope("LevelService");
|
|
59303
59584
|
});
|
|
59304
59585
|
var init_events = () => {};
|
|
59305
59586
|
function convertWebSocketUrlToHttp(wsUrl) {
|
|
@@ -59316,13 +59597,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
|
|
|
59316
59597
|
});
|
|
59317
59598
|
if (!res.ok) {
|
|
59318
59599
|
const text3 = await res.text().catch(() => "");
|
|
59319
|
-
|
|
59600
|
+
logger27.warn("Failed to publish to user", {
|
|
59320
59601
|
status: res.status,
|
|
59321
59602
|
body: text3
|
|
59322
59603
|
});
|
|
59323
59604
|
}
|
|
59324
59605
|
} catch (error) {
|
|
59325
|
-
|
|
59606
|
+
logger27.error("Publish to user error", { error });
|
|
59326
59607
|
}
|
|
59327
59608
|
}
|
|
59328
59609
|
|
|
@@ -59344,7 +59625,7 @@ class NotificationService {
|
|
|
59344
59625
|
conditions2.push(eq(notifications.type, type));
|
|
59345
59626
|
}
|
|
59346
59627
|
const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
|
|
59347
|
-
|
|
59628
|
+
logger27.debug("Listed notifications", { userId: user.id, count: results.length });
|
|
59348
59629
|
return results;
|
|
59349
59630
|
}
|
|
59350
59631
|
async updateStatus(notificationId, status, method) {
|
|
@@ -59363,7 +59644,7 @@ class NotificationService {
|
|
|
59363
59644
|
if (!updated) {
|
|
59364
59645
|
throw new NotFoundError("Notification", notificationId);
|
|
59365
59646
|
}
|
|
59366
|
-
|
|
59647
|
+
logger27.debug("Updated status", { notificationId, status });
|
|
59367
59648
|
return updated;
|
|
59368
59649
|
}
|
|
59369
59650
|
async getStats(user, options) {
|
|
@@ -59389,7 +59670,7 @@ class NotificationService {
|
|
|
59389
59670
|
const clicked = statsMap.clicked || 0;
|
|
59390
59671
|
const dismissed = statsMap.dismissed || 0;
|
|
59391
59672
|
const expired = statsMap.expired || 0;
|
|
59392
|
-
|
|
59673
|
+
logger27.debug("Retrieved stats", { userId: user.id, total });
|
|
59393
59674
|
return {
|
|
59394
59675
|
total,
|
|
59395
59676
|
delivered,
|
|
@@ -59438,7 +59719,7 @@ class NotificationService {
|
|
|
59438
59719
|
options: { data, clickUrl, metadata: metadata2 }
|
|
59439
59720
|
});
|
|
59440
59721
|
}
|
|
59441
|
-
|
|
59722
|
+
logger27.debug("Created notification", {
|
|
59442
59723
|
userId,
|
|
59443
59724
|
type,
|
|
59444
59725
|
id: notificationId,
|
|
@@ -59446,7 +59727,7 @@ class NotificationService {
|
|
|
59446
59727
|
});
|
|
59447
59728
|
return notificationId;
|
|
59448
59729
|
} catch (error) {
|
|
59449
|
-
|
|
59730
|
+
logger27.error("Failed to create notification", { userId, type, error });
|
|
59450
59731
|
return null;
|
|
59451
59732
|
}
|
|
59452
59733
|
}
|
|
@@ -59460,7 +59741,7 @@ class NotificationService {
|
|
|
59460
59741
|
}) {
|
|
59461
59742
|
const realtimeConfig = this.deps.realtime;
|
|
59462
59743
|
if (!realtimeConfig) {
|
|
59463
|
-
|
|
59744
|
+
logger27.warn("No realtime config for publish");
|
|
59464
59745
|
return;
|
|
59465
59746
|
}
|
|
59466
59747
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -59502,13 +59783,13 @@ class NotificationService {
|
|
|
59502
59783
|
metadata: data.metadata || {}
|
|
59503
59784
|
}).returning();
|
|
59504
59785
|
if (!notification) {
|
|
59505
|
-
|
|
59786
|
+
logger27.error("Notification insert returned no rows", {
|
|
59506
59787
|
userId: data.userId,
|
|
59507
59788
|
type: data.type
|
|
59508
59789
|
});
|
|
59509
59790
|
throw new InternalError("Failed to create notification");
|
|
59510
59791
|
}
|
|
59511
|
-
|
|
59792
|
+
logger27.info("Inserted notification", {
|
|
59512
59793
|
notificationId: notification.id,
|
|
59513
59794
|
userId: notification.userId,
|
|
59514
59795
|
type: notification.type
|
|
@@ -59518,7 +59799,7 @@ class NotificationService {
|
|
|
59518
59799
|
async deliverPending(userId) {
|
|
59519
59800
|
const realtimeConfig = this.deps.realtime;
|
|
59520
59801
|
if (!realtimeConfig) {
|
|
59521
|
-
|
|
59802
|
+
logger27.warn("No realtime config for delivery");
|
|
59522
59803
|
return;
|
|
59523
59804
|
}
|
|
59524
59805
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -59545,13 +59826,13 @@ class NotificationService {
|
|
|
59545
59826
|
metadata: notification.metadata,
|
|
59546
59827
|
clickUrl: notification.clickUrl
|
|
59547
59828
|
});
|
|
59548
|
-
|
|
59829
|
+
logger27.info("Delivered notification", {
|
|
59549
59830
|
notificationId: notification.id,
|
|
59550
59831
|
userId,
|
|
59551
59832
|
type: notification.type
|
|
59552
59833
|
});
|
|
59553
59834
|
} catch (error) {
|
|
59554
|
-
|
|
59835
|
+
logger27.warn("Failed to deliver", {
|
|
59555
59836
|
notificationId: notification.id,
|
|
59556
59837
|
error
|
|
59557
59838
|
});
|
|
@@ -59559,7 +59840,7 @@ class NotificationService {
|
|
|
59559
59840
|
}
|
|
59560
59841
|
}
|
|
59561
59842
|
}
|
|
59562
|
-
var
|
|
59843
|
+
var logger27;
|
|
59563
59844
|
var init_notification_service = __esm(() => {
|
|
59564
59845
|
init_drizzle_orm();
|
|
59565
59846
|
init_src();
|
|
@@ -59568,7 +59849,7 @@ var init_notification_service = __esm(() => {
|
|
|
59568
59849
|
init_events();
|
|
59569
59850
|
init_notification();
|
|
59570
59851
|
init_errors();
|
|
59571
|
-
|
|
59852
|
+
logger27 = log.scope("NotificationService");
|
|
59572
59853
|
});
|
|
59573
59854
|
function createPlayerServices(deps) {
|
|
59574
59855
|
const { db: db2, realtime } = deps;
|
|
@@ -59687,7 +59968,7 @@ class CharacterService {
|
|
|
59687
59968
|
createdAt: characterComponents.createdAt,
|
|
59688
59969
|
updatedAt: characterComponents.updatedAt
|
|
59689
59970
|
}).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
|
|
59690
|
-
|
|
59971
|
+
logger28.debug("Listed available components", {
|
|
59691
59972
|
level,
|
|
59692
59973
|
count: components.length
|
|
59693
59974
|
});
|
|
@@ -59705,7 +59986,7 @@ class CharacterService {
|
|
|
59705
59986
|
}
|
|
59706
59987
|
}
|
|
59707
59988
|
});
|
|
59708
|
-
|
|
59989
|
+
logger28.debug("Retrieved character", { userId: user.id, found: Boolean(pc3) });
|
|
59709
59990
|
return pc3 ?? null;
|
|
59710
59991
|
}
|
|
59711
59992
|
async getByUserId(userId) {
|
|
@@ -59720,7 +60001,7 @@ class CharacterService {
|
|
|
59720
60001
|
}
|
|
59721
60002
|
}
|
|
59722
60003
|
});
|
|
59723
|
-
|
|
60004
|
+
logger28.debug("Retrieved character by ID", { userId, found: Boolean(pc3) });
|
|
59724
60005
|
return pc3 ?? null;
|
|
59725
60006
|
}
|
|
59726
60007
|
async create(input, user) {
|
|
@@ -59735,13 +60016,13 @@ class CharacterService {
|
|
|
59735
60016
|
}
|
|
59736
60017
|
const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
|
|
59737
60018
|
if (!characterRow) {
|
|
59738
|
-
|
|
60019
|
+
logger28.error("Character insert returned no rows", { userId: user.id });
|
|
59739
60020
|
throw new InternalError("Failed to create character in database");
|
|
59740
60021
|
}
|
|
59741
60022
|
await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
|
|
59742
60023
|
return characterRow;
|
|
59743
60024
|
});
|
|
59744
|
-
|
|
60025
|
+
logger28.info("Created character", { userId: user.id, characterId: result.id });
|
|
59745
60026
|
return result;
|
|
59746
60027
|
}
|
|
59747
60028
|
async update(input, user) {
|
|
@@ -59753,7 +60034,7 @@ class CharacterService {
|
|
|
59753
60034
|
if (!row) {
|
|
59754
60035
|
throw new NotFoundError("Player character");
|
|
59755
60036
|
}
|
|
59756
|
-
|
|
60037
|
+
logger28.info("Updated character", {
|
|
59757
60038
|
userId: user.id,
|
|
59758
60039
|
characterId: row.id,
|
|
59759
60040
|
updatedFields: Object.keys(input)
|
|
@@ -59775,7 +60056,7 @@ class CharacterService {
|
|
|
59775
60056
|
const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
|
|
59776
60057
|
const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
|
|
59777
60058
|
if (!validation.isValid) {
|
|
59778
|
-
|
|
60059
|
+
logger28.warn("Accessory validation failed", {
|
|
59779
60060
|
userId: user.id,
|
|
59780
60061
|
slot,
|
|
59781
60062
|
accessoryComponentId,
|
|
@@ -59791,14 +60072,14 @@ class CharacterService {
|
|
|
59791
60072
|
slot
|
|
59792
60073
|
}).returning();
|
|
59793
60074
|
if (!result) {
|
|
59794
|
-
|
|
60075
|
+
logger28.error("Accessory insert returned no rows", {
|
|
59795
60076
|
userId: user.id,
|
|
59796
60077
|
slot,
|
|
59797
60078
|
accessoryComponentId
|
|
59798
60079
|
});
|
|
59799
60080
|
throw new InternalError("Failed to equip accessory");
|
|
59800
60081
|
}
|
|
59801
|
-
|
|
60082
|
+
logger28.info("Equipped accessory", {
|
|
59802
60083
|
userId: user.id,
|
|
59803
60084
|
slot,
|
|
59804
60085
|
accessoryComponentId
|
|
@@ -59819,7 +60100,7 @@ class CharacterService {
|
|
|
59819
60100
|
const playerLevel = userLevel?.currentLevel ?? 1;
|
|
59820
60101
|
const validation = validateAccessoryRemoval(slot, playerLevel);
|
|
59821
60102
|
if (!validation.isValid) {
|
|
59822
|
-
|
|
60103
|
+
logger28.warn("Accessory removal validation failed", {
|
|
59823
60104
|
userId: user.id,
|
|
59824
60105
|
slot,
|
|
59825
60106
|
playerLevel,
|
|
@@ -59828,17 +60109,17 @@ class CharacterService {
|
|
|
59828
60109
|
throw new ValidationError(validation.error ?? "Invalid accessory removal");
|
|
59829
60110
|
}
|
|
59830
60111
|
await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
|
|
59831
|
-
|
|
60112
|
+
logger28.info("Removed accessory", { userId: user.id, slot });
|
|
59832
60113
|
}
|
|
59833
60114
|
}
|
|
59834
|
-
var
|
|
60115
|
+
var logger28;
|
|
59835
60116
|
var init_character_service = __esm(() => {
|
|
59836
60117
|
init_drizzle_orm();
|
|
59837
60118
|
init_tables_index();
|
|
59838
60119
|
init_src2();
|
|
59839
60120
|
init_errors();
|
|
59840
60121
|
init_accessory_util();
|
|
59841
|
-
|
|
60122
|
+
logger28 = log.scope("CharacterService");
|
|
59842
60123
|
});
|
|
59843
60124
|
|
|
59844
60125
|
class CurrencyService {
|
|
@@ -59849,7 +60130,7 @@ class CurrencyService {
|
|
|
59849
60130
|
async list() {
|
|
59850
60131
|
const db2 = this.deps.db;
|
|
59851
60132
|
const allCurrencies = await db2.query.currencies.findMany();
|
|
59852
|
-
|
|
60133
|
+
logger29.debug("Listed currencies", { count: allCurrencies.length });
|
|
59853
60134
|
return allCurrencies;
|
|
59854
60135
|
}
|
|
59855
60136
|
async getById(currencyId) {
|
|
@@ -59860,7 +60141,7 @@ class CurrencyService {
|
|
|
59860
60141
|
if (!currency) {
|
|
59861
60142
|
throw new NotFoundError("Currency", currencyId);
|
|
59862
60143
|
}
|
|
59863
|
-
|
|
60144
|
+
logger29.debug("Retrieved currency", { currencyId });
|
|
59864
60145
|
return currency;
|
|
59865
60146
|
}
|
|
59866
60147
|
async create(data) {
|
|
@@ -59868,13 +60149,13 @@ class CurrencyService {
|
|
|
59868
60149
|
try {
|
|
59869
60150
|
const [newCurrency] = await db2.insert(currencies).values(data).returning();
|
|
59870
60151
|
if (!newCurrency) {
|
|
59871
|
-
|
|
60152
|
+
logger29.error("Currency insert returned no rows", {
|
|
59872
60153
|
itemId: data.itemId,
|
|
59873
60154
|
symbol: data.symbol
|
|
59874
60155
|
});
|
|
59875
60156
|
throw new InternalError("Failed to create currency");
|
|
59876
60157
|
}
|
|
59877
|
-
|
|
60158
|
+
logger29.info("Created currency", {
|
|
59878
60159
|
currencyId: newCurrency.id,
|
|
59879
60160
|
itemId: newCurrency.itemId,
|
|
59880
60161
|
symbol: newCurrency.symbol,
|
|
@@ -59903,7 +60184,7 @@ class CurrencyService {
|
|
|
59903
60184
|
if (!updatedCurrency) {
|
|
59904
60185
|
throw new NotFoundError("Currency", currencyId);
|
|
59905
60186
|
}
|
|
59906
|
-
|
|
60187
|
+
logger29.info("Updated currency", {
|
|
59907
60188
|
currencyId: updatedCurrency.id,
|
|
59908
60189
|
updatedFields: Object.keys(data)
|
|
59909
60190
|
});
|
|
@@ -59929,16 +60210,16 @@ class CurrencyService {
|
|
|
59929
60210
|
if (result.length === 0) {
|
|
59930
60211
|
throw new NotFoundError("Currency", currencyId);
|
|
59931
60212
|
}
|
|
59932
|
-
|
|
60213
|
+
logger29.info("Deleted currency", { currencyId });
|
|
59933
60214
|
}
|
|
59934
60215
|
}
|
|
59935
|
-
var
|
|
60216
|
+
var logger29;
|
|
59936
60217
|
var init_currency_service = __esm(() => {
|
|
59937
60218
|
init_drizzle_orm();
|
|
59938
60219
|
init_tables_index();
|
|
59939
60220
|
init_src2();
|
|
59940
60221
|
init_errors();
|
|
59941
|
-
|
|
60222
|
+
logger29 = log.scope("CurrencyService");
|
|
59942
60223
|
});
|
|
59943
60224
|
|
|
59944
60225
|
class LogsService {
|
|
@@ -59956,11 +60237,11 @@ class LogsService {
|
|
|
59956
60237
|
if (!game) {
|
|
59957
60238
|
throw new NotFoundError("Game", slug2);
|
|
59958
60239
|
}
|
|
59959
|
-
|
|
60240
|
+
logger30.info("Admin accessing game logs", { adminId: user.id, slug: slug2, sstStage });
|
|
59960
60241
|
} else {
|
|
59961
60242
|
const isApprovedDev = user.developerStatus === "approved";
|
|
59962
60243
|
if (!isApprovedDev) {
|
|
59963
|
-
|
|
60244
|
+
logger30.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
|
|
59964
60245
|
throw new AccessDeniedError("Must be an approved developer");
|
|
59965
60246
|
}
|
|
59966
60247
|
const game = await db2.query.games.findFirst({
|
|
@@ -59975,7 +60256,7 @@ class LogsService {
|
|
|
59975
60256
|
columns: { id: true }
|
|
59976
60257
|
});
|
|
59977
60258
|
if (!membership) {
|
|
59978
|
-
|
|
60259
|
+
logger30.warn("Developer attempted access to unowned game logs", {
|
|
59979
60260
|
userId: user.id,
|
|
59980
60261
|
slug: slug2
|
|
59981
60262
|
});
|
|
@@ -59984,7 +60265,7 @@ class LogsService {
|
|
|
59984
60265
|
}
|
|
59985
60266
|
const workerId = getDeploymentId(slug2, sstStage);
|
|
59986
60267
|
const token = await this.deps.mintLogStreamToken(user.id, workerId);
|
|
59987
|
-
|
|
60268
|
+
logger30.debug("Generated log stream token", {
|
|
59988
60269
|
userId: user.id,
|
|
59989
60270
|
slug: slug2,
|
|
59990
60271
|
workerId
|
|
@@ -59992,14 +60273,14 @@ class LogsService {
|
|
|
59992
60273
|
return { token, workerId };
|
|
59993
60274
|
}
|
|
59994
60275
|
}
|
|
59995
|
-
var
|
|
60276
|
+
var logger30;
|
|
59996
60277
|
var init_logs_service = __esm(() => {
|
|
59997
60278
|
init_drizzle_orm();
|
|
59998
60279
|
init_tables_index();
|
|
59999
60280
|
init_src2();
|
|
60000
60281
|
init_errors();
|
|
60001
60282
|
init_deployment_util();
|
|
60002
|
-
|
|
60283
|
+
logger30 = log.scope("LogsService");
|
|
60003
60284
|
});
|
|
60004
60285
|
|
|
60005
60286
|
class LtiService {
|
|
@@ -60050,7 +60331,7 @@ class MapService {
|
|
|
60050
60331
|
if (!mapDetails) {
|
|
60051
60332
|
throw new NotFoundError("Map", identifier);
|
|
60052
60333
|
}
|
|
60053
|
-
|
|
60334
|
+
logger31.debug("Retrieved map", { identifier });
|
|
60054
60335
|
return mapDetails;
|
|
60055
60336
|
}
|
|
60056
60337
|
async getElements(mapId) {
|
|
@@ -60066,7 +60347,7 @@ class MapService {
|
|
|
60066
60347
|
}
|
|
60067
60348
|
}
|
|
60068
60349
|
});
|
|
60069
|
-
|
|
60350
|
+
logger31.debug("Retrieved elements", { mapId, count: elements.length });
|
|
60070
60351
|
return elements;
|
|
60071
60352
|
}
|
|
60072
60353
|
async getObjects(mapId, userId) {
|
|
@@ -60087,7 +60368,7 @@ class MapService {
|
|
|
60087
60368
|
}
|
|
60088
60369
|
}
|
|
60089
60370
|
});
|
|
60090
|
-
|
|
60371
|
+
logger31.debug("Retrieved objects", { mapId, userId, count: objects.length });
|
|
60091
60372
|
return objects.map((object) => this.formatMapObjectWithItem(object));
|
|
60092
60373
|
}
|
|
60093
60374
|
async createObject(mapId, data, user) {
|
|
@@ -60114,7 +60395,7 @@ class MapService {
|
|
|
60114
60395
|
throw new NotFoundError("Item", data.itemId);
|
|
60115
60396
|
}
|
|
60116
60397
|
if (!item.isPlaceable) {
|
|
60117
|
-
|
|
60398
|
+
logger31.warn("Attempted to place non-placeable item", {
|
|
60118
60399
|
userId: user.id,
|
|
60119
60400
|
itemId: data.itemId,
|
|
60120
60401
|
mapId
|
|
@@ -60128,7 +60409,7 @@ class MapService {
|
|
|
60128
60409
|
};
|
|
60129
60410
|
const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
|
|
60130
60411
|
if (!createdObject) {
|
|
60131
|
-
|
|
60412
|
+
logger31.error("Map object insert returned no rows", {
|
|
60132
60413
|
userId: user.id,
|
|
60133
60414
|
mapId,
|
|
60134
60415
|
itemId: data.itemId
|
|
@@ -60152,12 +60433,12 @@ class MapService {
|
|
|
60152
60433
|
}
|
|
60153
60434
|
});
|
|
60154
60435
|
if (!objectWithItem) {
|
|
60155
|
-
|
|
60436
|
+
logger31.error("Map object query after insert returned no rows", {
|
|
60156
60437
|
objectId: createdObject.id
|
|
60157
60438
|
});
|
|
60158
60439
|
throw new InternalError("Failed to retrieve created object");
|
|
60159
60440
|
}
|
|
60160
|
-
|
|
60441
|
+
logger31.info("Created object", {
|
|
60161
60442
|
userId: user.id,
|
|
60162
60443
|
mapId,
|
|
60163
60444
|
objectId: createdObject.id,
|
|
@@ -60181,7 +60462,7 @@ class MapService {
|
|
|
60181
60462
|
if (result.length === 0) {
|
|
60182
60463
|
throw new NotFoundError("MapObject", objectId);
|
|
60183
60464
|
}
|
|
60184
|
-
|
|
60465
|
+
logger31.info("Deleted object", {
|
|
60185
60466
|
userId: user.id,
|
|
60186
60467
|
mapId,
|
|
60187
60468
|
objectId
|
|
@@ -60210,13 +60491,13 @@ class MapService {
|
|
|
60210
60491
|
};
|
|
60211
60492
|
}
|
|
60212
60493
|
}
|
|
60213
|
-
var
|
|
60494
|
+
var logger31;
|
|
60214
60495
|
var init_map_service = __esm(() => {
|
|
60215
60496
|
init_drizzle_orm();
|
|
60216
60497
|
init_tables_index();
|
|
60217
60498
|
init_src2();
|
|
60218
60499
|
init_errors();
|
|
60219
|
-
|
|
60500
|
+
logger31 = log.scope("MapService");
|
|
60220
60501
|
});
|
|
60221
60502
|
|
|
60222
60503
|
class RealtimeService {
|
|
@@ -60250,20 +60531,20 @@ class RealtimeService {
|
|
|
60250
60531
|
}
|
|
60251
60532
|
const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
|
|
60252
60533
|
const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
|
|
60253
|
-
|
|
60534
|
+
logger32.info("Generated token", {
|
|
60254
60535
|
userId: user.id,
|
|
60255
60536
|
gameId: resolvedGameId || "global"
|
|
60256
60537
|
});
|
|
60257
60538
|
return { token };
|
|
60258
60539
|
}
|
|
60259
60540
|
}
|
|
60260
|
-
var
|
|
60541
|
+
var logger32;
|
|
60261
60542
|
var init_realtime_service = __esm(() => {
|
|
60262
60543
|
init_drizzle_orm();
|
|
60263
60544
|
init_tables_index();
|
|
60264
60545
|
init_src2();
|
|
60265
60546
|
init_errors();
|
|
60266
|
-
|
|
60547
|
+
logger32 = log.scope("RealtimeService");
|
|
60267
60548
|
});
|
|
60268
60549
|
|
|
60269
60550
|
class SessionService {
|
|
@@ -60297,10 +60578,10 @@ class SessionService {
|
|
|
60297
60578
|
};
|
|
60298
60579
|
const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
|
|
60299
60580
|
if (!newSession?.sessionId) {
|
|
60300
|
-
|
|
60581
|
+
logger33.error("Game session insert returned no rows", { userId, gameId });
|
|
60301
60582
|
throw new InternalError("Failed to create game session");
|
|
60302
60583
|
}
|
|
60303
|
-
|
|
60584
|
+
logger33.info("Started new session", {
|
|
60304
60585
|
sessionId: newSession.sessionId,
|
|
60305
60586
|
gameId,
|
|
60306
60587
|
userId
|
|
@@ -60321,23 +60602,23 @@ class SessionService {
|
|
|
60321
60602
|
return { success: true, message: "Session already ended" };
|
|
60322
60603
|
}
|
|
60323
60604
|
await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
|
|
60324
|
-
|
|
60605
|
+
logger33.info("Ended session", { sessionId, gameId, userId });
|
|
60325
60606
|
return { success: true };
|
|
60326
60607
|
}
|
|
60327
60608
|
async mintToken(gameIdOrSlug, userId) {
|
|
60328
60609
|
const gameId = await this.resolveGameId(gameIdOrSlug);
|
|
60329
60610
|
const result = await this.deps.mintGameToken(gameId, userId);
|
|
60330
|
-
|
|
60611
|
+
logger33.debug("Minted game token", { gameId, userId });
|
|
60331
60612
|
return result;
|
|
60332
60613
|
}
|
|
60333
60614
|
}
|
|
60334
|
-
var
|
|
60615
|
+
var logger33;
|
|
60335
60616
|
var init_session_service = __esm(() => {
|
|
60336
60617
|
init_drizzle_orm();
|
|
60337
60618
|
init_tables_index();
|
|
60338
60619
|
init_src2();
|
|
60339
60620
|
init_errors();
|
|
60340
|
-
|
|
60621
|
+
logger33 = log.scope("SessionService");
|
|
60341
60622
|
});
|
|
60342
60623
|
|
|
60343
60624
|
class ShopService {
|
|
@@ -60382,7 +60663,7 @@ class ShopService {
|
|
|
60382
60663
|
const shopItems = [];
|
|
60383
60664
|
for (const listing of listingsWithRelations) {
|
|
60384
60665
|
if (!listing.item || !listing.currency) {
|
|
60385
|
-
|
|
60666
|
+
logger34.warn("Listing missing item or currency, skipping", {
|
|
60386
60667
|
listingId: listing.id
|
|
60387
60668
|
});
|
|
60388
60669
|
} else {
|
|
@@ -60399,7 +60680,7 @@ class ShopService {
|
|
|
60399
60680
|
});
|
|
60400
60681
|
}
|
|
60401
60682
|
}
|
|
60402
|
-
|
|
60683
|
+
logger34.debug("Retrieved shop view", {
|
|
60403
60684
|
userId: user.id,
|
|
60404
60685
|
itemCount: shopItems.length,
|
|
60405
60686
|
currencyCount: shopCurrencies.length
|
|
@@ -60410,12 +60691,12 @@ class ShopService {
|
|
|
60410
60691
|
};
|
|
60411
60692
|
}
|
|
60412
60693
|
}
|
|
60413
|
-
var
|
|
60694
|
+
var logger34;
|
|
60414
60695
|
var init_shop_service = __esm(() => {
|
|
60415
60696
|
init_drizzle_orm();
|
|
60416
60697
|
init_tables_index();
|
|
60417
60698
|
init_src2();
|
|
60418
|
-
|
|
60699
|
+
logger34 = log.scope("ShopService");
|
|
60419
60700
|
});
|
|
60420
60701
|
|
|
60421
60702
|
class SpriteService {
|
|
@@ -60431,17 +60712,17 @@ class SpriteService {
|
|
|
60431
60712
|
if (!template) {
|
|
60432
60713
|
throw new NotFoundError("SpriteTemplate", slug2);
|
|
60433
60714
|
}
|
|
60434
|
-
|
|
60715
|
+
logger35.debug("Retrieved sprite", { slug: slug2 });
|
|
60435
60716
|
return template;
|
|
60436
60717
|
}
|
|
60437
60718
|
}
|
|
60438
|
-
var
|
|
60719
|
+
var logger35;
|
|
60439
60720
|
var init_sprite_service = __esm(() => {
|
|
60440
60721
|
init_drizzle_orm();
|
|
60441
60722
|
init_tables_index();
|
|
60442
60723
|
init_src2();
|
|
60443
60724
|
init_errors();
|
|
60444
|
-
|
|
60725
|
+
logger35 = log.scope("SpriteService");
|
|
60445
60726
|
});
|
|
60446
60727
|
|
|
60447
60728
|
class UserService {
|
|
@@ -60455,12 +60736,12 @@ class UserService {
|
|
|
60455
60736
|
where: eq(users.id, user.id)
|
|
60456
60737
|
});
|
|
60457
60738
|
if (!userData) {
|
|
60458
|
-
|
|
60739
|
+
logger36.error("User not found", { userId: user.id });
|
|
60459
60740
|
throw new NotFoundError("User", user.id);
|
|
60460
60741
|
}
|
|
60461
60742
|
const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
|
|
60462
60743
|
if (gameId) {
|
|
60463
|
-
|
|
60744
|
+
logger36.debug("Fetched user profile (game context)", { userId: user.id, gameId });
|
|
60464
60745
|
return {
|
|
60465
60746
|
id: userData.id,
|
|
60466
60747
|
name: userData.name,
|
|
@@ -60473,7 +60754,7 @@ class UserService {
|
|
|
60473
60754
|
const timebackAccount = await db2.query.accounts.findFirst({
|
|
60474
60755
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
60475
60756
|
});
|
|
60476
|
-
|
|
60757
|
+
logger36.debug("Fetched user profile (platform context)", { userId: user.id });
|
|
60477
60758
|
return {
|
|
60478
60759
|
id: userData.id,
|
|
60479
60760
|
name: userData.name,
|
|
@@ -60496,7 +60777,7 @@ class UserService {
|
|
|
60496
60777
|
columns: { name: true }
|
|
60497
60778
|
});
|
|
60498
60779
|
if (!userData) {
|
|
60499
|
-
|
|
60780
|
+
logger36.error("Demo user not found", { userId });
|
|
60500
60781
|
throw new NotFoundError("User", userId);
|
|
60501
60782
|
}
|
|
60502
60783
|
return {
|
|
@@ -60510,10 +60791,10 @@ class UserService {
|
|
|
60510
60791
|
updatedAt: new Date
|
|
60511
60792
|
}).where(eq(users.id, userId)).returning({ name: users.name });
|
|
60512
60793
|
if (!updatedUser) {
|
|
60513
|
-
|
|
60794
|
+
logger36.error("Demo user not found for profile update", { userId });
|
|
60514
60795
|
throw new NotFoundError("User", userId);
|
|
60515
60796
|
}
|
|
60516
|
-
|
|
60797
|
+
logger36.debug("Updated demo profile", { userId, displayName });
|
|
60517
60798
|
return {
|
|
60518
60799
|
displayName: updatedUser.name,
|
|
60519
60800
|
isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
|
|
@@ -60526,7 +60807,7 @@ class UserService {
|
|
|
60526
60807
|
]);
|
|
60527
60808
|
const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
60528
60809
|
const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
60529
|
-
|
|
60810
|
+
logger36.debug("Fetched Timeback data", {
|
|
60530
60811
|
timebackId,
|
|
60531
60812
|
role,
|
|
60532
60813
|
enrollmentCount: enrollments.length,
|
|
@@ -60535,9 +60816,9 @@ class UserService {
|
|
|
60535
60816
|
return { id: timebackId, role, enrollments, organizations };
|
|
60536
60817
|
}
|
|
60537
60818
|
async fetchStudentProfile(timebackId) {
|
|
60538
|
-
|
|
60819
|
+
logger36.debug("Fetching student profile", { timebackId });
|
|
60539
60820
|
if (!this.deps.timeback) {
|
|
60540
|
-
|
|
60821
|
+
logger36.warn("Timeback client not available");
|
|
60541
60822
|
return { role: "student", organizations: [] };
|
|
60542
60823
|
}
|
|
60543
60824
|
try {
|
|
@@ -60565,14 +60846,14 @@ class UserService {
|
|
|
60565
60846
|
}
|
|
60566
60847
|
return { role, organizations: [...orgMap.values()] };
|
|
60567
60848
|
} catch (error) {
|
|
60568
|
-
|
|
60849
|
+
logger36.warn("Failed to fetch student profile", { error, timebackId });
|
|
60569
60850
|
return { role: "student", organizations: [] };
|
|
60570
60851
|
}
|
|
60571
60852
|
}
|
|
60572
60853
|
async fetchEnrollments(timebackId) {
|
|
60573
|
-
|
|
60854
|
+
logger36.debug("Fetching enrollments", { timebackId });
|
|
60574
60855
|
if (!this.deps.timeback) {
|
|
60575
|
-
|
|
60856
|
+
logger36.warn("Timeback client not available");
|
|
60576
60857
|
return [];
|
|
60577
60858
|
}
|
|
60578
60859
|
try {
|
|
@@ -60593,7 +60874,7 @@ class UserService {
|
|
|
60593
60874
|
orgId: courseToSchool.get(i2.courseId)
|
|
60594
60875
|
}));
|
|
60595
60876
|
} catch (error) {
|
|
60596
|
-
|
|
60877
|
+
logger36.warn("Failed to fetch enrollments", { error, timebackId });
|
|
60597
60878
|
return [];
|
|
60598
60879
|
}
|
|
60599
60880
|
}
|
|
@@ -60608,14 +60889,14 @@ class UserService {
|
|
|
60608
60889
|
return organizations.filter((o) => enrollmentOrgIds.has(o.id));
|
|
60609
60890
|
}
|
|
60610
60891
|
}
|
|
60611
|
-
var
|
|
60892
|
+
var logger36;
|
|
60612
60893
|
var init_user_service = __esm(() => {
|
|
60613
60894
|
init_drizzle_orm();
|
|
60614
60895
|
init_src();
|
|
60615
60896
|
init_tables_index();
|
|
60616
60897
|
init_src2();
|
|
60617
60898
|
init_errors();
|
|
60618
|
-
|
|
60899
|
+
logger36 = log.scope("UserService");
|
|
60619
60900
|
});
|
|
60620
60901
|
|
|
60621
60902
|
class VerifyService {
|
|
@@ -60624,16 +60905,16 @@ class VerifyService {
|
|
|
60624
60905
|
this.deps = deps;
|
|
60625
60906
|
}
|
|
60626
60907
|
async verifyGameToken(token) {
|
|
60627
|
-
|
|
60908
|
+
logger37.debug("Verifying game token");
|
|
60628
60909
|
const payload = await this.deps.validateGameToken(token);
|
|
60629
60910
|
if (!payload) {
|
|
60630
|
-
|
|
60911
|
+
logger37.warn("Invalid or expired game token presented");
|
|
60631
60912
|
throw new ValidationError("Invalid or expired token");
|
|
60632
60913
|
}
|
|
60633
60914
|
const gameId = payload.sub;
|
|
60634
60915
|
const userId = payload.uid;
|
|
60635
60916
|
if (typeof gameId !== "string" || typeof userId !== "string") {
|
|
60636
|
-
|
|
60917
|
+
logger37.warn("Game token missing required claims", {
|
|
60637
60918
|
hasGameId: typeof gameId === "string",
|
|
60638
60919
|
hasUserId: typeof userId === "string"
|
|
60639
60920
|
});
|
|
@@ -60644,7 +60925,7 @@ class VerifyService {
|
|
|
60644
60925
|
where: eq(users.id, userId)
|
|
60645
60926
|
});
|
|
60646
60927
|
if (!userData) {
|
|
60647
|
-
|
|
60928
|
+
logger37.error("User not found for valid token", {
|
|
60648
60929
|
userId
|
|
60649
60930
|
});
|
|
60650
60931
|
throw new NotFoundError("User", userId);
|
|
@@ -60658,7 +60939,7 @@ class VerifyService {
|
|
|
60658
60939
|
family_name: undefined,
|
|
60659
60940
|
timeback_id: userData.timebackId || undefined
|
|
60660
60941
|
};
|
|
60661
|
-
|
|
60942
|
+
logger37.info("Token verified", { gameId, userId });
|
|
60662
60943
|
return {
|
|
60663
60944
|
claims: payload,
|
|
60664
60945
|
gameId,
|
|
@@ -60666,13 +60947,13 @@ class VerifyService {
|
|
|
60666
60947
|
};
|
|
60667
60948
|
}
|
|
60668
60949
|
}
|
|
60669
|
-
var
|
|
60950
|
+
var logger37;
|
|
60670
60951
|
var init_verify_service = __esm(() => {
|
|
60671
60952
|
init_drizzle_orm();
|
|
60672
60953
|
init_tables_index();
|
|
60673
60954
|
init_src2();
|
|
60674
60955
|
init_errors();
|
|
60675
|
-
|
|
60956
|
+
logger37 = log.scope("VerifyService");
|
|
60676
60957
|
});
|
|
60677
60958
|
function createStandaloneServices(deps) {
|
|
60678
60959
|
const { db: db2, auth: auth2, timeback: timeback2 } = deps;
|
|
@@ -65804,7 +66085,7 @@ var colorStatus = async (status) => {
|
|
|
65804
66085
|
}
|
|
65805
66086
|
return `${status}`;
|
|
65806
66087
|
};
|
|
65807
|
-
var
|
|
66088
|
+
var logger38 = (fn = console.log) => {
|
|
65808
66089
|
return async function logger2(c, next) {
|
|
65809
66090
|
const { method, url: url2 } = c.req;
|
|
65810
66091
|
const path2 = url2.slice(url2.indexOf("/", 8));
|
|
@@ -65981,7 +66262,7 @@ function createApp(db2, options) {
|
|
|
65981
66262
|
const app = new Hono2;
|
|
65982
66263
|
app.use("*", cors({ origin: "*", credentials: true }));
|
|
65983
66264
|
if (options.verbose && !options.quiet) {
|
|
65984
|
-
app.use("*",
|
|
66265
|
+
app.use("*", logger38());
|
|
65985
66266
|
}
|
|
65986
66267
|
app.use("/api/*", async (c, next) => {
|
|
65987
66268
|
c.set("db", db2);
|
|
@@ -72683,12 +72964,12 @@ var init_session2 = __esm(() => {
|
|
|
72683
72964
|
init_utils();
|
|
72684
72965
|
init_dist5();
|
|
72685
72966
|
PglitePreparedQuery = class PglitePreparedQuery2 extends PgPreparedQuery {
|
|
72686
|
-
constructor(client, queryString, params,
|
|
72967
|
+
constructor(client, queryString, params, logger39, fields, name3, _isResponseInArrayMode, customResultMapper) {
|
|
72687
72968
|
super({ sql: queryString, params });
|
|
72688
72969
|
this.client = client;
|
|
72689
72970
|
this.queryString = queryString;
|
|
72690
72971
|
this.params = params;
|
|
72691
|
-
this.logger =
|
|
72972
|
+
this.logger = logger39;
|
|
72692
72973
|
this.fields = fields;
|
|
72693
72974
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
72694
72975
|
this.customResultMapper = customResultMapper;
|
|
@@ -72790,11 +73071,11 @@ var init_session2 = __esm(() => {
|
|
|
72790
73071
|
});
|
|
72791
73072
|
function construct(client, config2 = {}) {
|
|
72792
73073
|
const dialect2 = new PgDialect({ casing: config2.casing });
|
|
72793
|
-
let
|
|
73074
|
+
let logger39;
|
|
72794
73075
|
if (config2.logger === true) {
|
|
72795
|
-
|
|
73076
|
+
logger39 = new DefaultLogger;
|
|
72796
73077
|
} else if (config2.logger !== false) {
|
|
72797
|
-
|
|
73078
|
+
logger39 = config2.logger;
|
|
72798
73079
|
}
|
|
72799
73080
|
let schema2;
|
|
72800
73081
|
if (config2.schema) {
|
|
@@ -72805,7 +73086,7 @@ function construct(client, config2 = {}) {
|
|
|
72805
73086
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
72806
73087
|
};
|
|
72807
73088
|
}
|
|
72808
|
-
const driver = new PgliteDriver(client, dialect2, { logger:
|
|
73089
|
+
const driver = new PgliteDriver(client, dialect2, { logger: logger39 });
|
|
72809
73090
|
const session2 = driver.createSession(schema2);
|
|
72810
73091
|
const db2 = new PgliteDatabase(dialect2, session2, schema2);
|
|
72811
73092
|
db2.$client = client;
|
|
@@ -121410,8 +121691,8 @@ var init_currencies = __esm(() => {
|
|
|
121410
121691
|
init_tables_index();
|
|
121411
121692
|
init_constants();
|
|
121412
121693
|
});
|
|
121413
|
-
function setLogger(
|
|
121414
|
-
customLogger =
|
|
121694
|
+
function setLogger(logger39) {
|
|
121695
|
+
customLogger = logger39;
|
|
121415
121696
|
}
|
|
121416
121697
|
function getLogger() {
|
|
121417
121698
|
if (customLogger) {
|
|
@@ -121424,10 +121705,10 @@ function getLogger() {
|
|
|
121424
121705
|
};
|
|
121425
121706
|
}
|
|
121426
121707
|
var customLogger;
|
|
121427
|
-
var
|
|
121708
|
+
var logger39;
|
|
121428
121709
|
var init_adapter = __esm(() => {
|
|
121429
121710
|
init_config();
|
|
121430
|
-
|
|
121711
|
+
logger39 = {
|
|
121431
121712
|
info: (msg) => {
|
|
121432
121713
|
if (customLogger || !config.embedded) {
|
|
121433
121714
|
getLogger().info(msg);
|
|
@@ -121511,7 +121792,7 @@ async function seedCoreGames(db2) {
|
|
|
121511
121792
|
role: "owner"
|
|
121512
121793
|
}).onConflictDoNothing();
|
|
121513
121794
|
} catch (error2) {
|
|
121514
|
-
|
|
121795
|
+
logger39.error(`Error seeding core game '${gameData.slug}': ${error2}`);
|
|
121515
121796
|
}
|
|
121516
121797
|
}
|
|
121517
121798
|
}
|
|
@@ -121561,7 +121842,7 @@ async function seedCurrentProjectGame(db2, project) {
|
|
|
121561
121842
|
}
|
|
121562
121843
|
return newGame;
|
|
121563
121844
|
} catch (error2) {
|
|
121564
|
-
|
|
121845
|
+
logger39.error(`❌ Error seeding project game: ${error2}`);
|
|
121565
121846
|
throw error2;
|
|
121566
121847
|
}
|
|
121567
121848
|
}
|
|
@@ -122324,7 +122605,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
122324
122605
|
where: eq(users.id, existingAccount.userId)
|
|
122325
122606
|
});
|
|
122326
122607
|
if (user) {
|
|
122327
|
-
|
|
122608
|
+
logger40.info("Found user by LTI account", {
|
|
122328
122609
|
userId: user.id,
|
|
122329
122610
|
ltiTimebackId
|
|
122330
122611
|
});
|
|
@@ -122353,13 +122634,13 @@ async function provisionLtiUser(db2, claims) {
|
|
|
122353
122634
|
updatedAt: new Date
|
|
122354
122635
|
}).returning({ id: accounts.id });
|
|
122355
122636
|
if (!account) {
|
|
122356
|
-
|
|
122637
|
+
logger40.error("LTI account link insert returned no rows", {
|
|
122357
122638
|
userId: existingUser.id,
|
|
122358
122639
|
ltiTimebackId
|
|
122359
122640
|
});
|
|
122360
122641
|
throw new InternalError("Failed to link LTI account");
|
|
122361
122642
|
}
|
|
122362
|
-
|
|
122643
|
+
logger40.info("Linked LTI account to existing user", {
|
|
122363
122644
|
userId: existingUser.id,
|
|
122364
122645
|
ltiTimebackId
|
|
122365
122646
|
});
|
|
@@ -122379,7 +122660,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
122379
122660
|
updatedAt: new Date
|
|
122380
122661
|
}).returning();
|
|
122381
122662
|
if (!insertedUser) {
|
|
122382
|
-
|
|
122663
|
+
logger40.error("LTI user insert returned no rows", { email, ltiTimebackId });
|
|
122383
122664
|
throw new InternalError("Failed to create user");
|
|
122384
122665
|
}
|
|
122385
122666
|
await tx.insert(accounts).values({
|
|
@@ -122394,7 +122675,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
122394
122675
|
createdAt: new Date,
|
|
122395
122676
|
updatedAt: new Date
|
|
122396
122677
|
});
|
|
122397
|
-
|
|
122678
|
+
logger40.info("Provisioned new user from LTI", {
|
|
122398
122679
|
userId: insertedUser.id,
|
|
122399
122680
|
ltiTimebackId
|
|
122400
122681
|
});
|
|
@@ -122402,7 +122683,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
122402
122683
|
});
|
|
122403
122684
|
return createdUser;
|
|
122404
122685
|
}
|
|
122405
|
-
var
|
|
122686
|
+
var logger40;
|
|
122406
122687
|
var init_lti_provisioning = __esm(() => {
|
|
122407
122688
|
init_drizzle_orm();
|
|
122408
122689
|
init_src();
|
|
@@ -122410,7 +122691,7 @@ var init_lti_provisioning = __esm(() => {
|
|
|
122410
122691
|
init_src2();
|
|
122411
122692
|
init_errors();
|
|
122412
122693
|
init_lti_util();
|
|
122413
|
-
|
|
122694
|
+
logger40 = log.scope("LtiProvisioning");
|
|
122414
122695
|
});
|
|
122415
122696
|
function formatZodError(error2) {
|
|
122416
122697
|
const flat = error2.flatten();
|
|
@@ -122453,7 +122734,7 @@ var init_utils11 = __esm(() => {
|
|
|
122453
122734
|
init_timeback_util();
|
|
122454
122735
|
init_validation_util();
|
|
122455
122736
|
});
|
|
122456
|
-
var
|
|
122737
|
+
var logger41;
|
|
122457
122738
|
var listCurrent;
|
|
122458
122739
|
var listHistory;
|
|
122459
122740
|
var postProgress;
|
|
@@ -122464,14 +122745,14 @@ var init_achievement_controller = __esm(() => {
|
|
|
122464
122745
|
init_src2();
|
|
122465
122746
|
init_errors();
|
|
122466
122747
|
init_utils11();
|
|
122467
|
-
|
|
122748
|
+
logger41 = log.scope("AchievementController");
|
|
122468
122749
|
listCurrent = requireNonAnonymous(async (ctx) => {
|
|
122469
|
-
|
|
122750
|
+
logger41.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
122470
122751
|
return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
|
|
122471
122752
|
});
|
|
122472
122753
|
listHistory = requireNonAnonymous(async (ctx) => {
|
|
122473
122754
|
const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
|
|
122474
|
-
|
|
122755
|
+
logger41.debug("Listing achievement history", { userId: ctx.user.id, limit });
|
|
122475
122756
|
return ctx.services.achievement.listHistory(ctx.user, limit);
|
|
122476
122757
|
});
|
|
122477
122758
|
postProgress = requireNonAnonymous(async (ctx) => {
|
|
@@ -122482,12 +122763,12 @@ var init_achievement_controller = __esm(() => {
|
|
|
122482
122763
|
} catch (error2) {
|
|
122483
122764
|
if (error2 instanceof exports_external.ZodError) {
|
|
122484
122765
|
const details = formatZodError(error2);
|
|
122485
|
-
|
|
122766
|
+
logger41.warn("Submit achievement progress validation failed", { details });
|
|
122486
122767
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122487
122768
|
}
|
|
122488
122769
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122489
122770
|
}
|
|
122490
|
-
|
|
122771
|
+
logger41.debug("Submitting progress", {
|
|
122491
122772
|
userId: ctx.user.id,
|
|
122492
122773
|
achievementId: body2.achievementId
|
|
122493
122774
|
});
|
|
@@ -122499,15 +122780,15 @@ var init_achievement_controller = __esm(() => {
|
|
|
122499
122780
|
postProgress
|
|
122500
122781
|
};
|
|
122501
122782
|
});
|
|
122502
|
-
var
|
|
122783
|
+
var logger42;
|
|
122503
122784
|
var getAllowedOrigins;
|
|
122504
122785
|
var init_admin_controller = __esm(() => {
|
|
122505
122786
|
init_src2();
|
|
122506
122787
|
init_utils11();
|
|
122507
|
-
|
|
122788
|
+
logger42 = log.scope("AdminController");
|
|
122508
122789
|
getAllowedOrigins = requireAdmin(async (ctx) => {
|
|
122509
122790
|
const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
|
|
122510
|
-
|
|
122791
|
+
logger42.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
|
|
122511
122792
|
if (shouldRefresh) {
|
|
122512
122793
|
await ctx.providers.cache.refreshGameOrigins();
|
|
122513
122794
|
}
|
|
@@ -122520,7 +122801,7 @@ var init_admin_controller = __esm(() => {
|
|
|
122520
122801
|
};
|
|
122521
122802
|
});
|
|
122522
122803
|
});
|
|
122523
|
-
var
|
|
122804
|
+
var logger43;
|
|
122524
122805
|
var listFiles;
|
|
122525
122806
|
var getFile;
|
|
122526
122807
|
var putFile;
|
|
@@ -122532,7 +122813,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
122532
122813
|
init_src2();
|
|
122533
122814
|
init_errors();
|
|
122534
122815
|
init_utils11();
|
|
122535
|
-
|
|
122816
|
+
logger43 = log.scope("BucketController");
|
|
122536
122817
|
listFiles = requireDeveloper(async (ctx) => {
|
|
122537
122818
|
const slug2 = ctx.params.slug;
|
|
122538
122819
|
if (!slug2) {
|
|
@@ -122540,7 +122821,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
122540
122821
|
}
|
|
122541
122822
|
const url2 = ctx.url;
|
|
122542
122823
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
122543
|
-
|
|
122824
|
+
logger43.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
122544
122825
|
const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
|
|
122545
122826
|
return { files };
|
|
122546
122827
|
});
|
|
@@ -122550,7 +122831,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
122550
122831
|
if (!slug2 || !key) {
|
|
122551
122832
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
122552
122833
|
}
|
|
122553
|
-
|
|
122834
|
+
logger43.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
|
|
122554
122835
|
const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
|
|
122555
122836
|
return new Response(Buffer.from(object.body), {
|
|
122556
122837
|
status: 200,
|
|
@@ -122569,7 +122850,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
122569
122850
|
const arrayBuffer = await ctx.request.arrayBuffer();
|
|
122570
122851
|
const body2 = new Uint8Array(arrayBuffer);
|
|
122571
122852
|
const contentType = ctx.request.headers.get("content-type") || undefined;
|
|
122572
|
-
|
|
122853
|
+
logger43.debug("Uploading file", {
|
|
122573
122854
|
userId: ctx.user.id,
|
|
122574
122855
|
slug: slug2,
|
|
122575
122856
|
key,
|
|
@@ -122585,7 +122866,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
122585
122866
|
if (!slug2 || !key) {
|
|
122586
122867
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
122587
122868
|
}
|
|
122588
|
-
|
|
122869
|
+
logger43.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
|
|
122589
122870
|
await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
|
|
122590
122871
|
return { success: true, key };
|
|
122591
122872
|
});
|
|
@@ -122597,12 +122878,12 @@ var init_bucket_controller = __esm(() => {
|
|
|
122597
122878
|
} catch (error2) {
|
|
122598
122879
|
if (error2 instanceof exports_external.ZodError) {
|
|
122599
122880
|
const details = formatZodError(error2);
|
|
122600
|
-
|
|
122881
|
+
logger43.warn("Initiate upload validation failed", { details });
|
|
122601
122882
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122602
122883
|
}
|
|
122603
122884
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122604
122885
|
}
|
|
122605
|
-
|
|
122886
|
+
logger43.debug("Initiating multipart upload", {
|
|
122606
122887
|
userId: ctx.user.id,
|
|
122607
122888
|
gameId: body2.gameId,
|
|
122608
122889
|
fileName: body2.fileName
|
|
@@ -122617,10 +122898,10 @@ async function listComponents(ctx) {
|
|
|
122617
122898
|
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
122618
122899
|
level = Math.floor(Math.max(0, parsed));
|
|
122619
122900
|
}
|
|
122620
|
-
|
|
122901
|
+
logger44.debug("Listing components", { level });
|
|
122621
122902
|
return ctx.services.character.listAvailableComponents(level);
|
|
122622
122903
|
}
|
|
122623
|
-
var
|
|
122904
|
+
var logger44;
|
|
122624
122905
|
var get;
|
|
122625
122906
|
var getByUserId;
|
|
122626
122907
|
var create;
|
|
@@ -122634,9 +122915,9 @@ var init_character_controller = __esm(() => {
|
|
|
122634
122915
|
init_src2();
|
|
122635
122916
|
init_errors();
|
|
122636
122917
|
init_utils11();
|
|
122637
|
-
|
|
122918
|
+
logger44 = log.scope("CharacterController");
|
|
122638
122919
|
get = requireNonAnonymous(async (ctx) => {
|
|
122639
|
-
|
|
122920
|
+
logger44.debug("Getting character", { userId: ctx.user.id });
|
|
122640
122921
|
return ctx.services.character.getByUser(ctx.user);
|
|
122641
122922
|
});
|
|
122642
122923
|
getByUserId = requireNonAnonymous(async (ctx) => {
|
|
@@ -122644,7 +122925,7 @@ var init_character_controller = __esm(() => {
|
|
|
122644
122925
|
if (!userId) {
|
|
122645
122926
|
throw ApiError.badRequest("User ID is required in the URL path");
|
|
122646
122927
|
}
|
|
122647
|
-
|
|
122928
|
+
logger44.debug("Getting character by user ID", { requestedUserId: userId });
|
|
122648
122929
|
return ctx.services.character.getByUserId(userId);
|
|
122649
122930
|
});
|
|
122650
122931
|
create = requireNonAnonymous(async (ctx) => {
|
|
@@ -122655,12 +122936,12 @@ var init_character_controller = __esm(() => {
|
|
|
122655
122936
|
} catch (error2) {
|
|
122656
122937
|
if (error2 instanceof exports_external.ZodError) {
|
|
122657
122938
|
const details = formatZodError(error2);
|
|
122658
|
-
|
|
122939
|
+
logger44.warn("Create character validation failed", { details });
|
|
122659
122940
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122660
122941
|
}
|
|
122661
122942
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122662
122943
|
}
|
|
122663
|
-
|
|
122944
|
+
logger44.debug("Creating character", {
|
|
122664
122945
|
userId: ctx.user.id,
|
|
122665
122946
|
bodyComponentId: body2.bodyComponentId,
|
|
122666
122947
|
hairstyleComponentId: body2.hairstyleComponentId
|
|
@@ -122675,12 +122956,12 @@ var init_character_controller = __esm(() => {
|
|
|
122675
122956
|
} catch (error2) {
|
|
122676
122957
|
if (error2 instanceof exports_external.ZodError) {
|
|
122677
122958
|
const details = formatZodError(error2);
|
|
122678
|
-
|
|
122959
|
+
logger44.warn("Update character validation failed", { details });
|
|
122679
122960
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122680
122961
|
}
|
|
122681
122962
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122682
122963
|
}
|
|
122683
|
-
|
|
122964
|
+
logger44.debug("Updating character", {
|
|
122684
122965
|
userId: ctx.user.id,
|
|
122685
122966
|
bodyComponentId: body2.bodyComponentId,
|
|
122686
122967
|
hairstyleComponentId: body2.hairstyleComponentId,
|
|
@@ -122696,12 +122977,12 @@ var init_character_controller = __esm(() => {
|
|
|
122696
122977
|
} catch (error2) {
|
|
122697
122978
|
if (error2 instanceof exports_external.ZodError) {
|
|
122698
122979
|
const details = formatZodError(error2);
|
|
122699
|
-
|
|
122980
|
+
logger44.warn("Equip accessory validation failed", { details });
|
|
122700
122981
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
122701
122982
|
}
|
|
122702
122983
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122703
122984
|
}
|
|
122704
|
-
|
|
122985
|
+
logger44.debug("Equipping accessory", {
|
|
122705
122986
|
userId: ctx.user.id,
|
|
122706
122987
|
slot: body2.slot,
|
|
122707
122988
|
accessoryComponentId: body2.accessoryComponentId
|
|
@@ -122713,7 +122994,7 @@ var init_character_controller = __esm(() => {
|
|
|
122713
122994
|
if (!slot) {
|
|
122714
122995
|
throw ApiError.badRequest("Slot is required in the URL path");
|
|
122715
122996
|
}
|
|
122716
|
-
|
|
122997
|
+
logger44.debug("Removing accessory", { userId: ctx.user.id, slot });
|
|
122717
122998
|
await ctx.services.character.removeAccessory(slot, ctx.user);
|
|
122718
122999
|
return { success: true };
|
|
122719
123000
|
});
|
|
@@ -122727,7 +123008,7 @@ var init_character_controller = __esm(() => {
|
|
|
122727
123008
|
removeAccessory
|
|
122728
123009
|
};
|
|
122729
123010
|
});
|
|
122730
|
-
var
|
|
123011
|
+
var logger45;
|
|
122731
123012
|
var list;
|
|
122732
123013
|
var getById;
|
|
122733
123014
|
var create2;
|
|
@@ -122741,9 +123022,9 @@ var init_currency_controller = __esm(() => {
|
|
|
122741
123022
|
init_src4();
|
|
122742
123023
|
init_errors();
|
|
122743
123024
|
init_utils11();
|
|
122744
|
-
|
|
123025
|
+
logger45 = log.scope("CurrencyController");
|
|
122745
123026
|
list = requireNonAnonymous(async (ctx) => {
|
|
122746
|
-
|
|
123027
|
+
logger45.debug("Listing currencies", { userId: ctx.user.id });
|
|
122747
123028
|
return ctx.services.currency.list();
|
|
122748
123029
|
});
|
|
122749
123030
|
getById = requireNonAnonymous(async (ctx) => {
|
|
@@ -122754,7 +123035,7 @@ var init_currency_controller = __esm(() => {
|
|
|
122754
123035
|
if (!isValidUUID(currencyId)) {
|
|
122755
123036
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
122756
123037
|
}
|
|
122757
|
-
|
|
123038
|
+
logger45.debug("Getting currency", { userId: ctx.user.id, currencyId });
|
|
122758
123039
|
return ctx.services.currency.getById(currencyId);
|
|
122759
123040
|
});
|
|
122760
123041
|
create2 = requireAdmin(async (ctx) => {
|
|
@@ -122765,12 +123046,12 @@ var init_currency_controller = __esm(() => {
|
|
|
122765
123046
|
} catch (error2) {
|
|
122766
123047
|
if (error2 instanceof exports_external.ZodError) {
|
|
122767
123048
|
const details = formatZodError(error2);
|
|
122768
|
-
|
|
123049
|
+
logger45.warn("Create currency validation failed", { details });
|
|
122769
123050
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122770
123051
|
}
|
|
122771
123052
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122772
123053
|
}
|
|
122773
|
-
|
|
123054
|
+
logger45.debug("Creating currency", {
|
|
122774
123055
|
userId: ctx.user.id,
|
|
122775
123056
|
symbol: body2.symbol,
|
|
122776
123057
|
itemId: body2.itemId,
|
|
@@ -122793,12 +123074,12 @@ var init_currency_controller = __esm(() => {
|
|
|
122793
123074
|
} catch (error2) {
|
|
122794
123075
|
if (error2 instanceof exports_external.ZodError) {
|
|
122795
123076
|
const details = formatZodError(error2);
|
|
122796
|
-
|
|
123077
|
+
logger45.warn("Update currency validation failed", { details });
|
|
122797
123078
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122798
123079
|
}
|
|
122799
123080
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122800
123081
|
}
|
|
122801
|
-
|
|
123082
|
+
logger45.debug("Updating currency", {
|
|
122802
123083
|
userId: ctx.user.id,
|
|
122803
123084
|
currencyId,
|
|
122804
123085
|
symbol: body2.symbol,
|
|
@@ -122815,7 +123096,7 @@ var init_currency_controller = __esm(() => {
|
|
|
122815
123096
|
if (!isValidUUID(currencyId)) {
|
|
122816
123097
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
122817
123098
|
}
|
|
122818
|
-
|
|
123099
|
+
logger45.debug("Deleting currency", { userId: ctx.user.id, currencyId });
|
|
122819
123100
|
await ctx.services.currency.delete(currencyId);
|
|
122820
123101
|
});
|
|
122821
123102
|
currencyController = {
|
|
@@ -122826,7 +123107,7 @@ var init_currency_controller = __esm(() => {
|
|
|
122826
123107
|
remove
|
|
122827
123108
|
};
|
|
122828
123109
|
});
|
|
122829
|
-
var
|
|
123110
|
+
var logger46;
|
|
122830
123111
|
var reset;
|
|
122831
123112
|
var init_database_controller = __esm(() => {
|
|
122832
123113
|
init_esm();
|
|
@@ -122834,7 +123115,7 @@ var init_database_controller = __esm(() => {
|
|
|
122834
123115
|
init_src2();
|
|
122835
123116
|
init_errors();
|
|
122836
123117
|
init_utils11();
|
|
122837
|
-
|
|
123118
|
+
logger46 = log.scope("DatabaseController");
|
|
122838
123119
|
reset = requireDeveloper(async (ctx) => {
|
|
122839
123120
|
const slug2 = ctx.params.slug;
|
|
122840
123121
|
if (!slug2) {
|
|
@@ -122847,11 +123128,11 @@ var init_database_controller = __esm(() => {
|
|
|
122847
123128
|
} catch (error2) {
|
|
122848
123129
|
if (error2 instanceof exports_external.ZodError) {
|
|
122849
123130
|
const details = formatZodError(error2);
|
|
122850
|
-
|
|
123131
|
+
logger46.warn("Database reset validation failed", { details });
|
|
122851
123132
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122852
123133
|
}
|
|
122853
123134
|
}
|
|
122854
|
-
|
|
123135
|
+
logger46.debug("Resetting database", {
|
|
122855
123136
|
userId: ctx.user.id,
|
|
122856
123137
|
slug: slug2,
|
|
122857
123138
|
hasSchema: Boolean(body2.schema)
|
|
@@ -122867,7 +123148,7 @@ async function createJob(ctx) {
|
|
|
122867
123148
|
let body2;
|
|
122868
123149
|
try {
|
|
122869
123150
|
const json4 = await ctx.request.json();
|
|
122870
|
-
|
|
123151
|
+
logger47.debug("Deploy request body", {
|
|
122871
123152
|
keys: Object.keys(json4 || {}),
|
|
122872
123153
|
hasUploadToken: Boolean(json4?.uploadToken),
|
|
122873
123154
|
hasCode: Boolean(json4?.code),
|
|
@@ -122877,7 +123158,7 @@ async function createJob(ctx) {
|
|
|
122877
123158
|
} catch (error2) {
|
|
122878
123159
|
if (error2 instanceof exports_external.ZodError) {
|
|
122879
123160
|
const details = formatZodError(error2);
|
|
122880
|
-
|
|
123161
|
+
logger47.warn("Deploy validation failed", { details });
|
|
122881
123162
|
throw ApiError.unprocessableEntity("Invalid deploy request", details);
|
|
122882
123163
|
}
|
|
122883
123164
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -122898,7 +123179,7 @@ async function getJob(ctx) {
|
|
|
122898
123179
|
}
|
|
122899
123180
|
return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
|
|
122900
123181
|
}
|
|
122901
|
-
var
|
|
123182
|
+
var logger47;
|
|
122902
123183
|
var deploy;
|
|
122903
123184
|
var init_deploy_controller = __esm(() => {
|
|
122904
123185
|
init_esm();
|
|
@@ -122906,26 +123187,26 @@ var init_deploy_controller = __esm(() => {
|
|
|
122906
123187
|
init_src2();
|
|
122907
123188
|
init_errors();
|
|
122908
123189
|
init_utils11();
|
|
122909
|
-
|
|
123190
|
+
logger47 = log.scope("DeployController");
|
|
122910
123191
|
deploy = {
|
|
122911
123192
|
createJob: requireDeveloper(createJob),
|
|
122912
123193
|
getJob: requireDeveloper(getJob)
|
|
122913
123194
|
};
|
|
122914
123195
|
});
|
|
122915
|
-
var
|
|
123196
|
+
var logger48;
|
|
122916
123197
|
var apply;
|
|
122917
123198
|
var getStatus;
|
|
122918
123199
|
var developer;
|
|
122919
123200
|
var init_developer_controller = __esm(() => {
|
|
122920
123201
|
init_src2();
|
|
122921
123202
|
init_utils11();
|
|
122922
|
-
|
|
123203
|
+
logger48 = log.scope("DeveloperController");
|
|
122923
123204
|
apply = requireNonAnonymous(async (ctx) => {
|
|
122924
|
-
|
|
123205
|
+
logger48.debug("Applying for developer status", { userId: ctx.user.id });
|
|
122925
123206
|
await ctx.services.developer.apply(ctx.user);
|
|
122926
123207
|
});
|
|
122927
123208
|
getStatus = requireNonAnonymous(async (ctx) => {
|
|
122928
|
-
|
|
123209
|
+
logger48.debug("Getting developer status", { userId: ctx.user.id });
|
|
122929
123210
|
const status = await ctx.services.developer.getStatus(ctx.user.id);
|
|
122930
123211
|
return { status };
|
|
122931
123212
|
});
|
|
@@ -122934,7 +123215,7 @@ var init_developer_controller = __esm(() => {
|
|
|
122934
123215
|
getStatus
|
|
122935
123216
|
};
|
|
122936
123217
|
});
|
|
122937
|
-
var
|
|
123218
|
+
var logger49;
|
|
122938
123219
|
var add;
|
|
122939
123220
|
var list2;
|
|
122940
123221
|
var getStatus2;
|
|
@@ -122947,7 +123228,7 @@ var init_domain_controller = __esm(() => {
|
|
|
122947
123228
|
init_config2();
|
|
122948
123229
|
init_errors();
|
|
122949
123230
|
init_utils11();
|
|
122950
|
-
|
|
123231
|
+
logger49 = log.scope("DomainController");
|
|
122951
123232
|
add = requireDeveloper(async (ctx) => {
|
|
122952
123233
|
const slug2 = ctx.params.slug;
|
|
122953
123234
|
if (!slug2) {
|
|
@@ -122960,13 +123241,13 @@ var init_domain_controller = __esm(() => {
|
|
|
122960
123241
|
} catch (error2) {
|
|
122961
123242
|
if (error2 instanceof exports_external.ZodError) {
|
|
122962
123243
|
const details = formatZodError(error2);
|
|
122963
|
-
|
|
123244
|
+
logger49.warn("Add domain validation failed", { details });
|
|
122964
123245
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
122965
123246
|
}
|
|
122966
123247
|
throw ApiError.badRequest("Invalid JSON body");
|
|
122967
123248
|
}
|
|
122968
123249
|
const environment = getPlatformEnvironment(ctx.config);
|
|
122969
|
-
|
|
123250
|
+
logger49.debug("Adding domain", {
|
|
122970
123251
|
userId: ctx.user.id,
|
|
122971
123252
|
slug: slug2,
|
|
122972
123253
|
hostname: body2.hostname,
|
|
@@ -122980,7 +123261,7 @@ var init_domain_controller = __esm(() => {
|
|
|
122980
123261
|
throw ApiError.badRequest("Missing game slug");
|
|
122981
123262
|
}
|
|
122982
123263
|
const environment = getPlatformEnvironment(ctx.config);
|
|
122983
|
-
|
|
123264
|
+
logger49.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
|
|
122984
123265
|
const domains22 = await ctx.services.domain.list(slug2, environment, ctx.user);
|
|
122985
123266
|
return { domains: domains22 };
|
|
122986
123267
|
});
|
|
@@ -122995,7 +123276,7 @@ var init_domain_controller = __esm(() => {
|
|
|
122995
123276
|
}
|
|
122996
123277
|
const refresh = ctx.url.searchParams.get("refresh") === "true";
|
|
122997
123278
|
const environment = getPlatformEnvironment(ctx.config);
|
|
122998
|
-
|
|
123279
|
+
logger49.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
|
|
122999
123280
|
return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
|
|
123000
123281
|
});
|
|
123001
123282
|
remove2 = requireDeveloper(async (ctx) => {
|
|
@@ -123008,7 +123289,7 @@ var init_domain_controller = __esm(() => {
|
|
|
123008
123289
|
throw ApiError.badRequest("Missing hostname");
|
|
123009
123290
|
}
|
|
123010
123291
|
const environment = getPlatformEnvironment(ctx.config);
|
|
123011
|
-
|
|
123292
|
+
logger49.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
|
|
123012
123293
|
await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
|
|
123013
123294
|
});
|
|
123014
123295
|
domains2 = {
|
|
@@ -123018,7 +123299,7 @@ var init_domain_controller = __esm(() => {
|
|
|
123018
123299
|
remove: remove2
|
|
123019
123300
|
};
|
|
123020
123301
|
});
|
|
123021
|
-
var
|
|
123302
|
+
var logger50;
|
|
123022
123303
|
var list3;
|
|
123023
123304
|
var listAccessible;
|
|
123024
123305
|
var getSubjects;
|
|
@@ -123035,17 +123316,17 @@ var init_game_controller = __esm(() => {
|
|
|
123035
123316
|
init_src4();
|
|
123036
123317
|
init_errors();
|
|
123037
123318
|
init_utils11();
|
|
123038
|
-
|
|
123319
|
+
logger50 = log.scope("GameController");
|
|
123039
123320
|
list3 = requireNonAnonymous(async (ctx) => {
|
|
123040
|
-
|
|
123321
|
+
logger50.debug("Listing games", { userId: ctx.user.id });
|
|
123041
123322
|
return ctx.services.game.list(ctx.user);
|
|
123042
123323
|
});
|
|
123043
123324
|
listAccessible = requireNonAnonymous(async (ctx) => {
|
|
123044
|
-
|
|
123325
|
+
logger50.debug("Listing accessible games", { userId: ctx.user.id });
|
|
123045
123326
|
return ctx.services.game.listAccessible(ctx.user);
|
|
123046
123327
|
});
|
|
123047
123328
|
getSubjects = requireNonAnonymous(async (ctx) => {
|
|
123048
|
-
|
|
123329
|
+
logger50.debug("Getting game subjects", { userId: ctx.user.id });
|
|
123049
123330
|
return ctx.services.game.getSubjects();
|
|
123050
123331
|
});
|
|
123051
123332
|
getById2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -123056,7 +123337,7 @@ var init_game_controller = __esm(() => {
|
|
|
123056
123337
|
if (!isValidUUID(gameId)) {
|
|
123057
123338
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
123058
123339
|
}
|
|
123059
|
-
|
|
123340
|
+
logger50.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
|
|
123060
123341
|
return ctx.services.game.getById(gameId, ctx.user);
|
|
123061
123342
|
});
|
|
123062
123343
|
getBySlug = requireNonAnonymous(async (ctx) => {
|
|
@@ -123064,7 +123345,7 @@ var init_game_controller = __esm(() => {
|
|
|
123064
123345
|
if (!slug2) {
|
|
123065
123346
|
throw ApiError.badRequest("Missing game slug");
|
|
123066
123347
|
}
|
|
123067
|
-
|
|
123348
|
+
logger50.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
|
|
123068
123349
|
return ctx.services.game.getBySlug(slug2, ctx.user);
|
|
123069
123350
|
});
|
|
123070
123351
|
getManifest = requireNonAnonymous(async (ctx) => {
|
|
@@ -123075,7 +123356,7 @@ var init_game_controller = __esm(() => {
|
|
|
123075
123356
|
if (!isValidUUID(gameId)) {
|
|
123076
123357
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
123077
123358
|
}
|
|
123078
|
-
|
|
123359
|
+
logger50.debug("Getting game manifest by ID", {
|
|
123079
123360
|
userId: ctx.user.id,
|
|
123080
123361
|
gameId,
|
|
123081
123362
|
launchId: ctx.launchId
|
|
@@ -123094,12 +123375,12 @@ var init_game_controller = __esm(() => {
|
|
|
123094
123375
|
} catch (error2) {
|
|
123095
123376
|
if (error2 instanceof exports_external.ZodError) {
|
|
123096
123377
|
const details = formatZodError(error2);
|
|
123097
|
-
|
|
123378
|
+
logger50.warn("Upsert game validation failed", { details });
|
|
123098
123379
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123099
123380
|
}
|
|
123100
123381
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123101
123382
|
}
|
|
123102
|
-
|
|
123383
|
+
logger50.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
|
|
123103
123384
|
return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
|
|
123104
123385
|
});
|
|
123105
123386
|
remove3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -123110,7 +123391,7 @@ var init_game_controller = __esm(() => {
|
|
|
123110
123391
|
if (!isValidUUID(gameId)) {
|
|
123111
123392
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
123112
123393
|
}
|
|
123113
|
-
|
|
123394
|
+
logger50.debug("Deleting game", { userId: ctx.user.id, gameId });
|
|
123114
123395
|
await ctx.services.game.delete(gameId, ctx.user);
|
|
123115
123396
|
});
|
|
123116
123397
|
games2 = {
|
|
@@ -123124,7 +123405,7 @@ var init_game_controller = __esm(() => {
|
|
|
123124
123405
|
remove: remove3
|
|
123125
123406
|
};
|
|
123126
123407
|
});
|
|
123127
|
-
var
|
|
123408
|
+
var logger51;
|
|
123128
123409
|
var list4;
|
|
123129
123410
|
var addItem;
|
|
123130
123411
|
var removeItem;
|
|
@@ -123135,9 +123416,9 @@ var init_inventory_controller = __esm(() => {
|
|
|
123135
123416
|
init_src2();
|
|
123136
123417
|
init_errors();
|
|
123137
123418
|
init_utils11();
|
|
123138
|
-
|
|
123419
|
+
logger51 = log.scope("InventoryController");
|
|
123139
123420
|
list4 = requireNonAnonymous(async (ctx) => {
|
|
123140
|
-
|
|
123421
|
+
logger51.debug("Listing inventory", { userId: ctx.user.id });
|
|
123141
123422
|
return ctx.services.inventory.list(ctx.user);
|
|
123142
123423
|
});
|
|
123143
123424
|
addItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -123148,12 +123429,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
123148
123429
|
} catch (error2) {
|
|
123149
123430
|
if (error2 instanceof exports_external.ZodError) {
|
|
123150
123431
|
const details = formatZodError(error2);
|
|
123151
|
-
|
|
123432
|
+
logger51.warn("Add inventory item validation failed", { details });
|
|
123152
123433
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
123153
123434
|
}
|
|
123154
123435
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123155
123436
|
}
|
|
123156
|
-
|
|
123437
|
+
logger51.debug("Adding item", {
|
|
123157
123438
|
userId: ctx.user.id,
|
|
123158
123439
|
itemId: body2.itemId,
|
|
123159
123440
|
qty: body2.qty
|
|
@@ -123168,12 +123449,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
123168
123449
|
} catch (error2) {
|
|
123169
123450
|
if (error2 instanceof exports_external.ZodError) {
|
|
123170
123451
|
const details = formatZodError(error2);
|
|
123171
|
-
|
|
123452
|
+
logger51.warn("Remove inventory item validation failed", { details });
|
|
123172
123453
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
123173
123454
|
}
|
|
123174
123455
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123175
123456
|
}
|
|
123176
|
-
|
|
123457
|
+
logger51.debug("Removing item", {
|
|
123177
123458
|
userId: ctx.user.id,
|
|
123178
123459
|
itemId: body2.itemId,
|
|
123179
123460
|
qty: body2.qty
|
|
@@ -123186,7 +123467,7 @@ var init_inventory_controller = __esm(() => {
|
|
|
123186
123467
|
removeItem
|
|
123187
123468
|
};
|
|
123188
123469
|
});
|
|
123189
|
-
var
|
|
123470
|
+
var logger52;
|
|
123190
123471
|
var list5;
|
|
123191
123472
|
var getById3;
|
|
123192
123473
|
var resolve2;
|
|
@@ -123205,10 +123486,10 @@ var init_item_controller = __esm(() => {
|
|
|
123205
123486
|
init_src4();
|
|
123206
123487
|
init_errors();
|
|
123207
123488
|
init_utils11();
|
|
123208
|
-
|
|
123489
|
+
logger52 = log.scope("ItemController");
|
|
123209
123490
|
list5 = requireNonAnonymous(async (ctx) => {
|
|
123210
123491
|
const gameId = ctx.url.searchParams.get("gameId") || undefined;
|
|
123211
|
-
|
|
123492
|
+
logger52.debug("Listing items", { userId: ctx.user.id, gameId });
|
|
123212
123493
|
return ctx.services.item.list(gameId);
|
|
123213
123494
|
});
|
|
123214
123495
|
getById3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -123219,7 +123500,7 @@ var init_item_controller = __esm(() => {
|
|
|
123219
123500
|
if (!isValidUUID(itemId)) {
|
|
123220
123501
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
123221
123502
|
}
|
|
123222
|
-
|
|
123503
|
+
logger52.debug("Getting item", { userId: ctx.user.id, itemId });
|
|
123223
123504
|
return ctx.services.item.getById(itemId);
|
|
123224
123505
|
});
|
|
123225
123506
|
resolve2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -123231,7 +123512,7 @@ var init_item_controller = __esm(() => {
|
|
|
123231
123512
|
if (gameId && !isValidUUID(gameId)) {
|
|
123232
123513
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
123233
123514
|
}
|
|
123234
|
-
|
|
123515
|
+
logger52.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
|
|
123235
123516
|
return ctx.services.item.resolveBySlug(slug2, gameId);
|
|
123236
123517
|
});
|
|
123237
123518
|
create3 = requireRole(["admin"], async (ctx) => {
|
|
@@ -123242,12 +123523,12 @@ var init_item_controller = __esm(() => {
|
|
|
123242
123523
|
} catch (error2) {
|
|
123243
123524
|
if (error2 instanceof exports_external.ZodError) {
|
|
123244
123525
|
const details = formatZodError(error2);
|
|
123245
|
-
|
|
123526
|
+
logger52.warn("Create item validation failed", { details });
|
|
123246
123527
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123247
123528
|
}
|
|
123248
123529
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123249
123530
|
}
|
|
123250
|
-
|
|
123531
|
+
logger52.debug("Creating item", {
|
|
123251
123532
|
userId: ctx.user.id,
|
|
123252
123533
|
slug: body2.slug,
|
|
123253
123534
|
displayName: body2.displayName
|
|
@@ -123269,7 +123550,7 @@ var init_item_controller = __esm(() => {
|
|
|
123269
123550
|
} catch (error2) {
|
|
123270
123551
|
if (error2 instanceof exports_external.ZodError) {
|
|
123271
123552
|
const details = formatZodError(error2);
|
|
123272
|
-
|
|
123553
|
+
logger52.warn("Update item validation failed", { details });
|
|
123273
123554
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123274
123555
|
}
|
|
123275
123556
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -123277,7 +123558,7 @@ var init_item_controller = __esm(() => {
|
|
|
123277
123558
|
if (Object.keys(body2).length === 0) {
|
|
123278
123559
|
throw ApiError.badRequest("No update data provided");
|
|
123279
123560
|
}
|
|
123280
|
-
|
|
123561
|
+
logger52.debug("Updating item", {
|
|
123281
123562
|
userId: ctx.user.id,
|
|
123282
123563
|
itemId,
|
|
123283
123564
|
slug: body2.slug,
|
|
@@ -123294,7 +123575,7 @@ var init_item_controller = __esm(() => {
|
|
|
123294
123575
|
if (!isValidUUID(itemId)) {
|
|
123295
123576
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
123296
123577
|
}
|
|
123297
|
-
|
|
123578
|
+
logger52.debug("Deleting item", { userId: ctx.user.id, itemId });
|
|
123298
123579
|
await ctx.services.item.delete(itemId);
|
|
123299
123580
|
});
|
|
123300
123581
|
listByGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -123305,7 +123586,7 @@ var init_item_controller = __esm(() => {
|
|
|
123305
123586
|
if (!isValidUUID(gameId)) {
|
|
123306
123587
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
123307
123588
|
}
|
|
123308
|
-
|
|
123589
|
+
logger52.debug("Listing game items", { userId: ctx.user.id, gameId });
|
|
123309
123590
|
return ctx.services.item.listByGame(gameId);
|
|
123310
123591
|
});
|
|
123311
123592
|
createForGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -123323,12 +123604,12 @@ var init_item_controller = __esm(() => {
|
|
|
123323
123604
|
} catch (error2) {
|
|
123324
123605
|
if (error2 instanceof exports_external.ZodError) {
|
|
123325
123606
|
const details = formatZodError(error2);
|
|
123326
|
-
|
|
123607
|
+
logger52.warn("Create game item validation failed", { details });
|
|
123327
123608
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123328
123609
|
}
|
|
123329
123610
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123330
123611
|
}
|
|
123331
|
-
|
|
123612
|
+
logger52.debug("Creating game item", {
|
|
123332
123613
|
userId: ctx.user.id,
|
|
123333
123614
|
gameId,
|
|
123334
123615
|
slug: body2.slug,
|
|
@@ -123355,7 +123636,7 @@ var init_item_controller = __esm(() => {
|
|
|
123355
123636
|
} catch (error2) {
|
|
123356
123637
|
if (error2 instanceof exports_external.ZodError) {
|
|
123357
123638
|
const details = formatZodError(error2);
|
|
123358
|
-
|
|
123639
|
+
logger52.warn("Update game item validation failed", { details });
|
|
123359
123640
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123360
123641
|
}
|
|
123361
123642
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -123363,7 +123644,7 @@ var init_item_controller = __esm(() => {
|
|
|
123363
123644
|
if (Object.keys(body2).length === 0) {
|
|
123364
123645
|
throw ApiError.badRequest("No update data provided");
|
|
123365
123646
|
}
|
|
123366
|
-
|
|
123647
|
+
logger52.debug("Updating game item", {
|
|
123367
123648
|
userId: ctx.user.id,
|
|
123368
123649
|
gameId,
|
|
123369
123650
|
itemId,
|
|
@@ -123385,7 +123666,7 @@ var init_item_controller = __esm(() => {
|
|
|
123385
123666
|
if (!isValidUUID(itemId)) {
|
|
123386
123667
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
123387
123668
|
}
|
|
123388
|
-
|
|
123669
|
+
logger52.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
|
|
123389
123670
|
await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
|
|
123390
123671
|
});
|
|
123391
123672
|
items2 = {
|
|
@@ -123401,7 +123682,7 @@ var init_item_controller = __esm(() => {
|
|
|
123401
123682
|
deleteForGame
|
|
123402
123683
|
};
|
|
123403
123684
|
});
|
|
123404
|
-
var
|
|
123685
|
+
var logger53;
|
|
123405
123686
|
var listKeys;
|
|
123406
123687
|
var getStats;
|
|
123407
123688
|
var seed;
|
|
@@ -123416,7 +123697,7 @@ var init_kv_controller = __esm(() => {
|
|
|
123416
123697
|
init_src2();
|
|
123417
123698
|
init_errors();
|
|
123418
123699
|
init_utils11();
|
|
123419
|
-
|
|
123700
|
+
logger53 = log.scope("KVController");
|
|
123420
123701
|
listKeys = requireDeveloper(async (ctx) => {
|
|
123421
123702
|
const slug2 = ctx.params.slug;
|
|
123422
123703
|
if (!slug2) {
|
|
@@ -123424,7 +123705,7 @@ var init_kv_controller = __esm(() => {
|
|
|
123424
123705
|
}
|
|
123425
123706
|
const url2 = ctx.url;
|
|
123426
123707
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
123427
|
-
|
|
123708
|
+
logger53.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
123428
123709
|
const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
|
|
123429
123710
|
return { keys };
|
|
123430
123711
|
});
|
|
@@ -123433,7 +123714,7 @@ var init_kv_controller = __esm(() => {
|
|
|
123433
123714
|
if (!slug2) {
|
|
123434
123715
|
throw ApiError.badRequest("Missing game slug");
|
|
123435
123716
|
}
|
|
123436
|
-
|
|
123717
|
+
logger53.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
|
|
123437
123718
|
return ctx.services.kv.getStats(slug2, ctx.user);
|
|
123438
123719
|
});
|
|
123439
123720
|
seed = requireDeveloper(async (ctx) => {
|
|
@@ -123448,12 +123729,12 @@ var init_kv_controller = __esm(() => {
|
|
|
123448
123729
|
} catch (error2) {
|
|
123449
123730
|
if (error2 instanceof exports_external.ZodError) {
|
|
123450
123731
|
const details = formatZodError(error2);
|
|
123451
|
-
|
|
123732
|
+
logger53.warn("Seed validation failed", { details });
|
|
123452
123733
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123453
123734
|
}
|
|
123454
123735
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123455
123736
|
}
|
|
123456
|
-
|
|
123737
|
+
logger53.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
|
|
123457
123738
|
await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
|
|
123458
123739
|
return { success: true, count: body2.entries.length };
|
|
123459
123740
|
});
|
|
@@ -123463,7 +123744,7 @@ var init_kv_controller = __esm(() => {
|
|
|
123463
123744
|
if (!slug2 || !key) {
|
|
123464
123745
|
throw ApiError.badRequest("Missing game slug or key");
|
|
123465
123746
|
}
|
|
123466
|
-
|
|
123747
|
+
logger53.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
|
|
123467
123748
|
const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
|
|
123468
123749
|
return { key, value };
|
|
123469
123750
|
});
|
|
@@ -123477,7 +123758,7 @@ var init_kv_controller = __esm(() => {
|
|
|
123477
123758
|
if (!value) {
|
|
123478
123759
|
throw ApiError.badRequest("Missing value in request body");
|
|
123479
123760
|
}
|
|
123480
|
-
|
|
123761
|
+
logger53.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
|
|
123481
123762
|
await ctx.services.kv.setValue(slug2, key, value, ctx.user);
|
|
123482
123763
|
return { success: true, key };
|
|
123483
123764
|
});
|
|
@@ -123487,7 +123768,7 @@ var init_kv_controller = __esm(() => {
|
|
|
123487
123768
|
if (!slug2 || !key) {
|
|
123488
123769
|
throw ApiError.badRequest("Missing game slug or key");
|
|
123489
123770
|
}
|
|
123490
|
-
|
|
123771
|
+
logger53.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
|
|
123491
123772
|
await ctx.services.kv.deleteValue(slug2, key, ctx.user);
|
|
123492
123773
|
return { success: true, key };
|
|
123493
123774
|
});
|
|
@@ -123497,7 +123778,7 @@ var init_kv_controller = __esm(() => {
|
|
|
123497
123778
|
if (!slug2 || !key) {
|
|
123498
123779
|
throw ApiError.badRequest("Missing game slug or key");
|
|
123499
123780
|
}
|
|
123500
|
-
|
|
123781
|
+
logger53.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
|
|
123501
123782
|
const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
|
|
123502
123783
|
return { key, metadata: metadata2 };
|
|
123503
123784
|
});
|
|
@@ -123506,12 +123787,12 @@ var init_kv_controller = __esm(() => {
|
|
|
123506
123787
|
if (!slug2) {
|
|
123507
123788
|
throw ApiError.badRequest("Missing game slug");
|
|
123508
123789
|
}
|
|
123509
|
-
|
|
123790
|
+
logger53.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
|
|
123510
123791
|
const deleted = await ctx.services.kv.clear(slug2, ctx.user);
|
|
123511
123792
|
return { success: true, deleted };
|
|
123512
123793
|
});
|
|
123513
123794
|
});
|
|
123514
|
-
var
|
|
123795
|
+
var logger54;
|
|
123515
123796
|
var submitScore;
|
|
123516
123797
|
var getGlobalLeaderboard;
|
|
123517
123798
|
var getLeaderboard;
|
|
@@ -123525,7 +123806,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123525
123806
|
init_src2();
|
|
123526
123807
|
init_errors();
|
|
123527
123808
|
init_utils11();
|
|
123528
|
-
|
|
123809
|
+
logger54 = log.scope("LeaderboardController");
|
|
123529
123810
|
submitScore = requireAuth(async (ctx) => {
|
|
123530
123811
|
const gameId = ctx.params.gameId;
|
|
123531
123812
|
if (!gameId) {
|
|
@@ -123538,12 +123819,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123538
123819
|
} catch (error2) {
|
|
123539
123820
|
if (error2 instanceof exports_external.ZodError) {
|
|
123540
123821
|
const details = formatZodError(error2);
|
|
123541
|
-
|
|
123822
|
+
logger54.warn("Submit score validation failed", { details });
|
|
123542
123823
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123543
123824
|
}
|
|
123544
123825
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123545
123826
|
}
|
|
123546
|
-
|
|
123827
|
+
logger54.debug("Submitting score", {
|
|
123547
123828
|
userId: ctx.user.id,
|
|
123548
123829
|
gameId,
|
|
123549
123830
|
score: body2.score
|
|
@@ -123566,12 +123847,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123566
123847
|
} catch (error2) {
|
|
123567
123848
|
if (error2 instanceof exports_external.ZodError) {
|
|
123568
123849
|
const details = formatZodError(error2);
|
|
123569
|
-
|
|
123850
|
+
logger54.warn("Get global leaderboard query validation failed", { details });
|
|
123570
123851
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
123571
123852
|
}
|
|
123572
123853
|
throw ApiError.badRequest("Invalid query parameters");
|
|
123573
123854
|
}
|
|
123574
|
-
|
|
123855
|
+
logger54.debug("Getting global leaderboard", {
|
|
123575
123856
|
userId: ctx.user.id,
|
|
123576
123857
|
gameId,
|
|
123577
123858
|
...query
|
|
@@ -123594,12 +123875,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123594
123875
|
} catch (error2) {
|
|
123595
123876
|
if (error2 instanceof exports_external.ZodError) {
|
|
123596
123877
|
const details = formatZodError(error2);
|
|
123597
|
-
|
|
123878
|
+
logger54.warn("Get leaderboard query validation failed", { details });
|
|
123598
123879
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
123599
123880
|
}
|
|
123600
123881
|
throw ApiError.badRequest("Invalid query parameters");
|
|
123601
123882
|
}
|
|
123602
|
-
|
|
123883
|
+
logger54.debug("Getting leaderboard", {
|
|
123603
123884
|
userId: ctx.user.id,
|
|
123604
123885
|
gameId,
|
|
123605
123886
|
...query
|
|
@@ -123611,7 +123892,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123611
123892
|
if (!gameId || !userId) {
|
|
123612
123893
|
throw ApiError.badRequest("Game ID and User ID are required");
|
|
123613
123894
|
}
|
|
123614
|
-
|
|
123895
|
+
logger54.debug("Getting user rank", {
|
|
123615
123896
|
requesterId: ctx.user.id,
|
|
123616
123897
|
gameId,
|
|
123617
123898
|
targetUserId: userId
|
|
@@ -123626,7 +123907,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123626
123907
|
const url2 = ctx.url;
|
|
123627
123908
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "50"), 100);
|
|
123628
123909
|
const gameId = url2.searchParams.get("gameId") || undefined;
|
|
123629
|
-
|
|
123910
|
+
logger54.debug("Getting user all scores", {
|
|
123630
123911
|
requesterId: ctx.user.id,
|
|
123631
123912
|
targetUserId: userId,
|
|
123632
123913
|
gameId,
|
|
@@ -123641,7 +123922,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123641
123922
|
}
|
|
123642
123923
|
const url2 = ctx.url;
|
|
123643
123924
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "10"), 100);
|
|
123644
|
-
|
|
123925
|
+
logger54.debug("Getting user scores", {
|
|
123645
123926
|
requesterId: ctx.user.id,
|
|
123646
123927
|
gameId,
|
|
123647
123928
|
targetUserId: userId,
|
|
@@ -123659,7 +123940,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
123659
123940
|
};
|
|
123660
123941
|
});
|
|
123661
123942
|
async function listConfigs(ctx) {
|
|
123662
|
-
|
|
123943
|
+
logger55.debug("Listing level configs");
|
|
123663
123944
|
return ctx.services.level.listConfigs();
|
|
123664
123945
|
}
|
|
123665
123946
|
async function getConfig(ctx) {
|
|
@@ -123671,10 +123952,10 @@ async function getConfig(ctx) {
|
|
|
123671
123952
|
if (isNaN(level) || level < 1) {
|
|
123672
123953
|
throw ApiError.badRequest("Level must be a positive integer");
|
|
123673
123954
|
}
|
|
123674
|
-
|
|
123955
|
+
logger55.debug("Getting level config", { level });
|
|
123675
123956
|
return ctx.services.level.getConfig(level);
|
|
123676
123957
|
}
|
|
123677
|
-
var
|
|
123958
|
+
var logger55;
|
|
123678
123959
|
var getByUser;
|
|
123679
123960
|
var getProgress;
|
|
123680
123961
|
var levels;
|
|
@@ -123682,13 +123963,13 @@ var init_level_controller = __esm(() => {
|
|
|
123682
123963
|
init_src2();
|
|
123683
123964
|
init_errors();
|
|
123684
123965
|
init_utils11();
|
|
123685
|
-
|
|
123966
|
+
logger55 = log.scope("LevelController");
|
|
123686
123967
|
getByUser = requireNonAnonymous(async (ctx) => {
|
|
123687
|
-
|
|
123968
|
+
logger55.debug("Getting user level", { userId: ctx.user.id });
|
|
123688
123969
|
return ctx.services.level.getByUser(ctx.user);
|
|
123689
123970
|
});
|
|
123690
123971
|
getProgress = requireNonAnonymous(async (ctx) => {
|
|
123691
|
-
|
|
123972
|
+
logger55.debug("Getting level progress", { userId: ctx.user.id });
|
|
123692
123973
|
return ctx.services.level.getProgress(ctx.user);
|
|
123693
123974
|
});
|
|
123694
123975
|
levels = {
|
|
@@ -123698,14 +123979,14 @@ var init_level_controller = __esm(() => {
|
|
|
123698
123979
|
getProgress
|
|
123699
123980
|
};
|
|
123700
123981
|
});
|
|
123701
|
-
var
|
|
123982
|
+
var logger56;
|
|
123702
123983
|
var generateToken;
|
|
123703
123984
|
var logs;
|
|
123704
123985
|
var init_logs_controller = __esm(() => {
|
|
123705
123986
|
init_src2();
|
|
123706
123987
|
init_errors();
|
|
123707
123988
|
init_utils11();
|
|
123708
|
-
|
|
123989
|
+
logger56 = log.scope("LogsController");
|
|
123709
123990
|
generateToken = requireDeveloper(async (ctx) => {
|
|
123710
123991
|
const slug2 = ctx.params.slug;
|
|
123711
123992
|
if (!slug2) {
|
|
@@ -123724,7 +124005,7 @@ var init_logs_controller = __esm(() => {
|
|
|
123724
124005
|
}
|
|
123725
124006
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123726
124007
|
}
|
|
123727
|
-
|
|
124008
|
+
logger56.debug("Generating log stream token", {
|
|
123728
124009
|
userId: ctx.user.id,
|
|
123729
124010
|
slug: slug2,
|
|
123730
124011
|
environment: body2.environment
|
|
@@ -123741,22 +124022,22 @@ var init_logs_controller = __esm(() => {
|
|
|
123741
124022
|
generateToken
|
|
123742
124023
|
};
|
|
123743
124024
|
});
|
|
123744
|
-
var
|
|
124025
|
+
var logger57;
|
|
123745
124026
|
var getStatus3;
|
|
123746
124027
|
var lti;
|
|
123747
124028
|
var init_lti_controller = __esm(() => {
|
|
123748
124029
|
init_src2();
|
|
123749
124030
|
init_utils11();
|
|
123750
|
-
|
|
124031
|
+
logger57 = log.scope("LtiController");
|
|
123751
124032
|
getStatus3 = requireNonAnonymous(async (ctx) => {
|
|
123752
|
-
|
|
124033
|
+
logger57.debug("Getting status", { userId: ctx.user.id });
|
|
123753
124034
|
return ctx.services.lti.getStatus(ctx.user);
|
|
123754
124035
|
});
|
|
123755
124036
|
lti = {
|
|
123756
124037
|
getStatus: getStatus3
|
|
123757
124038
|
};
|
|
123758
124039
|
});
|
|
123759
|
-
var
|
|
124040
|
+
var logger58;
|
|
123760
124041
|
var getByIdentifier;
|
|
123761
124042
|
var getElements;
|
|
123762
124043
|
var getObjects;
|
|
@@ -123770,13 +124051,13 @@ var init_map_controller = __esm(() => {
|
|
|
123770
124051
|
init_src4();
|
|
123771
124052
|
init_errors();
|
|
123772
124053
|
init_utils11();
|
|
123773
|
-
|
|
124054
|
+
logger58 = log.scope("MapController");
|
|
123774
124055
|
getByIdentifier = requireNonAnonymous(async (ctx) => {
|
|
123775
124056
|
const identifier = ctx.params.identifier;
|
|
123776
124057
|
if (!identifier) {
|
|
123777
124058
|
throw ApiError.badRequest("Missing map identifier");
|
|
123778
124059
|
}
|
|
123779
|
-
|
|
124060
|
+
logger58.debug("Getting map", { userId: ctx.user.id, identifier });
|
|
123780
124061
|
return ctx.services.map.getByIdentifier(identifier);
|
|
123781
124062
|
});
|
|
123782
124063
|
getElements = requireNonAnonymous(async (ctx) => {
|
|
@@ -123787,7 +124068,7 @@ var init_map_controller = __esm(() => {
|
|
|
123787
124068
|
if (!isValidUUID(mapId)) {
|
|
123788
124069
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
123789
124070
|
}
|
|
123790
|
-
|
|
124071
|
+
logger58.debug("Getting map elements", { userId: ctx.user.id, mapId });
|
|
123791
124072
|
return ctx.services.map.getElements(mapId);
|
|
123792
124073
|
});
|
|
123793
124074
|
getObjects = requireNonAnonymous(async (ctx) => {
|
|
@@ -123798,7 +124079,7 @@ var init_map_controller = __esm(() => {
|
|
|
123798
124079
|
if (!isValidUUID(mapId)) {
|
|
123799
124080
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
123800
124081
|
}
|
|
123801
|
-
|
|
124082
|
+
logger58.debug("Getting map objects", { userId: ctx.user.id, mapId });
|
|
123802
124083
|
return ctx.services.map.getObjects(mapId, ctx.user.id);
|
|
123803
124084
|
});
|
|
123804
124085
|
createObject = requireNonAnonymous(async (ctx) => {
|
|
@@ -123820,12 +124101,12 @@ var init_map_controller = __esm(() => {
|
|
|
123820
124101
|
} catch (error2) {
|
|
123821
124102
|
if (error2 instanceof exports_external.ZodError) {
|
|
123822
124103
|
const details = formatZodError(error2);
|
|
123823
|
-
|
|
124104
|
+
logger58.warn("Create map object validation failed", { details });
|
|
123824
124105
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
123825
124106
|
}
|
|
123826
124107
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123827
124108
|
}
|
|
123828
|
-
|
|
124109
|
+
logger58.debug("Creating map object", {
|
|
123829
124110
|
userId: ctx.user.id,
|
|
123830
124111
|
mapId,
|
|
123831
124112
|
itemId: body2.itemId,
|
|
@@ -123849,7 +124130,7 @@ var init_map_controller = __esm(() => {
|
|
|
123849
124130
|
if (!isValidUUID(objectId)) {
|
|
123850
124131
|
throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
|
|
123851
124132
|
}
|
|
123852
|
-
|
|
124133
|
+
logger58.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
|
|
123853
124134
|
await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
|
|
123854
124135
|
});
|
|
123855
124136
|
maps2 = {
|
|
@@ -123860,7 +124141,7 @@ var init_map_controller = __esm(() => {
|
|
|
123860
124141
|
deleteObject
|
|
123861
124142
|
};
|
|
123862
124143
|
});
|
|
123863
|
-
var
|
|
124144
|
+
var logger59;
|
|
123864
124145
|
var list6;
|
|
123865
124146
|
var updateStatus;
|
|
123866
124147
|
var getStats2;
|
|
@@ -123873,7 +124154,7 @@ var init_notification_controller = __esm(() => {
|
|
|
123873
124154
|
init_src2();
|
|
123874
124155
|
init_errors();
|
|
123875
124156
|
init_utils11();
|
|
123876
|
-
|
|
124157
|
+
logger59 = log.scope("NotificationController");
|
|
123877
124158
|
list6 = requireNonAnonymous(async (ctx) => {
|
|
123878
124159
|
const query = {
|
|
123879
124160
|
status: ctx.url.searchParams.get("status") || undefined,
|
|
@@ -123884,10 +124165,10 @@ var init_notification_controller = __esm(() => {
|
|
|
123884
124165
|
const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
|
|
123885
124166
|
if (!result.success) {
|
|
123886
124167
|
const details = formatZodError(result.error);
|
|
123887
|
-
|
|
124168
|
+
logger59.warn("List notifications query validation failed", { details });
|
|
123888
124169
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
123889
124170
|
}
|
|
123890
|
-
|
|
124171
|
+
logger59.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
|
|
123891
124172
|
return ctx.services.notification.list(ctx.user, result.data);
|
|
123892
124173
|
});
|
|
123893
124174
|
updateStatus = requireNonAnonymous(async (ctx) => {
|
|
@@ -123902,12 +124183,12 @@ var init_notification_controller = __esm(() => {
|
|
|
123902
124183
|
} catch (error2) {
|
|
123903
124184
|
if (error2 instanceof exports_external.ZodError) {
|
|
123904
124185
|
const details = formatZodError(error2);
|
|
123905
|
-
|
|
124186
|
+
logger59.warn("Update notification status validation failed", { details });
|
|
123906
124187
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
123907
124188
|
}
|
|
123908
124189
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123909
124190
|
}
|
|
123910
|
-
|
|
124191
|
+
logger59.debug("Updating status", {
|
|
123911
124192
|
userId: ctx.user.id,
|
|
123912
124193
|
notificationId,
|
|
123913
124194
|
status: body2.status
|
|
@@ -123917,7 +124198,7 @@ var init_notification_controller = __esm(() => {
|
|
|
123917
124198
|
getStats2 = requireNonAnonymous(async (ctx) => {
|
|
123918
124199
|
const startDate = ctx.url.searchParams.get("startDate");
|
|
123919
124200
|
const endDate = ctx.url.searchParams.get("endDate");
|
|
123920
|
-
|
|
124201
|
+
logger59.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
|
|
123921
124202
|
return ctx.services.notification.getStats(ctx.user, {
|
|
123922
124203
|
startDate: startDate ? new Date(startDate) : undefined,
|
|
123923
124204
|
endDate: endDate ? new Date(endDate) : undefined
|
|
@@ -123931,12 +124212,12 @@ var init_notification_controller = __esm(() => {
|
|
|
123931
124212
|
} catch (error2) {
|
|
123932
124213
|
if (error2 instanceof exports_external.ZodError) {
|
|
123933
124214
|
const details = formatZodError(error2);
|
|
123934
|
-
|
|
124215
|
+
logger59.warn("Create notification validation failed", { details });
|
|
123935
124216
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
123936
124217
|
}
|
|
123937
124218
|
throw ApiError.badRequest("Invalid JSON body");
|
|
123938
124219
|
}
|
|
123939
|
-
|
|
124220
|
+
logger59.debug("Creating notification", {
|
|
123940
124221
|
userId: ctx.user.id,
|
|
123941
124222
|
targetUserId: body2.userId,
|
|
123942
124223
|
type: body2.type
|
|
@@ -123954,12 +124235,12 @@ var init_notification_controller = __esm(() => {
|
|
|
123954
124235
|
});
|
|
123955
124236
|
});
|
|
123956
124237
|
deliver = requireNonAnonymous(async (ctx) => {
|
|
123957
|
-
|
|
124238
|
+
logger59.debug("Delivering notifications", { userId: ctx.user.id });
|
|
123958
124239
|
try {
|
|
123959
124240
|
await ctx.services.notification.deliverPending(ctx.user.id);
|
|
123960
124241
|
return { success: true };
|
|
123961
124242
|
} catch (error2) {
|
|
123962
|
-
|
|
124243
|
+
logger59.error("Failed to deliver notifications", { error: error2 });
|
|
123963
124244
|
throw ApiError.internal("Failed to deliver notifications");
|
|
123964
124245
|
}
|
|
123965
124246
|
});
|
|
@@ -123971,16 +124252,16 @@ var init_notification_controller = __esm(() => {
|
|
|
123971
124252
|
deliver
|
|
123972
124253
|
};
|
|
123973
124254
|
});
|
|
123974
|
-
var
|
|
124255
|
+
var logger60;
|
|
123975
124256
|
var generateToken2;
|
|
123976
124257
|
var realtime;
|
|
123977
124258
|
var init_realtime_controller = __esm(() => {
|
|
123978
124259
|
init_src2();
|
|
123979
124260
|
init_utils11();
|
|
123980
|
-
|
|
124261
|
+
logger60 = log.scope("RealtimeController");
|
|
123981
124262
|
generateToken2 = requireNonAnonymous(async (ctx) => {
|
|
123982
124263
|
const gameIdOrSlug = ctx.params.gameId;
|
|
123983
|
-
|
|
124264
|
+
logger60.debug("Generating token", {
|
|
123984
124265
|
userId: ctx.user.id,
|
|
123985
124266
|
gameId: gameIdOrSlug || "global",
|
|
123986
124267
|
launchId: ctx.launchId
|
|
@@ -123991,7 +124272,7 @@ var init_realtime_controller = __esm(() => {
|
|
|
123991
124272
|
generateToken: generateToken2
|
|
123992
124273
|
};
|
|
123993
124274
|
});
|
|
123994
|
-
var
|
|
124275
|
+
var logger61;
|
|
123995
124276
|
var listKeys2;
|
|
123996
124277
|
var setSecrets;
|
|
123997
124278
|
var deleteSecret;
|
|
@@ -124002,13 +124283,13 @@ var init_secrets_controller = __esm(() => {
|
|
|
124002
124283
|
init_src2();
|
|
124003
124284
|
init_errors();
|
|
124004
124285
|
init_utils11();
|
|
124005
|
-
|
|
124286
|
+
logger61 = log.scope("SecretsController");
|
|
124006
124287
|
listKeys2 = requireDeveloper(async (ctx) => {
|
|
124007
124288
|
const slug2 = ctx.params.slug;
|
|
124008
124289
|
if (!slug2) {
|
|
124009
124290
|
throw ApiError.badRequest("Missing game slug");
|
|
124010
124291
|
}
|
|
124011
|
-
|
|
124292
|
+
logger61.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
|
|
124012
124293
|
const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
|
|
124013
124294
|
return { keys };
|
|
124014
124295
|
});
|
|
@@ -124024,12 +124305,12 @@ var init_secrets_controller = __esm(() => {
|
|
|
124024
124305
|
} catch (error2) {
|
|
124025
124306
|
if (error2 instanceof exports_external.ZodError) {
|
|
124026
124307
|
const details = formatZodError(error2);
|
|
124027
|
-
|
|
124308
|
+
logger61.warn("Set secrets validation failed", { details });
|
|
124028
124309
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124029
124310
|
}
|
|
124030
124311
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124031
124312
|
}
|
|
124032
|
-
|
|
124313
|
+
logger61.debug("Setting secrets", {
|
|
124033
124314
|
userId: ctx.user.id,
|
|
124034
124315
|
slug: slug2,
|
|
124035
124316
|
keyCount: Object.keys(body2).length
|
|
@@ -124046,7 +124327,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
124046
124327
|
if (!key) {
|
|
124047
124328
|
throw ApiError.badRequest("Missing secret key");
|
|
124048
124329
|
}
|
|
124049
|
-
|
|
124330
|
+
logger61.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
|
|
124050
124331
|
await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
|
|
124051
124332
|
return { success: true };
|
|
124052
124333
|
});
|
|
@@ -124056,7 +124337,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
124056
124337
|
deleteSecret
|
|
124057
124338
|
};
|
|
124058
124339
|
});
|
|
124059
|
-
var
|
|
124340
|
+
var logger62;
|
|
124060
124341
|
var seed2;
|
|
124061
124342
|
var init_seed_controller = __esm(() => {
|
|
124062
124343
|
init_esm();
|
|
@@ -124064,7 +124345,7 @@ var init_seed_controller = __esm(() => {
|
|
|
124064
124345
|
init_src2();
|
|
124065
124346
|
init_errors();
|
|
124066
124347
|
init_utils11();
|
|
124067
|
-
|
|
124348
|
+
logger62 = log.scope("SeedController");
|
|
124068
124349
|
seed2 = requireDeveloper(async (ctx) => {
|
|
124069
124350
|
const slug2 = ctx.params.slug;
|
|
124070
124351
|
if (!slug2) {
|
|
@@ -124077,12 +124358,12 @@ var init_seed_controller = __esm(() => {
|
|
|
124077
124358
|
} catch (error2) {
|
|
124078
124359
|
if (error2 instanceof exports_external.ZodError) {
|
|
124079
124360
|
const details = formatZodError(error2);
|
|
124080
|
-
|
|
124361
|
+
logger62.warn("Seed database validation failed", { details });
|
|
124081
124362
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124082
124363
|
}
|
|
124083
124364
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124084
124365
|
}
|
|
124085
|
-
|
|
124366
|
+
logger62.debug("Seeding database", {
|
|
124086
124367
|
userId: ctx.user.id,
|
|
124087
124368
|
slug: slug2,
|
|
124088
124369
|
codeLength: body2.code.length,
|
|
@@ -124091,7 +124372,7 @@ var init_seed_controller = __esm(() => {
|
|
|
124091
124372
|
return ctx.services.seed.seed(slug2, body2.code, ctx.user, body2.secrets);
|
|
124092
124373
|
});
|
|
124093
124374
|
});
|
|
124094
|
-
var
|
|
124375
|
+
var logger63;
|
|
124095
124376
|
var start2;
|
|
124096
124377
|
var end;
|
|
124097
124378
|
var mintToken;
|
|
@@ -124101,13 +124382,13 @@ var init_session_controller = __esm(() => {
|
|
|
124101
124382
|
init_tunnel();
|
|
124102
124383
|
init_errors();
|
|
124103
124384
|
init_utils11();
|
|
124104
|
-
|
|
124385
|
+
logger63 = log.scope("SessionController");
|
|
124105
124386
|
start2 = requireAuth(async (ctx) => {
|
|
124106
124387
|
const gameIdOrSlug = ctx.params.gameId;
|
|
124107
124388
|
if (!gameIdOrSlug) {
|
|
124108
124389
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
124109
124390
|
}
|
|
124110
|
-
|
|
124391
|
+
logger63.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
124111
124392
|
return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
|
|
124112
124393
|
});
|
|
124113
124394
|
end = requireAuth(async (ctx) => {
|
|
@@ -124119,7 +124400,7 @@ var init_session_controller = __esm(() => {
|
|
|
124119
124400
|
if (!sessionId) {
|
|
124120
124401
|
throw ApiError.badRequest("Missing session ID");
|
|
124121
124402
|
}
|
|
124122
|
-
|
|
124403
|
+
logger63.debug("Ending session", {
|
|
124123
124404
|
userId: ctx.user.id,
|
|
124124
124405
|
gameIdOrSlug,
|
|
124125
124406
|
sessionId,
|
|
@@ -124132,7 +124413,7 @@ var init_session_controller = __esm(() => {
|
|
|
124132
124413
|
if (!gameIdOrSlug) {
|
|
124133
124414
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
124134
124415
|
}
|
|
124135
|
-
|
|
124416
|
+
logger63.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
124136
124417
|
const { token, exp } = await ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
|
|
124137
124418
|
let baseUrl;
|
|
124138
124419
|
if (ctx.config.isLocal) {
|
|
@@ -124148,22 +124429,22 @@ var init_session_controller = __esm(() => {
|
|
|
124148
124429
|
mintToken
|
|
124149
124430
|
};
|
|
124150
124431
|
});
|
|
124151
|
-
var
|
|
124432
|
+
var logger64;
|
|
124152
124433
|
var getShopView;
|
|
124153
124434
|
var shop;
|
|
124154
124435
|
var init_shop_controller = __esm(() => {
|
|
124155
124436
|
init_src2();
|
|
124156
124437
|
init_utils11();
|
|
124157
|
-
|
|
124438
|
+
logger64 = log.scope("ShopController");
|
|
124158
124439
|
getShopView = requireNonAnonymous(async (ctx) => {
|
|
124159
|
-
|
|
124440
|
+
logger64.debug("Getting shop view", { userId: ctx.user.id });
|
|
124160
124441
|
return ctx.services.shop.getShopView(ctx.user);
|
|
124161
124442
|
});
|
|
124162
124443
|
shop = {
|
|
124163
124444
|
getShopView
|
|
124164
124445
|
};
|
|
124165
124446
|
});
|
|
124166
|
-
var
|
|
124447
|
+
var logger65;
|
|
124167
124448
|
var list7;
|
|
124168
124449
|
var getById4;
|
|
124169
124450
|
var create5;
|
|
@@ -124182,9 +124463,9 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124182
124463
|
init_src4();
|
|
124183
124464
|
init_errors();
|
|
124184
124465
|
init_utils11();
|
|
124185
|
-
|
|
124466
|
+
logger65 = log.scope("ShopListingController");
|
|
124186
124467
|
list7 = requireAdmin(async (ctx) => {
|
|
124187
|
-
|
|
124468
|
+
logger65.debug("Listing shop listings", { userId: ctx.user.id });
|
|
124188
124469
|
return ctx.services.shopListing.list();
|
|
124189
124470
|
});
|
|
124190
124471
|
getById4 = requireAdmin(async (ctx) => {
|
|
@@ -124195,7 +124476,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124195
124476
|
if (!isValidUUID(listingId)) {
|
|
124196
124477
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
124197
124478
|
}
|
|
124198
|
-
|
|
124479
|
+
logger65.debug("Getting listing", { userId: ctx.user.id, listingId });
|
|
124199
124480
|
return ctx.services.shopListing.getById(listingId);
|
|
124200
124481
|
});
|
|
124201
124482
|
create5 = requireAdmin(async (ctx) => {
|
|
@@ -124206,12 +124487,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124206
124487
|
} catch (error2) {
|
|
124207
124488
|
if (error2 instanceof exports_external.ZodError) {
|
|
124208
124489
|
const details = formatZodError(error2);
|
|
124209
|
-
|
|
124490
|
+
logger65.warn("Create shop listing validation failed", { details });
|
|
124210
124491
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124211
124492
|
}
|
|
124212
124493
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124213
124494
|
}
|
|
124214
|
-
|
|
124495
|
+
logger65.debug("Creating listing", {
|
|
124215
124496
|
userId: ctx.user.id,
|
|
124216
124497
|
itemId: body2.itemId,
|
|
124217
124498
|
currencyId: body2.currencyId,
|
|
@@ -124234,12 +124515,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124234
124515
|
} catch (error2) {
|
|
124235
124516
|
if (error2 instanceof exports_external.ZodError) {
|
|
124236
124517
|
const details = formatZodError(error2);
|
|
124237
|
-
|
|
124518
|
+
logger65.warn("Update shop listing validation failed", { details });
|
|
124238
124519
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124239
124520
|
}
|
|
124240
124521
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124241
124522
|
}
|
|
124242
|
-
|
|
124523
|
+
logger65.debug("Updating listing", {
|
|
124243
124524
|
userId: ctx.user.id,
|
|
124244
124525
|
listingId,
|
|
124245
124526
|
price: body2.price,
|
|
@@ -124256,7 +124537,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124256
124537
|
if (!isValidUUID(listingId)) {
|
|
124257
124538
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
124258
124539
|
}
|
|
124259
|
-
|
|
124540
|
+
logger65.debug("Deleting listing", { userId: ctx.user.id, listingId });
|
|
124260
124541
|
await ctx.services.shopListing.delete(listingId);
|
|
124261
124542
|
});
|
|
124262
124543
|
listByGame2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -124267,7 +124548,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124267
124548
|
if (!isValidUUID(gameId)) {
|
|
124268
124549
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
124269
124550
|
}
|
|
124270
|
-
|
|
124551
|
+
logger65.debug("Listing game listings", { userId: ctx.user.id, gameId });
|
|
124271
124552
|
return ctx.services.shopListing.listByGame(gameId, ctx.user);
|
|
124272
124553
|
});
|
|
124273
124554
|
getByGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -124282,7 +124563,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124282
124563
|
if (!isValidUUID(itemId)) {
|
|
124283
124564
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
124284
124565
|
}
|
|
124285
|
-
|
|
124566
|
+
logger65.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
|
|
124286
124567
|
return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
|
|
124287
124568
|
});
|
|
124288
124569
|
createForGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -124304,12 +124585,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124304
124585
|
} catch (error2) {
|
|
124305
124586
|
if (error2 instanceof exports_external.ZodError) {
|
|
124306
124587
|
const details = formatZodError(error2);
|
|
124307
|
-
|
|
124588
|
+
logger65.warn("Create game item listing validation failed", { details });
|
|
124308
124589
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124309
124590
|
}
|
|
124310
124591
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124311
124592
|
}
|
|
124312
|
-
|
|
124593
|
+
logger65.debug("Creating game item listing", {
|
|
124313
124594
|
userId: ctx.user.id,
|
|
124314
124595
|
gameId,
|
|
124315
124596
|
itemId,
|
|
@@ -124337,12 +124618,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124337
124618
|
} catch (error2) {
|
|
124338
124619
|
if (error2 instanceof exports_external.ZodError) {
|
|
124339
124620
|
const details = formatZodError(error2);
|
|
124340
|
-
|
|
124621
|
+
logger65.warn("Update game item listing validation failed", { details });
|
|
124341
124622
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124342
124623
|
}
|
|
124343
124624
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124344
124625
|
}
|
|
124345
|
-
|
|
124626
|
+
logger65.debug("Updating game item listing", {
|
|
124346
124627
|
userId: ctx.user.id,
|
|
124347
124628
|
gameId,
|
|
124348
124629
|
itemId,
|
|
@@ -124364,7 +124645,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
124364
124645
|
if (!isValidUUID(itemId)) {
|
|
124365
124646
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
124366
124647
|
}
|
|
124367
|
-
|
|
124648
|
+
logger65.debug("Deleting game item listing", {
|
|
124368
124649
|
userId: ctx.user.id,
|
|
124369
124650
|
gameId,
|
|
124370
124651
|
itemId
|
|
@@ -124389,20 +124670,20 @@ async function getBySlug2(ctx) {
|
|
|
124389
124670
|
if (!slug2) {
|
|
124390
124671
|
throw ApiError.badRequest("Template slug is required");
|
|
124391
124672
|
}
|
|
124392
|
-
|
|
124673
|
+
logger66.debug("Getting sprite by slug", { slug: slug2 });
|
|
124393
124674
|
return ctx.services.sprite.getBySlug(slug2);
|
|
124394
124675
|
}
|
|
124395
|
-
var
|
|
124676
|
+
var logger66;
|
|
124396
124677
|
var sprites;
|
|
124397
124678
|
var init_sprite_controller = __esm(() => {
|
|
124398
124679
|
init_src2();
|
|
124399
124680
|
init_errors();
|
|
124400
|
-
|
|
124681
|
+
logger66 = log.scope("SpriteController");
|
|
124401
124682
|
sprites = {
|
|
124402
124683
|
getBySlug: getBySlug2
|
|
124403
124684
|
};
|
|
124404
124685
|
});
|
|
124405
|
-
var
|
|
124686
|
+
var logger67;
|
|
124406
124687
|
var getTodayXp;
|
|
124407
124688
|
var getTotalXp;
|
|
124408
124689
|
var updateTodayXp;
|
|
@@ -124412,6 +124693,8 @@ var getUser;
|
|
|
124412
124693
|
var getUserById;
|
|
124413
124694
|
var setupIntegration;
|
|
124414
124695
|
var getIntegrations;
|
|
124696
|
+
var updateIntegration;
|
|
124697
|
+
var getIntegrationConfig;
|
|
124415
124698
|
var verifyIntegration;
|
|
124416
124699
|
var getConfig2;
|
|
124417
124700
|
var deleteIntegrations;
|
|
@@ -124427,6 +124710,7 @@ var getActivityDetail;
|
|
|
124427
124710
|
var grantXp;
|
|
124428
124711
|
var adjustTime;
|
|
124429
124712
|
var adjustMastery;
|
|
124713
|
+
var reconcileMasteryForConfigChange;
|
|
124430
124714
|
var searchStudents;
|
|
124431
124715
|
var enrollStudent;
|
|
124432
124716
|
var unenrollStudent;
|
|
@@ -124452,15 +124736,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
124452
124736
|
init_src4();
|
|
124453
124737
|
init_errors();
|
|
124454
124738
|
init_utils11();
|
|
124455
|
-
|
|
124739
|
+
logger67 = log.scope("TimebackController");
|
|
124456
124740
|
getTodayXp = requireNonAnonymous(async (ctx) => {
|
|
124457
124741
|
const date4 = ctx.url.searchParams.get("date") || undefined;
|
|
124458
124742
|
const tz = ctx.url.searchParams.get("tz") || undefined;
|
|
124459
|
-
|
|
124743
|
+
logger67.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
|
|
124460
124744
|
return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
|
|
124461
124745
|
});
|
|
124462
124746
|
getTotalXp = requireNonAnonymous(async (ctx) => {
|
|
124463
|
-
|
|
124747
|
+
logger67.debug("Getting total XP", { userId: ctx.user.id });
|
|
124464
124748
|
return ctx.services.timeback.getTotalXp(ctx.user.id);
|
|
124465
124749
|
});
|
|
124466
124750
|
updateTodayXp = requireNonAnonymous(async (ctx) => {
|
|
@@ -124471,18 +124755,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
124471
124755
|
} catch (error2) {
|
|
124472
124756
|
if (error2 instanceof exports_external.ZodError) {
|
|
124473
124757
|
const details = formatZodError(error2);
|
|
124474
|
-
|
|
124758
|
+
logger67.warn("Update today XP validation failed", { details });
|
|
124475
124759
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124476
124760
|
}
|
|
124477
124761
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124478
124762
|
}
|
|
124479
|
-
|
|
124763
|
+
logger67.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
|
|
124480
124764
|
return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
|
|
124481
124765
|
});
|
|
124482
124766
|
getXpHistory = requireNonAnonymous(async (ctx) => {
|
|
124483
124767
|
const startDate = ctx.url.searchParams.get("startDate") || undefined;
|
|
124484
124768
|
const endDate = ctx.url.searchParams.get("endDate") || undefined;
|
|
124485
|
-
|
|
124769
|
+
logger67.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
|
|
124486
124770
|
return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
|
|
124487
124771
|
});
|
|
124488
124772
|
populateStudent = requireNonAnonymous(async (ctx) => {
|
|
@@ -124493,18 +124777,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
124493
124777
|
} catch (error2) {
|
|
124494
124778
|
if (error2 instanceof exports_external.ZodError) {
|
|
124495
124779
|
const details = formatZodError(error2);
|
|
124496
|
-
|
|
124780
|
+
logger67.warn("Populate student validation failed", { details });
|
|
124497
124781
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124498
124782
|
}
|
|
124499
124783
|
}
|
|
124500
|
-
|
|
124784
|
+
logger67.debug("Populating student", {
|
|
124501
124785
|
userId: ctx.user.id,
|
|
124502
124786
|
hasProvidedNames: Boolean(providedNames)
|
|
124503
124787
|
});
|
|
124504
124788
|
return ctx.services.timeback.populateStudent(ctx.user, providedNames);
|
|
124505
124789
|
});
|
|
124506
124790
|
getUser = requireNonAnonymous(async (ctx) => {
|
|
124507
|
-
|
|
124791
|
+
logger67.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
124508
124792
|
return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
|
|
124509
124793
|
});
|
|
124510
124794
|
getUserById = requireNonAnonymous(async (ctx) => {
|
|
@@ -124512,7 +124796,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124512
124796
|
if (!timebackId) {
|
|
124513
124797
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
124514
124798
|
}
|
|
124515
|
-
|
|
124799
|
+
logger67.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
|
|
124516
124800
|
return ctx.services.timeback.getUserDataByTimebackId(timebackId);
|
|
124517
124801
|
});
|
|
124518
124802
|
setupIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -124523,12 +124807,12 @@ var init_timeback_controller = __esm(() => {
|
|
|
124523
124807
|
} catch (error2) {
|
|
124524
124808
|
if (error2 instanceof exports_external.ZodError) {
|
|
124525
124809
|
const details = formatZodError(error2);
|
|
124526
|
-
|
|
124810
|
+
logger67.warn("Setup integration validation failed", { details });
|
|
124527
124811
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124528
124812
|
}
|
|
124529
124813
|
throw ApiError.badRequest("Invalid JSON body");
|
|
124530
124814
|
}
|
|
124531
|
-
|
|
124815
|
+
logger67.debug("Setting up integration", {
|
|
124532
124816
|
userId: ctx.user.id,
|
|
124533
124817
|
gameId: body2.gameId
|
|
124534
124818
|
});
|
|
@@ -124542,9 +124826,37 @@ var init_timeback_controller = __esm(() => {
|
|
|
124542
124826
|
if (!isValidUUID(gameId)) {
|
|
124543
124827
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
124544
124828
|
}
|
|
124545
|
-
|
|
124829
|
+
logger67.debug("Getting integrations", { userId: ctx.user.id, gameId });
|
|
124546
124830
|
return ctx.services.timeback.getIntegrations(gameId, ctx.user);
|
|
124547
124831
|
});
|
|
124832
|
+
updateIntegration = requireDeveloper(async (ctx) => {
|
|
124833
|
+
const { gameId, courseId } = ctx.params;
|
|
124834
|
+
if (!gameId || !courseId) {
|
|
124835
|
+
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
124836
|
+
}
|
|
124837
|
+
if (!isValidUUID(gameId)) {
|
|
124838
|
+
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
124839
|
+
}
|
|
124840
|
+
const body2 = await parseRequestBody(ctx.request, UpdateGameTimebackIntegrationRequestSchema);
|
|
124841
|
+
logger67.debug("Updating integration", {
|
|
124842
|
+
userId: ctx.user.id,
|
|
124843
|
+
gameId,
|
|
124844
|
+
courseId,
|
|
124845
|
+
fields: Object.keys(body2)
|
|
124846
|
+
});
|
|
124847
|
+
return ctx.services.timeback.updateIntegration(gameId, courseId, ctx.user, body2);
|
|
124848
|
+
});
|
|
124849
|
+
getIntegrationConfig = requireGameManagementAccess(async (ctx) => {
|
|
124850
|
+
const { gameId, courseId } = ctx.params;
|
|
124851
|
+
if (!gameId || !courseId) {
|
|
124852
|
+
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
124853
|
+
}
|
|
124854
|
+
if (!isValidUUID(gameId)) {
|
|
124855
|
+
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
124856
|
+
}
|
|
124857
|
+
logger67.debug("Getting integration config", { userId: ctx.user.id, gameId, courseId });
|
|
124858
|
+
return ctx.services.timeback.getIntegrationConfig(gameId, courseId, ctx.user);
|
|
124859
|
+
});
|
|
124548
124860
|
verifyIntegration = requireDeveloper(async (ctx) => {
|
|
124549
124861
|
const gameId = ctx.params.gameId;
|
|
124550
124862
|
if (!gameId) {
|
|
@@ -124553,7 +124865,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124553
124865
|
if (!isValidUUID(gameId)) {
|
|
124554
124866
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
124555
124867
|
}
|
|
124556
|
-
|
|
124868
|
+
logger67.debug("Verifying integration", { userId: ctx.user.id, gameId });
|
|
124557
124869
|
return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
|
|
124558
124870
|
});
|
|
124559
124871
|
getConfig2 = requireDeveloper(async (ctx) => {
|
|
@@ -124564,7 +124876,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124564
124876
|
if (!isValidUUID(gameId)) {
|
|
124565
124877
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
124566
124878
|
}
|
|
124567
|
-
|
|
124879
|
+
logger67.debug("Getting config", { userId: ctx.user.id, gameId });
|
|
124568
124880
|
return ctx.services.timeback.getConfig(gameId, ctx.user);
|
|
124569
124881
|
});
|
|
124570
124882
|
deleteIntegrations = requireDeveloper(async (ctx) => {
|
|
@@ -124575,7 +124887,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124575
124887
|
if (!isValidUUID(gameId)) {
|
|
124576
124888
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
124577
124889
|
}
|
|
124578
|
-
|
|
124890
|
+
logger67.debug("Deleting integrations", { userId: ctx.user.id, gameId });
|
|
124579
124891
|
await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
|
|
124580
124892
|
});
|
|
124581
124893
|
endActivity = requireDeveloper(async (ctx) => {
|
|
@@ -124586,7 +124898,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124586
124898
|
} catch (error2) {
|
|
124587
124899
|
if (error2 instanceof exports_external.ZodError) {
|
|
124588
124900
|
const details = formatZodError(error2);
|
|
124589
|
-
|
|
124901
|
+
logger67.warn("End activity validation failed", { details });
|
|
124590
124902
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124591
124903
|
}
|
|
124592
124904
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -124604,7 +124916,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124604
124916
|
masteredUnits,
|
|
124605
124917
|
extensions
|
|
124606
124918
|
} = body2;
|
|
124607
|
-
|
|
124919
|
+
logger67.debug("Ending activity", { userId: ctx.user.id, gameId });
|
|
124608
124920
|
return ctx.services.timeback.endActivity({
|
|
124609
124921
|
gameId,
|
|
124610
124922
|
studentId,
|
|
@@ -124628,7 +124940,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124628
124940
|
} catch (error2) {
|
|
124629
124941
|
if (error2 instanceof exports_external.ZodError) {
|
|
124630
124942
|
const details = formatZodError(error2);
|
|
124631
|
-
|
|
124943
|
+
logger67.warn("Heartbeat validation failed", { details });
|
|
124632
124944
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
124633
124945
|
}
|
|
124634
124946
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -124644,7 +124956,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124644
124956
|
windowSequence,
|
|
124645
124957
|
isFinal
|
|
124646
124958
|
} = body2;
|
|
124647
|
-
|
|
124959
|
+
logger67.debug("Recording heartbeat", {
|
|
124648
124960
|
userId: ctx.user.id,
|
|
124649
124961
|
gameId,
|
|
124650
124962
|
runId,
|
|
@@ -124669,7 +124981,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124669
124981
|
});
|
|
124670
124982
|
advanceCourse = requireDeveloper(async (ctx) => {
|
|
124671
124983
|
const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
|
|
124672
|
-
|
|
124984
|
+
logger67.debug("Advancing student manually", {
|
|
124673
124985
|
userId: ctx.user.id,
|
|
124674
124986
|
gameId: body2.gameId,
|
|
124675
124987
|
studentId: body2.studentId,
|
|
@@ -124710,7 +125022,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124710
125022
|
perCourse: includeOptions.includes("percourse"),
|
|
124711
125023
|
today: includeOptions.includes("today")
|
|
124712
125024
|
};
|
|
124713
|
-
|
|
125025
|
+
logger67.debug("Getting student XP", {
|
|
124714
125026
|
requesterId: ctx.user.id,
|
|
124715
125027
|
timebackId,
|
|
124716
125028
|
gameId,
|
|
@@ -124732,7 +125044,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124732
125044
|
if (!gameId || !courseId) {
|
|
124733
125045
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
124734
125046
|
}
|
|
124735
|
-
|
|
125047
|
+
logger67.debug("Getting course roster", {
|
|
124736
125048
|
requesterId: ctx.user.id,
|
|
124737
125049
|
gameId,
|
|
124738
125050
|
courseId,
|
|
@@ -124749,7 +125061,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124749
125061
|
if (!timebackId || !gameId) {
|
|
124750
125062
|
throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
|
|
124751
125063
|
}
|
|
124752
|
-
|
|
125064
|
+
logger67.debug("Getting student overview", {
|
|
124753
125065
|
requesterId: ctx.user.id,
|
|
124754
125066
|
timebackId,
|
|
124755
125067
|
gameId,
|
|
@@ -124763,7 +125075,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124763
125075
|
if (!gameId || !timebackId) {
|
|
124764
125076
|
throw ApiError.badRequest("Missing gameId or timebackId path parameter");
|
|
124765
125077
|
}
|
|
124766
|
-
|
|
125078
|
+
logger67.debug("Getting game metrics", {
|
|
124767
125079
|
requesterId: ctx.user.id,
|
|
124768
125080
|
gameId,
|
|
124769
125081
|
timebackId
|
|
@@ -124781,7 +125093,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124781
125093
|
if (!timebackId || !courseId || !gameId) {
|
|
124782
125094
|
throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
|
|
124783
125095
|
}
|
|
124784
|
-
|
|
125096
|
+
logger67.debug("Getting student activity", {
|
|
124785
125097
|
requesterId: ctx.user.id,
|
|
124786
125098
|
timebackId,
|
|
124787
125099
|
courseId,
|
|
@@ -124806,7 +125118,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124806
125118
|
if (!timebackId || !courseId || !activityId || !gameId) {
|
|
124807
125119
|
throw ApiError.badRequest("Missing timebackId, courseId, or activityId path parameter, or gameId query parameter");
|
|
124808
125120
|
}
|
|
124809
|
-
|
|
125121
|
+
logger67.debug("Getting activity detail", {
|
|
124810
125122
|
requesterId: ctx.user.id,
|
|
124811
125123
|
timebackId,
|
|
124812
125124
|
courseId,
|
|
@@ -124824,7 +125136,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124824
125136
|
});
|
|
124825
125137
|
grantXp = requireDeveloper(async (ctx) => {
|
|
124826
125138
|
const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
|
|
124827
|
-
|
|
125139
|
+
logger67.debug("Granting manual XP", {
|
|
124828
125140
|
requesterId: ctx.user.id,
|
|
124829
125141
|
gameId: body2.gameId,
|
|
124830
125142
|
courseId: body2.courseId,
|
|
@@ -124836,7 +125148,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124836
125148
|
});
|
|
124837
125149
|
adjustTime = requireDeveloper(async (ctx) => {
|
|
124838
125150
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
|
|
124839
|
-
|
|
125151
|
+
logger67.debug("Adjusting time spent", {
|
|
124840
125152
|
requesterId: ctx.user.id,
|
|
124841
125153
|
gameId: body2.gameId,
|
|
124842
125154
|
courseId: body2.courseId,
|
|
@@ -124848,7 +125160,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124848
125160
|
});
|
|
124849
125161
|
adjustMastery = requireDeveloper(async (ctx) => {
|
|
124850
125162
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
|
|
124851
|
-
|
|
125163
|
+
logger67.debug("Adjusting mastered units", {
|
|
124852
125164
|
requesterId: ctx.user.id,
|
|
124853
125165
|
gameId: body2.gameId,
|
|
124854
125166
|
courseId: body2.courseId,
|
|
@@ -124858,6 +125170,22 @@ var init_timeback_controller = __esm(() => {
|
|
|
124858
125170
|
});
|
|
124859
125171
|
return ctx.services.timebackAdmin.adjustMasteredUnits(body2, ctx.user);
|
|
124860
125172
|
});
|
|
125173
|
+
reconcileMasteryForConfigChange = requireDeveloper(async (ctx) => {
|
|
125174
|
+
const body2 = await parseRequestBody(ctx.request, ReconcileMasteryForConfigChangeSchema);
|
|
125175
|
+
logger67.debug("Reconciling mastery completion for config change", {
|
|
125176
|
+
requesterId: ctx.user.id,
|
|
125177
|
+
gameId: body2.gameId,
|
|
125178
|
+
courseId: body2.courseId,
|
|
125179
|
+
oldMasterableUnits: body2.oldMasterableUnits,
|
|
125180
|
+
newMasterableUnits: body2.newMasterableUnits,
|
|
125181
|
+
affectedCount: body2.affectedStudentIds.length
|
|
125182
|
+
});
|
|
125183
|
+
return ctx.services.timebackAdmin.reconcileMasteryForConfigChange(body2.gameId, body2.courseId, ctx.user, {
|
|
125184
|
+
oldMasterableUnits: body2.oldMasterableUnits,
|
|
125185
|
+
newMasterableUnits: body2.newMasterableUnits,
|
|
125186
|
+
affectedStudentIds: body2.affectedStudentIds
|
|
125187
|
+
});
|
|
125188
|
+
});
|
|
124861
125189
|
searchStudents = requireGameManagementAccess(async (ctx) => {
|
|
124862
125190
|
const gameId = ctx.params.gameId;
|
|
124863
125191
|
const courseId = ctx.params.courseId;
|
|
@@ -124865,7 +125193,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124865
125193
|
if (!gameId || !courseId) {
|
|
124866
125194
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
124867
125195
|
}
|
|
124868
|
-
|
|
125196
|
+
logger67.debug("Searching students for enrollment", {
|
|
124869
125197
|
requesterId: ctx.user.id,
|
|
124870
125198
|
gameId,
|
|
124871
125199
|
courseId,
|
|
@@ -124875,7 +125203,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124875
125203
|
});
|
|
124876
125204
|
enrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
124877
125205
|
const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
|
|
124878
|
-
|
|
125206
|
+
logger67.debug("Enrolling student", {
|
|
124879
125207
|
requesterId: ctx.user.id,
|
|
124880
125208
|
gameId: body2.gameId,
|
|
124881
125209
|
courseId: body2.courseId,
|
|
@@ -124885,7 +125213,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124885
125213
|
});
|
|
124886
125214
|
unenrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
124887
125215
|
const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
|
|
124888
|
-
|
|
125216
|
+
logger67.debug("Unenrolling student", {
|
|
124889
125217
|
requesterId: ctx.user.id,
|
|
124890
125218
|
gameId: body2.gameId,
|
|
124891
125219
|
courseId: body2.courseId,
|
|
@@ -124895,7 +125223,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
124895
125223
|
});
|
|
124896
125224
|
reactivateEnrollment = requireGameManagementAccess(async (ctx) => {
|
|
124897
125225
|
const body2 = await parseRequestBody(ctx.request, ReactivateEnrollmentRequestSchema);
|
|
124898
|
-
|
|
125226
|
+
logger67.debug("Reactivating enrollment", {
|
|
124899
125227
|
requesterId: ctx.user.id,
|
|
124900
125228
|
gameId: body2.gameId,
|
|
124901
125229
|
courseId: body2.courseId,
|
|
@@ -125035,6 +125363,8 @@ var init_timeback_controller = __esm(() => {
|
|
|
125035
125363
|
getUserById,
|
|
125036
125364
|
setupIntegration,
|
|
125037
125365
|
getIntegrations,
|
|
125366
|
+
updateIntegration,
|
|
125367
|
+
getIntegrationConfig,
|
|
125038
125368
|
verifyIntegration,
|
|
125039
125369
|
getConfig: getConfig2,
|
|
125040
125370
|
deleteIntegrations,
|
|
@@ -125050,6 +125380,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
125050
125380
|
grantXp,
|
|
125051
125381
|
adjustTime,
|
|
125052
125382
|
adjustMastery,
|
|
125383
|
+
reconcileMasteryForConfigChange,
|
|
125053
125384
|
searchStudents,
|
|
125054
125385
|
enrollStudent,
|
|
125055
125386
|
unenrollStudent,
|
|
@@ -125069,7 +125400,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
125069
125400
|
destroyAssessmentBank
|
|
125070
125401
|
};
|
|
125071
125402
|
});
|
|
125072
|
-
var
|
|
125403
|
+
var logger68;
|
|
125073
125404
|
var initiate;
|
|
125074
125405
|
var init_upload_controller = __esm(() => {
|
|
125075
125406
|
init_esm();
|
|
@@ -125077,7 +125408,7 @@ var init_upload_controller = __esm(() => {
|
|
|
125077
125408
|
init_src2();
|
|
125078
125409
|
init_errors();
|
|
125079
125410
|
init_utils11();
|
|
125080
|
-
|
|
125411
|
+
logger68 = log.scope("UploadController");
|
|
125081
125412
|
initiate = requireDeveloper(async (ctx) => {
|
|
125082
125413
|
let body2;
|
|
125083
125414
|
try {
|
|
@@ -125086,16 +125417,16 @@ var init_upload_controller = __esm(() => {
|
|
|
125086
125417
|
} catch (error2) {
|
|
125087
125418
|
if (error2 instanceof exports_external.ZodError) {
|
|
125088
125419
|
const details = formatZodError(error2);
|
|
125089
|
-
|
|
125420
|
+
logger68.warn("Initiate upload validation failed", { details });
|
|
125090
125421
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
125091
125422
|
}
|
|
125092
125423
|
throw ApiError.badRequest("Invalid JSON body");
|
|
125093
125424
|
}
|
|
125094
|
-
|
|
125425
|
+
logger68.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
|
|
125095
125426
|
return ctx.services.upload.initiate(body2, ctx.user);
|
|
125096
125427
|
});
|
|
125097
125428
|
});
|
|
125098
|
-
var
|
|
125429
|
+
var logger69;
|
|
125099
125430
|
var getMe;
|
|
125100
125431
|
var getDemoProfile;
|
|
125101
125432
|
var updateDemoProfile;
|
|
@@ -125104,18 +125435,18 @@ var init_user_controller = __esm(() => {
|
|
|
125104
125435
|
init_schemas_index();
|
|
125105
125436
|
init_src2();
|
|
125106
125437
|
init_utils11();
|
|
125107
|
-
|
|
125438
|
+
logger69 = log.scope("UserController");
|
|
125108
125439
|
getMe = requireNonAnonymous(async (ctx) => {
|
|
125109
|
-
|
|
125440
|
+
logger69.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
125110
125441
|
return ctx.services.user.getMe(ctx.user, ctx.gameId);
|
|
125111
125442
|
});
|
|
125112
125443
|
getDemoProfile = requireAnonymous(async (ctx) => {
|
|
125113
|
-
|
|
125444
|
+
logger69.debug("Getting demo profile", { userId: ctx.user.id });
|
|
125114
125445
|
return ctx.services.user.getDemoProfile(ctx.user.id);
|
|
125115
125446
|
});
|
|
125116
125447
|
updateDemoProfile = requireAnonymous(async (ctx) => {
|
|
125117
125448
|
const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
|
|
125118
|
-
|
|
125449
|
+
logger69.debug("Updating demo profile", {
|
|
125119
125450
|
userId: ctx.user.id,
|
|
125120
125451
|
displayName: body2.displayName
|
|
125121
125452
|
});
|
|
@@ -125127,13 +125458,13 @@ var init_user_controller = __esm(() => {
|
|
|
125127
125458
|
updateDemoProfile
|
|
125128
125459
|
};
|
|
125129
125460
|
});
|
|
125130
|
-
var
|
|
125461
|
+
var logger70;
|
|
125131
125462
|
var init_verify_controller = __esm(() => {
|
|
125132
125463
|
init_schemas_index();
|
|
125133
125464
|
init_src2();
|
|
125134
125465
|
init_errors();
|
|
125135
125466
|
init_utils11();
|
|
125136
|
-
|
|
125467
|
+
logger70 = log.scope("VerifyController");
|
|
125137
125468
|
});
|
|
125138
125469
|
var init_controllers = __esm(() => {
|
|
125139
125470
|
init_achievement_controller();
|
|
@@ -125431,7 +125762,7 @@ var init_uploads = __esm(() => {
|
|
|
125431
125762
|
gameUploadsRouter.post("/uploads/finalize", finalizeHandler);
|
|
125432
125763
|
gameUploadsRouter.post("/uploads/finalize/", finalizeHandler);
|
|
125433
125764
|
});
|
|
125434
|
-
var
|
|
125765
|
+
var logger71;
|
|
125435
125766
|
var gameDeployRouter;
|
|
125436
125767
|
var init_deploy = __esm(() => {
|
|
125437
125768
|
init_drizzle_orm();
|
|
@@ -125442,7 +125773,7 @@ var init_deploy = __esm(() => {
|
|
|
125442
125773
|
init_src2();
|
|
125443
125774
|
init_api();
|
|
125444
125775
|
init_uploads();
|
|
125445
|
-
|
|
125776
|
+
logger71 = log.scope("SandboxDeploy");
|
|
125446
125777
|
gameDeployRouter = new Hono2;
|
|
125447
125778
|
gameDeployRouter.post("/:slug/deploy", async (c2) => {
|
|
125448
125779
|
const user = c2.get("user");
|
|
@@ -125568,7 +125899,7 @@ var init_deploy = __esm(() => {
|
|
|
125568
125899
|
completedAt: now2
|
|
125569
125900
|
};
|
|
125570
125901
|
const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
|
|
125571
|
-
|
|
125902
|
+
logger71.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
|
|
125572
125903
|
return c2.json({
|
|
125573
125904
|
id: insertedJob.id,
|
|
125574
125905
|
status: "succeeded",
|
|
@@ -126166,7 +126497,7 @@ function verifyMockToken(idToken) {
|
|
|
126166
126497
|
throw new Error("Invalid LTI token format");
|
|
126167
126498
|
}
|
|
126168
126499
|
}
|
|
126169
|
-
var
|
|
126500
|
+
var logger72;
|
|
126170
126501
|
var ltiRouter;
|
|
126171
126502
|
var init_lti = __esm(() => {
|
|
126172
126503
|
init_drizzle_orm();
|
|
@@ -126177,7 +126508,7 @@ var init_lti = __esm(() => {
|
|
|
126177
126508
|
init_src2();
|
|
126178
126509
|
init_constants();
|
|
126179
126510
|
init_api();
|
|
126180
|
-
|
|
126511
|
+
logger72 = log.scope("SandboxLti");
|
|
126181
126512
|
ltiRouter = new Hono2;
|
|
126182
126513
|
ltiRouter.post("/launch", async (c2) => {
|
|
126183
126514
|
const db2 = c2.get("db");
|
|
@@ -126195,7 +126526,7 @@ var init_lti = __esm(() => {
|
|
|
126195
126526
|
claims = verifyMockToken(idToken);
|
|
126196
126527
|
} catch (error2) {
|
|
126197
126528
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
126198
|
-
|
|
126529
|
+
logger72.error("LTI token verification failed", { error: errorMessage });
|
|
126199
126530
|
return c2.json({
|
|
126200
126531
|
error: "invalid_token",
|
|
126201
126532
|
message: errorMessage
|
|
@@ -126203,7 +126534,7 @@ var init_lti = __esm(() => {
|
|
|
126203
126534
|
}
|
|
126204
126535
|
const validationError = validateLtiClaims(claims);
|
|
126205
126536
|
if (validationError) {
|
|
126206
|
-
|
|
126537
|
+
logger72.warn("LTI claims validation failed", {
|
|
126207
126538
|
error: validationError,
|
|
126208
126539
|
sub: claims.sub
|
|
126209
126540
|
});
|
|
@@ -126223,7 +126554,7 @@ var init_lti = __esm(() => {
|
|
|
126223
126554
|
createdAt: new Date,
|
|
126224
126555
|
updatedAt: new Date
|
|
126225
126556
|
});
|
|
126226
|
-
|
|
126557
|
+
logger72.info("LTI launch successful", { userId: user.id });
|
|
126227
126558
|
const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
|
|
126228
126559
|
const currentHost = new URL(c2.req.url).hostname;
|
|
126229
126560
|
const redirectPath = extractRedirectPath(targetUri, currentHost);
|
|
@@ -126231,7 +126562,7 @@ var init_lti = __esm(() => {
|
|
|
126231
126562
|
return c2.redirect(redirectPath);
|
|
126232
126563
|
} catch (error2) {
|
|
126233
126564
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
126234
|
-
|
|
126565
|
+
logger72.error("Unexpected error during LTI launch", { error: errorMessage });
|
|
126235
126566
|
return c2.json({
|
|
126236
126567
|
error: "unexpected_error",
|
|
126237
126568
|
message: "An unexpected error occurred during LTI launch"
|
|
@@ -127905,7 +128236,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
|
127905
128236
|
// package.json
|
|
127906
128237
|
var package_default2 = {
|
|
127907
128238
|
name: "@playcademy/vite-plugin",
|
|
127908
|
-
version: "0.2.
|
|
128239
|
+
version: "0.2.35-beta.1",
|
|
127909
128240
|
type: "module",
|
|
127910
128241
|
exports: {
|
|
127911
128242
|
".": {
|