@playcademy/sandbox 0.3.18 → 0.3.19-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +840 -501
- package/dist/server.js +840 -501
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -1316,7 +1316,7 @@ var package_default;
|
|
|
1316
1316
|
var init_package = __esm(() => {
|
|
1317
1317
|
package_default = {
|
|
1318
1318
|
name: "@playcademy/sandbox",
|
|
1319
|
-
version: "0.3.
|
|
1319
|
+
version: "0.3.19-beta.2",
|
|
1320
1320
|
description: "Local development server for Playcademy game development",
|
|
1321
1321
|
type: "module",
|
|
1322
1322
|
exports: {
|
|
@@ -5897,7 +5897,8 @@ var init_schema = __esm(() => {
|
|
|
5897
5897
|
ltiTestMode: exports_external.boolean().default(false),
|
|
5898
5898
|
realtime: realtimeConfigSchema.optional(),
|
|
5899
5899
|
platformServiceJwt: platformServiceJwtConfigSchema.optional(),
|
|
5900
|
-
uploadBucket: exports_external.string().optional()
|
|
5900
|
+
uploadBucket: exports_external.string().optional(),
|
|
5901
|
+
queueIngressSecret: exports_external.string().optional()
|
|
5901
5902
|
});
|
|
5902
5903
|
});
|
|
5903
5904
|
|
|
@@ -26417,6 +26418,14 @@ class DeployService {
|
|
|
26417
26418
|
await cf.setSecrets(deploymentId, { PLAYCADEMY_API_KEY: apiKey });
|
|
26418
26419
|
logger3.info("Set API key on worker", { slug, deploymentId });
|
|
26419
26420
|
}
|
|
26421
|
+
async ensureQueueIngressSecretOnWorker(slug, deploymentId) {
|
|
26422
|
+
const secret = this.deps.config.queueIngressSecret;
|
|
26423
|
+
if (!secret) {
|
|
26424
|
+
return;
|
|
26425
|
+
}
|
|
26426
|
+
const cf = this.getCloudflare();
|
|
26427
|
+
await cf.setSecrets(deploymentId, { QUEUE_INGRESS_SECRET: secret });
|
|
26428
|
+
}
|
|
26420
26429
|
async fetchAndExtractFrontendAssets(slug, gameId, uploadToken, uploadDeps, extractZip) {
|
|
26421
26430
|
const frontendZip = await this.timeStep("Fetch temporary files", () => uploadDeps.getObjectAsByteArray(uploadToken), { slug });
|
|
26422
26431
|
if (!frontendZip || frontendZip.length === 0) {
|
|
@@ -26499,7 +26508,10 @@ class DeployService {
|
|
|
26499
26508
|
const codeHash = hasBackend ? await generateDeploymentHash(request.code) : null;
|
|
26500
26509
|
await this.saveDeployment(game.id, result.deploymentId, result.url, codeHash, result.resources);
|
|
26501
26510
|
if (hasBackend) {
|
|
26502
|
-
await this.timeStep("Configure worker secrets", () =>
|
|
26511
|
+
await this.timeStep("Configure worker secrets", async () => {
|
|
26512
|
+
await this.ensureApiKeyOnWorker(user, slug, result.deploymentId);
|
|
26513
|
+
await this.ensureQueueIngressSecretOnWorker(slug, result.deploymentId);
|
|
26514
|
+
}, { slug, deploymentId: result.deploymentId });
|
|
26503
26515
|
}
|
|
26504
26516
|
if (hasMetadata || hasFrontend) {
|
|
26505
26517
|
await this.applyGameMetadata(game.id, request, hasFrontend, hasMetadata, result.url);
|
|
@@ -31180,7 +31192,7 @@ function isValidAdminAttributionDate(value) {
|
|
|
31180
31192
|
const date3 = new Date(Date.UTC(year, month - 1, day, 12, 0, 0));
|
|
31181
31193
|
return date3.getUTCFullYear() === year && date3.getUTCMonth() + 1 === month && date3.getUTCDate() === day;
|
|
31182
31194
|
}
|
|
31183
|
-
var TIMEBACK_GRADES, TIMEBACK_SUBJECTS4, TimebackGradeSchema, TimebackSubjectSchema, UpdateTimebackXpRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameActivityMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, HeartbeatRequestSchema, PopulateStudentRequestSchema, DerivedPlatformCourseConfigSchema, TimebackBaseConfigSchema, PlatformTimebackSetupRequestSchema, AdminTimebackMutationBaseSchema, AdminAttributionDateSchema, ADMIN_GRANT_XP_MIN = -1e5, ADMIN_GRANT_XP_MAX = 1e5, ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE, GrantTimebackXpRequestSchema, AdjustTimebackTimeRequestSchema, AdjustTimebackMasteryRequestSchema, EnrollStudentRequestSchema, UnenrollStudentRequestSchema, ReactivateEnrollmentRequestSchema, InsertAssessmentTestSchema, CreateAssessmentRequestSchema, ReorderAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
|
|
31195
|
+
var TIMEBACK_GRADES, TIMEBACK_SUBJECTS4, TimebackGradeSchema, TimebackSubjectSchema, UpdateTimebackXpRequestSchema, CourseGoalsSchema, UpdateGameTimebackIntegrationRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameActivityMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, HeartbeatRequestSchema, PopulateStudentRequestSchema, DerivedPlatformCourseConfigSchema, TimebackBaseConfigSchema, PlatformTimebackSetupRequestSchema, AdminTimebackMutationBaseSchema, AdminAttributionDateSchema, ADMIN_GRANT_XP_MIN = -1e5, ADMIN_GRANT_XP_MAX = 1e5, ADMIN_GRANT_XP_AMOUNT_RANGE_MESSAGE, GrantTimebackXpRequestSchema, AdjustTimebackTimeRequestSchema, AdjustTimebackMasteryRequestSchema, ReconcileMasteryForConfigChangeSchema, EnrollStudentRequestSchema, UnenrollStudentRequestSchema, ReactivateEnrollmentRequestSchema, InsertAssessmentTestSchema, CreateAssessmentRequestSchema, ReorderAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
|
|
31184
31196
|
var init_schemas11 = __esm(() => {
|
|
31185
31197
|
init_drizzle_zod();
|
|
31186
31198
|
init_esm();
|
|
@@ -31205,6 +31217,24 @@ var init_schemas11 = __esm(() => {
|
|
|
31205
31217
|
xp: exports_external.number().min(0, "XP must be a non-negative number"),
|
|
31206
31218
|
userTimestamp: exports_external.string().datetime().optional()
|
|
31207
31219
|
});
|
|
31220
|
+
CourseGoalsSchema = exports_external.object({
|
|
31221
|
+
dailyXp: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31222
|
+
dailyLessons: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31223
|
+
dailyActiveMinutes: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31224
|
+
dailyAccuracy: exports_external.number().int().min(0).max(100).nullable().optional(),
|
|
31225
|
+
dailyMasteredUnits: exports_external.number().int().nonnegative().nullable().optional()
|
|
31226
|
+
});
|
|
31227
|
+
UpdateGameTimebackIntegrationRequestSchema = exports_external.object({
|
|
31228
|
+
title: exports_external.string().trim().min(1).optional(),
|
|
31229
|
+
courseCode: exports_external.string().trim().min(1).optional(),
|
|
31230
|
+
subject: TimebackSubjectSchema.optional(),
|
|
31231
|
+
totalXp: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31232
|
+
masterableUnits: exports_external.number().int().nonnegative().nullable().optional(),
|
|
31233
|
+
goals: CourseGoalsSchema.optional(),
|
|
31234
|
+
publishStatus: exports_external.enum(["draft", "testing", "published", "deactivated"]).nullable().optional(),
|
|
31235
|
+
isSupplemental: exports_external.boolean().optional(),
|
|
31236
|
+
timebackVisible: exports_external.boolean().nullable().optional()
|
|
31237
|
+
});
|
|
31208
31238
|
TimebackActivityDataSchema = exports_external.object({
|
|
31209
31239
|
activityId: exports_external.string().min(1),
|
|
31210
31240
|
activityName: exports_external.string().optional(),
|
|
@@ -31374,6 +31404,13 @@ var init_schemas11 = __esm(() => {
|
|
|
31374
31404
|
date: AdminAttributionDateSchema.optional(),
|
|
31375
31405
|
useCurrentTime: exports_external.boolean().optional()
|
|
31376
31406
|
});
|
|
31407
|
+
ReconcileMasteryForConfigChangeSchema = exports_external.object({
|
|
31408
|
+
gameId: exports_external.string().uuid(),
|
|
31409
|
+
courseId: exports_external.string().min(1),
|
|
31410
|
+
oldMasterableUnits: exports_external.number().int().positive(),
|
|
31411
|
+
newMasterableUnits: exports_external.number().int().positive(),
|
|
31412
|
+
affectedStudentIds: exports_external.array(exports_external.string().min(1)).min(1).max(500)
|
|
31413
|
+
});
|
|
31377
31414
|
EnrollStudentRequestSchema = exports_external.object({
|
|
31378
31415
|
gameId: exports_external.string().uuid(),
|
|
31379
31416
|
courseId: exports_external.string().min(1),
|
|
@@ -31529,6 +31566,65 @@ var init_timeback_admin_util = __esm(() => {
|
|
|
31529
31566
|
init_errors();
|
|
31530
31567
|
});
|
|
31531
31568
|
|
|
31569
|
+
// ../api-core/src/utils/timeback-mastery-completion.util.ts
|
|
31570
|
+
async function upsertMasteryCompletionEntry(params) {
|
|
31571
|
+
const { client, courseId, studentId, appName, action } = params;
|
|
31572
|
+
const ids = deriveSourcedIds(courseId);
|
|
31573
|
+
const lineItemId = `${ids.course}-mastery-completion-assessment`;
|
|
31574
|
+
const resultId = `${lineItemId}:${studentId}:completion`;
|
|
31575
|
+
if (action === "complete") {
|
|
31576
|
+
await client.oneroster.assessmentLineItems.findOrCreate(lineItemId, {
|
|
31577
|
+
sourcedId: lineItemId,
|
|
31578
|
+
title: "Mastery Completion",
|
|
31579
|
+
status: ONEROSTER_STATUS.active,
|
|
31580
|
+
course: { sourcedId: ids.course },
|
|
31581
|
+
...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
|
|
31582
|
+
});
|
|
31583
|
+
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
31584
|
+
sourcedId: resultId,
|
|
31585
|
+
status: ONEROSTER_STATUS.active,
|
|
31586
|
+
assessmentLineItem: { sourcedId: lineItemId },
|
|
31587
|
+
student: { sourcedId: studentId },
|
|
31588
|
+
score: 100,
|
|
31589
|
+
scoreDate: new Date().toISOString(),
|
|
31590
|
+
scoreStatus: SCORE_STATUS.fullyGraded,
|
|
31591
|
+
inProgress: "false",
|
|
31592
|
+
metadata: {
|
|
31593
|
+
isMasteryCompletion: true,
|
|
31594
|
+
adminAction: true,
|
|
31595
|
+
appName
|
|
31596
|
+
}
|
|
31597
|
+
});
|
|
31598
|
+
} else {
|
|
31599
|
+
try {
|
|
31600
|
+
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
31601
|
+
sourcedId: resultId,
|
|
31602
|
+
status: ONEROSTER_STATUS.active,
|
|
31603
|
+
assessmentLineItem: { sourcedId: lineItemId },
|
|
31604
|
+
student: { sourcedId: studentId },
|
|
31605
|
+
score: 0,
|
|
31606
|
+
scoreDate: new Date().toISOString(),
|
|
31607
|
+
scoreStatus: SCORE_STATUS.notSubmitted,
|
|
31608
|
+
inProgress: "true",
|
|
31609
|
+
metadata: {
|
|
31610
|
+
isMasteryCompletion: true,
|
|
31611
|
+
adminAction: true,
|
|
31612
|
+
appName
|
|
31613
|
+
}
|
|
31614
|
+
});
|
|
31615
|
+
} catch {
|
|
31616
|
+
logger17.debug("No completion entry to revoke", { studentId, courseId });
|
|
31617
|
+
}
|
|
31618
|
+
}
|
|
31619
|
+
}
|
|
31620
|
+
var logger17;
|
|
31621
|
+
var init_timeback_mastery_completion_util = __esm(() => {
|
|
31622
|
+
init_src2();
|
|
31623
|
+
init_constants4();
|
|
31624
|
+
init_utils6();
|
|
31625
|
+
logger17 = log.scope("timeback-mastery-completion");
|
|
31626
|
+
});
|
|
31627
|
+
|
|
31532
31628
|
// ../api-core/src/utils/timeback.util.ts
|
|
31533
31629
|
function isRecord2(value) {
|
|
31534
31630
|
return typeof value === "object" && value !== null;
|
|
@@ -31886,7 +31982,7 @@ class TimebackAdminService {
|
|
|
31886
31982
|
}
|
|
31887
31983
|
requireClient() {
|
|
31888
31984
|
if (!this.deps.timeback) {
|
|
31889
|
-
|
|
31985
|
+
logger18.error("Timeback client not available in context");
|
|
31890
31986
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
31891
31987
|
}
|
|
31892
31988
|
return this.deps.timeback;
|
|
@@ -32106,7 +32202,7 @@ class TimebackAdminService {
|
|
|
32106
32202
|
});
|
|
32107
32203
|
return [enrollmentId, this.summarizeAnalyticsFacts(analytics.facts)];
|
|
32108
32204
|
} catch (error) {
|
|
32109
|
-
|
|
32205
|
+
logger18.warn("Failed to load enrollment analytics summary", {
|
|
32110
32206
|
enrollmentId,
|
|
32111
32207
|
error: error instanceof Error ? error.message : String(error)
|
|
32112
32208
|
});
|
|
@@ -32136,7 +32232,7 @@ class TimebackAdminService {
|
|
|
32136
32232
|
const events = await this.fetchCaliperEventsForStudent(client, studentId, source, eventLimit);
|
|
32137
32233
|
return TimebackAdminService.mapRecentActivityItems(events, relevantCourseIds).slice(0, maxResults);
|
|
32138
32234
|
} catch (error) {
|
|
32139
|
-
|
|
32235
|
+
logger18.warn("Failed to load recent Caliper activity", {
|
|
32140
32236
|
studentId,
|
|
32141
32237
|
gameId: source.gameId,
|
|
32142
32238
|
sourceMode: source.sourceMode,
|
|
@@ -32462,60 +32558,44 @@ class TimebackAdminService {
|
|
|
32462
32558
|
const wasMastered = currentMastered >= masterableUnits;
|
|
32463
32559
|
const willBeMastered = currentMastered + data.units >= masterableUnits;
|
|
32464
32560
|
if (wasMastered !== willBeMastered) {
|
|
32465
|
-
|
|
32466
|
-
|
|
32467
|
-
|
|
32468
|
-
|
|
32469
|
-
|
|
32470
|
-
|
|
32471
|
-
|
|
32472
|
-
status: ONEROSTER_STATUS.active,
|
|
32473
|
-
course: { sourcedId: ids.course },
|
|
32474
|
-
...ids.componentResource ? { componentResource: { sourcedId: ids.componentResource } } : {}
|
|
32475
|
-
});
|
|
32476
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
32477
|
-
sourcedId: resultId,
|
|
32478
|
-
status: ONEROSTER_STATUS.active,
|
|
32479
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
32480
|
-
student: { sourcedId: data.studentId },
|
|
32481
|
-
score: 100,
|
|
32482
|
-
scoreDate: new Date().toISOString(),
|
|
32483
|
-
scoreStatus: SCORE_STATUS.fullyGraded,
|
|
32484
|
-
inProgress: "false",
|
|
32485
|
-
metadata: {
|
|
32486
|
-
isMasteryCompletion: true,
|
|
32487
|
-
adminAction: true,
|
|
32488
|
-
appName
|
|
32489
|
-
}
|
|
32490
|
-
});
|
|
32491
|
-
} else {
|
|
32492
|
-
try {
|
|
32493
|
-
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
32494
|
-
sourcedId: resultId,
|
|
32495
|
-
status: ONEROSTER_STATUS.active,
|
|
32496
|
-
assessmentLineItem: { sourcedId: lineItemId },
|
|
32497
|
-
student: { sourcedId: data.studentId },
|
|
32498
|
-
score: 0,
|
|
32499
|
-
scoreDate: new Date().toISOString(),
|
|
32500
|
-
scoreStatus: SCORE_STATUS.notSubmitted,
|
|
32501
|
-
inProgress: "true",
|
|
32502
|
-
metadata: {
|
|
32503
|
-
isMasteryCompletion: true,
|
|
32504
|
-
adminAction: true,
|
|
32505
|
-
appName
|
|
32506
|
-
}
|
|
32507
|
-
});
|
|
32508
|
-
} catch {
|
|
32509
|
-
logger17.debug("No completion entry to revoke", {
|
|
32510
|
-
studentId: data.studentId,
|
|
32511
|
-
courseId: data.courseId
|
|
32512
|
-
});
|
|
32513
|
-
}
|
|
32514
|
-
}
|
|
32561
|
+
await upsertMasteryCompletionEntry({
|
|
32562
|
+
client,
|
|
32563
|
+
courseId: data.courseId,
|
|
32564
|
+
studentId: data.studentId,
|
|
32565
|
+
appName,
|
|
32566
|
+
action: willBeMastered ? "complete" : "revoke"
|
|
32567
|
+
});
|
|
32515
32568
|
}
|
|
32516
32569
|
}
|
|
32517
32570
|
return { status: "ok" };
|
|
32518
32571
|
}
|
|
32572
|
+
async reconcileMasteryForConfigChange(gameId, courseId, user, context) {
|
|
32573
|
+
const { client, appName } = await this.resolveAdminMutationContext(gameId, courseId, user);
|
|
32574
|
+
const action = context.newMasterableUnits < context.oldMasterableUnits ? "complete" : "revoke";
|
|
32575
|
+
const failed = [];
|
|
32576
|
+
let processed = 0;
|
|
32577
|
+
await TimebackAdminService.runWithConcurrency(context.affectedStudentIds, 8, async (studentId) => {
|
|
32578
|
+
try {
|
|
32579
|
+
await upsertMasteryCompletionEntry({
|
|
32580
|
+
client,
|
|
32581
|
+
courseId,
|
|
32582
|
+
studentId,
|
|
32583
|
+
appName,
|
|
32584
|
+
action
|
|
32585
|
+
});
|
|
32586
|
+
processed++;
|
|
32587
|
+
} catch (error) {
|
|
32588
|
+
logger18.warn("Failed to reconcile mastery completion for student", {
|
|
32589
|
+
studentId,
|
|
32590
|
+
courseId,
|
|
32591
|
+
action,
|
|
32592
|
+
error: error instanceof Error ? error.message : String(error)
|
|
32593
|
+
});
|
|
32594
|
+
failed.push(studentId);
|
|
32595
|
+
}
|
|
32596
|
+
});
|
|
32597
|
+
return { processed, failed };
|
|
32598
|
+
}
|
|
32519
32599
|
async searchStudentsForEnrollment(gameId, courseId, query, user) {
|
|
32520
32600
|
const client = this.requireClient();
|
|
32521
32601
|
await this.deps.validateGameManagementAccess(user, gameId);
|
|
@@ -32542,7 +32622,7 @@ class TimebackAdminService {
|
|
|
32542
32622
|
const response = await client["request"](endpoint, "GET");
|
|
32543
32623
|
allUsers = response.users || [];
|
|
32544
32624
|
} catch (error) {
|
|
32545
|
-
|
|
32625
|
+
logger18.warn("Failed to search OneRoster users", {
|
|
32546
32626
|
query: trimmedQuery,
|
|
32547
32627
|
error: error instanceof Error ? error.message : String(error)
|
|
32548
32628
|
});
|
|
@@ -32687,7 +32767,7 @@ class TimebackAdminService {
|
|
|
32687
32767
|
return results;
|
|
32688
32768
|
}
|
|
32689
32769
|
}
|
|
32690
|
-
var
|
|
32770
|
+
var logger18;
|
|
32691
32771
|
var init_timeback_admin_service = __esm(() => {
|
|
32692
32772
|
init_drizzle_orm();
|
|
32693
32773
|
init_src();
|
|
@@ -32700,8 +32780,9 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
32700
32780
|
init_errors();
|
|
32701
32781
|
init_timeback_admin_metrics_util();
|
|
32702
32782
|
init_timeback_admin_util();
|
|
32783
|
+
init_timeback_mastery_completion_util();
|
|
32703
32784
|
init_timeback_util();
|
|
32704
|
-
|
|
32785
|
+
logger18 = log.scope("TimebackAdminService");
|
|
32705
32786
|
});
|
|
32706
32787
|
|
|
32707
32788
|
// ../timeback/dist/errors.js
|
|
@@ -32948,7 +33029,7 @@ class TimebackAssessmentsService {
|
|
|
32948
33029
|
isActive: row.bankActive
|
|
32949
33030
|
};
|
|
32950
33031
|
} catch {
|
|
32951
|
-
|
|
33032
|
+
logger19.warn("Failed to fetch QTI test metadata", {
|
|
32952
33033
|
identifier: row.qtiTestIdentifier
|
|
32953
33034
|
});
|
|
32954
33035
|
return {
|
|
@@ -33002,7 +33083,7 @@ class TimebackAssessmentsService {
|
|
|
33002
33083
|
});
|
|
33003
33084
|
} catch (error) {
|
|
33004
33085
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33005
|
-
|
|
33086
|
+
logger19.info("QTI test already exists (idempotent retry)", {
|
|
33006
33087
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
33007
33088
|
});
|
|
33008
33089
|
} else {
|
|
@@ -33015,7 +33096,7 @@ class TimebackAssessmentsService {
|
|
|
33015
33096
|
qtiTestIdentifier: input.qtiTestIdentifier,
|
|
33016
33097
|
sortOrder: maxSortOrder + 1
|
|
33017
33098
|
}).returning();
|
|
33018
|
-
|
|
33099
|
+
logger19.info("Assessment created", {
|
|
33019
33100
|
integrationId,
|
|
33020
33101
|
qtiTestIdentifier: input.qtiTestIdentifier
|
|
33021
33102
|
});
|
|
@@ -33037,13 +33118,13 @@ class TimebackAssessmentsService {
|
|
|
33037
33118
|
}
|
|
33038
33119
|
await client.qti.tests.delete(qtiTestIdentifier);
|
|
33039
33120
|
} catch (error) {
|
|
33040
|
-
|
|
33121
|
+
logger19.warn("Partial QTI cleanup during assessment deletion", {
|
|
33041
33122
|
qtiTestIdentifier,
|
|
33042
33123
|
error: error instanceof Error ? error.message : String(error)
|
|
33043
33124
|
});
|
|
33044
33125
|
}
|
|
33045
33126
|
await this.deps.db.delete(gameTimebackAssessmentTests).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33046
|
-
|
|
33127
|
+
logger19.info("Assessment deleted", { integrationId, qtiTestIdentifier });
|
|
33047
33128
|
}
|
|
33048
33129
|
async reorderAssessments(integrationId, identifiers) {
|
|
33049
33130
|
await this.requireIntegration(integrationId);
|
|
@@ -33088,7 +33169,7 @@ class TimebackAssessmentsService {
|
|
|
33088
33169
|
return client.qti.tests.reorderItems(qtiTestIdentifier, partId, sectionId, items2);
|
|
33089
33170
|
}
|
|
33090
33171
|
async activateAssessment(integrationId, qtiTestIdentifier) {
|
|
33091
|
-
|
|
33172
|
+
logger19.debug("Activating assessment", { integrationId, qtiTestIdentifier });
|
|
33092
33173
|
const client = this.requireClient();
|
|
33093
33174
|
const integration = await this.requireIntegration(integrationId);
|
|
33094
33175
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -33126,7 +33207,7 @@ class TimebackAssessmentsService {
|
|
|
33126
33207
|
});
|
|
33127
33208
|
}
|
|
33128
33209
|
} catch {
|
|
33129
|
-
|
|
33210
|
+
logger19.warn("Failed to reactivate existing child resource, will create new", {
|
|
33130
33211
|
childResourceId
|
|
33131
33212
|
});
|
|
33132
33213
|
childResourceId = null;
|
|
@@ -33139,7 +33220,7 @@ class TimebackAssessmentsService {
|
|
|
33139
33220
|
const resourceUrl = resource.metadata?.url;
|
|
33140
33221
|
if (resourceUrl === qtiTestUrl) {
|
|
33141
33222
|
childResourceId = resourceId;
|
|
33142
|
-
|
|
33223
|
+
logger19.info("Found existing child Resource for QTI test (idempotent retry)", {
|
|
33143
33224
|
qtiTestIdentifier,
|
|
33144
33225
|
childResourceId
|
|
33145
33226
|
});
|
|
@@ -33148,7 +33229,7 @@ class TimebackAssessmentsService {
|
|
|
33148
33229
|
} catch {}
|
|
33149
33230
|
}
|
|
33150
33231
|
if (!childResourceId) {
|
|
33151
|
-
|
|
33232
|
+
logger19.debug("Creating child resource", { qtiTestIdentifier, qtiTestUrl });
|
|
33152
33233
|
const childResult = await client.oneroster.resources.create({
|
|
33153
33234
|
resource: {
|
|
33154
33235
|
status: "active",
|
|
@@ -33176,10 +33257,10 @@ class TimebackAssessmentsService {
|
|
|
33176
33257
|
}
|
|
33177
33258
|
}
|
|
33178
33259
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: childResourceId, bankActive: true }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33179
|
-
|
|
33260
|
+
logger19.info("Assessment activated", { integrationId, qtiTestIdentifier, childResourceId });
|
|
33180
33261
|
}
|
|
33181
33262
|
async deactivateAssessment(integrationId, qtiTestIdentifier) {
|
|
33182
|
-
|
|
33263
|
+
logger19.debug("Deactivating assessment", { integrationId, qtiTestIdentifier });
|
|
33183
33264
|
const client = this.requireClient();
|
|
33184
33265
|
const integration = await this.requireIntegration(integrationId);
|
|
33185
33266
|
const row = await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
|
|
@@ -33192,7 +33273,7 @@ class TimebackAssessmentsService {
|
|
|
33192
33273
|
const childResourceId = row.bankResourceId;
|
|
33193
33274
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
33194
33275
|
try {
|
|
33195
|
-
|
|
33276
|
+
logger19.debug("Reading parent resource for deactivation", {
|
|
33196
33277
|
resourceId: bankIds.resource
|
|
33197
33278
|
});
|
|
33198
33279
|
const parentResource = await client.oneroster.resources.get(bankIds.resource);
|
|
@@ -33211,22 +33292,22 @@ class TimebackAssessmentsService {
|
|
|
33211
33292
|
});
|
|
33212
33293
|
}
|
|
33213
33294
|
} catch (error) {
|
|
33214
|
-
|
|
33295
|
+
logger19.warn("Failed to update parent resource during deactivation", {
|
|
33215
33296
|
bankResourceId: bankIds.resource,
|
|
33216
33297
|
error: error instanceof Error ? error.message : String(error)
|
|
33217
33298
|
});
|
|
33218
33299
|
}
|
|
33219
33300
|
try {
|
|
33220
|
-
|
|
33301
|
+
logger19.debug("Deleting child resource", { childResourceId });
|
|
33221
33302
|
await client.oneroster.resources.delete(childResourceId);
|
|
33222
33303
|
} catch (error) {
|
|
33223
|
-
|
|
33304
|
+
logger19.warn("Failed to delete child resource (may already be deleted)", {
|
|
33224
33305
|
childResourceId,
|
|
33225
33306
|
error: error instanceof Error ? error.message : String(error)
|
|
33226
33307
|
});
|
|
33227
33308
|
}
|
|
33228
33309
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankActive: false }).where(eq(gameTimebackAssessmentTests.id, row.id));
|
|
33229
|
-
|
|
33310
|
+
logger19.info("Assessment deactivated", { integrationId, qtiTestIdentifier });
|
|
33230
33311
|
}
|
|
33231
33312
|
isAssessmentActive(row) {
|
|
33232
33313
|
return row.bankActive;
|
|
@@ -33257,14 +33338,14 @@ class TimebackAssessmentsService {
|
|
|
33257
33338
|
status: "tobedeleted"
|
|
33258
33339
|
});
|
|
33259
33340
|
} catch (error) {
|
|
33260
|
-
|
|
33341
|
+
logger19.warn("Failed to delete component resource", { error });
|
|
33261
33342
|
}
|
|
33262
33343
|
for (const row of activeRows) {
|
|
33263
33344
|
if (row.bankResourceId) {
|
|
33264
33345
|
try {
|
|
33265
33346
|
await client.oneroster.resources.delete(row.bankResourceId);
|
|
33266
33347
|
} catch (error) {
|
|
33267
|
-
|
|
33348
|
+
logger19.warn("Failed to delete child resource", {
|
|
33268
33349
|
childResourceId: row.bankResourceId,
|
|
33269
33350
|
error
|
|
33270
33351
|
});
|
|
@@ -33274,17 +33355,17 @@ class TimebackAssessmentsService {
|
|
|
33274
33355
|
try {
|
|
33275
33356
|
await client.oneroster.resources.delete(bankIds.resource);
|
|
33276
33357
|
} catch (error) {
|
|
33277
|
-
|
|
33358
|
+
logger19.warn("Failed to delete parent resource", { error });
|
|
33278
33359
|
}
|
|
33279
33360
|
try {
|
|
33280
33361
|
await client.oneroster.courseComponents.update(bankIds.component, {
|
|
33281
33362
|
status: "tobedeleted"
|
|
33282
33363
|
});
|
|
33283
33364
|
} catch (error) {
|
|
33284
|
-
|
|
33365
|
+
logger19.warn("Failed to delete course component", { error });
|
|
33285
33366
|
}
|
|
33286
33367
|
await this.deps.db.update(gameTimebackAssessmentTests).set({ bankResourceId: null, bankActive: false }).where(eq(gameTimebackAssessmentTests.integrationId, integrationId));
|
|
33287
|
-
|
|
33368
|
+
logger19.info("Bank destroyed", { integrationId });
|
|
33288
33369
|
}
|
|
33289
33370
|
requireClient() {
|
|
33290
33371
|
if (!this.deps.timeback) {
|
|
@@ -33313,7 +33394,7 @@ class TimebackAssessmentsService {
|
|
|
33313
33394
|
async ensureBank(integration) {
|
|
33314
33395
|
const client = this.requireClient();
|
|
33315
33396
|
const bankIds = deriveAssessmentBankIds(integration.courseId);
|
|
33316
|
-
|
|
33397
|
+
logger19.debug("Ensuring assessment bank hierarchy", {
|
|
33317
33398
|
courseId: integration.courseId,
|
|
33318
33399
|
bankIds
|
|
33319
33400
|
});
|
|
@@ -33330,7 +33411,7 @@ class TimebackAssessmentsService {
|
|
|
33330
33411
|
});
|
|
33331
33412
|
} catch (error) {
|
|
33332
33413
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33333
|
-
|
|
33414
|
+
logger19.debug("Course component already exists", { sourcedId: bankIds.component });
|
|
33334
33415
|
} else {
|
|
33335
33416
|
throw error;
|
|
33336
33417
|
}
|
|
@@ -33354,7 +33435,7 @@ class TimebackAssessmentsService {
|
|
|
33354
33435
|
});
|
|
33355
33436
|
} catch (error) {
|
|
33356
33437
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33357
|
-
|
|
33438
|
+
logger19.debug("Parent resource already exists", { sourcedId: bankIds.resource });
|
|
33358
33439
|
} else {
|
|
33359
33440
|
throw error;
|
|
33360
33441
|
}
|
|
@@ -33374,14 +33455,14 @@ class TimebackAssessmentsService {
|
|
|
33374
33455
|
});
|
|
33375
33456
|
} catch (error) {
|
|
33376
33457
|
if (error instanceof TimebackApiError && error.status === 409) {
|
|
33377
|
-
|
|
33458
|
+
logger19.debug("Component resource already exists", {
|
|
33378
33459
|
sourcedId: bankIds.componentResource
|
|
33379
33460
|
});
|
|
33380
33461
|
} else {
|
|
33381
33462
|
throw error;
|
|
33382
33463
|
}
|
|
33383
33464
|
}
|
|
33384
|
-
|
|
33465
|
+
logger19.info("Assessment bank hierarchy created", {
|
|
33385
33466
|
courseId: integration.courseId
|
|
33386
33467
|
});
|
|
33387
33468
|
}
|
|
@@ -33396,7 +33477,7 @@ class TimebackAssessmentsService {
|
|
|
33396
33477
|
return Math.max(...rows.map((r) => r.sortOrder));
|
|
33397
33478
|
}
|
|
33398
33479
|
}
|
|
33399
|
-
var
|
|
33480
|
+
var logger19;
|
|
33400
33481
|
var init_timeback_assessments_service = __esm(() => {
|
|
33401
33482
|
init_drizzle_orm();
|
|
33402
33483
|
init_tables_index();
|
|
@@ -33405,7 +33486,7 @@ var init_timeback_assessments_service = __esm(() => {
|
|
|
33405
33486
|
init_errors4();
|
|
33406
33487
|
init_utils6();
|
|
33407
33488
|
init_errors();
|
|
33408
|
-
|
|
33489
|
+
logger19 = log.scope("TimebackAssessmentsService");
|
|
33409
33490
|
});
|
|
33410
33491
|
|
|
33411
33492
|
// ../api-core/src/utils/timeback-promotion.util.ts
|
|
@@ -33421,7 +33502,7 @@ async function promoteCompletedCourse({
|
|
|
33421
33502
|
});
|
|
33422
33503
|
const nextIntegration = subjectIntegrations.filter((integration) => integration.grade > currentIntegration.grade).toSorted((left, right) => left.grade - right.grade)[0];
|
|
33423
33504
|
if (!nextIntegration) {
|
|
33424
|
-
|
|
33505
|
+
logger20.debug("Skipping promotion because no next course is configured", {
|
|
33425
33506
|
gameId: currentIntegration.gameId,
|
|
33426
33507
|
studentId,
|
|
33427
33508
|
grade: currentIntegration.grade,
|
|
@@ -33438,7 +33519,7 @@ async function promoteCompletedCourse({
|
|
|
33438
33519
|
const nextEnrollment = enrollments.find((enrollment) => enrollment.course.id === nextIntegration.courseId);
|
|
33439
33520
|
if (!currentEnrollment) {
|
|
33440
33521
|
if (nextEnrollment) {
|
|
33441
|
-
|
|
33522
|
+
logger20.debug("Skipping promotion because student is already on the next course", {
|
|
33442
33523
|
gameId: currentIntegration.gameId,
|
|
33443
33524
|
studentId,
|
|
33444
33525
|
grade: currentIntegration.grade,
|
|
@@ -33452,7 +33533,7 @@ async function promoteCompletedCourse({
|
|
|
33452
33533
|
nextCourseId: nextIntegration.courseId
|
|
33453
33534
|
};
|
|
33454
33535
|
}
|
|
33455
|
-
|
|
33536
|
+
logger20.debug("Skipping promotion because student is not enrolled in the current course", {
|
|
33456
33537
|
gameId: currentIntegration.gameId,
|
|
33457
33538
|
studentId,
|
|
33458
33539
|
grade: currentIntegration.grade,
|
|
@@ -33483,7 +33564,7 @@ async function promoteCompletedCourse({
|
|
|
33483
33564
|
client.invalidateEnrollments(studentId);
|
|
33484
33565
|
}
|
|
33485
33566
|
}
|
|
33486
|
-
|
|
33567
|
+
logger20.info("Promoted student to next course", {
|
|
33487
33568
|
gameId: currentIntegration.gameId,
|
|
33488
33569
|
studentId,
|
|
33489
33570
|
subject: currentIntegration.subject,
|
|
@@ -33498,16 +33579,16 @@ async function promoteCompletedCourse({
|
|
|
33498
33579
|
nextCourseId: nextIntegration.courseId
|
|
33499
33580
|
};
|
|
33500
33581
|
}
|
|
33501
|
-
var
|
|
33582
|
+
var logger20;
|
|
33502
33583
|
var init_timeback_promotion_util = __esm(() => {
|
|
33503
33584
|
init_drizzle_orm();
|
|
33504
33585
|
init_tables_index();
|
|
33505
33586
|
init_src2();
|
|
33506
|
-
|
|
33587
|
+
logger20 = log.scope("TimebackPromotion");
|
|
33507
33588
|
});
|
|
33508
33589
|
|
|
33509
33590
|
// ../api-core/src/services/timeback.service.ts
|
|
33510
|
-
var
|
|
33591
|
+
var logger21, TimebackService;
|
|
33511
33592
|
var init_timeback_service = __esm(() => {
|
|
33512
33593
|
init_drizzle_orm();
|
|
33513
33594
|
init_src();
|
|
@@ -33518,7 +33599,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33518
33599
|
init_errors();
|
|
33519
33600
|
init_timeback_promotion_util();
|
|
33520
33601
|
init_timeback_util();
|
|
33521
|
-
|
|
33602
|
+
logger21 = log.scope("TimebackService");
|
|
33522
33603
|
TimebackService = class TimebackService {
|
|
33523
33604
|
static HEARTBEAT_DEDUPE_TTL_MS = 5 * 60 * 1000;
|
|
33524
33605
|
static processedHeartbeatWindows = new Map;
|
|
@@ -33564,7 +33645,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33564
33645
|
}
|
|
33565
33646
|
requireClient() {
|
|
33566
33647
|
if (!this.deps.timeback) {
|
|
33567
|
-
|
|
33648
|
+
logger21.error("Timeback client not available in context");
|
|
33568
33649
|
throw new ValidationError("Timeback integration not available in this environment");
|
|
33569
33650
|
}
|
|
33570
33651
|
return this.deps.timeback;
|
|
@@ -33617,7 +33698,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33617
33698
|
set: { xp: sql`excluded.xp`, updatedAt: new Date }
|
|
33618
33699
|
}).returning({ xp: timebackDailyXp.xp, date: timebackDailyXp.date });
|
|
33619
33700
|
if (!result) {
|
|
33620
|
-
|
|
33701
|
+
logger21.error("Daily XP upsert returned no rows", { userId, date: targetDate });
|
|
33621
33702
|
throw new InternalError("Failed to update daily XP record");
|
|
33622
33703
|
}
|
|
33623
33704
|
return { xp: result.xp, date: result.date.toISOString() };
|
|
@@ -33648,7 +33729,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33648
33729
|
columns: { id: true, timebackId: true }
|
|
33649
33730
|
});
|
|
33650
33731
|
if (dbUser?.timebackId) {
|
|
33651
|
-
|
|
33732
|
+
logger21.info("Student already onboarded", { userId: user.id });
|
|
33652
33733
|
return { status: "already_populated" };
|
|
33653
33734
|
}
|
|
33654
33735
|
let timebackId;
|
|
@@ -33657,7 +33738,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33657
33738
|
const existingUser = await client.oneroster.users.findByEmail(user.email);
|
|
33658
33739
|
timebackId = existingUser.sourcedId;
|
|
33659
33740
|
name3 = `${existingUser.givenName} ${existingUser.familyName}`;
|
|
33660
|
-
|
|
33741
|
+
logger21.info("Found existing student in OneRoster", {
|
|
33661
33742
|
userId: user.id,
|
|
33662
33743
|
timebackId
|
|
33663
33744
|
});
|
|
@@ -33686,7 +33767,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33686
33767
|
}
|
|
33687
33768
|
timebackId = response.sourcedIdPairs.allocatedSourcedId;
|
|
33688
33769
|
name3 = `${providedNames.firstName} ${providedNames.lastName}`;
|
|
33689
|
-
|
|
33770
|
+
logger21.info("Created student in OneRoster", { userId: user.id, timebackId });
|
|
33690
33771
|
}
|
|
33691
33772
|
const assessments = await this.fetchAssessments(timebackId);
|
|
33692
33773
|
await db2.transaction(async (tx) => {
|
|
@@ -33720,7 +33801,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33720
33801
|
}
|
|
33721
33802
|
const [updated] = await tx.update(users).set({ timebackId, name: name3 }).where(eq(users.id, user.id)).returning({ id: users.id });
|
|
33722
33803
|
if (!updated) {
|
|
33723
|
-
|
|
33804
|
+
logger21.error("User Timeback ID update returned no rows", {
|
|
33724
33805
|
userId: user.id,
|
|
33725
33806
|
timebackId
|
|
33726
33807
|
});
|
|
@@ -33744,13 +33825,13 @@ var init_timeback_service = __esm(() => {
|
|
|
33744
33825
|
}
|
|
33745
33826
|
offset += limit;
|
|
33746
33827
|
}
|
|
33747
|
-
|
|
33828
|
+
logger21.debug("Fetched assessments", {
|
|
33748
33829
|
studentSourcedId,
|
|
33749
33830
|
totalCount: allAssessments.length
|
|
33750
33831
|
});
|
|
33751
33832
|
return allAssessments;
|
|
33752
33833
|
} catch (error) {
|
|
33753
|
-
|
|
33834
|
+
logger21.warn("Failed to fetch assessments", { studentSourcedId, error });
|
|
33754
33835
|
return [];
|
|
33755
33836
|
}
|
|
33756
33837
|
}
|
|
@@ -33863,7 +33944,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33863
33944
|
masterableUnits: derivedMasterableUnits
|
|
33864
33945
|
} = courseConfig;
|
|
33865
33946
|
if (!isTimebackSubject(subjectInput)) {
|
|
33866
|
-
|
|
33947
|
+
logger21.warn("Invalid Timeback subject in course config", {
|
|
33867
33948
|
subject: subjectInput,
|
|
33868
33949
|
courseCode,
|
|
33869
33950
|
title
|
|
@@ -33871,7 +33952,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33871
33952
|
throw new ValidationError(`Invalid subject "${subjectInput}"`);
|
|
33872
33953
|
}
|
|
33873
33954
|
if (!isTimebackGrade(grade)) {
|
|
33874
|
-
|
|
33955
|
+
logger21.warn("Invalid Timeback grade in course config", {
|
|
33875
33956
|
grade,
|
|
33876
33957
|
courseCode,
|
|
33877
33958
|
title
|
|
@@ -33883,7 +33964,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33883
33964
|
const totalXp = derivedTotalXp ?? courseMetadata?.metrics?.totalXp;
|
|
33884
33965
|
const masterableUnits = derivedMasterableUnits ?? (isPlaycademyResourceMetadata(courseMetadata?.playcademy) ? courseMetadata?.playcademy?.mastery?.masterableUnits : undefined);
|
|
33885
33966
|
if (typeof totalXp !== "number") {
|
|
33886
|
-
|
|
33967
|
+
logger21.warn("Course missing totalXp in Timeback config", {
|
|
33887
33968
|
courseCode,
|
|
33888
33969
|
title
|
|
33889
33970
|
});
|
|
@@ -33899,7 +33980,9 @@ var init_timeback_service = __esm(() => {
|
|
|
33899
33980
|
courseCode,
|
|
33900
33981
|
level,
|
|
33901
33982
|
gradingScheme: "STANDARD",
|
|
33902
|
-
metadata: metadata2
|
|
33983
|
+
metadata: TimebackService.patchCourseMetadata(metadata2, totalXp, {
|
|
33984
|
+
masterableUnits: masterableUnits ?? null
|
|
33985
|
+
})
|
|
33903
33986
|
},
|
|
33904
33987
|
component: {
|
|
33905
33988
|
...baseConfig.component,
|
|
@@ -33924,7 +34007,7 @@ var init_timeback_service = __esm(() => {
|
|
|
33924
34007
|
const existingIntegration = existing.find((i2) => i2.grade === grade && i2.subject === subject);
|
|
33925
34008
|
if (existingIntegration) {
|
|
33926
34009
|
await client.update(existingIntegration.courseId, fullConfig);
|
|
33927
|
-
const [updated] = await db2.update(gameTimebackIntegrations).set({ totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
|
|
34010
|
+
const [updated] = await db2.update(gameTimebackIntegrations).set({ subject, totalXp, updatedAt: new Date }).where(eq(gameTimebackIntegrations.id, existingIntegration.id)).returning();
|
|
33928
34011
|
if (updated) {
|
|
33929
34012
|
integrations.push(this.toGameTimebackIntegration(updated));
|
|
33930
34013
|
}
|
|
@@ -33949,6 +34032,60 @@ var init_timeback_service = __esm(() => {
|
|
|
33949
34032
|
});
|
|
33950
34033
|
return rows.map((row) => this.toGameTimebackIntegration(row));
|
|
33951
34034
|
}
|
|
34035
|
+
async getIntegrationConfig(gameId, courseId, user) {
|
|
34036
|
+
const client = this.requireClient();
|
|
34037
|
+
await this.deps.validateGameManagementAccess(user, gameId);
|
|
34038
|
+
const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
34039
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
|
|
34040
|
+
});
|
|
34041
|
+
if (!integration) {
|
|
34042
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
34043
|
+
}
|
|
34044
|
+
const config2 = await client.getConfig(courseId);
|
|
34045
|
+
return this.toGameTimebackIntegrationConfig(integration, config2);
|
|
34046
|
+
}
|
|
34047
|
+
async updateIntegration(gameId, courseId, user, patch) {
|
|
34048
|
+
const client = this.requireClient();
|
|
34049
|
+
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34050
|
+
const integration = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
34051
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.courseId, courseId))
|
|
34052
|
+
});
|
|
34053
|
+
if (!integration) {
|
|
34054
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
34055
|
+
}
|
|
34056
|
+
const timebackConfig = await client.getConfig(courseId);
|
|
34057
|
+
const liveSubject = timebackConfig.course.subjects[0];
|
|
34058
|
+
const subject = patch.subject ?? (isTimebackSubject(liveSubject) ? liveSubject : integration.subject);
|
|
34059
|
+
if (!isTimebackSubject(subject)) {
|
|
34060
|
+
throw new ValidationError(`Invalid subject "${subject}"`);
|
|
34061
|
+
}
|
|
34062
|
+
if (subject !== integration.subject) {
|
|
34063
|
+
const subjectConflict = await this.deps.db.query.gameTimebackIntegrations.findFirst({
|
|
34064
|
+
where: and(eq(gameTimebackIntegrations.gameId, gameId), eq(gameTimebackIntegrations.grade, integration.grade), eq(gameTimebackIntegrations.subject, subject))
|
|
34065
|
+
});
|
|
34066
|
+
if (subjectConflict && subjectConflict.id !== integration.id) {
|
|
34067
|
+
throw new ValidationError(`A TimeBack integration already exists for ${subject} Grade ${integration.grade}`);
|
|
34068
|
+
}
|
|
34069
|
+
}
|
|
34070
|
+
const totalXp = "totalXp" in patch ? patch.totalXp ?? null : TimebackService.getTotalXpFromConfig(timebackConfig) ?? integration.totalXp ?? null;
|
|
34071
|
+
const masterableUnits = "masterableUnits" in patch ? patch.masterableUnits ?? null : TimebackService.getMasterableUnitsFromConfig(timebackConfig);
|
|
34072
|
+
await client.update(courseId, TimebackService.patchTimebackConfig(timebackConfig, {
|
|
34073
|
+
...patch,
|
|
34074
|
+
subject,
|
|
34075
|
+
totalXp,
|
|
34076
|
+
masterableUnits,
|
|
34077
|
+
grade: integration.grade
|
|
34078
|
+
}));
|
|
34079
|
+
const [updated] = await this.deps.db.update(gameTimebackIntegrations).set({
|
|
34080
|
+
subject,
|
|
34081
|
+
totalXp,
|
|
34082
|
+
updatedAt: new Date
|
|
34083
|
+
}).where(eq(gameTimebackIntegrations.id, integration.id)).returning();
|
|
34084
|
+
if (!updated) {
|
|
34085
|
+
throw new NotFoundError("Timeback integration", `${gameId}:${courseId}`);
|
|
34086
|
+
}
|
|
34087
|
+
return this.toGameTimebackIntegration(updated);
|
|
34088
|
+
}
|
|
33952
34089
|
async verifyIntegration(gameId, user) {
|
|
33953
34090
|
const client = this.requireClient();
|
|
33954
34091
|
const db2 = this.deps.db;
|
|
@@ -34006,6 +34143,146 @@ var init_timeback_service = __esm(() => {
|
|
|
34006
34143
|
}
|
|
34007
34144
|
await db2.delete(gameTimebackIntegrations).where(eq(gameTimebackIntegrations.gameId, gameId));
|
|
34008
34145
|
}
|
|
34146
|
+
static getMasterableUnitsFromConfig(config2) {
|
|
34147
|
+
const playcademyMetadata = config2.resource.metadata?.playcademy;
|
|
34148
|
+
if (!isPlaycademyResourceMetadata(playcademyMetadata)) {
|
|
34149
|
+
return null;
|
|
34150
|
+
}
|
|
34151
|
+
return playcademyMetadata?.mastery?.masterableUnits ?? null;
|
|
34152
|
+
}
|
|
34153
|
+
static getTotalXpFromConfig(config2) {
|
|
34154
|
+
const courseMetadata = isCourseMetadata(config2.course.metadata) ? config2.course.metadata : undefined;
|
|
34155
|
+
if (typeof courseMetadata?.metrics?.totalXp === "number") {
|
|
34156
|
+
return courseMetadata.metrics.totalXp;
|
|
34157
|
+
}
|
|
34158
|
+
const resourceMetadata = config2.resource.metadata;
|
|
34159
|
+
if (isRecord2(resourceMetadata) && typeof resourceMetadata.xp === "number") {
|
|
34160
|
+
return resourceMetadata.xp;
|
|
34161
|
+
}
|
|
34162
|
+
return null;
|
|
34163
|
+
}
|
|
34164
|
+
static patchCourseMetadata(metadata2, totalXp, options) {
|
|
34165
|
+
const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
|
|
34166
|
+
const currentMetrics = isRecord2(nextMetadata.metrics) ? nextMetadata.metrics : {};
|
|
34167
|
+
const metrics = { ...currentMetrics };
|
|
34168
|
+
if (totalXp === null) {
|
|
34169
|
+
delete metrics.totalXp;
|
|
34170
|
+
} else {
|
|
34171
|
+
metrics.totalXp = totalXp;
|
|
34172
|
+
}
|
|
34173
|
+
if (options?.masterableUnits !== undefined) {
|
|
34174
|
+
if (options.masterableUnits === null) {
|
|
34175
|
+
delete metrics.totalLessons;
|
|
34176
|
+
} else {
|
|
34177
|
+
metrics.totalLessons = options.masterableUnits;
|
|
34178
|
+
}
|
|
34179
|
+
}
|
|
34180
|
+
metrics.totalGrades = 1;
|
|
34181
|
+
if (Object.keys(metrics).length > 0) {
|
|
34182
|
+
nextMetadata.metrics = metrics;
|
|
34183
|
+
} else {
|
|
34184
|
+
delete nextMetadata.metrics;
|
|
34185
|
+
}
|
|
34186
|
+
const goals = options?.goals;
|
|
34187
|
+
if (goals !== undefined) {
|
|
34188
|
+
if (goals === null) {
|
|
34189
|
+
delete nextMetadata.goals;
|
|
34190
|
+
} else {
|
|
34191
|
+
const currentGoals = isRecord2(nextMetadata.goals) ? nextMetadata.goals : {};
|
|
34192
|
+
const nextGoals = { ...currentGoals };
|
|
34193
|
+
for (const [key, value] of Object.entries(goals)) {
|
|
34194
|
+
if (value === null) {
|
|
34195
|
+
delete nextGoals[key];
|
|
34196
|
+
} else if (value !== undefined) {
|
|
34197
|
+
nextGoals[key] = value;
|
|
34198
|
+
}
|
|
34199
|
+
}
|
|
34200
|
+
if (Object.keys(nextGoals).length > 0) {
|
|
34201
|
+
nextMetadata.goals = nextGoals;
|
|
34202
|
+
} else {
|
|
34203
|
+
delete nextMetadata.goals;
|
|
34204
|
+
}
|
|
34205
|
+
}
|
|
34206
|
+
}
|
|
34207
|
+
if (options?.publishStatus !== undefined) {
|
|
34208
|
+
if (options.publishStatus === null) {
|
|
34209
|
+
delete nextMetadata.publishStatus;
|
|
34210
|
+
const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
|
|
34211
|
+
delete alphaLearn.publishStatus;
|
|
34212
|
+
if (Object.keys(alphaLearn).length > 0) {
|
|
34213
|
+
nextMetadata.AlphaLearn = alphaLearn;
|
|
34214
|
+
} else {
|
|
34215
|
+
delete nextMetadata.AlphaLearn;
|
|
34216
|
+
}
|
|
34217
|
+
} else {
|
|
34218
|
+
nextMetadata.publishStatus = options.publishStatus;
|
|
34219
|
+
const alphaLearn = isRecord2(nextMetadata.AlphaLearn) ? { ...nextMetadata.AlphaLearn } : {};
|
|
34220
|
+
alphaLearn.publishStatus = options.publishStatus === "published" ? "active" : options.publishStatus;
|
|
34221
|
+
nextMetadata.AlphaLearn = alphaLearn;
|
|
34222
|
+
}
|
|
34223
|
+
}
|
|
34224
|
+
if (options?.isSupplemental !== undefined) {
|
|
34225
|
+
nextMetadata.isSupplemental = options.isSupplemental;
|
|
34226
|
+
}
|
|
34227
|
+
if (options?.timebackVisible !== undefined) {
|
|
34228
|
+
if (options.timebackVisible === null) {
|
|
34229
|
+
delete nextMetadata.timebackVisible;
|
|
34230
|
+
} else {
|
|
34231
|
+
nextMetadata.timebackVisible = options.timebackVisible;
|
|
34232
|
+
}
|
|
34233
|
+
}
|
|
34234
|
+
return Object.keys(nextMetadata).length > 0 ? nextMetadata : undefined;
|
|
34235
|
+
}
|
|
34236
|
+
static patchResourceMetadata(metadata2, options) {
|
|
34237
|
+
const nextMetadata = isRecord2(metadata2) ? { ...metadata2 } : {};
|
|
34238
|
+
const playcademyMetadata = isRecord2(nextMetadata.playcademy) ? { ...nextMetadata.playcademy } : {};
|
|
34239
|
+
const masteryMetadata = isRecord2(playcademyMetadata.mastery) ? { ...playcademyMetadata.mastery } : {};
|
|
34240
|
+
nextMetadata.subject = options.subject;
|
|
34241
|
+
nextMetadata.grades = [options.grade];
|
|
34242
|
+
if (options.totalXp === null) {
|
|
34243
|
+
delete nextMetadata.xp;
|
|
34244
|
+
} else {
|
|
34245
|
+
nextMetadata.xp = options.totalXp;
|
|
34246
|
+
}
|
|
34247
|
+
if (options.masterableUnits === null) {
|
|
34248
|
+
delete masteryMetadata.masterableUnits;
|
|
34249
|
+
} else {
|
|
34250
|
+
masteryMetadata.masterableUnits = options.masterableUnits;
|
|
34251
|
+
}
|
|
34252
|
+
if (Object.keys(masteryMetadata).length > 0) {
|
|
34253
|
+
playcademyMetadata.mastery = masteryMetadata;
|
|
34254
|
+
} else {
|
|
34255
|
+
delete playcademyMetadata.mastery;
|
|
34256
|
+
}
|
|
34257
|
+
if (Object.keys(playcademyMetadata).length > 0) {
|
|
34258
|
+
nextMetadata.playcademy = playcademyMetadata;
|
|
34259
|
+
} else {
|
|
34260
|
+
delete nextMetadata.playcademy;
|
|
34261
|
+
}
|
|
34262
|
+
return nextMetadata;
|
|
34263
|
+
}
|
|
34264
|
+
static patchTimebackConfig(config2, patch) {
|
|
34265
|
+
return {
|
|
34266
|
+
...config2,
|
|
34267
|
+
course: {
|
|
34268
|
+
...config2.course,
|
|
34269
|
+
title: patch.title ?? config2.course.title,
|
|
34270
|
+
courseCode: patch.courseCode ?? config2.course.courseCode,
|
|
34271
|
+
subjects: [patch.subject],
|
|
34272
|
+
metadata: TimebackService.patchCourseMetadata(config2.course.metadata, patch.totalXp, {
|
|
34273
|
+
masterableUnits: patch.masterableUnits,
|
|
34274
|
+
goals: patch.goals,
|
|
34275
|
+
publishStatus: patch.publishStatus,
|
|
34276
|
+
isSupplemental: patch.isSupplemental,
|
|
34277
|
+
timebackVisible: patch.timebackVisible
|
|
34278
|
+
})
|
|
34279
|
+
},
|
|
34280
|
+
resource: {
|
|
34281
|
+
...config2.resource,
|
|
34282
|
+
metadata: TimebackService.patchResourceMetadata(config2.resource.metadata, patch)
|
|
34283
|
+
}
|
|
34284
|
+
};
|
|
34285
|
+
}
|
|
34009
34286
|
toGameTimebackIntegration(integration) {
|
|
34010
34287
|
return {
|
|
34011
34288
|
id: integration.id,
|
|
@@ -34019,6 +34296,21 @@ var init_timeback_service = __esm(() => {
|
|
|
34019
34296
|
lastVerifiedAt: integration.lastVerifiedAt ?? null
|
|
34020
34297
|
};
|
|
34021
34298
|
}
|
|
34299
|
+
toGameTimebackIntegrationConfig(integration, config2) {
|
|
34300
|
+
const subject = config2.course.subjects[0] ?? integration.subject;
|
|
34301
|
+
if (!isTimebackSubject(subject)) {
|
|
34302
|
+
throw new ValidationError(`Invalid subject "${subject}"`);
|
|
34303
|
+
}
|
|
34304
|
+
return {
|
|
34305
|
+
integration: this.toGameTimebackIntegration(integration),
|
|
34306
|
+
title: config2.course.title,
|
|
34307
|
+
courseCode: config2.course.courseCode,
|
|
34308
|
+
subject,
|
|
34309
|
+
totalXp: TimebackService.getTotalXpFromConfig(config2) ?? integration.totalXp ?? null,
|
|
34310
|
+
masterableUnits: TimebackService.getMasterableUnitsFromConfig(config2),
|
|
34311
|
+
metadata: isCourseMetadata(config2.course.metadata) ? config2.course.metadata : null
|
|
34312
|
+
};
|
|
34313
|
+
}
|
|
34022
34314
|
async endActivity({
|
|
34023
34315
|
gameId,
|
|
34024
34316
|
studentId,
|
|
@@ -34084,7 +34376,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34084
34376
|
...runId ? { runId } : {}
|
|
34085
34377
|
});
|
|
34086
34378
|
}
|
|
34087
|
-
|
|
34379
|
+
logger21.info("Recorded activity completion", {
|
|
34088
34380
|
gameId,
|
|
34089
34381
|
courseId: integration.courseId,
|
|
34090
34382
|
studentId,
|
|
@@ -34138,7 +34430,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34138
34430
|
masteredUnits: masteryStatus.masteredUnits,
|
|
34139
34431
|
masterableUnits: masteryStatus.masterableUnits
|
|
34140
34432
|
};
|
|
34141
|
-
|
|
34433
|
+
logger21.debug("Skipping course advancement because mastery is incomplete", {
|
|
34142
34434
|
gameId,
|
|
34143
34435
|
studentId,
|
|
34144
34436
|
subject: currentIntegration.subject,
|
|
@@ -34156,7 +34448,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34156
34448
|
studentId,
|
|
34157
34449
|
enrollments
|
|
34158
34450
|
});
|
|
34159
|
-
|
|
34451
|
+
logger21.info("Manually advanced student", {
|
|
34160
34452
|
gameId,
|
|
34161
34453
|
studentId,
|
|
34162
34454
|
subject: currentIntegration.subject,
|
|
@@ -34189,7 +34481,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34189
34481
|
const heartbeatWindowKey = hasWindowStartedAtMs ? `${runId}:t:${windowStartedAtMs}` : `${runId}:s:${windowSequence}`;
|
|
34190
34482
|
const effectiveResumeId = resumeId ?? runId;
|
|
34191
34483
|
if (TimebackService.isDuplicateHeartbeatWindow(heartbeatWindowKey)) {
|
|
34192
|
-
|
|
34484
|
+
logger21.debug("Skipping duplicate heartbeat window", {
|
|
34193
34485
|
gameId,
|
|
34194
34486
|
studentId,
|
|
34195
34487
|
runId,
|
|
@@ -34202,7 +34494,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34202
34494
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34203
34495
|
const inFlightHeartbeat = TimebackService.getInFlightHeartbeatWindow(heartbeatWindowKey);
|
|
34204
34496
|
if (inFlightHeartbeat) {
|
|
34205
|
-
|
|
34497
|
+
logger21.debug("Joining in-flight heartbeat window", {
|
|
34206
34498
|
gameId,
|
|
34207
34499
|
studentId,
|
|
34208
34500
|
runId,
|
|
@@ -34239,7 +34531,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34239
34531
|
});
|
|
34240
34532
|
}
|
|
34241
34533
|
TimebackService.markHeartbeatWindowProcessed(heartbeatWindowKey);
|
|
34242
|
-
|
|
34534
|
+
logger21.debug("Recorded heartbeat", {
|
|
34243
34535
|
gameId,
|
|
34244
34536
|
courseId: integration.courseId,
|
|
34245
34537
|
studentId,
|
|
@@ -34274,7 +34566,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34274
34566
|
});
|
|
34275
34567
|
courseIds = integrations.map((i2) => i2.courseId);
|
|
34276
34568
|
if (courseIds.length === 0) {
|
|
34277
|
-
|
|
34569
|
+
logger21.debug("No integrations found for game, returning 0 XP", {
|
|
34278
34570
|
timebackId,
|
|
34279
34571
|
gameId: options.gameId,
|
|
34280
34572
|
grade: options.grade,
|
|
@@ -34291,7 +34583,7 @@ var init_timeback_service = __esm(() => {
|
|
|
34291
34583
|
courseIds: courseIds.length > 0 ? courseIds : undefined,
|
|
34292
34584
|
include: options?.include
|
|
34293
34585
|
});
|
|
34294
|
-
|
|
34586
|
+
logger21.debug("Retrieved student XP", {
|
|
34295
34587
|
timebackId,
|
|
34296
34588
|
gameId: options?.gameId,
|
|
34297
34589
|
grade: options?.grade,
|
|
@@ -34320,15 +34612,15 @@ class UploadService {
|
|
|
34320
34612
|
const { fileName, gameId } = request;
|
|
34321
34613
|
const bucketName = this.deps.uploadBucket;
|
|
34322
34614
|
if (!bucketName) {
|
|
34323
|
-
|
|
34615
|
+
logger22.error("Upload bucket not configured in environment");
|
|
34324
34616
|
throw new ValidationError("Upload bucket not configured");
|
|
34325
34617
|
}
|
|
34326
34618
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
34327
34619
|
const version2 = ulid();
|
|
34328
34620
|
const tempS3Key = `uploads-temp/${gameId}/${version2}/${fileName}`;
|
|
34329
|
-
|
|
34621
|
+
logger22.debug("Initiating upload", { userId: user.id, gameId, fileName, version: version2 });
|
|
34330
34622
|
const presignedUrl = await this.deps.generatePresignedPutUrl(bucketName, tempS3Key, UploadService.getContentType(fileName));
|
|
34331
|
-
|
|
34623
|
+
logger22.info("Presigned URL generated", {
|
|
34332
34624
|
userId: user.id,
|
|
34333
34625
|
gameId,
|
|
34334
34626
|
version: version2
|
|
@@ -34341,12 +34633,12 @@ class UploadService {
|
|
|
34341
34633
|
};
|
|
34342
34634
|
}
|
|
34343
34635
|
}
|
|
34344
|
-
var
|
|
34636
|
+
var logger22;
|
|
34345
34637
|
var init_upload_service = __esm(() => {
|
|
34346
34638
|
init_node();
|
|
34347
34639
|
init_src2();
|
|
34348
34640
|
init_errors();
|
|
34349
|
-
|
|
34641
|
+
logger22 = log.scope("UploadService");
|
|
34350
34642
|
});
|
|
34351
34643
|
|
|
34352
34644
|
// ../api-core/src/services/factory/platform.ts
|
|
@@ -34660,7 +34952,7 @@ class AchievementService {
|
|
|
34660
34952
|
results.push(result);
|
|
34661
34953
|
}
|
|
34662
34954
|
}
|
|
34663
|
-
|
|
34955
|
+
logger23.debug("Listed current achievements", { userId: user.id, count: results.length });
|
|
34664
34956
|
return results;
|
|
34665
34957
|
}
|
|
34666
34958
|
async listHistory(user, limit) {
|
|
@@ -34678,14 +34970,14 @@ class AchievementService {
|
|
|
34678
34970
|
createdAt: c.createdAt,
|
|
34679
34971
|
scopeKey: c.scopeKey
|
|
34680
34972
|
}));
|
|
34681
|
-
|
|
34973
|
+
logger23.debug("Listed achievement history", { userId: user.id, count: results.length });
|
|
34682
34974
|
return results;
|
|
34683
34975
|
}
|
|
34684
34976
|
async submitProgress(achievementId, user) {
|
|
34685
34977
|
const { claim, wasNewClaim } = await this.award(user.id, achievementId, {
|
|
34686
34978
|
broadcast: false
|
|
34687
34979
|
});
|
|
34688
|
-
|
|
34980
|
+
logger23.debug("Submitted progress", {
|
|
34689
34981
|
userId: user.id,
|
|
34690
34982
|
achievementId,
|
|
34691
34983
|
wasNewClaim
|
|
@@ -34717,7 +35009,7 @@ class AchievementService {
|
|
|
34717
35009
|
rewardCredits
|
|
34718
35010
|
}).returning();
|
|
34719
35011
|
if (!newClaim) {
|
|
34720
|
-
|
|
35012
|
+
logger23.error("Achievement claim insert returned no rows", {
|
|
34721
35013
|
userId,
|
|
34722
35014
|
achievementId,
|
|
34723
35015
|
scopeKey
|
|
@@ -34726,7 +35018,7 @@ class AchievementService {
|
|
|
34726
35018
|
}
|
|
34727
35019
|
await this.deps.addCredits(userId, rewardCredits);
|
|
34728
35020
|
await this.deps.createAchievementNotification(userId, achievement, rewardCredits, scopeKey, { broadcast, metadata: metadata2 });
|
|
34729
|
-
|
|
35021
|
+
logger23.info("Awarded achievement", {
|
|
34730
35022
|
userId,
|
|
34731
35023
|
achievementId,
|
|
34732
35024
|
scopeKey,
|
|
@@ -34763,7 +35055,7 @@ class AchievementService {
|
|
|
34763
35055
|
return { title, body: body2 };
|
|
34764
35056
|
}
|
|
34765
35057
|
}
|
|
34766
|
-
var
|
|
35058
|
+
var logger23;
|
|
34767
35059
|
var init_achievement_service = __esm(() => {
|
|
34768
35060
|
init_drizzle_orm();
|
|
34769
35061
|
init_tables_index();
|
|
@@ -34772,7 +35064,7 @@ var init_achievement_service = __esm(() => {
|
|
|
34772
35064
|
init_errors();
|
|
34773
35065
|
init_leaderboard_util();
|
|
34774
35066
|
init_scope_util();
|
|
34775
|
-
|
|
35067
|
+
logger23 = log.scope("AchievementService");
|
|
34776
35068
|
});
|
|
34777
35069
|
|
|
34778
35070
|
// ../api-core/src/services/inventory.service.ts
|
|
@@ -34800,7 +35092,7 @@ class InventoryService {
|
|
|
34800
35092
|
},
|
|
34801
35093
|
updatedAt: inventoryItems.updatedAt
|
|
34802
35094
|
}).from(inventoryItems).where(eq(inventoryItems.userId, user.id)).innerJoin(items, eq(inventoryItems.itemId, items.id));
|
|
34803
|
-
|
|
35095
|
+
logger24.debug("Listed inventory", { userId: user.id, count: inventory.length });
|
|
34804
35096
|
return inventory;
|
|
34805
35097
|
}
|
|
34806
35098
|
async addItem(itemId, quantity, user) {
|
|
@@ -34817,7 +35109,7 @@ class InventoryService {
|
|
|
34817
35109
|
const [inserted] = await tx.insert(inventoryItems).values({ userId: user.id, itemId, quantity }).returning({ quantity: inventoryItems.quantity });
|
|
34818
35110
|
return inserted?.quantity ?? 0;
|
|
34819
35111
|
});
|
|
34820
|
-
|
|
35112
|
+
logger24.debug("Added item", { userId: user.id, itemId, quantity, newTotal });
|
|
34821
35113
|
return { newTotal };
|
|
34822
35114
|
}
|
|
34823
35115
|
async removeItem(itemId, quantity, user) {
|
|
@@ -34828,7 +35120,7 @@ class InventoryService {
|
|
|
34828
35120
|
}
|
|
34829
35121
|
const [currentItem] = await tx.select({ id: inventoryItems.id, quantity: inventoryItems.quantity }).from(inventoryItems).where(and(eq(inventoryItems.userId, user.id), eq(inventoryItems.itemId, itemId), gte(inventoryItems.quantity, quantity))).limit(1);
|
|
34830
35122
|
if (!currentItem) {
|
|
34831
|
-
|
|
35123
|
+
logger24.warn("Insufficient inventory for removal", {
|
|
34832
35124
|
userId: user.id,
|
|
34833
35125
|
itemId,
|
|
34834
35126
|
requestedQuantity: quantity
|
|
@@ -34838,13 +35130,13 @@ class InventoryService {
|
|
|
34838
35130
|
const [updated] = await tx.update(inventoryItems).set({ quantity: sql`${inventoryItems.quantity} - ${quantity}` }).where(eq(inventoryItems.id, currentItem.id)).returning({ quantity: inventoryItems.quantity });
|
|
34839
35131
|
return updated?.quantity ?? 0;
|
|
34840
35132
|
});
|
|
34841
|
-
|
|
35133
|
+
logger24.debug("Removed item", { userId: user.id, itemId, quantity, newTotal });
|
|
34842
35134
|
return { newTotal };
|
|
34843
35135
|
}
|
|
34844
35136
|
async addCredits(userId, amount) {
|
|
34845
35137
|
const [creditsItem] = await this.deps.db.select({ id: items.id }).from(items).where(eq(items.slug, CURRENCIES.PRIMARY)).limit(1);
|
|
34846
35138
|
if (!creditsItem) {
|
|
34847
|
-
|
|
35139
|
+
logger24.error("Primary currency not found", {
|
|
34848
35140
|
userId,
|
|
34849
35141
|
amount
|
|
34850
35142
|
});
|
|
@@ -34857,17 +35149,17 @@ class InventoryService {
|
|
|
34857
35149
|
updatedAt: new Date
|
|
34858
35150
|
}
|
|
34859
35151
|
});
|
|
34860
|
-
|
|
35152
|
+
logger24.debug("Added credits", { userId, amount });
|
|
34861
35153
|
}
|
|
34862
35154
|
}
|
|
34863
|
-
var
|
|
35155
|
+
var logger24;
|
|
34864
35156
|
var init_inventory_service = __esm(() => {
|
|
34865
35157
|
init_drizzle_orm();
|
|
34866
35158
|
init_src();
|
|
34867
35159
|
init_tables_index();
|
|
34868
35160
|
init_src2();
|
|
34869
35161
|
init_errors();
|
|
34870
|
-
|
|
35162
|
+
logger24 = log.scope("InventoryService");
|
|
34871
35163
|
});
|
|
34872
35164
|
|
|
34873
35165
|
// ../api-core/src/services/leaderboard.service.ts
|
|
@@ -34899,7 +35191,7 @@ class LeaderboardService {
|
|
|
34899
35191
|
sessionId
|
|
34900
35192
|
}).returning();
|
|
34901
35193
|
if (!newScore) {
|
|
34902
|
-
|
|
35194
|
+
logger25.error("Score insert returned no rows", { userId, gameId, score: input.score });
|
|
34903
35195
|
throw new InternalError("Failed to insert score");
|
|
34904
35196
|
}
|
|
34905
35197
|
const bestScoreRows = await db2.select({ score: sql`MAX(${gameScores.score})` }).from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId)));
|
|
@@ -34927,7 +35219,7 @@ class LeaderboardService {
|
|
|
34927
35219
|
movedUpWithinTop3
|
|
34928
35220
|
});
|
|
34929
35221
|
}
|
|
34930
|
-
|
|
35222
|
+
logger25.info("Score submitted", {
|
|
34931
35223
|
gameId,
|
|
34932
35224
|
userId,
|
|
34933
35225
|
isAnonymousUser,
|
|
@@ -35004,7 +35296,7 @@ class LeaderboardService {
|
|
|
35004
35296
|
});
|
|
35005
35297
|
}
|
|
35006
35298
|
} catch (error) {
|
|
35007
|
-
|
|
35299
|
+
logger25.warn("Failed to publish notification", { error });
|
|
35008
35300
|
}
|
|
35009
35301
|
}
|
|
35010
35302
|
async getLeaderboard(gameId, query, isAnonymousUser) {
|
|
@@ -35123,7 +35415,7 @@ class LeaderboardService {
|
|
|
35123
35415
|
return db2.select().from(gameScores).where(and(eq(gameScores.gameId, gameId), eq(gameScores.userId, userId))).orderBy(desc(gameScores.achievedAt)).limit(effectiveLimit);
|
|
35124
35416
|
}
|
|
35125
35417
|
}
|
|
35126
|
-
var
|
|
35418
|
+
var logger25;
|
|
35127
35419
|
var init_leaderboard_service = __esm(() => {
|
|
35128
35420
|
init_drizzle_orm();
|
|
35129
35421
|
init_src();
|
|
@@ -35133,7 +35425,7 @@ var init_leaderboard_service = __esm(() => {
|
|
|
35133
35425
|
init_notification();
|
|
35134
35426
|
init_errors();
|
|
35135
35427
|
init_leaderboard_util();
|
|
35136
|
-
|
|
35428
|
+
logger25 = log.scope("LeaderboardService");
|
|
35137
35429
|
});
|
|
35138
35430
|
|
|
35139
35431
|
// ../api-core/src/services/level.service.ts
|
|
@@ -35149,9 +35441,9 @@ class LevelService {
|
|
|
35149
35441
|
for (const config2 of configs) {
|
|
35150
35442
|
levelConfigCache.set(config2.level, config2);
|
|
35151
35443
|
}
|
|
35152
|
-
|
|
35444
|
+
logger26.info("Cache pre-warmed", { count: configs.length });
|
|
35153
35445
|
} catch (error) {
|
|
35154
|
-
|
|
35446
|
+
logger26.error("Cache pre-warm failed", { error });
|
|
35155
35447
|
}
|
|
35156
35448
|
}
|
|
35157
35449
|
async getConfig(level) {
|
|
@@ -35185,7 +35477,7 @@ class LevelService {
|
|
|
35185
35477
|
totalXP
|
|
35186
35478
|
}).returning();
|
|
35187
35479
|
if (!newUserLevel) {
|
|
35188
|
-
|
|
35480
|
+
logger26.error("User level insert returned no rows", { userId: user.id });
|
|
35189
35481
|
throw new InternalError("Failed to create user level cache record");
|
|
35190
35482
|
}
|
|
35191
35483
|
userLevel = newUserLevel;
|
|
@@ -35200,7 +35492,7 @@ class LevelService {
|
|
|
35200
35492
|
userLevel = updatedUserLevel;
|
|
35201
35493
|
}
|
|
35202
35494
|
}
|
|
35203
|
-
|
|
35495
|
+
logger26.debug("Retrieved user level", {
|
|
35204
35496
|
userId: user.id,
|
|
35205
35497
|
totalXP,
|
|
35206
35498
|
currentLevel,
|
|
@@ -35211,7 +35503,7 @@ class LevelService {
|
|
|
35211
35503
|
async getProgress(user) {
|
|
35212
35504
|
const userLevel = await this.getByUser(user);
|
|
35213
35505
|
const xpToNextLevel = await this.calculateXPToNextLevel(userLevel.currentLevel, userLevel.currentXp);
|
|
35214
|
-
|
|
35506
|
+
logger26.debug("Retrieved progress", { userId: user.id });
|
|
35215
35507
|
return {
|
|
35216
35508
|
level: userLevel.currentLevel,
|
|
35217
35509
|
currentXp: userLevel.currentXp,
|
|
@@ -35245,7 +35537,7 @@ class LevelService {
|
|
|
35245
35537
|
if (leveledUp && previousUserLevel) {
|
|
35246
35538
|
await this.awardLevelUpCredits(userId, previousUserLevel.currentLevel, currentLevel);
|
|
35247
35539
|
}
|
|
35248
|
-
|
|
35540
|
+
logger26.info("Synced from Timeback", {
|
|
35249
35541
|
userId,
|
|
35250
35542
|
totalXP,
|
|
35251
35543
|
currentLevel,
|
|
@@ -35286,7 +35578,7 @@ class LevelService {
|
|
|
35286
35578
|
}
|
|
35287
35579
|
if (totalCredits > 0) {
|
|
35288
35580
|
await this.deps.addCredits(userId, totalCredits);
|
|
35289
|
-
|
|
35581
|
+
logger26.info("Awarded level-up credits", {
|
|
35290
35582
|
userId,
|
|
35291
35583
|
fromLevel,
|
|
35292
35584
|
toLevel,
|
|
@@ -35324,14 +35616,14 @@ class LevelService {
|
|
|
35324
35616
|
};
|
|
35325
35617
|
}
|
|
35326
35618
|
}
|
|
35327
|
-
var
|
|
35619
|
+
var logger26, levelConfigCache = null;
|
|
35328
35620
|
var init_level_service = __esm(() => {
|
|
35329
35621
|
init_drizzle_orm();
|
|
35330
35622
|
init_src();
|
|
35331
35623
|
init_tables_index();
|
|
35332
35624
|
init_src2();
|
|
35333
35625
|
init_errors();
|
|
35334
|
-
|
|
35626
|
+
logger26 = log.scope("LevelService");
|
|
35335
35627
|
});
|
|
35336
35628
|
|
|
35337
35629
|
// ../realtime/src/server/domain/events.ts
|
|
@@ -35352,13 +35644,13 @@ async function publishToUser(baseUrl, secret, userId, type, payload) {
|
|
|
35352
35644
|
});
|
|
35353
35645
|
if (!res.ok) {
|
|
35354
35646
|
const text3 = await res.text().catch(() => "");
|
|
35355
|
-
|
|
35647
|
+
logger27.warn("Failed to publish to user", {
|
|
35356
35648
|
status: res.status,
|
|
35357
35649
|
body: text3
|
|
35358
35650
|
});
|
|
35359
35651
|
}
|
|
35360
35652
|
} catch (error) {
|
|
35361
|
-
|
|
35653
|
+
logger27.error("Publish to user error", { error });
|
|
35362
35654
|
}
|
|
35363
35655
|
}
|
|
35364
35656
|
|
|
@@ -35380,7 +35672,7 @@ class NotificationService {
|
|
|
35380
35672
|
conditions2.push(eq(notifications.type, type));
|
|
35381
35673
|
}
|
|
35382
35674
|
const results = await this.deps.db.select().from(notifications).where(and(...conditions2)).orderBy(desc(notifications.createdAt)).limit(limit).offset(offset);
|
|
35383
|
-
|
|
35675
|
+
logger27.debug("Listed notifications", { userId: user.id, count: results.length });
|
|
35384
35676
|
return results;
|
|
35385
35677
|
}
|
|
35386
35678
|
async updateStatus(notificationId, status, method) {
|
|
@@ -35399,7 +35691,7 @@ class NotificationService {
|
|
|
35399
35691
|
if (!updated) {
|
|
35400
35692
|
throw new NotFoundError("Notification", notificationId);
|
|
35401
35693
|
}
|
|
35402
|
-
|
|
35694
|
+
logger27.debug("Updated status", { notificationId, status });
|
|
35403
35695
|
return updated;
|
|
35404
35696
|
}
|
|
35405
35697
|
async getStats(user, options) {
|
|
@@ -35425,7 +35717,7 @@ class NotificationService {
|
|
|
35425
35717
|
const clicked = statsMap.clicked || 0;
|
|
35426
35718
|
const dismissed = statsMap.dismissed || 0;
|
|
35427
35719
|
const expired = statsMap.expired || 0;
|
|
35428
|
-
|
|
35720
|
+
logger27.debug("Retrieved stats", { userId: user.id, total });
|
|
35429
35721
|
return {
|
|
35430
35722
|
total,
|
|
35431
35723
|
delivered,
|
|
@@ -35474,7 +35766,7 @@ class NotificationService {
|
|
|
35474
35766
|
options: { data, clickUrl, metadata: metadata2 }
|
|
35475
35767
|
});
|
|
35476
35768
|
}
|
|
35477
|
-
|
|
35769
|
+
logger27.debug("Created notification", {
|
|
35478
35770
|
userId,
|
|
35479
35771
|
type,
|
|
35480
35772
|
id: notificationId,
|
|
@@ -35482,7 +35774,7 @@ class NotificationService {
|
|
|
35482
35774
|
});
|
|
35483
35775
|
return notificationId;
|
|
35484
35776
|
} catch (error) {
|
|
35485
|
-
|
|
35777
|
+
logger27.error("Failed to create notification", { userId, type, error });
|
|
35486
35778
|
return null;
|
|
35487
35779
|
}
|
|
35488
35780
|
}
|
|
@@ -35496,7 +35788,7 @@ class NotificationService {
|
|
|
35496
35788
|
}) {
|
|
35497
35789
|
const realtimeConfig = this.deps.realtime;
|
|
35498
35790
|
if (!realtimeConfig) {
|
|
35499
|
-
|
|
35791
|
+
logger27.warn("No realtime config for publish");
|
|
35500
35792
|
return;
|
|
35501
35793
|
}
|
|
35502
35794
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -35538,13 +35830,13 @@ class NotificationService {
|
|
|
35538
35830
|
metadata: data.metadata || {}
|
|
35539
35831
|
}).returning();
|
|
35540
35832
|
if (!notification) {
|
|
35541
|
-
|
|
35833
|
+
logger27.error("Notification insert returned no rows", {
|
|
35542
35834
|
userId: data.userId,
|
|
35543
35835
|
type: data.type
|
|
35544
35836
|
});
|
|
35545
35837
|
throw new InternalError("Failed to create notification");
|
|
35546
35838
|
}
|
|
35547
|
-
|
|
35839
|
+
logger27.info("Inserted notification", {
|
|
35548
35840
|
notificationId: notification.id,
|
|
35549
35841
|
userId: notification.userId,
|
|
35550
35842
|
type: notification.type
|
|
@@ -35554,7 +35846,7 @@ class NotificationService {
|
|
|
35554
35846
|
async deliverPending(userId) {
|
|
35555
35847
|
const realtimeConfig = this.deps.realtime;
|
|
35556
35848
|
if (!realtimeConfig) {
|
|
35557
|
-
|
|
35849
|
+
logger27.warn("No realtime config for delivery");
|
|
35558
35850
|
return;
|
|
35559
35851
|
}
|
|
35560
35852
|
const { relayUrl, publishSecret } = realtimeConfig;
|
|
@@ -35581,13 +35873,13 @@ class NotificationService {
|
|
|
35581
35873
|
metadata: notification.metadata,
|
|
35582
35874
|
clickUrl: notification.clickUrl
|
|
35583
35875
|
});
|
|
35584
|
-
|
|
35876
|
+
logger27.info("Delivered notification", {
|
|
35585
35877
|
notificationId: notification.id,
|
|
35586
35878
|
userId,
|
|
35587
35879
|
type: notification.type
|
|
35588
35880
|
});
|
|
35589
35881
|
} catch (error) {
|
|
35590
|
-
|
|
35882
|
+
logger27.warn("Failed to deliver", {
|
|
35591
35883
|
notificationId: notification.id,
|
|
35592
35884
|
error
|
|
35593
35885
|
});
|
|
@@ -35595,7 +35887,7 @@ class NotificationService {
|
|
|
35595
35887
|
}
|
|
35596
35888
|
}
|
|
35597
35889
|
}
|
|
35598
|
-
var
|
|
35890
|
+
var logger27;
|
|
35599
35891
|
var init_notification_service = __esm(() => {
|
|
35600
35892
|
init_drizzle_orm();
|
|
35601
35893
|
init_src();
|
|
@@ -35604,7 +35896,7 @@ var init_notification_service = __esm(() => {
|
|
|
35604
35896
|
init_events();
|
|
35605
35897
|
init_notification();
|
|
35606
35898
|
init_errors();
|
|
35607
|
-
|
|
35899
|
+
logger27 = log.scope("NotificationService");
|
|
35608
35900
|
});
|
|
35609
35901
|
|
|
35610
35902
|
// ../api-core/src/services/factory/player.ts
|
|
@@ -35728,7 +36020,7 @@ class CharacterService {
|
|
|
35728
36020
|
createdAt: characterComponents.createdAt,
|
|
35729
36021
|
updatedAt: characterComponents.updatedAt
|
|
35730
36022
|
}).from(characterComponents).innerJoin(spriteSheets, eq(characterComponents.spriteSheetId, spriteSheets.id)).where(lte(characterComponents.unlockLevel, level)).orderBy(characterComponents.componentType, characterComponents.variant);
|
|
35731
|
-
|
|
36023
|
+
logger28.debug("Listed available components", {
|
|
35732
36024
|
level,
|
|
35733
36025
|
count: components.length
|
|
35734
36026
|
});
|
|
@@ -35746,7 +36038,7 @@ class CharacterService {
|
|
|
35746
36038
|
}
|
|
35747
36039
|
}
|
|
35748
36040
|
});
|
|
35749
|
-
|
|
36041
|
+
logger28.debug("Retrieved character", { userId: user.id, found: Boolean(pc) });
|
|
35750
36042
|
return pc ?? null;
|
|
35751
36043
|
}
|
|
35752
36044
|
async getByUserId(userId) {
|
|
@@ -35761,7 +36053,7 @@ class CharacterService {
|
|
|
35761
36053
|
}
|
|
35762
36054
|
}
|
|
35763
36055
|
});
|
|
35764
|
-
|
|
36056
|
+
logger28.debug("Retrieved character by ID", { userId, found: Boolean(pc) });
|
|
35765
36057
|
return pc ?? null;
|
|
35766
36058
|
}
|
|
35767
36059
|
async create(input, user) {
|
|
@@ -35776,13 +36068,13 @@ class CharacterService {
|
|
|
35776
36068
|
}
|
|
35777
36069
|
const [characterRow] = await tx.insert(playerCharacters).values({ ...input, userId: user.id }).returning();
|
|
35778
36070
|
if (!characterRow) {
|
|
35779
|
-
|
|
36071
|
+
logger28.error("Character insert returned no rows", { userId: user.id });
|
|
35780
36072
|
throw new InternalError("Failed to create character in database");
|
|
35781
36073
|
}
|
|
35782
36074
|
await tx.update(users).set({ characterCreated: true }).where(eq(users.id, user.id));
|
|
35783
36075
|
return characterRow;
|
|
35784
36076
|
});
|
|
35785
|
-
|
|
36077
|
+
logger28.info("Created character", { userId: user.id, characterId: result.id });
|
|
35786
36078
|
return result;
|
|
35787
36079
|
}
|
|
35788
36080
|
async update(input, user) {
|
|
@@ -35794,7 +36086,7 @@ class CharacterService {
|
|
|
35794
36086
|
if (!row) {
|
|
35795
36087
|
throw new NotFoundError("Player character");
|
|
35796
36088
|
}
|
|
35797
|
-
|
|
36089
|
+
logger28.info("Updated character", {
|
|
35798
36090
|
userId: user.id,
|
|
35799
36091
|
characterId: row.id,
|
|
35800
36092
|
updatedFields: Object.keys(input)
|
|
@@ -35816,7 +36108,7 @@ class CharacterService {
|
|
|
35816
36108
|
const availableComponents = await db2.select().from(characterComponents).where(lte(characterComponents.unlockLevel, playerLevel));
|
|
35817
36109
|
const validation = validateAccessorySlot(accessoryComponentId, slot, playerLevel, availableComponents);
|
|
35818
36110
|
if (!validation.isValid) {
|
|
35819
|
-
|
|
36111
|
+
logger28.warn("Accessory validation failed", {
|
|
35820
36112
|
userId: user.id,
|
|
35821
36113
|
slot,
|
|
35822
36114
|
accessoryComponentId,
|
|
@@ -35832,14 +36124,14 @@ class CharacterService {
|
|
|
35832
36124
|
slot
|
|
35833
36125
|
}).returning();
|
|
35834
36126
|
if (!result) {
|
|
35835
|
-
|
|
36127
|
+
logger28.error("Accessory insert returned no rows", {
|
|
35836
36128
|
userId: user.id,
|
|
35837
36129
|
slot,
|
|
35838
36130
|
accessoryComponentId
|
|
35839
36131
|
});
|
|
35840
36132
|
throw new InternalError("Failed to equip accessory");
|
|
35841
36133
|
}
|
|
35842
|
-
|
|
36134
|
+
logger28.info("Equipped accessory", {
|
|
35843
36135
|
userId: user.id,
|
|
35844
36136
|
slot,
|
|
35845
36137
|
accessoryComponentId
|
|
@@ -35860,7 +36152,7 @@ class CharacterService {
|
|
|
35860
36152
|
const playerLevel = userLevel?.currentLevel ?? 1;
|
|
35861
36153
|
const validation = validateAccessoryRemoval(slot, playerLevel);
|
|
35862
36154
|
if (!validation.isValid) {
|
|
35863
|
-
|
|
36155
|
+
logger28.warn("Accessory removal validation failed", {
|
|
35864
36156
|
userId: user.id,
|
|
35865
36157
|
slot,
|
|
35866
36158
|
playerLevel,
|
|
@@ -35869,17 +36161,17 @@ class CharacterService {
|
|
|
35869
36161
|
throw new ValidationError(validation.error ?? "Invalid accessory removal");
|
|
35870
36162
|
}
|
|
35871
36163
|
await db2.delete(playerCharacterAccessories).where(and(eq(playerCharacterAccessories.playerCharacterId, playerCharacter.id), eq(playerCharacterAccessories.slot, slot)));
|
|
35872
|
-
|
|
36164
|
+
logger28.info("Removed accessory", { userId: user.id, slot });
|
|
35873
36165
|
}
|
|
35874
36166
|
}
|
|
35875
|
-
var
|
|
36167
|
+
var logger28;
|
|
35876
36168
|
var init_character_service = __esm(() => {
|
|
35877
36169
|
init_drizzle_orm();
|
|
35878
36170
|
init_tables_index();
|
|
35879
36171
|
init_src2();
|
|
35880
36172
|
init_errors();
|
|
35881
36173
|
init_accessory_util();
|
|
35882
|
-
|
|
36174
|
+
logger28 = log.scope("CharacterService");
|
|
35883
36175
|
});
|
|
35884
36176
|
|
|
35885
36177
|
// ../api-core/src/services/currency.service.ts
|
|
@@ -35891,7 +36183,7 @@ class CurrencyService {
|
|
|
35891
36183
|
async list() {
|
|
35892
36184
|
const db2 = this.deps.db;
|
|
35893
36185
|
const allCurrencies = await db2.query.currencies.findMany();
|
|
35894
|
-
|
|
36186
|
+
logger29.debug("Listed currencies", { count: allCurrencies.length });
|
|
35895
36187
|
return allCurrencies;
|
|
35896
36188
|
}
|
|
35897
36189
|
async getById(currencyId) {
|
|
@@ -35902,7 +36194,7 @@ class CurrencyService {
|
|
|
35902
36194
|
if (!currency) {
|
|
35903
36195
|
throw new NotFoundError("Currency", currencyId);
|
|
35904
36196
|
}
|
|
35905
|
-
|
|
36197
|
+
logger29.debug("Retrieved currency", { currencyId });
|
|
35906
36198
|
return currency;
|
|
35907
36199
|
}
|
|
35908
36200
|
async create(data) {
|
|
@@ -35910,13 +36202,13 @@ class CurrencyService {
|
|
|
35910
36202
|
try {
|
|
35911
36203
|
const [newCurrency] = await db2.insert(currencies).values(data).returning();
|
|
35912
36204
|
if (!newCurrency) {
|
|
35913
|
-
|
|
36205
|
+
logger29.error("Currency insert returned no rows", {
|
|
35914
36206
|
itemId: data.itemId,
|
|
35915
36207
|
symbol: data.symbol
|
|
35916
36208
|
});
|
|
35917
36209
|
throw new InternalError("Failed to create currency");
|
|
35918
36210
|
}
|
|
35919
|
-
|
|
36211
|
+
logger29.info("Created currency", {
|
|
35920
36212
|
currencyId: newCurrency.id,
|
|
35921
36213
|
itemId: newCurrency.itemId,
|
|
35922
36214
|
symbol: newCurrency.symbol,
|
|
@@ -35945,7 +36237,7 @@ class CurrencyService {
|
|
|
35945
36237
|
if (!updatedCurrency) {
|
|
35946
36238
|
throw new NotFoundError("Currency", currencyId);
|
|
35947
36239
|
}
|
|
35948
|
-
|
|
36240
|
+
logger29.info("Updated currency", {
|
|
35949
36241
|
currencyId: updatedCurrency.id,
|
|
35950
36242
|
updatedFields: Object.keys(data)
|
|
35951
36243
|
});
|
|
@@ -35971,16 +36263,16 @@ class CurrencyService {
|
|
|
35971
36263
|
if (result.length === 0) {
|
|
35972
36264
|
throw new NotFoundError("Currency", currencyId);
|
|
35973
36265
|
}
|
|
35974
|
-
|
|
36266
|
+
logger29.info("Deleted currency", { currencyId });
|
|
35975
36267
|
}
|
|
35976
36268
|
}
|
|
35977
|
-
var
|
|
36269
|
+
var logger29;
|
|
35978
36270
|
var init_currency_service = __esm(() => {
|
|
35979
36271
|
init_drizzle_orm();
|
|
35980
36272
|
init_tables_index();
|
|
35981
36273
|
init_src2();
|
|
35982
36274
|
init_errors();
|
|
35983
|
-
|
|
36275
|
+
logger29 = log.scope("CurrencyService");
|
|
35984
36276
|
});
|
|
35985
36277
|
|
|
35986
36278
|
// ../api-core/src/services/logs.service.ts
|
|
@@ -35999,11 +36291,11 @@ class LogsService {
|
|
|
35999
36291
|
if (!game) {
|
|
36000
36292
|
throw new NotFoundError("Game", slug2);
|
|
36001
36293
|
}
|
|
36002
|
-
|
|
36294
|
+
logger30.info("Admin accessing game logs", { adminId: user.id, slug: slug2, sstStage });
|
|
36003
36295
|
} else {
|
|
36004
36296
|
const isApprovedDev = user.developerStatus === "approved";
|
|
36005
36297
|
if (!isApprovedDev) {
|
|
36006
|
-
|
|
36298
|
+
logger30.warn("Unapproved developer attempted log access", { userId: user.id, slug: slug2 });
|
|
36007
36299
|
throw new AccessDeniedError("Must be an approved developer");
|
|
36008
36300
|
}
|
|
36009
36301
|
const game = await db2.query.games.findFirst({
|
|
@@ -36018,7 +36310,7 @@ class LogsService {
|
|
|
36018
36310
|
columns: { id: true }
|
|
36019
36311
|
});
|
|
36020
36312
|
if (!membership) {
|
|
36021
|
-
|
|
36313
|
+
logger30.warn("Developer attempted access to unowned game logs", {
|
|
36022
36314
|
userId: user.id,
|
|
36023
36315
|
slug: slug2
|
|
36024
36316
|
});
|
|
@@ -36027,7 +36319,7 @@ class LogsService {
|
|
|
36027
36319
|
}
|
|
36028
36320
|
const workerId = getDeploymentId(slug2, sstStage);
|
|
36029
36321
|
const token = await this.deps.mintLogStreamToken(user.id, workerId);
|
|
36030
|
-
|
|
36322
|
+
logger30.debug("Generated log stream token", {
|
|
36031
36323
|
userId: user.id,
|
|
36032
36324
|
slug: slug2,
|
|
36033
36325
|
workerId
|
|
@@ -36035,14 +36327,14 @@ class LogsService {
|
|
|
36035
36327
|
return { token, workerId };
|
|
36036
36328
|
}
|
|
36037
36329
|
}
|
|
36038
|
-
var
|
|
36330
|
+
var logger30;
|
|
36039
36331
|
var init_logs_service = __esm(() => {
|
|
36040
36332
|
init_drizzle_orm();
|
|
36041
36333
|
init_tables_index();
|
|
36042
36334
|
init_src2();
|
|
36043
36335
|
init_errors();
|
|
36044
36336
|
init_deployment_util();
|
|
36045
|
-
|
|
36337
|
+
logger30 = log.scope("LogsService");
|
|
36046
36338
|
});
|
|
36047
36339
|
|
|
36048
36340
|
// ../api-core/src/services/lti.service.ts
|
|
@@ -36095,7 +36387,7 @@ class MapService {
|
|
|
36095
36387
|
if (!mapDetails) {
|
|
36096
36388
|
throw new NotFoundError("Map", identifier);
|
|
36097
36389
|
}
|
|
36098
|
-
|
|
36390
|
+
logger31.debug("Retrieved map", { identifier });
|
|
36099
36391
|
return mapDetails;
|
|
36100
36392
|
}
|
|
36101
36393
|
async getElements(mapId) {
|
|
@@ -36111,7 +36403,7 @@ class MapService {
|
|
|
36111
36403
|
}
|
|
36112
36404
|
}
|
|
36113
36405
|
});
|
|
36114
|
-
|
|
36406
|
+
logger31.debug("Retrieved elements", { mapId, count: elements.length });
|
|
36115
36407
|
return elements;
|
|
36116
36408
|
}
|
|
36117
36409
|
async getObjects(mapId, userId) {
|
|
@@ -36132,7 +36424,7 @@ class MapService {
|
|
|
36132
36424
|
}
|
|
36133
36425
|
}
|
|
36134
36426
|
});
|
|
36135
|
-
|
|
36427
|
+
logger31.debug("Retrieved objects", { mapId, userId, count: objects.length });
|
|
36136
36428
|
return objects.map((object) => this.formatMapObjectWithItem(object));
|
|
36137
36429
|
}
|
|
36138
36430
|
async createObject(mapId, data, user) {
|
|
@@ -36159,7 +36451,7 @@ class MapService {
|
|
|
36159
36451
|
throw new NotFoundError("Item", data.itemId);
|
|
36160
36452
|
}
|
|
36161
36453
|
if (!item.isPlaceable) {
|
|
36162
|
-
|
|
36454
|
+
logger31.warn("Attempted to place non-placeable item", {
|
|
36163
36455
|
userId: user.id,
|
|
36164
36456
|
itemId: data.itemId,
|
|
36165
36457
|
mapId
|
|
@@ -36173,7 +36465,7 @@ class MapService {
|
|
|
36173
36465
|
};
|
|
36174
36466
|
const [createdObject] = await db2.insert(mapObjects).values(objectData).returning();
|
|
36175
36467
|
if (!createdObject) {
|
|
36176
|
-
|
|
36468
|
+
logger31.error("Map object insert returned no rows", {
|
|
36177
36469
|
userId: user.id,
|
|
36178
36470
|
mapId,
|
|
36179
36471
|
itemId: data.itemId
|
|
@@ -36197,12 +36489,12 @@ class MapService {
|
|
|
36197
36489
|
}
|
|
36198
36490
|
});
|
|
36199
36491
|
if (!objectWithItem) {
|
|
36200
|
-
|
|
36492
|
+
logger31.error("Map object query after insert returned no rows", {
|
|
36201
36493
|
objectId: createdObject.id
|
|
36202
36494
|
});
|
|
36203
36495
|
throw new InternalError("Failed to retrieve created object");
|
|
36204
36496
|
}
|
|
36205
|
-
|
|
36497
|
+
logger31.info("Created object", {
|
|
36206
36498
|
userId: user.id,
|
|
36207
36499
|
mapId,
|
|
36208
36500
|
objectId: createdObject.id,
|
|
@@ -36226,7 +36518,7 @@ class MapService {
|
|
|
36226
36518
|
if (result.length === 0) {
|
|
36227
36519
|
throw new NotFoundError("MapObject", objectId);
|
|
36228
36520
|
}
|
|
36229
|
-
|
|
36521
|
+
logger31.info("Deleted object", {
|
|
36230
36522
|
userId: user.id,
|
|
36231
36523
|
mapId,
|
|
36232
36524
|
objectId
|
|
@@ -36255,13 +36547,13 @@ class MapService {
|
|
|
36255
36547
|
};
|
|
36256
36548
|
}
|
|
36257
36549
|
}
|
|
36258
|
-
var
|
|
36550
|
+
var logger31;
|
|
36259
36551
|
var init_map_service = __esm(() => {
|
|
36260
36552
|
init_drizzle_orm();
|
|
36261
36553
|
init_tables_index();
|
|
36262
36554
|
init_src2();
|
|
36263
36555
|
init_errors();
|
|
36264
|
-
|
|
36556
|
+
logger31 = log.scope("MapService");
|
|
36265
36557
|
});
|
|
36266
36558
|
|
|
36267
36559
|
// ../api-core/src/services/realtime.service.ts
|
|
@@ -36296,20 +36588,20 @@ class RealtimeService {
|
|
|
36296
36588
|
}
|
|
36297
36589
|
const displayName = user.username || (user.name ? user.name.split(" ")[0] : undefined) || undefined;
|
|
36298
36590
|
const token = await this.deps.mintRealtimeToken(user.id, resolvedGameId, displayName, user.role);
|
|
36299
|
-
|
|
36591
|
+
logger32.info("Generated token", {
|
|
36300
36592
|
userId: user.id,
|
|
36301
36593
|
gameId: resolvedGameId || "global"
|
|
36302
36594
|
});
|
|
36303
36595
|
return { token };
|
|
36304
36596
|
}
|
|
36305
36597
|
}
|
|
36306
|
-
var
|
|
36598
|
+
var logger32;
|
|
36307
36599
|
var init_realtime_service = __esm(() => {
|
|
36308
36600
|
init_drizzle_orm();
|
|
36309
36601
|
init_tables_index();
|
|
36310
36602
|
init_src2();
|
|
36311
36603
|
init_errors();
|
|
36312
|
-
|
|
36604
|
+
logger32 = log.scope("RealtimeService");
|
|
36313
36605
|
});
|
|
36314
36606
|
|
|
36315
36607
|
// ../api-core/src/services/session.service.ts
|
|
@@ -36344,10 +36636,10 @@ class SessionService {
|
|
|
36344
36636
|
};
|
|
36345
36637
|
const [newSession] = await db2.insert(gameSessions).values(sessionToInsert).returning({ sessionId: gameSessions.id });
|
|
36346
36638
|
if (!newSession?.sessionId) {
|
|
36347
|
-
|
|
36639
|
+
logger33.error("Game session insert returned no rows", { userId, gameId });
|
|
36348
36640
|
throw new InternalError("Failed to create game session");
|
|
36349
36641
|
}
|
|
36350
|
-
|
|
36642
|
+
logger33.info("Started new session", {
|
|
36351
36643
|
sessionId: newSession.sessionId,
|
|
36352
36644
|
gameId,
|
|
36353
36645
|
userId
|
|
@@ -36368,23 +36660,23 @@ class SessionService {
|
|
|
36368
36660
|
return { success: true, message: "Session already ended" };
|
|
36369
36661
|
}
|
|
36370
36662
|
await db2.update(gameSessions).set({ endedAt: new Date }).where(eq(gameSessions.id, sessionId));
|
|
36371
|
-
|
|
36663
|
+
logger33.info("Ended session", { sessionId, gameId, userId });
|
|
36372
36664
|
return { success: true };
|
|
36373
36665
|
}
|
|
36374
36666
|
async mintToken(gameIdOrSlug, userId) {
|
|
36375
36667
|
const gameId = await this.resolveGameId(gameIdOrSlug);
|
|
36376
36668
|
const result = await this.deps.mintGameToken(gameId, userId);
|
|
36377
|
-
|
|
36669
|
+
logger33.debug("Minted game token", { gameId, userId });
|
|
36378
36670
|
return result;
|
|
36379
36671
|
}
|
|
36380
36672
|
}
|
|
36381
|
-
var
|
|
36673
|
+
var logger33;
|
|
36382
36674
|
var init_session_service = __esm(() => {
|
|
36383
36675
|
init_drizzle_orm();
|
|
36384
36676
|
init_tables_index();
|
|
36385
36677
|
init_src2();
|
|
36386
36678
|
init_errors();
|
|
36387
|
-
|
|
36679
|
+
logger33 = log.scope("SessionService");
|
|
36388
36680
|
});
|
|
36389
36681
|
|
|
36390
36682
|
// ../api-core/src/services/shop.service.ts
|
|
@@ -36430,7 +36722,7 @@ class ShopService {
|
|
|
36430
36722
|
const shopItems = [];
|
|
36431
36723
|
for (const listing of listingsWithRelations) {
|
|
36432
36724
|
if (!listing.item || !listing.currency) {
|
|
36433
|
-
|
|
36725
|
+
logger34.warn("Listing missing item or currency, skipping", {
|
|
36434
36726
|
listingId: listing.id
|
|
36435
36727
|
});
|
|
36436
36728
|
} else {
|
|
@@ -36447,7 +36739,7 @@ class ShopService {
|
|
|
36447
36739
|
});
|
|
36448
36740
|
}
|
|
36449
36741
|
}
|
|
36450
|
-
|
|
36742
|
+
logger34.debug("Retrieved shop view", {
|
|
36451
36743
|
userId: user.id,
|
|
36452
36744
|
itemCount: shopItems.length,
|
|
36453
36745
|
currencyCount: shopCurrencies.length
|
|
@@ -36458,12 +36750,12 @@ class ShopService {
|
|
|
36458
36750
|
};
|
|
36459
36751
|
}
|
|
36460
36752
|
}
|
|
36461
|
-
var
|
|
36753
|
+
var logger34;
|
|
36462
36754
|
var init_shop_service = __esm(() => {
|
|
36463
36755
|
init_drizzle_orm();
|
|
36464
36756
|
init_tables_index();
|
|
36465
36757
|
init_src2();
|
|
36466
|
-
|
|
36758
|
+
logger34 = log.scope("ShopService");
|
|
36467
36759
|
});
|
|
36468
36760
|
|
|
36469
36761
|
// ../api-core/src/services/sprite.service.ts
|
|
@@ -36480,17 +36772,17 @@ class SpriteService {
|
|
|
36480
36772
|
if (!template) {
|
|
36481
36773
|
throw new NotFoundError("SpriteTemplate", slug2);
|
|
36482
36774
|
}
|
|
36483
|
-
|
|
36775
|
+
logger35.debug("Retrieved sprite", { slug: slug2 });
|
|
36484
36776
|
return template;
|
|
36485
36777
|
}
|
|
36486
36778
|
}
|
|
36487
|
-
var
|
|
36779
|
+
var logger35;
|
|
36488
36780
|
var init_sprite_service = __esm(() => {
|
|
36489
36781
|
init_drizzle_orm();
|
|
36490
36782
|
init_tables_index();
|
|
36491
36783
|
init_src2();
|
|
36492
36784
|
init_errors();
|
|
36493
|
-
|
|
36785
|
+
logger35 = log.scope("SpriteService");
|
|
36494
36786
|
});
|
|
36495
36787
|
|
|
36496
36788
|
// ../api-core/src/services/user.service.ts
|
|
@@ -36505,12 +36797,12 @@ class UserService {
|
|
|
36505
36797
|
where: eq(users.id, user.id)
|
|
36506
36798
|
});
|
|
36507
36799
|
if (!userData) {
|
|
36508
|
-
|
|
36800
|
+
logger36.error("User not found", { userId: user.id });
|
|
36509
36801
|
throw new NotFoundError("User", user.id);
|
|
36510
36802
|
}
|
|
36511
36803
|
const timeback2 = userData.timebackId ? await this.fetchTimebackData(userData.timebackId, gameId) : undefined;
|
|
36512
36804
|
if (gameId) {
|
|
36513
|
-
|
|
36805
|
+
logger36.debug("Fetched user profile (game context)", { userId: user.id, gameId });
|
|
36514
36806
|
return {
|
|
36515
36807
|
id: userData.id,
|
|
36516
36808
|
name: userData.name,
|
|
@@ -36523,7 +36815,7 @@ class UserService {
|
|
|
36523
36815
|
const timebackAccount = await db2.query.accounts.findFirst({
|
|
36524
36816
|
where: and(eq(accounts.userId, user.id), eq(accounts.providerId, "timeback"))
|
|
36525
36817
|
});
|
|
36526
|
-
|
|
36818
|
+
logger36.debug("Fetched user profile (platform context)", { userId: user.id });
|
|
36527
36819
|
return {
|
|
36528
36820
|
id: userData.id,
|
|
36529
36821
|
name: userData.name,
|
|
@@ -36546,7 +36838,7 @@ class UserService {
|
|
|
36546
36838
|
columns: { name: true }
|
|
36547
36839
|
});
|
|
36548
36840
|
if (!userData) {
|
|
36549
|
-
|
|
36841
|
+
logger36.error("Demo user not found", { userId });
|
|
36550
36842
|
throw new NotFoundError("User", userId);
|
|
36551
36843
|
}
|
|
36552
36844
|
return {
|
|
@@ -36560,10 +36852,10 @@ class UserService {
|
|
|
36560
36852
|
updatedAt: new Date
|
|
36561
36853
|
}).where(eq(users.id, userId)).returning({ name: users.name });
|
|
36562
36854
|
if (!updatedUser) {
|
|
36563
|
-
|
|
36855
|
+
logger36.error("Demo user not found for profile update", { userId });
|
|
36564
36856
|
throw new NotFoundError("User", userId);
|
|
36565
36857
|
}
|
|
36566
|
-
|
|
36858
|
+
logger36.debug("Updated demo profile", { userId, displayName });
|
|
36567
36859
|
return {
|
|
36568
36860
|
displayName: updatedUser.name,
|
|
36569
36861
|
isDefault: updatedUser.name === DEMO_DISPLAY_NAME_PLACEHOLDER
|
|
@@ -36576,7 +36868,7 @@ class UserService {
|
|
|
36576
36868
|
]);
|
|
36577
36869
|
const enrollments = gameId ? this.filterEnrollmentsByGame(allEnrollments, gameId) : allEnrollments;
|
|
36578
36870
|
const organizations = gameId ? this.filterOrganizationsByEnrollments(allOrganizations, enrollments) : allOrganizations;
|
|
36579
|
-
|
|
36871
|
+
logger36.debug("Fetched Timeback data", {
|
|
36580
36872
|
timebackId,
|
|
36581
36873
|
role,
|
|
36582
36874
|
enrollmentCount: enrollments.length,
|
|
@@ -36585,9 +36877,9 @@ class UserService {
|
|
|
36585
36877
|
return { id: timebackId, role, enrollments, organizations };
|
|
36586
36878
|
}
|
|
36587
36879
|
async fetchStudentProfile(timebackId) {
|
|
36588
|
-
|
|
36880
|
+
logger36.debug("Fetching student profile", { timebackId });
|
|
36589
36881
|
if (!this.deps.timeback) {
|
|
36590
|
-
|
|
36882
|
+
logger36.warn("Timeback client not available");
|
|
36591
36883
|
return { role: "student", organizations: [] };
|
|
36592
36884
|
}
|
|
36593
36885
|
try {
|
|
@@ -36615,14 +36907,14 @@ class UserService {
|
|
|
36615
36907
|
}
|
|
36616
36908
|
return { role, organizations: [...orgMap.values()] };
|
|
36617
36909
|
} catch (error) {
|
|
36618
|
-
|
|
36910
|
+
logger36.warn("Failed to fetch student profile", { error, timebackId });
|
|
36619
36911
|
return { role: "student", organizations: [] };
|
|
36620
36912
|
}
|
|
36621
36913
|
}
|
|
36622
36914
|
async fetchEnrollments(timebackId) {
|
|
36623
|
-
|
|
36915
|
+
logger36.debug("Fetching enrollments", { timebackId });
|
|
36624
36916
|
if (!this.deps.timeback) {
|
|
36625
|
-
|
|
36917
|
+
logger36.warn("Timeback client not available");
|
|
36626
36918
|
return [];
|
|
36627
36919
|
}
|
|
36628
36920
|
try {
|
|
@@ -36643,7 +36935,7 @@ class UserService {
|
|
|
36643
36935
|
orgId: courseToSchool.get(i2.courseId)
|
|
36644
36936
|
}));
|
|
36645
36937
|
} catch (error) {
|
|
36646
|
-
|
|
36938
|
+
logger36.warn("Failed to fetch enrollments", { error, timebackId });
|
|
36647
36939
|
return [];
|
|
36648
36940
|
}
|
|
36649
36941
|
}
|
|
@@ -36658,14 +36950,14 @@ class UserService {
|
|
|
36658
36950
|
return organizations.filter((o) => enrollmentOrgIds.has(o.id));
|
|
36659
36951
|
}
|
|
36660
36952
|
}
|
|
36661
|
-
var
|
|
36953
|
+
var logger36;
|
|
36662
36954
|
var init_user_service = __esm(() => {
|
|
36663
36955
|
init_drizzle_orm();
|
|
36664
36956
|
init_src();
|
|
36665
36957
|
init_tables_index();
|
|
36666
36958
|
init_src2();
|
|
36667
36959
|
init_errors();
|
|
36668
|
-
|
|
36960
|
+
logger36 = log.scope("UserService");
|
|
36669
36961
|
});
|
|
36670
36962
|
|
|
36671
36963
|
// ../api-core/src/services/verify.service.ts
|
|
@@ -36675,16 +36967,16 @@ class VerifyService {
|
|
|
36675
36967
|
this.deps = deps;
|
|
36676
36968
|
}
|
|
36677
36969
|
async verifyGameToken(token) {
|
|
36678
|
-
|
|
36970
|
+
logger37.debug("Verifying game token");
|
|
36679
36971
|
const payload = await this.deps.validateGameToken(token);
|
|
36680
36972
|
if (!payload) {
|
|
36681
|
-
|
|
36973
|
+
logger37.warn("Invalid or expired game token presented");
|
|
36682
36974
|
throw new ValidationError("Invalid or expired token");
|
|
36683
36975
|
}
|
|
36684
36976
|
const gameId = payload.sub;
|
|
36685
36977
|
const userId = payload.uid;
|
|
36686
36978
|
if (typeof gameId !== "string" || typeof userId !== "string") {
|
|
36687
|
-
|
|
36979
|
+
logger37.warn("Game token missing required claims", {
|
|
36688
36980
|
hasGameId: typeof gameId === "string",
|
|
36689
36981
|
hasUserId: typeof userId === "string"
|
|
36690
36982
|
});
|
|
@@ -36695,7 +36987,7 @@ class VerifyService {
|
|
|
36695
36987
|
where: eq(users.id, userId)
|
|
36696
36988
|
});
|
|
36697
36989
|
if (!userData) {
|
|
36698
|
-
|
|
36990
|
+
logger37.error("User not found for valid token", {
|
|
36699
36991
|
userId
|
|
36700
36992
|
});
|
|
36701
36993
|
throw new NotFoundError("User", userId);
|
|
@@ -36709,7 +37001,7 @@ class VerifyService {
|
|
|
36709
37001
|
family_name: undefined,
|
|
36710
37002
|
timeback_id: userData.timebackId || undefined
|
|
36711
37003
|
};
|
|
36712
|
-
|
|
37004
|
+
logger37.info("Token verified", { gameId, userId });
|
|
36713
37005
|
return {
|
|
36714
37006
|
claims: payload,
|
|
36715
37007
|
gameId,
|
|
@@ -36717,13 +37009,13 @@ class VerifyService {
|
|
|
36717
37009
|
};
|
|
36718
37010
|
}
|
|
36719
37011
|
}
|
|
36720
|
-
var
|
|
37012
|
+
var logger37;
|
|
36721
37013
|
var init_verify_service = __esm(() => {
|
|
36722
37014
|
init_drizzle_orm();
|
|
36723
37015
|
init_tables_index();
|
|
36724
37016
|
init_src2();
|
|
36725
37017
|
init_errors();
|
|
36726
|
-
|
|
37018
|
+
logger37 = log.scope("VerifyService");
|
|
36727
37019
|
});
|
|
36728
37020
|
|
|
36729
37021
|
// ../api-core/src/services/factory/standalone.ts
|
|
@@ -41841,7 +42133,7 @@ var humanize = (times) => {
|
|
|
41841
42133
|
}
|
|
41842
42134
|
}
|
|
41843
42135
|
return `${status}`;
|
|
41844
|
-
},
|
|
42136
|
+
}, logger38 = (fn = console.log) => {
|
|
41845
42137
|
return async function logger2(c, next) {
|
|
41846
42138
|
const { method, url: url2 } = c.req;
|
|
41847
42139
|
const path = url2.slice(url2.indexOf("/", 8));
|
|
@@ -42022,7 +42314,7 @@ function createApp(db2, options) {
|
|
|
42022
42314
|
const app = new Hono2;
|
|
42023
42315
|
app.use("*", cors({ origin: "*", credentials: true }));
|
|
42024
42316
|
if (options.verbose && !options.quiet) {
|
|
42025
|
-
app.use("*",
|
|
42317
|
+
app.use("*", logger38());
|
|
42026
42318
|
}
|
|
42027
42319
|
app.use("/api/*", async (c, next) => {
|
|
42028
42320
|
c.set("db", db2);
|
|
@@ -48455,12 +48747,12 @@ var init_session2 = __esm(() => {
|
|
|
48455
48747
|
init_utils();
|
|
48456
48748
|
init_dist5();
|
|
48457
48749
|
PglitePreparedQuery = class PglitePreparedQuery extends PgPreparedQuery {
|
|
48458
|
-
constructor(client, queryString, params,
|
|
48750
|
+
constructor(client, queryString, params, logger39, fields, name3, _isResponseInArrayMode, customResultMapper) {
|
|
48459
48751
|
super({ sql: queryString, params });
|
|
48460
48752
|
this.client = client;
|
|
48461
48753
|
this.queryString = queryString;
|
|
48462
48754
|
this.params = params;
|
|
48463
|
-
this.logger =
|
|
48755
|
+
this.logger = logger39;
|
|
48464
48756
|
this.fields = fields;
|
|
48465
48757
|
this._isResponseInArrayMode = _isResponseInArrayMode;
|
|
48466
48758
|
this.customResultMapper = customResultMapper;
|
|
@@ -48564,11 +48856,11 @@ var init_session2 = __esm(() => {
|
|
|
48564
48856
|
// ../../node_modules/.bun/drizzle-orm@0.42.0+f8aef3f54a4d48e2/node_modules/drizzle-orm/pglite/driver.js
|
|
48565
48857
|
function construct(client, config2 = {}) {
|
|
48566
48858
|
const dialect2 = new PgDialect({ casing: config2.casing });
|
|
48567
|
-
let
|
|
48859
|
+
let logger39;
|
|
48568
48860
|
if (config2.logger === true) {
|
|
48569
|
-
|
|
48861
|
+
logger39 = new DefaultLogger;
|
|
48570
48862
|
} else if (config2.logger !== false) {
|
|
48571
|
-
|
|
48863
|
+
logger39 = config2.logger;
|
|
48572
48864
|
}
|
|
48573
48865
|
let schema2;
|
|
48574
48866
|
if (config2.schema) {
|
|
@@ -48579,7 +48871,7 @@ function construct(client, config2 = {}) {
|
|
|
48579
48871
|
tableNamesMap: tablesConfig.tableNamesMap
|
|
48580
48872
|
};
|
|
48581
48873
|
}
|
|
48582
|
-
const driver = new PgliteDriver(client, dialect2, { logger:
|
|
48874
|
+
const driver = new PgliteDriver(client, dialect2, { logger: logger39 });
|
|
48583
48875
|
const session2 = driver.createSession(schema2);
|
|
48584
48876
|
const db2 = new PgliteDatabase(dialect2, session2, schema2);
|
|
48585
48877
|
db2.$client = client;
|
|
@@ -94793,8 +95085,8 @@ var init_currencies = __esm(() => {
|
|
|
94793
95085
|
});
|
|
94794
95086
|
|
|
94795
95087
|
// src/lib/logging/adapter.ts
|
|
94796
|
-
function setLogger(
|
|
94797
|
-
customLogger =
|
|
95088
|
+
function setLogger(logger39) {
|
|
95089
|
+
customLogger = logger39;
|
|
94798
95090
|
}
|
|
94799
95091
|
function getLogger() {
|
|
94800
95092
|
if (customLogger) {
|
|
@@ -94806,10 +95098,10 @@ function getLogger() {
|
|
|
94806
95098
|
error: (msg) => console.error(msg)
|
|
94807
95099
|
};
|
|
94808
95100
|
}
|
|
94809
|
-
var customLogger,
|
|
95101
|
+
var customLogger, logger39;
|
|
94810
95102
|
var init_adapter = __esm(() => {
|
|
94811
95103
|
init_config();
|
|
94812
|
-
|
|
95104
|
+
logger39 = {
|
|
94813
95105
|
info: (msg) => {
|
|
94814
95106
|
if (customLogger || !config.embedded) {
|
|
94815
95107
|
getLogger().info(msg);
|
|
@@ -94899,7 +95191,7 @@ async function seedCoreGames(db2) {
|
|
|
94899
95191
|
role: "owner"
|
|
94900
95192
|
}).onConflictDoNothing();
|
|
94901
95193
|
} catch (error2) {
|
|
94902
|
-
|
|
95194
|
+
logger39.error(`Error seeding core game '${gameData.slug}': ${error2}`);
|
|
94903
95195
|
}
|
|
94904
95196
|
}
|
|
94905
95197
|
}
|
|
@@ -94949,7 +95241,7 @@ async function seedCurrentProjectGame(db2, project) {
|
|
|
94949
95241
|
}
|
|
94950
95242
|
return newGame;
|
|
94951
95243
|
} catch (error2) {
|
|
94952
|
-
|
|
95244
|
+
logger39.error(`❌ Error seeding project game: ${error2}`);
|
|
94953
95245
|
throw error2;
|
|
94954
95246
|
}
|
|
94955
95247
|
}
|
|
@@ -95742,7 +96034,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95742
96034
|
where: eq(users.id, existingAccount.userId)
|
|
95743
96035
|
});
|
|
95744
96036
|
if (user) {
|
|
95745
|
-
|
|
96037
|
+
logger40.info("Found user by LTI account", {
|
|
95746
96038
|
userId: user.id,
|
|
95747
96039
|
ltiTimebackId
|
|
95748
96040
|
});
|
|
@@ -95771,13 +96063,13 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95771
96063
|
updatedAt: new Date
|
|
95772
96064
|
}).returning({ id: accounts.id });
|
|
95773
96065
|
if (!account) {
|
|
95774
|
-
|
|
96066
|
+
logger40.error("LTI account link insert returned no rows", {
|
|
95775
96067
|
userId: existingUser.id,
|
|
95776
96068
|
ltiTimebackId
|
|
95777
96069
|
});
|
|
95778
96070
|
throw new InternalError("Failed to link LTI account");
|
|
95779
96071
|
}
|
|
95780
|
-
|
|
96072
|
+
logger40.info("Linked LTI account to existing user", {
|
|
95781
96073
|
userId: existingUser.id,
|
|
95782
96074
|
ltiTimebackId
|
|
95783
96075
|
});
|
|
@@ -95797,7 +96089,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95797
96089
|
updatedAt: new Date
|
|
95798
96090
|
}).returning();
|
|
95799
96091
|
if (!insertedUser) {
|
|
95800
|
-
|
|
96092
|
+
logger40.error("LTI user insert returned no rows", { email, ltiTimebackId });
|
|
95801
96093
|
throw new InternalError("Failed to create user");
|
|
95802
96094
|
}
|
|
95803
96095
|
await tx.insert(accounts).values({
|
|
@@ -95812,7 +96104,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95812
96104
|
createdAt: new Date,
|
|
95813
96105
|
updatedAt: new Date
|
|
95814
96106
|
});
|
|
95815
|
-
|
|
96107
|
+
logger40.info("Provisioned new user from LTI", {
|
|
95816
96108
|
userId: insertedUser.id,
|
|
95817
96109
|
ltiTimebackId
|
|
95818
96110
|
});
|
|
@@ -95820,7 +96112,7 @@ async function provisionLtiUser(db2, claims) {
|
|
|
95820
96112
|
});
|
|
95821
96113
|
return createdUser;
|
|
95822
96114
|
}
|
|
95823
|
-
var
|
|
96115
|
+
var logger40;
|
|
95824
96116
|
var init_lti_provisioning = __esm(() => {
|
|
95825
96117
|
init_drizzle_orm();
|
|
95826
96118
|
init_src();
|
|
@@ -95828,7 +96120,7 @@ var init_lti_provisioning = __esm(() => {
|
|
|
95828
96120
|
init_src2();
|
|
95829
96121
|
init_errors();
|
|
95830
96122
|
init_lti_util();
|
|
95831
|
-
|
|
96123
|
+
logger40 = log.scope("LtiProvisioning");
|
|
95832
96124
|
});
|
|
95833
96125
|
|
|
95834
96126
|
// ../api-core/src/utils/validation.util.ts
|
|
@@ -95876,21 +96168,21 @@ var init_utils11 = __esm(() => {
|
|
|
95876
96168
|
});
|
|
95877
96169
|
|
|
95878
96170
|
// ../api-core/src/controllers/achievement.controller.ts
|
|
95879
|
-
var
|
|
96171
|
+
var logger41, listCurrent, listHistory, postProgress, achievements3;
|
|
95880
96172
|
var init_achievement_controller = __esm(() => {
|
|
95881
96173
|
init_esm();
|
|
95882
96174
|
init_schemas_index();
|
|
95883
96175
|
init_src2();
|
|
95884
96176
|
init_errors();
|
|
95885
96177
|
init_utils11();
|
|
95886
|
-
|
|
96178
|
+
logger41 = log.scope("AchievementController");
|
|
95887
96179
|
listCurrent = requireNonAnonymous(async (ctx) => {
|
|
95888
|
-
|
|
96180
|
+
logger41.debug("Listing current achievements", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
95889
96181
|
return ctx.services.achievement.listCurrent(ctx.user, ctx.gameId);
|
|
95890
96182
|
});
|
|
95891
96183
|
listHistory = requireNonAnonymous(async (ctx) => {
|
|
95892
96184
|
const limit = Math.max(1, Math.min(100, Number(ctx.url.searchParams.get("limit")) || 20));
|
|
95893
|
-
|
|
96185
|
+
logger41.debug("Listing achievement history", { userId: ctx.user.id, limit });
|
|
95894
96186
|
return ctx.services.achievement.listHistory(ctx.user, limit);
|
|
95895
96187
|
});
|
|
95896
96188
|
postProgress = requireNonAnonymous(async (ctx) => {
|
|
@@ -95901,12 +96193,12 @@ var init_achievement_controller = __esm(() => {
|
|
|
95901
96193
|
} catch (error2) {
|
|
95902
96194
|
if (error2 instanceof exports_external.ZodError) {
|
|
95903
96195
|
const details = formatZodError(error2);
|
|
95904
|
-
|
|
96196
|
+
logger41.warn("Submit achievement progress validation failed", { details });
|
|
95905
96197
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
95906
96198
|
}
|
|
95907
96199
|
throw ApiError.badRequest("Invalid JSON body");
|
|
95908
96200
|
}
|
|
95909
|
-
|
|
96201
|
+
logger41.debug("Submitting progress", {
|
|
95910
96202
|
userId: ctx.user.id,
|
|
95911
96203
|
achievementId: body2.achievementId
|
|
95912
96204
|
});
|
|
@@ -95920,14 +96212,14 @@ var init_achievement_controller = __esm(() => {
|
|
|
95920
96212
|
});
|
|
95921
96213
|
|
|
95922
96214
|
// ../api-core/src/controllers/admin.controller.ts
|
|
95923
|
-
var
|
|
96215
|
+
var logger42, getAllowedOrigins;
|
|
95924
96216
|
var init_admin_controller = __esm(() => {
|
|
95925
96217
|
init_src2();
|
|
95926
96218
|
init_utils11();
|
|
95927
|
-
|
|
96219
|
+
logger42 = log.scope("AdminController");
|
|
95928
96220
|
getAllowedOrigins = requireAdmin(async (ctx) => {
|
|
95929
96221
|
const shouldRefresh = ctx.url.searchParams.get("refresh") === "true";
|
|
95930
|
-
|
|
96222
|
+
logger42.debug("Getting allowed origins", { userId: ctx.user.id, refresh: shouldRefresh });
|
|
95931
96223
|
if (shouldRefresh) {
|
|
95932
96224
|
await ctx.providers.cache.refreshGameOrigins();
|
|
95933
96225
|
}
|
|
@@ -95942,14 +96234,14 @@ var init_admin_controller = __esm(() => {
|
|
|
95942
96234
|
});
|
|
95943
96235
|
|
|
95944
96236
|
// ../api-core/src/controllers/bucket.controller.ts
|
|
95945
|
-
var
|
|
96237
|
+
var logger43, listFiles, getFile, putFile, deleteFile, initiateUpload;
|
|
95946
96238
|
var init_bucket_controller = __esm(() => {
|
|
95947
96239
|
init_esm();
|
|
95948
96240
|
init_schemas_index();
|
|
95949
96241
|
init_src2();
|
|
95950
96242
|
init_errors();
|
|
95951
96243
|
init_utils11();
|
|
95952
|
-
|
|
96244
|
+
logger43 = log.scope("BucketController");
|
|
95953
96245
|
listFiles = requireDeveloper(async (ctx) => {
|
|
95954
96246
|
const slug2 = ctx.params.slug;
|
|
95955
96247
|
if (!slug2) {
|
|
@@ -95957,7 +96249,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95957
96249
|
}
|
|
95958
96250
|
const url2 = ctx.url;
|
|
95959
96251
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
95960
|
-
|
|
96252
|
+
logger43.debug("Listing files", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
95961
96253
|
const files = await ctx.services.bucket.listFiles(slug2, ctx.user, prefix2);
|
|
95962
96254
|
return { files };
|
|
95963
96255
|
});
|
|
@@ -95967,7 +96259,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95967
96259
|
if (!slug2 || !key) {
|
|
95968
96260
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
95969
96261
|
}
|
|
95970
|
-
|
|
96262
|
+
logger43.debug("Getting file", { userId: ctx.user.id, slug: slug2, key });
|
|
95971
96263
|
const object = await ctx.services.bucket.getFile(slug2, key, ctx.user);
|
|
95972
96264
|
return new Response(Buffer.from(object.body), {
|
|
95973
96265
|
status: 200,
|
|
@@ -95986,7 +96278,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
95986
96278
|
const arrayBuffer = await ctx.request.arrayBuffer();
|
|
95987
96279
|
const body2 = new Uint8Array(arrayBuffer);
|
|
95988
96280
|
const contentType = ctx.request.headers.get("content-type") || undefined;
|
|
95989
|
-
|
|
96281
|
+
logger43.debug("Uploading file", {
|
|
95990
96282
|
userId: ctx.user.id,
|
|
95991
96283
|
slug: slug2,
|
|
95992
96284
|
key,
|
|
@@ -96002,7 +96294,7 @@ var init_bucket_controller = __esm(() => {
|
|
|
96002
96294
|
if (!slug2 || !key) {
|
|
96003
96295
|
throw ApiError.badRequest("Missing game slug or file key");
|
|
96004
96296
|
}
|
|
96005
|
-
|
|
96297
|
+
logger43.debug("Deleting file", { userId: ctx.user.id, slug: slug2, key });
|
|
96006
96298
|
await ctx.services.bucket.deleteFile(slug2, key, ctx.user);
|
|
96007
96299
|
return { success: true, key };
|
|
96008
96300
|
});
|
|
@@ -96014,12 +96306,12 @@ var init_bucket_controller = __esm(() => {
|
|
|
96014
96306
|
} catch (error2) {
|
|
96015
96307
|
if (error2 instanceof exports_external.ZodError) {
|
|
96016
96308
|
const details = formatZodError(error2);
|
|
96017
|
-
|
|
96309
|
+
logger43.warn("Initiate upload validation failed", { details });
|
|
96018
96310
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96019
96311
|
}
|
|
96020
96312
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96021
96313
|
}
|
|
96022
|
-
|
|
96314
|
+
logger43.debug("Initiating multipart upload", {
|
|
96023
96315
|
userId: ctx.user.id,
|
|
96024
96316
|
gameId: body2.gameId,
|
|
96025
96317
|
fileName: body2.fileName
|
|
@@ -96036,19 +96328,19 @@ async function listComponents(ctx) {
|
|
|
96036
96328
|
if (!isNaN(parsed) && isFinite(parsed)) {
|
|
96037
96329
|
level = Math.floor(Math.max(0, parsed));
|
|
96038
96330
|
}
|
|
96039
|
-
|
|
96331
|
+
logger44.debug("Listing components", { level });
|
|
96040
96332
|
return ctx.services.character.listAvailableComponents(level);
|
|
96041
96333
|
}
|
|
96042
|
-
var
|
|
96334
|
+
var logger44, get, getByUserId, create, update2, equipAccessory, removeAccessory, character2;
|
|
96043
96335
|
var init_character_controller = __esm(() => {
|
|
96044
96336
|
init_esm();
|
|
96045
96337
|
init_schemas_index();
|
|
96046
96338
|
init_src2();
|
|
96047
96339
|
init_errors();
|
|
96048
96340
|
init_utils11();
|
|
96049
|
-
|
|
96341
|
+
logger44 = log.scope("CharacterController");
|
|
96050
96342
|
get = requireNonAnonymous(async (ctx) => {
|
|
96051
|
-
|
|
96343
|
+
logger44.debug("Getting character", { userId: ctx.user.id });
|
|
96052
96344
|
return ctx.services.character.getByUser(ctx.user);
|
|
96053
96345
|
});
|
|
96054
96346
|
getByUserId = requireNonAnonymous(async (ctx) => {
|
|
@@ -96056,7 +96348,7 @@ var init_character_controller = __esm(() => {
|
|
|
96056
96348
|
if (!userId) {
|
|
96057
96349
|
throw ApiError.badRequest("User ID is required in the URL path");
|
|
96058
96350
|
}
|
|
96059
|
-
|
|
96351
|
+
logger44.debug("Getting character by user ID", { requestedUserId: userId });
|
|
96060
96352
|
return ctx.services.character.getByUserId(userId);
|
|
96061
96353
|
});
|
|
96062
96354
|
create = requireNonAnonymous(async (ctx) => {
|
|
@@ -96067,12 +96359,12 @@ var init_character_controller = __esm(() => {
|
|
|
96067
96359
|
} catch (error2) {
|
|
96068
96360
|
if (error2 instanceof exports_external.ZodError) {
|
|
96069
96361
|
const details = formatZodError(error2);
|
|
96070
|
-
|
|
96362
|
+
logger44.warn("Create character validation failed", { details });
|
|
96071
96363
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96072
96364
|
}
|
|
96073
96365
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96074
96366
|
}
|
|
96075
|
-
|
|
96367
|
+
logger44.debug("Creating character", {
|
|
96076
96368
|
userId: ctx.user.id,
|
|
96077
96369
|
bodyComponentId: body2.bodyComponentId,
|
|
96078
96370
|
hairstyleComponentId: body2.hairstyleComponentId
|
|
@@ -96087,12 +96379,12 @@ var init_character_controller = __esm(() => {
|
|
|
96087
96379
|
} catch (error2) {
|
|
96088
96380
|
if (error2 instanceof exports_external.ZodError) {
|
|
96089
96381
|
const details = formatZodError(error2);
|
|
96090
|
-
|
|
96382
|
+
logger44.warn("Update character validation failed", { details });
|
|
96091
96383
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96092
96384
|
}
|
|
96093
96385
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96094
96386
|
}
|
|
96095
|
-
|
|
96387
|
+
logger44.debug("Updating character", {
|
|
96096
96388
|
userId: ctx.user.id,
|
|
96097
96389
|
bodyComponentId: body2.bodyComponentId,
|
|
96098
96390
|
hairstyleComponentId: body2.hairstyleComponentId,
|
|
@@ -96108,12 +96400,12 @@ var init_character_controller = __esm(() => {
|
|
|
96108
96400
|
} catch (error2) {
|
|
96109
96401
|
if (error2 instanceof exports_external.ZodError) {
|
|
96110
96402
|
const details = formatZodError(error2);
|
|
96111
|
-
|
|
96403
|
+
logger44.warn("Equip accessory validation failed", { details });
|
|
96112
96404
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96113
96405
|
}
|
|
96114
96406
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96115
96407
|
}
|
|
96116
|
-
|
|
96408
|
+
logger44.debug("Equipping accessory", {
|
|
96117
96409
|
userId: ctx.user.id,
|
|
96118
96410
|
slot: body2.slot,
|
|
96119
96411
|
accessoryComponentId: body2.accessoryComponentId
|
|
@@ -96125,7 +96417,7 @@ var init_character_controller = __esm(() => {
|
|
|
96125
96417
|
if (!slot) {
|
|
96126
96418
|
throw ApiError.badRequest("Slot is required in the URL path");
|
|
96127
96419
|
}
|
|
96128
|
-
|
|
96420
|
+
logger44.debug("Removing accessory", { userId: ctx.user.id, slot });
|
|
96129
96421
|
await ctx.services.character.removeAccessory(slot, ctx.user);
|
|
96130
96422
|
return { success: true };
|
|
96131
96423
|
});
|
|
@@ -96141,7 +96433,7 @@ var init_character_controller = __esm(() => {
|
|
|
96141
96433
|
});
|
|
96142
96434
|
|
|
96143
96435
|
// ../api-core/src/controllers/currency.controller.ts
|
|
96144
|
-
var
|
|
96436
|
+
var logger45, list, getById, create2, update3, remove, currencyController;
|
|
96145
96437
|
var init_currency_controller = __esm(() => {
|
|
96146
96438
|
init_esm();
|
|
96147
96439
|
init_schemas_index();
|
|
@@ -96149,9 +96441,9 @@ var init_currency_controller = __esm(() => {
|
|
|
96149
96441
|
init_src4();
|
|
96150
96442
|
init_errors();
|
|
96151
96443
|
init_utils11();
|
|
96152
|
-
|
|
96444
|
+
logger45 = log.scope("CurrencyController");
|
|
96153
96445
|
list = requireNonAnonymous(async (ctx) => {
|
|
96154
|
-
|
|
96446
|
+
logger45.debug("Listing currencies", { userId: ctx.user.id });
|
|
96155
96447
|
return ctx.services.currency.list();
|
|
96156
96448
|
});
|
|
96157
96449
|
getById = requireNonAnonymous(async (ctx) => {
|
|
@@ -96162,7 +96454,7 @@ var init_currency_controller = __esm(() => {
|
|
|
96162
96454
|
if (!isValidUUID(currencyId)) {
|
|
96163
96455
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
96164
96456
|
}
|
|
96165
|
-
|
|
96457
|
+
logger45.debug("Getting currency", { userId: ctx.user.id, currencyId });
|
|
96166
96458
|
return ctx.services.currency.getById(currencyId);
|
|
96167
96459
|
});
|
|
96168
96460
|
create2 = requireAdmin(async (ctx) => {
|
|
@@ -96173,12 +96465,12 @@ var init_currency_controller = __esm(() => {
|
|
|
96173
96465
|
} catch (error2) {
|
|
96174
96466
|
if (error2 instanceof exports_external.ZodError) {
|
|
96175
96467
|
const details = formatZodError(error2);
|
|
96176
|
-
|
|
96468
|
+
logger45.warn("Create currency validation failed", { details });
|
|
96177
96469
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96178
96470
|
}
|
|
96179
96471
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96180
96472
|
}
|
|
96181
|
-
|
|
96473
|
+
logger45.debug("Creating currency", {
|
|
96182
96474
|
userId: ctx.user.id,
|
|
96183
96475
|
symbol: body2.symbol,
|
|
96184
96476
|
itemId: body2.itemId,
|
|
@@ -96201,12 +96493,12 @@ var init_currency_controller = __esm(() => {
|
|
|
96201
96493
|
} catch (error2) {
|
|
96202
96494
|
if (error2 instanceof exports_external.ZodError) {
|
|
96203
96495
|
const details = formatZodError(error2);
|
|
96204
|
-
|
|
96496
|
+
logger45.warn("Update currency validation failed", { details });
|
|
96205
96497
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96206
96498
|
}
|
|
96207
96499
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96208
96500
|
}
|
|
96209
|
-
|
|
96501
|
+
logger45.debug("Updating currency", {
|
|
96210
96502
|
userId: ctx.user.id,
|
|
96211
96503
|
currencyId,
|
|
96212
96504
|
symbol: body2.symbol,
|
|
@@ -96223,7 +96515,7 @@ var init_currency_controller = __esm(() => {
|
|
|
96223
96515
|
if (!isValidUUID(currencyId)) {
|
|
96224
96516
|
throw ApiError.unprocessableEntity("currencyId must be a valid UUID format");
|
|
96225
96517
|
}
|
|
96226
|
-
|
|
96518
|
+
logger45.debug("Deleting currency", { userId: ctx.user.id, currencyId });
|
|
96227
96519
|
await ctx.services.currency.delete(currencyId);
|
|
96228
96520
|
});
|
|
96229
96521
|
currencyController = {
|
|
@@ -96236,14 +96528,14 @@ var init_currency_controller = __esm(() => {
|
|
|
96236
96528
|
});
|
|
96237
96529
|
|
|
96238
96530
|
// ../api-core/src/controllers/database.controller.ts
|
|
96239
|
-
var
|
|
96531
|
+
var logger46, reset;
|
|
96240
96532
|
var init_database_controller = __esm(() => {
|
|
96241
96533
|
init_esm();
|
|
96242
96534
|
init_schemas_index();
|
|
96243
96535
|
init_src2();
|
|
96244
96536
|
init_errors();
|
|
96245
96537
|
init_utils11();
|
|
96246
|
-
|
|
96538
|
+
logger46 = log.scope("DatabaseController");
|
|
96247
96539
|
reset = requireDeveloper(async (ctx) => {
|
|
96248
96540
|
const slug2 = ctx.params.slug;
|
|
96249
96541
|
if (!slug2) {
|
|
@@ -96256,11 +96548,11 @@ var init_database_controller = __esm(() => {
|
|
|
96256
96548
|
} catch (error2) {
|
|
96257
96549
|
if (error2 instanceof exports_external.ZodError) {
|
|
96258
96550
|
const details = formatZodError(error2);
|
|
96259
|
-
|
|
96551
|
+
logger46.warn("Database reset validation failed", { details });
|
|
96260
96552
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96261
96553
|
}
|
|
96262
96554
|
}
|
|
96263
|
-
|
|
96555
|
+
logger46.debug("Resetting database", {
|
|
96264
96556
|
userId: ctx.user.id,
|
|
96265
96557
|
slug: slug2,
|
|
96266
96558
|
hasSchema: Boolean(body2.schema)
|
|
@@ -96278,7 +96570,7 @@ async function createJob(ctx) {
|
|
|
96278
96570
|
let body2;
|
|
96279
96571
|
try {
|
|
96280
96572
|
const json4 = await ctx.request.json();
|
|
96281
|
-
|
|
96573
|
+
logger47.debug("Deploy request body", {
|
|
96282
96574
|
keys: Object.keys(json4 || {}),
|
|
96283
96575
|
hasUploadToken: Boolean(json4?.uploadToken),
|
|
96284
96576
|
hasCode: Boolean(json4?.code),
|
|
@@ -96288,7 +96580,7 @@ async function createJob(ctx) {
|
|
|
96288
96580
|
} catch (error2) {
|
|
96289
96581
|
if (error2 instanceof exports_external.ZodError) {
|
|
96290
96582
|
const details = formatZodError(error2);
|
|
96291
|
-
|
|
96583
|
+
logger47.warn("Deploy validation failed", { details });
|
|
96292
96584
|
throw ApiError.unprocessableEntity("Invalid deploy request", details);
|
|
96293
96585
|
}
|
|
96294
96586
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96309,14 +96601,14 @@ async function getJob(ctx) {
|
|
|
96309
96601
|
}
|
|
96310
96602
|
return ctx.services.deployJobs.get(jobId, slug2, ctx.user);
|
|
96311
96603
|
}
|
|
96312
|
-
var
|
|
96604
|
+
var logger47, deploy;
|
|
96313
96605
|
var init_deploy_controller = __esm(() => {
|
|
96314
96606
|
init_esm();
|
|
96315
96607
|
init_schemas_index();
|
|
96316
96608
|
init_src2();
|
|
96317
96609
|
init_errors();
|
|
96318
96610
|
init_utils11();
|
|
96319
|
-
|
|
96611
|
+
logger47 = log.scope("DeployController");
|
|
96320
96612
|
deploy = {
|
|
96321
96613
|
createJob: requireDeveloper(createJob),
|
|
96322
96614
|
getJob: requireDeveloper(getJob)
|
|
@@ -96324,17 +96616,17 @@ var init_deploy_controller = __esm(() => {
|
|
|
96324
96616
|
});
|
|
96325
96617
|
|
|
96326
96618
|
// ../api-core/src/controllers/developer.controller.ts
|
|
96327
|
-
var
|
|
96619
|
+
var logger48, apply, getStatus, developer;
|
|
96328
96620
|
var init_developer_controller = __esm(() => {
|
|
96329
96621
|
init_src2();
|
|
96330
96622
|
init_utils11();
|
|
96331
|
-
|
|
96623
|
+
logger48 = log.scope("DeveloperController");
|
|
96332
96624
|
apply = requireNonAnonymous(async (ctx) => {
|
|
96333
|
-
|
|
96625
|
+
logger48.debug("Applying for developer status", { userId: ctx.user.id });
|
|
96334
96626
|
await ctx.services.developer.apply(ctx.user);
|
|
96335
96627
|
});
|
|
96336
96628
|
getStatus = requireNonAnonymous(async (ctx) => {
|
|
96337
|
-
|
|
96629
|
+
logger48.debug("Getting developer status", { userId: ctx.user.id });
|
|
96338
96630
|
const status = await ctx.services.developer.getStatus(ctx.user.id);
|
|
96339
96631
|
return { status };
|
|
96340
96632
|
});
|
|
@@ -96345,7 +96637,7 @@ var init_developer_controller = __esm(() => {
|
|
|
96345
96637
|
});
|
|
96346
96638
|
|
|
96347
96639
|
// ../api-core/src/controllers/domain.controller.ts
|
|
96348
|
-
var
|
|
96640
|
+
var logger49, add, list2, getStatus2, remove2, domains2;
|
|
96349
96641
|
var init_domain_controller = __esm(() => {
|
|
96350
96642
|
init_esm();
|
|
96351
96643
|
init_schemas_index();
|
|
@@ -96353,7 +96645,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96353
96645
|
init_config2();
|
|
96354
96646
|
init_errors();
|
|
96355
96647
|
init_utils11();
|
|
96356
|
-
|
|
96648
|
+
logger49 = log.scope("DomainController");
|
|
96357
96649
|
add = requireDeveloper(async (ctx) => {
|
|
96358
96650
|
const slug2 = ctx.params.slug;
|
|
96359
96651
|
if (!slug2) {
|
|
@@ -96366,13 +96658,13 @@ var init_domain_controller = __esm(() => {
|
|
|
96366
96658
|
} catch (error2) {
|
|
96367
96659
|
if (error2 instanceof exports_external.ZodError) {
|
|
96368
96660
|
const details = formatZodError(error2);
|
|
96369
|
-
|
|
96661
|
+
logger49.warn("Add domain validation failed", { details });
|
|
96370
96662
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96371
96663
|
}
|
|
96372
96664
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96373
96665
|
}
|
|
96374
96666
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96375
|
-
|
|
96667
|
+
logger49.debug("Adding domain", {
|
|
96376
96668
|
userId: ctx.user.id,
|
|
96377
96669
|
slug: slug2,
|
|
96378
96670
|
hostname: body2.hostname,
|
|
@@ -96386,7 +96678,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96386
96678
|
throw ApiError.badRequest("Missing game slug");
|
|
96387
96679
|
}
|
|
96388
96680
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96389
|
-
|
|
96681
|
+
logger49.debug("Listing domains", { userId: ctx.user.id, slug: slug2, environment });
|
|
96390
96682
|
const domains2 = await ctx.services.domain.list(slug2, environment, ctx.user);
|
|
96391
96683
|
return { domains: domains2 };
|
|
96392
96684
|
});
|
|
@@ -96401,7 +96693,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96401
96693
|
}
|
|
96402
96694
|
const refresh = ctx.url.searchParams.get("refresh") === "true";
|
|
96403
96695
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96404
|
-
|
|
96696
|
+
logger49.debug("Getting domain status", { userId: ctx.user.id, slug: slug2, hostname, refresh });
|
|
96405
96697
|
return ctx.services.domain.getStatus(slug2, hostname, environment, ctx.user, refresh);
|
|
96406
96698
|
});
|
|
96407
96699
|
remove2 = requireDeveloper(async (ctx) => {
|
|
@@ -96414,7 +96706,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96414
96706
|
throw ApiError.badRequest("Missing hostname");
|
|
96415
96707
|
}
|
|
96416
96708
|
const environment = getPlatformEnvironment(ctx.config);
|
|
96417
|
-
|
|
96709
|
+
logger49.debug("Removing domain", { userId: ctx.user.id, slug: slug2, hostname, environment });
|
|
96418
96710
|
await ctx.services.domain.delete(slug2, hostname, environment, ctx.user);
|
|
96419
96711
|
});
|
|
96420
96712
|
domains2 = {
|
|
@@ -96426,7 +96718,7 @@ var init_domain_controller = __esm(() => {
|
|
|
96426
96718
|
});
|
|
96427
96719
|
|
|
96428
96720
|
// ../api-core/src/controllers/game.controller.ts
|
|
96429
|
-
var
|
|
96721
|
+
var logger50, list3, listAccessible, getSubjects, getById2, getBySlug, getManifest, upsertBySlug, remove3, games2;
|
|
96430
96722
|
var init_game_controller = __esm(() => {
|
|
96431
96723
|
init_esm();
|
|
96432
96724
|
init_schemas_index();
|
|
@@ -96434,17 +96726,17 @@ var init_game_controller = __esm(() => {
|
|
|
96434
96726
|
init_src4();
|
|
96435
96727
|
init_errors();
|
|
96436
96728
|
init_utils11();
|
|
96437
|
-
|
|
96729
|
+
logger50 = log.scope("GameController");
|
|
96438
96730
|
list3 = requireNonAnonymous(async (ctx) => {
|
|
96439
|
-
|
|
96731
|
+
logger50.debug("Listing games", { userId: ctx.user.id });
|
|
96440
96732
|
return ctx.services.game.list(ctx.user);
|
|
96441
96733
|
});
|
|
96442
96734
|
listAccessible = requireNonAnonymous(async (ctx) => {
|
|
96443
|
-
|
|
96735
|
+
logger50.debug("Listing accessible games", { userId: ctx.user.id });
|
|
96444
96736
|
return ctx.services.game.listAccessible(ctx.user);
|
|
96445
96737
|
});
|
|
96446
96738
|
getSubjects = requireNonAnonymous(async (ctx) => {
|
|
96447
|
-
|
|
96739
|
+
logger50.debug("Getting game subjects", { userId: ctx.user.id });
|
|
96448
96740
|
return ctx.services.game.getSubjects();
|
|
96449
96741
|
});
|
|
96450
96742
|
getById2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96455,7 +96747,7 @@ var init_game_controller = __esm(() => {
|
|
|
96455
96747
|
if (!isValidUUID(gameId)) {
|
|
96456
96748
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96457
96749
|
}
|
|
96458
|
-
|
|
96750
|
+
logger50.debug("Getting game by ID", { userId: ctx.user.id, gameId, launchId: ctx.launchId });
|
|
96459
96751
|
return ctx.services.game.getById(gameId, ctx.user);
|
|
96460
96752
|
});
|
|
96461
96753
|
getBySlug = requireNonAnonymous(async (ctx) => {
|
|
@@ -96463,7 +96755,7 @@ var init_game_controller = __esm(() => {
|
|
|
96463
96755
|
if (!slug2) {
|
|
96464
96756
|
throw ApiError.badRequest("Missing game slug");
|
|
96465
96757
|
}
|
|
96466
|
-
|
|
96758
|
+
logger50.debug("Getting game by slug", { userId: ctx.user.id, slug: slug2, launchId: ctx.launchId });
|
|
96467
96759
|
return ctx.services.game.getBySlug(slug2, ctx.user);
|
|
96468
96760
|
});
|
|
96469
96761
|
getManifest = requireNonAnonymous(async (ctx) => {
|
|
@@ -96474,7 +96766,7 @@ var init_game_controller = __esm(() => {
|
|
|
96474
96766
|
if (!isValidUUID(gameId)) {
|
|
96475
96767
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96476
96768
|
}
|
|
96477
|
-
|
|
96769
|
+
logger50.debug("Getting game manifest by ID", {
|
|
96478
96770
|
userId: ctx.user.id,
|
|
96479
96771
|
gameId,
|
|
96480
96772
|
launchId: ctx.launchId
|
|
@@ -96493,12 +96785,12 @@ var init_game_controller = __esm(() => {
|
|
|
96493
96785
|
} catch (error2) {
|
|
96494
96786
|
if (error2 instanceof exports_external.ZodError) {
|
|
96495
96787
|
const details = formatZodError(error2);
|
|
96496
|
-
|
|
96788
|
+
logger50.warn("Upsert game validation failed", { details });
|
|
96497
96789
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96498
96790
|
}
|
|
96499
96791
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96500
96792
|
}
|
|
96501
|
-
|
|
96793
|
+
logger50.debug("Upserting game", { userId: ctx.user.id, slug: slug2, displayName: body2.displayName });
|
|
96502
96794
|
return ctx.services.game.upsertBySlug(slug2, body2, ctx.user);
|
|
96503
96795
|
});
|
|
96504
96796
|
remove3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96509,7 +96801,7 @@ var init_game_controller = __esm(() => {
|
|
|
96509
96801
|
if (!isValidUUID(gameId)) {
|
|
96510
96802
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96511
96803
|
}
|
|
96512
|
-
|
|
96804
|
+
logger50.debug("Deleting game", { userId: ctx.user.id, gameId });
|
|
96513
96805
|
await ctx.services.game.delete(gameId, ctx.user);
|
|
96514
96806
|
});
|
|
96515
96807
|
games2 = {
|
|
@@ -96525,16 +96817,16 @@ var init_game_controller = __esm(() => {
|
|
|
96525
96817
|
});
|
|
96526
96818
|
|
|
96527
96819
|
// ../api-core/src/controllers/inventory.controller.ts
|
|
96528
|
-
var
|
|
96820
|
+
var logger51, list4, addItem, removeItem, inventory;
|
|
96529
96821
|
var init_inventory_controller = __esm(() => {
|
|
96530
96822
|
init_esm();
|
|
96531
96823
|
init_schemas_index();
|
|
96532
96824
|
init_src2();
|
|
96533
96825
|
init_errors();
|
|
96534
96826
|
init_utils11();
|
|
96535
|
-
|
|
96827
|
+
logger51 = log.scope("InventoryController");
|
|
96536
96828
|
list4 = requireNonAnonymous(async (ctx) => {
|
|
96537
|
-
|
|
96829
|
+
logger51.debug("Listing inventory", { userId: ctx.user.id });
|
|
96538
96830
|
return ctx.services.inventory.list(ctx.user);
|
|
96539
96831
|
});
|
|
96540
96832
|
addItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -96545,12 +96837,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
96545
96837
|
} catch (error2) {
|
|
96546
96838
|
if (error2 instanceof exports_external.ZodError) {
|
|
96547
96839
|
const details = formatZodError(error2);
|
|
96548
|
-
|
|
96840
|
+
logger51.warn("Add inventory item validation failed", { details });
|
|
96549
96841
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96550
96842
|
}
|
|
96551
96843
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96552
96844
|
}
|
|
96553
|
-
|
|
96845
|
+
logger51.debug("Adding item", {
|
|
96554
96846
|
userId: ctx.user.id,
|
|
96555
96847
|
itemId: body2.itemId,
|
|
96556
96848
|
qty: body2.qty
|
|
@@ -96565,12 +96857,12 @@ var init_inventory_controller = __esm(() => {
|
|
|
96565
96857
|
} catch (error2) {
|
|
96566
96858
|
if (error2 instanceof exports_external.ZodError) {
|
|
96567
96859
|
const details = formatZodError(error2);
|
|
96568
|
-
|
|
96860
|
+
logger51.warn("Remove inventory item validation failed", { details });
|
|
96569
96861
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
96570
96862
|
}
|
|
96571
96863
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96572
96864
|
}
|
|
96573
|
-
|
|
96865
|
+
logger51.debug("Removing item", {
|
|
96574
96866
|
userId: ctx.user.id,
|
|
96575
96867
|
itemId: body2.itemId,
|
|
96576
96868
|
qty: body2.qty
|
|
@@ -96585,7 +96877,7 @@ var init_inventory_controller = __esm(() => {
|
|
|
96585
96877
|
});
|
|
96586
96878
|
|
|
96587
96879
|
// ../api-core/src/controllers/item.controller.ts
|
|
96588
|
-
var
|
|
96880
|
+
var logger52, list5, getById3, resolve2, create3, update4, remove4, listByGame, createForGame, updateForGame, deleteForGame, items2;
|
|
96589
96881
|
var init_item_controller = __esm(() => {
|
|
96590
96882
|
init_esm();
|
|
96591
96883
|
init_schemas_index();
|
|
@@ -96593,10 +96885,10 @@ var init_item_controller = __esm(() => {
|
|
|
96593
96885
|
init_src4();
|
|
96594
96886
|
init_errors();
|
|
96595
96887
|
init_utils11();
|
|
96596
|
-
|
|
96888
|
+
logger52 = log.scope("ItemController");
|
|
96597
96889
|
list5 = requireNonAnonymous(async (ctx) => {
|
|
96598
96890
|
const gameId = ctx.url.searchParams.get("gameId") || undefined;
|
|
96599
|
-
|
|
96891
|
+
logger52.debug("Listing items", { userId: ctx.user.id, gameId });
|
|
96600
96892
|
return ctx.services.item.list(gameId);
|
|
96601
96893
|
});
|
|
96602
96894
|
getById3 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96607,7 +96899,7 @@ var init_item_controller = __esm(() => {
|
|
|
96607
96899
|
if (!isValidUUID(itemId)) {
|
|
96608
96900
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96609
96901
|
}
|
|
96610
|
-
|
|
96902
|
+
logger52.debug("Getting item", { userId: ctx.user.id, itemId });
|
|
96611
96903
|
return ctx.services.item.getById(itemId);
|
|
96612
96904
|
});
|
|
96613
96905
|
resolve2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -96619,7 +96911,7 @@ var init_item_controller = __esm(() => {
|
|
|
96619
96911
|
if (gameId && !isValidUUID(gameId)) {
|
|
96620
96912
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96621
96913
|
}
|
|
96622
|
-
|
|
96914
|
+
logger52.debug("Resolving item", { userId: ctx.user.id, slug: slug2, gameId });
|
|
96623
96915
|
return ctx.services.item.resolveBySlug(slug2, gameId);
|
|
96624
96916
|
});
|
|
96625
96917
|
create3 = requireRole(["admin"], async (ctx) => {
|
|
@@ -96630,12 +96922,12 @@ var init_item_controller = __esm(() => {
|
|
|
96630
96922
|
} catch (error2) {
|
|
96631
96923
|
if (error2 instanceof exports_external.ZodError) {
|
|
96632
96924
|
const details = formatZodError(error2);
|
|
96633
|
-
|
|
96925
|
+
logger52.warn("Create item validation failed", { details });
|
|
96634
96926
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96635
96927
|
}
|
|
96636
96928
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96637
96929
|
}
|
|
96638
|
-
|
|
96930
|
+
logger52.debug("Creating item", {
|
|
96639
96931
|
userId: ctx.user.id,
|
|
96640
96932
|
slug: body2.slug,
|
|
96641
96933
|
displayName: body2.displayName
|
|
@@ -96657,7 +96949,7 @@ var init_item_controller = __esm(() => {
|
|
|
96657
96949
|
} catch (error2) {
|
|
96658
96950
|
if (error2 instanceof exports_external.ZodError) {
|
|
96659
96951
|
const details = formatZodError(error2);
|
|
96660
|
-
|
|
96952
|
+
logger52.warn("Update item validation failed", { details });
|
|
96661
96953
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96662
96954
|
}
|
|
96663
96955
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96665,7 +96957,7 @@ var init_item_controller = __esm(() => {
|
|
|
96665
96957
|
if (Object.keys(body2).length === 0) {
|
|
96666
96958
|
throw ApiError.badRequest("No update data provided");
|
|
96667
96959
|
}
|
|
96668
|
-
|
|
96960
|
+
logger52.debug("Updating item", {
|
|
96669
96961
|
userId: ctx.user.id,
|
|
96670
96962
|
itemId,
|
|
96671
96963
|
slug: body2.slug,
|
|
@@ -96682,7 +96974,7 @@ var init_item_controller = __esm(() => {
|
|
|
96682
96974
|
if (!isValidUUID(itemId)) {
|
|
96683
96975
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96684
96976
|
}
|
|
96685
|
-
|
|
96977
|
+
logger52.debug("Deleting item", { userId: ctx.user.id, itemId });
|
|
96686
96978
|
await ctx.services.item.delete(itemId);
|
|
96687
96979
|
});
|
|
96688
96980
|
listByGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -96693,7 +96985,7 @@ var init_item_controller = __esm(() => {
|
|
|
96693
96985
|
if (!isValidUUID(gameId)) {
|
|
96694
96986
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
96695
96987
|
}
|
|
96696
|
-
|
|
96988
|
+
logger52.debug("Listing game items", { userId: ctx.user.id, gameId });
|
|
96697
96989
|
return ctx.services.item.listByGame(gameId);
|
|
96698
96990
|
});
|
|
96699
96991
|
createForGame = requireNonAnonymous(async (ctx) => {
|
|
@@ -96711,12 +97003,12 @@ var init_item_controller = __esm(() => {
|
|
|
96711
97003
|
} catch (error2) {
|
|
96712
97004
|
if (error2 instanceof exports_external.ZodError) {
|
|
96713
97005
|
const details = formatZodError(error2);
|
|
96714
|
-
|
|
97006
|
+
logger52.warn("Create game item validation failed", { details });
|
|
96715
97007
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96716
97008
|
}
|
|
96717
97009
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96718
97010
|
}
|
|
96719
|
-
|
|
97011
|
+
logger52.debug("Creating game item", {
|
|
96720
97012
|
userId: ctx.user.id,
|
|
96721
97013
|
gameId,
|
|
96722
97014
|
slug: body2.slug,
|
|
@@ -96743,7 +97035,7 @@ var init_item_controller = __esm(() => {
|
|
|
96743
97035
|
} catch (error2) {
|
|
96744
97036
|
if (error2 instanceof exports_external.ZodError) {
|
|
96745
97037
|
const details = formatZodError(error2);
|
|
96746
|
-
|
|
97038
|
+
logger52.warn("Update game item validation failed", { details });
|
|
96747
97039
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96748
97040
|
}
|
|
96749
97041
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -96751,7 +97043,7 @@ var init_item_controller = __esm(() => {
|
|
|
96751
97043
|
if (Object.keys(body2).length === 0) {
|
|
96752
97044
|
throw ApiError.badRequest("No update data provided");
|
|
96753
97045
|
}
|
|
96754
|
-
|
|
97046
|
+
logger52.debug("Updating game item", {
|
|
96755
97047
|
userId: ctx.user.id,
|
|
96756
97048
|
gameId,
|
|
96757
97049
|
itemId,
|
|
@@ -96773,7 +97065,7 @@ var init_item_controller = __esm(() => {
|
|
|
96773
97065
|
if (!isValidUUID(itemId)) {
|
|
96774
97066
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
96775
97067
|
}
|
|
96776
|
-
|
|
97068
|
+
logger52.debug("Deleting game item", { userId: ctx.user.id, gameId, itemId });
|
|
96777
97069
|
await ctx.services.item.deleteForGame(gameId, itemId, ctx.user);
|
|
96778
97070
|
});
|
|
96779
97071
|
items2 = {
|
|
@@ -96791,14 +97083,14 @@ var init_item_controller = __esm(() => {
|
|
|
96791
97083
|
});
|
|
96792
97084
|
|
|
96793
97085
|
// ../api-core/src/controllers/kv.controller.ts
|
|
96794
|
-
var
|
|
97086
|
+
var logger53, listKeys, getStats, seed, getValue2, setValue2, deleteValue, getMetadata, clear;
|
|
96795
97087
|
var init_kv_controller = __esm(() => {
|
|
96796
97088
|
init_esm();
|
|
96797
97089
|
init_schemas_index();
|
|
96798
97090
|
init_src2();
|
|
96799
97091
|
init_errors();
|
|
96800
97092
|
init_utils11();
|
|
96801
|
-
|
|
97093
|
+
logger53 = log.scope("KVController");
|
|
96802
97094
|
listKeys = requireDeveloper(async (ctx) => {
|
|
96803
97095
|
const slug2 = ctx.params.slug;
|
|
96804
97096
|
if (!slug2) {
|
|
@@ -96806,7 +97098,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96806
97098
|
}
|
|
96807
97099
|
const url2 = ctx.url;
|
|
96808
97100
|
const prefix2 = url2.searchParams.get("prefix") || undefined;
|
|
96809
|
-
|
|
97101
|
+
logger53.debug("Listing keys", { userId: ctx.user.id, slug: slug2, prefix: prefix2 });
|
|
96810
97102
|
const keys = await ctx.services.kv.listKeys(slug2, ctx.user, prefix2);
|
|
96811
97103
|
return { keys };
|
|
96812
97104
|
});
|
|
@@ -96815,7 +97107,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96815
97107
|
if (!slug2) {
|
|
96816
97108
|
throw ApiError.badRequest("Missing game slug");
|
|
96817
97109
|
}
|
|
96818
|
-
|
|
97110
|
+
logger53.debug("Getting stats", { userId: ctx.user.id, slug: slug2 });
|
|
96819
97111
|
return ctx.services.kv.getStats(slug2, ctx.user);
|
|
96820
97112
|
});
|
|
96821
97113
|
seed = requireDeveloper(async (ctx) => {
|
|
@@ -96830,12 +97122,12 @@ var init_kv_controller = __esm(() => {
|
|
|
96830
97122
|
} catch (error2) {
|
|
96831
97123
|
if (error2 instanceof exports_external.ZodError) {
|
|
96832
97124
|
const details = formatZodError(error2);
|
|
96833
|
-
|
|
97125
|
+
logger53.warn("Seed validation failed", { details });
|
|
96834
97126
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96835
97127
|
}
|
|
96836
97128
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96837
97129
|
}
|
|
96838
|
-
|
|
97130
|
+
logger53.debug("Seeding values", { userId: ctx.user.id, slug: slug2, count: body2.entries.length });
|
|
96839
97131
|
await ctx.services.kv.seed(slug2, body2.entries, ctx.user);
|
|
96840
97132
|
return { success: true, count: body2.entries.length };
|
|
96841
97133
|
});
|
|
@@ -96845,7 +97137,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96845
97137
|
if (!slug2 || !key) {
|
|
96846
97138
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96847
97139
|
}
|
|
96848
|
-
|
|
97140
|
+
logger53.debug("Getting value", { userId: ctx.user.id, slug: slug2, key });
|
|
96849
97141
|
const value = await ctx.services.kv.getValue(slug2, key, ctx.user);
|
|
96850
97142
|
return { key, value };
|
|
96851
97143
|
});
|
|
@@ -96859,7 +97151,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96859
97151
|
if (!value) {
|
|
96860
97152
|
throw ApiError.badRequest("Missing value in request body");
|
|
96861
97153
|
}
|
|
96862
|
-
|
|
97154
|
+
logger53.debug("Setting value", { userId: ctx.user.id, slug: slug2, key, size: value.length });
|
|
96863
97155
|
await ctx.services.kv.setValue(slug2, key, value, ctx.user);
|
|
96864
97156
|
return { success: true, key };
|
|
96865
97157
|
});
|
|
@@ -96869,7 +97161,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96869
97161
|
if (!slug2 || !key) {
|
|
96870
97162
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96871
97163
|
}
|
|
96872
|
-
|
|
97164
|
+
logger53.debug("Deleting value", { userId: ctx.user.id, slug: slug2, key });
|
|
96873
97165
|
await ctx.services.kv.deleteValue(slug2, key, ctx.user);
|
|
96874
97166
|
return { success: true, key };
|
|
96875
97167
|
});
|
|
@@ -96879,7 +97171,7 @@ var init_kv_controller = __esm(() => {
|
|
|
96879
97171
|
if (!slug2 || !key) {
|
|
96880
97172
|
throw ApiError.badRequest("Missing game slug or key");
|
|
96881
97173
|
}
|
|
96882
|
-
|
|
97174
|
+
logger53.debug("Getting metadata", { userId: ctx.user.id, slug: slug2, key });
|
|
96883
97175
|
const metadata2 = await ctx.services.kv.getMetadata(slug2, key, ctx.user);
|
|
96884
97176
|
return { key, metadata: metadata2 };
|
|
96885
97177
|
});
|
|
@@ -96888,21 +97180,21 @@ var init_kv_controller = __esm(() => {
|
|
|
96888
97180
|
if (!slug2) {
|
|
96889
97181
|
throw ApiError.badRequest("Missing game slug");
|
|
96890
97182
|
}
|
|
96891
|
-
|
|
97183
|
+
logger53.debug("Clearing all keys", { userId: ctx.user.id, slug: slug2 });
|
|
96892
97184
|
const deleted = await ctx.services.kv.clear(slug2, ctx.user);
|
|
96893
97185
|
return { success: true, deleted };
|
|
96894
97186
|
});
|
|
96895
97187
|
});
|
|
96896
97188
|
|
|
96897
97189
|
// ../api-core/src/controllers/leaderboard.controller.ts
|
|
96898
|
-
var
|
|
97190
|
+
var logger54, submitScore, getGlobalLeaderboard, getLeaderboard, getUserRank, getUserAllScores, getUserScores, leaderboard;
|
|
96899
97191
|
var init_leaderboard_controller = __esm(() => {
|
|
96900
97192
|
init_esm();
|
|
96901
97193
|
init_schemas_index();
|
|
96902
97194
|
init_src2();
|
|
96903
97195
|
init_errors();
|
|
96904
97196
|
init_utils11();
|
|
96905
|
-
|
|
97197
|
+
logger54 = log.scope("LeaderboardController");
|
|
96906
97198
|
submitScore = requireAuth(async (ctx) => {
|
|
96907
97199
|
const gameId = ctx.params.gameId;
|
|
96908
97200
|
if (!gameId) {
|
|
@@ -96915,12 +97207,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96915
97207
|
} catch (error2) {
|
|
96916
97208
|
if (error2 instanceof exports_external.ZodError) {
|
|
96917
97209
|
const details = formatZodError(error2);
|
|
96918
|
-
|
|
97210
|
+
logger54.warn("Submit score validation failed", { details });
|
|
96919
97211
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
96920
97212
|
}
|
|
96921
97213
|
throw ApiError.badRequest("Invalid JSON body");
|
|
96922
97214
|
}
|
|
96923
|
-
|
|
97215
|
+
logger54.debug("Submitting score", {
|
|
96924
97216
|
userId: ctx.user.id,
|
|
96925
97217
|
gameId,
|
|
96926
97218
|
score: body2.score
|
|
@@ -96943,12 +97235,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96943
97235
|
} catch (error2) {
|
|
96944
97236
|
if (error2 instanceof exports_external.ZodError) {
|
|
96945
97237
|
const details = formatZodError(error2);
|
|
96946
|
-
|
|
97238
|
+
logger54.warn("Get global leaderboard query validation failed", { details });
|
|
96947
97239
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
96948
97240
|
}
|
|
96949
97241
|
throw ApiError.badRequest("Invalid query parameters");
|
|
96950
97242
|
}
|
|
96951
|
-
|
|
97243
|
+
logger54.debug("Getting global leaderboard", {
|
|
96952
97244
|
userId: ctx.user.id,
|
|
96953
97245
|
gameId,
|
|
96954
97246
|
...query
|
|
@@ -96971,12 +97263,12 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96971
97263
|
} catch (error2) {
|
|
96972
97264
|
if (error2 instanceof exports_external.ZodError) {
|
|
96973
97265
|
const details = formatZodError(error2);
|
|
96974
|
-
|
|
97266
|
+
logger54.warn("Get leaderboard query validation failed", { details });
|
|
96975
97267
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
96976
97268
|
}
|
|
96977
97269
|
throw ApiError.badRequest("Invalid query parameters");
|
|
96978
97270
|
}
|
|
96979
|
-
|
|
97271
|
+
logger54.debug("Getting leaderboard", {
|
|
96980
97272
|
userId: ctx.user.id,
|
|
96981
97273
|
gameId,
|
|
96982
97274
|
...query
|
|
@@ -96988,7 +97280,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
96988
97280
|
if (!gameId || !userId) {
|
|
96989
97281
|
throw ApiError.badRequest("Game ID and User ID are required");
|
|
96990
97282
|
}
|
|
96991
|
-
|
|
97283
|
+
logger54.debug("Getting user rank", {
|
|
96992
97284
|
requesterId: ctx.user.id,
|
|
96993
97285
|
gameId,
|
|
96994
97286
|
targetUserId: userId
|
|
@@ -97003,7 +97295,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
97003
97295
|
const url2 = ctx.url;
|
|
97004
97296
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "50"), 100);
|
|
97005
97297
|
const gameId = url2.searchParams.get("gameId") || undefined;
|
|
97006
|
-
|
|
97298
|
+
logger54.debug("Getting user all scores", {
|
|
97007
97299
|
requesterId: ctx.user.id,
|
|
97008
97300
|
targetUserId: userId,
|
|
97009
97301
|
gameId,
|
|
@@ -97018,7 +97310,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
97018
97310
|
}
|
|
97019
97311
|
const url2 = ctx.url;
|
|
97020
97312
|
const limit = Math.min(Number(url2.searchParams.get("limit") || "10"), 100);
|
|
97021
|
-
|
|
97313
|
+
logger54.debug("Getting user scores", {
|
|
97022
97314
|
requesterId: ctx.user.id,
|
|
97023
97315
|
gameId,
|
|
97024
97316
|
targetUserId: userId,
|
|
@@ -97038,7 +97330,7 @@ var init_leaderboard_controller = __esm(() => {
|
|
|
97038
97330
|
|
|
97039
97331
|
// ../api-core/src/controllers/level.controller.ts
|
|
97040
97332
|
async function listConfigs(ctx) {
|
|
97041
|
-
|
|
97333
|
+
logger55.debug("Listing level configs");
|
|
97042
97334
|
return ctx.services.level.listConfigs();
|
|
97043
97335
|
}
|
|
97044
97336
|
async function getConfig(ctx) {
|
|
@@ -97050,21 +97342,21 @@ async function getConfig(ctx) {
|
|
|
97050
97342
|
if (isNaN(level) || level < 1) {
|
|
97051
97343
|
throw ApiError.badRequest("Level must be a positive integer");
|
|
97052
97344
|
}
|
|
97053
|
-
|
|
97345
|
+
logger55.debug("Getting level config", { level });
|
|
97054
97346
|
return ctx.services.level.getConfig(level);
|
|
97055
97347
|
}
|
|
97056
|
-
var
|
|
97348
|
+
var logger55, getByUser, getProgress, levels;
|
|
97057
97349
|
var init_level_controller = __esm(() => {
|
|
97058
97350
|
init_src2();
|
|
97059
97351
|
init_errors();
|
|
97060
97352
|
init_utils11();
|
|
97061
|
-
|
|
97353
|
+
logger55 = log.scope("LevelController");
|
|
97062
97354
|
getByUser = requireNonAnonymous(async (ctx) => {
|
|
97063
|
-
|
|
97355
|
+
logger55.debug("Getting user level", { userId: ctx.user.id });
|
|
97064
97356
|
return ctx.services.level.getByUser(ctx.user);
|
|
97065
97357
|
});
|
|
97066
97358
|
getProgress = requireNonAnonymous(async (ctx) => {
|
|
97067
|
-
|
|
97359
|
+
logger55.debug("Getting level progress", { userId: ctx.user.id });
|
|
97068
97360
|
return ctx.services.level.getProgress(ctx.user);
|
|
97069
97361
|
});
|
|
97070
97362
|
levels = {
|
|
@@ -97076,12 +97368,12 @@ var init_level_controller = __esm(() => {
|
|
|
97076
97368
|
});
|
|
97077
97369
|
|
|
97078
97370
|
// ../api-core/src/controllers/logs.controller.ts
|
|
97079
|
-
var
|
|
97371
|
+
var logger56, generateToken, logs;
|
|
97080
97372
|
var init_logs_controller = __esm(() => {
|
|
97081
97373
|
init_src2();
|
|
97082
97374
|
init_errors();
|
|
97083
97375
|
init_utils11();
|
|
97084
|
-
|
|
97376
|
+
logger56 = log.scope("LogsController");
|
|
97085
97377
|
generateToken = requireDeveloper(async (ctx) => {
|
|
97086
97378
|
const slug2 = ctx.params.slug;
|
|
97087
97379
|
if (!slug2) {
|
|
@@ -97100,7 +97392,7 @@ var init_logs_controller = __esm(() => {
|
|
|
97100
97392
|
}
|
|
97101
97393
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97102
97394
|
}
|
|
97103
|
-
|
|
97395
|
+
logger56.debug("Generating log stream token", {
|
|
97104
97396
|
userId: ctx.user.id,
|
|
97105
97397
|
slug: slug2,
|
|
97106
97398
|
environment: body2.environment
|
|
@@ -97119,13 +97411,13 @@ var init_logs_controller = __esm(() => {
|
|
|
97119
97411
|
});
|
|
97120
97412
|
|
|
97121
97413
|
// ../api-core/src/controllers/lti.controller.ts
|
|
97122
|
-
var
|
|
97414
|
+
var logger57, getStatus3, lti;
|
|
97123
97415
|
var init_lti_controller = __esm(() => {
|
|
97124
97416
|
init_src2();
|
|
97125
97417
|
init_utils11();
|
|
97126
|
-
|
|
97418
|
+
logger57 = log.scope("LtiController");
|
|
97127
97419
|
getStatus3 = requireNonAnonymous(async (ctx) => {
|
|
97128
|
-
|
|
97420
|
+
logger57.debug("Getting status", { userId: ctx.user.id });
|
|
97129
97421
|
return ctx.services.lti.getStatus(ctx.user);
|
|
97130
97422
|
});
|
|
97131
97423
|
lti = {
|
|
@@ -97134,7 +97426,7 @@ var init_lti_controller = __esm(() => {
|
|
|
97134
97426
|
});
|
|
97135
97427
|
|
|
97136
97428
|
// ../api-core/src/controllers/map.controller.ts
|
|
97137
|
-
var
|
|
97429
|
+
var logger58, getByIdentifier, getElements, getObjects, createObject, deleteObject, maps2;
|
|
97138
97430
|
var init_map_controller = __esm(() => {
|
|
97139
97431
|
init_esm();
|
|
97140
97432
|
init_schemas_index();
|
|
@@ -97142,13 +97434,13 @@ var init_map_controller = __esm(() => {
|
|
|
97142
97434
|
init_src4();
|
|
97143
97435
|
init_errors();
|
|
97144
97436
|
init_utils11();
|
|
97145
|
-
|
|
97437
|
+
logger58 = log.scope("MapController");
|
|
97146
97438
|
getByIdentifier = requireNonAnonymous(async (ctx) => {
|
|
97147
97439
|
const identifier = ctx.params.identifier;
|
|
97148
97440
|
if (!identifier) {
|
|
97149
97441
|
throw ApiError.badRequest("Missing map identifier");
|
|
97150
97442
|
}
|
|
97151
|
-
|
|
97443
|
+
logger58.debug("Getting map", { userId: ctx.user.id, identifier });
|
|
97152
97444
|
return ctx.services.map.getByIdentifier(identifier);
|
|
97153
97445
|
});
|
|
97154
97446
|
getElements = requireNonAnonymous(async (ctx) => {
|
|
@@ -97159,7 +97451,7 @@ var init_map_controller = __esm(() => {
|
|
|
97159
97451
|
if (!isValidUUID(mapId)) {
|
|
97160
97452
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
97161
97453
|
}
|
|
97162
|
-
|
|
97454
|
+
logger58.debug("Getting map elements", { userId: ctx.user.id, mapId });
|
|
97163
97455
|
return ctx.services.map.getElements(mapId);
|
|
97164
97456
|
});
|
|
97165
97457
|
getObjects = requireNonAnonymous(async (ctx) => {
|
|
@@ -97170,7 +97462,7 @@ var init_map_controller = __esm(() => {
|
|
|
97170
97462
|
if (!isValidUUID(mapId)) {
|
|
97171
97463
|
throw ApiError.unprocessableEntity("mapId must be a valid UUID format");
|
|
97172
97464
|
}
|
|
97173
|
-
|
|
97465
|
+
logger58.debug("Getting map objects", { userId: ctx.user.id, mapId });
|
|
97174
97466
|
return ctx.services.map.getObjects(mapId, ctx.user.id);
|
|
97175
97467
|
});
|
|
97176
97468
|
createObject = requireNonAnonymous(async (ctx) => {
|
|
@@ -97192,12 +97484,12 @@ var init_map_controller = __esm(() => {
|
|
|
97192
97484
|
} catch (error2) {
|
|
97193
97485
|
if (error2 instanceof exports_external.ZodError) {
|
|
97194
97486
|
const details = formatZodError(error2);
|
|
97195
|
-
|
|
97487
|
+
logger58.warn("Create map object validation failed", { details });
|
|
97196
97488
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97197
97489
|
}
|
|
97198
97490
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97199
97491
|
}
|
|
97200
|
-
|
|
97492
|
+
logger58.debug("Creating map object", {
|
|
97201
97493
|
userId: ctx.user.id,
|
|
97202
97494
|
mapId,
|
|
97203
97495
|
itemId: body2.itemId,
|
|
@@ -97221,7 +97513,7 @@ var init_map_controller = __esm(() => {
|
|
|
97221
97513
|
if (!isValidUUID(objectId)) {
|
|
97222
97514
|
throw ApiError.unprocessableEntity("objectId must be a valid UUID format");
|
|
97223
97515
|
}
|
|
97224
|
-
|
|
97516
|
+
logger58.debug("Deleting map object", { userId: ctx.user.id, mapId, objectId });
|
|
97225
97517
|
await ctx.services.map.deleteObject(mapId, objectId, ctx.user);
|
|
97226
97518
|
});
|
|
97227
97519
|
maps2 = {
|
|
@@ -97234,14 +97526,14 @@ var init_map_controller = __esm(() => {
|
|
|
97234
97526
|
});
|
|
97235
97527
|
|
|
97236
97528
|
// ../api-core/src/controllers/notification.controller.ts
|
|
97237
|
-
var
|
|
97529
|
+
var logger59, list6, updateStatus, getStats2, create4, deliver, notifications2;
|
|
97238
97530
|
var init_notification_controller = __esm(() => {
|
|
97239
97531
|
init_esm();
|
|
97240
97532
|
init_schemas_index();
|
|
97241
97533
|
init_src2();
|
|
97242
97534
|
init_errors();
|
|
97243
97535
|
init_utils11();
|
|
97244
|
-
|
|
97536
|
+
logger59 = log.scope("NotificationController");
|
|
97245
97537
|
list6 = requireNonAnonymous(async (ctx) => {
|
|
97246
97538
|
const query = {
|
|
97247
97539
|
status: ctx.url.searchParams.get("status") || undefined,
|
|
@@ -97252,10 +97544,10 @@ var init_notification_controller = __esm(() => {
|
|
|
97252
97544
|
const result = NotificationListQuerySchema.omit({ userId: true }).safeParse(query);
|
|
97253
97545
|
if (!result.success) {
|
|
97254
97546
|
const details = formatZodError(result.error);
|
|
97255
|
-
|
|
97547
|
+
logger59.warn("List notifications query validation failed", { details });
|
|
97256
97548
|
throw ApiError.badRequest("Invalid query parameters", details);
|
|
97257
97549
|
}
|
|
97258
|
-
|
|
97550
|
+
logger59.debug("Listing notifications", { userId: ctx.user.id, ...result.data });
|
|
97259
97551
|
return ctx.services.notification.list(ctx.user, result.data);
|
|
97260
97552
|
});
|
|
97261
97553
|
updateStatus = requireNonAnonymous(async (ctx) => {
|
|
@@ -97270,12 +97562,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97270
97562
|
} catch (error2) {
|
|
97271
97563
|
if (error2 instanceof exports_external.ZodError) {
|
|
97272
97564
|
const details = formatZodError(error2);
|
|
97273
|
-
|
|
97565
|
+
logger59.warn("Update notification status validation failed", { details });
|
|
97274
97566
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
97275
97567
|
}
|
|
97276
97568
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97277
97569
|
}
|
|
97278
|
-
|
|
97570
|
+
logger59.debug("Updating status", {
|
|
97279
97571
|
userId: ctx.user.id,
|
|
97280
97572
|
notificationId,
|
|
97281
97573
|
status: body2.status
|
|
@@ -97285,7 +97577,7 @@ var init_notification_controller = __esm(() => {
|
|
|
97285
97577
|
getStats2 = requireNonAnonymous(async (ctx) => {
|
|
97286
97578
|
const startDate = ctx.url.searchParams.get("startDate");
|
|
97287
97579
|
const endDate = ctx.url.searchParams.get("endDate");
|
|
97288
|
-
|
|
97580
|
+
logger59.debug("Getting stats", { userId: ctx.user.id, startDate, endDate });
|
|
97289
97581
|
return ctx.services.notification.getStats(ctx.user, {
|
|
97290
97582
|
startDate: startDate ? new Date(startDate) : undefined,
|
|
97291
97583
|
endDate: endDate ? new Date(endDate) : undefined
|
|
@@ -97299,12 +97591,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97299
97591
|
} catch (error2) {
|
|
97300
97592
|
if (error2 instanceof exports_external.ZodError) {
|
|
97301
97593
|
const details = formatZodError(error2);
|
|
97302
|
-
|
|
97594
|
+
logger59.warn("Create notification validation failed", { details });
|
|
97303
97595
|
throw ApiError.unprocessableEntity("Invalid request body", details);
|
|
97304
97596
|
}
|
|
97305
97597
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97306
97598
|
}
|
|
97307
|
-
|
|
97599
|
+
logger59.debug("Creating notification", {
|
|
97308
97600
|
userId: ctx.user.id,
|
|
97309
97601
|
targetUserId: body2.userId,
|
|
97310
97602
|
type: body2.type
|
|
@@ -97322,12 +97614,12 @@ var init_notification_controller = __esm(() => {
|
|
|
97322
97614
|
});
|
|
97323
97615
|
});
|
|
97324
97616
|
deliver = requireNonAnonymous(async (ctx) => {
|
|
97325
|
-
|
|
97617
|
+
logger59.debug("Delivering notifications", { userId: ctx.user.id });
|
|
97326
97618
|
try {
|
|
97327
97619
|
await ctx.services.notification.deliverPending(ctx.user.id);
|
|
97328
97620
|
return { success: true };
|
|
97329
97621
|
} catch (error2) {
|
|
97330
|
-
|
|
97622
|
+
logger59.error("Failed to deliver notifications", { error: error2 });
|
|
97331
97623
|
throw ApiError.internal("Failed to deliver notifications");
|
|
97332
97624
|
}
|
|
97333
97625
|
});
|
|
@@ -97341,14 +97633,14 @@ var init_notification_controller = __esm(() => {
|
|
|
97341
97633
|
});
|
|
97342
97634
|
|
|
97343
97635
|
// ../api-core/src/controllers/realtime.controller.ts
|
|
97344
|
-
var
|
|
97636
|
+
var logger60, generateToken2, realtime;
|
|
97345
97637
|
var init_realtime_controller = __esm(() => {
|
|
97346
97638
|
init_src2();
|
|
97347
97639
|
init_utils11();
|
|
97348
|
-
|
|
97640
|
+
logger60 = log.scope("RealtimeController");
|
|
97349
97641
|
generateToken2 = requireNonAnonymous(async (ctx) => {
|
|
97350
97642
|
const gameIdOrSlug = ctx.params.gameId;
|
|
97351
|
-
|
|
97643
|
+
logger60.debug("Generating token", {
|
|
97352
97644
|
userId: ctx.user.id,
|
|
97353
97645
|
gameId: gameIdOrSlug || "global",
|
|
97354
97646
|
launchId: ctx.launchId
|
|
@@ -97361,20 +97653,20 @@ var init_realtime_controller = __esm(() => {
|
|
|
97361
97653
|
});
|
|
97362
97654
|
|
|
97363
97655
|
// ../api-core/src/controllers/secrets.controller.ts
|
|
97364
|
-
var
|
|
97656
|
+
var logger61, listKeys2, setSecrets, deleteSecret, secrets;
|
|
97365
97657
|
var init_secrets_controller = __esm(() => {
|
|
97366
97658
|
init_esm();
|
|
97367
97659
|
init_schemas_index();
|
|
97368
97660
|
init_src2();
|
|
97369
97661
|
init_errors();
|
|
97370
97662
|
init_utils11();
|
|
97371
|
-
|
|
97663
|
+
logger61 = log.scope("SecretsController");
|
|
97372
97664
|
listKeys2 = requireDeveloper(async (ctx) => {
|
|
97373
97665
|
const slug2 = ctx.params.slug;
|
|
97374
97666
|
if (!slug2) {
|
|
97375
97667
|
throw ApiError.badRequest("Missing game slug");
|
|
97376
97668
|
}
|
|
97377
|
-
|
|
97669
|
+
logger61.debug("Listing secret keys", { userId: ctx.user.id, slug: slug2 });
|
|
97378
97670
|
const keys = await ctx.services.secrets.listKeys(slug2, ctx.user);
|
|
97379
97671
|
return { keys };
|
|
97380
97672
|
});
|
|
@@ -97390,12 +97682,12 @@ var init_secrets_controller = __esm(() => {
|
|
|
97390
97682
|
} catch (error2) {
|
|
97391
97683
|
if (error2 instanceof exports_external.ZodError) {
|
|
97392
97684
|
const details = formatZodError(error2);
|
|
97393
|
-
|
|
97685
|
+
logger61.warn("Set secrets validation failed", { details });
|
|
97394
97686
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97395
97687
|
}
|
|
97396
97688
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97397
97689
|
}
|
|
97398
|
-
|
|
97690
|
+
logger61.debug("Setting secrets", {
|
|
97399
97691
|
userId: ctx.user.id,
|
|
97400
97692
|
slug: slug2,
|
|
97401
97693
|
keyCount: Object.keys(body2).length
|
|
@@ -97412,7 +97704,7 @@ var init_secrets_controller = __esm(() => {
|
|
|
97412
97704
|
if (!key) {
|
|
97413
97705
|
throw ApiError.badRequest("Missing secret key");
|
|
97414
97706
|
}
|
|
97415
|
-
|
|
97707
|
+
logger61.debug("Deleting secret", { userId: ctx.user.id, slug: slug2, key });
|
|
97416
97708
|
await ctx.services.secrets.deleteSecret(slug2, key, ctx.user);
|
|
97417
97709
|
return { success: true };
|
|
97418
97710
|
});
|
|
@@ -97424,14 +97716,14 @@ var init_secrets_controller = __esm(() => {
|
|
|
97424
97716
|
});
|
|
97425
97717
|
|
|
97426
97718
|
// ../api-core/src/controllers/seed.controller.ts
|
|
97427
|
-
var
|
|
97719
|
+
var logger62, seed2;
|
|
97428
97720
|
var init_seed_controller = __esm(() => {
|
|
97429
97721
|
init_esm();
|
|
97430
97722
|
init_schemas_index();
|
|
97431
97723
|
init_src2();
|
|
97432
97724
|
init_errors();
|
|
97433
97725
|
init_utils11();
|
|
97434
|
-
|
|
97726
|
+
logger62 = log.scope("SeedController");
|
|
97435
97727
|
seed2 = requireDeveloper(async (ctx) => {
|
|
97436
97728
|
const slug2 = ctx.params.slug;
|
|
97437
97729
|
if (!slug2) {
|
|
@@ -97444,12 +97736,12 @@ var init_seed_controller = __esm(() => {
|
|
|
97444
97736
|
} catch (error2) {
|
|
97445
97737
|
if (error2 instanceof exports_external.ZodError) {
|
|
97446
97738
|
const details = formatZodError(error2);
|
|
97447
|
-
|
|
97739
|
+
logger62.warn("Seed database validation failed", { details });
|
|
97448
97740
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97449
97741
|
}
|
|
97450
97742
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97451
97743
|
}
|
|
97452
|
-
|
|
97744
|
+
logger62.debug("Seeding database", {
|
|
97453
97745
|
userId: ctx.user.id,
|
|
97454
97746
|
slug: slug2,
|
|
97455
97747
|
codeLength: body2.code.length,
|
|
@@ -97460,19 +97752,19 @@ var init_seed_controller = __esm(() => {
|
|
|
97460
97752
|
});
|
|
97461
97753
|
|
|
97462
97754
|
// ../api-core/src/controllers/session.controller.ts
|
|
97463
|
-
var
|
|
97755
|
+
var logger63, start2, end, mintToken, sessions2;
|
|
97464
97756
|
var init_session_controller = __esm(() => {
|
|
97465
97757
|
init_src2();
|
|
97466
97758
|
init_tunnel();
|
|
97467
97759
|
init_errors();
|
|
97468
97760
|
init_utils11();
|
|
97469
|
-
|
|
97761
|
+
logger63 = log.scope("SessionController");
|
|
97470
97762
|
start2 = requireAuth(async (ctx) => {
|
|
97471
97763
|
const gameIdOrSlug = ctx.params.gameId;
|
|
97472
97764
|
if (!gameIdOrSlug) {
|
|
97473
97765
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
97474
97766
|
}
|
|
97475
|
-
|
|
97767
|
+
logger63.debug("Starting session", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
97476
97768
|
return ctx.services.session.start(gameIdOrSlug, ctx.user.id);
|
|
97477
97769
|
});
|
|
97478
97770
|
end = requireAuth(async (ctx) => {
|
|
@@ -97484,7 +97776,7 @@ var init_session_controller = __esm(() => {
|
|
|
97484
97776
|
if (!sessionId) {
|
|
97485
97777
|
throw ApiError.badRequest("Missing session ID");
|
|
97486
97778
|
}
|
|
97487
|
-
|
|
97779
|
+
logger63.debug("Ending session", {
|
|
97488
97780
|
userId: ctx.user.id,
|
|
97489
97781
|
gameIdOrSlug,
|
|
97490
97782
|
sessionId,
|
|
@@ -97497,7 +97789,7 @@ var init_session_controller = __esm(() => {
|
|
|
97497
97789
|
if (!gameIdOrSlug) {
|
|
97498
97790
|
throw ApiError.badRequest("Missing game ID or slug");
|
|
97499
97791
|
}
|
|
97500
|
-
|
|
97792
|
+
logger63.debug("Minting token", { userId: ctx.user.id, gameIdOrSlug, launchId: ctx.launchId });
|
|
97501
97793
|
const { token, exp } = await ctx.services.session.mintToken(gameIdOrSlug, ctx.user.id);
|
|
97502
97794
|
let baseUrl;
|
|
97503
97795
|
if (ctx.config.isLocal) {
|
|
@@ -97515,13 +97807,13 @@ var init_session_controller = __esm(() => {
|
|
|
97515
97807
|
});
|
|
97516
97808
|
|
|
97517
97809
|
// ../api-core/src/controllers/shop.controller.ts
|
|
97518
|
-
var
|
|
97810
|
+
var logger64, getShopView, shop;
|
|
97519
97811
|
var init_shop_controller = __esm(() => {
|
|
97520
97812
|
init_src2();
|
|
97521
97813
|
init_utils11();
|
|
97522
|
-
|
|
97814
|
+
logger64 = log.scope("ShopController");
|
|
97523
97815
|
getShopView = requireNonAnonymous(async (ctx) => {
|
|
97524
|
-
|
|
97816
|
+
logger64.debug("Getting shop view", { userId: ctx.user.id });
|
|
97525
97817
|
return ctx.services.shop.getShopView(ctx.user);
|
|
97526
97818
|
});
|
|
97527
97819
|
shop = {
|
|
@@ -97530,7 +97822,7 @@ var init_shop_controller = __esm(() => {
|
|
|
97530
97822
|
});
|
|
97531
97823
|
|
|
97532
97824
|
// ../api-core/src/controllers/shop-listing.controller.ts
|
|
97533
|
-
var
|
|
97825
|
+
var logger65, list7, getById4, create5, update5, remove5, listByGame2, getByGameItem, createForGameItem, updateForGameItem, deleteForGameItem, shopListings2;
|
|
97534
97826
|
var init_shop_listing_controller = __esm(() => {
|
|
97535
97827
|
init_esm();
|
|
97536
97828
|
init_schemas_index();
|
|
@@ -97538,9 +97830,9 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97538
97830
|
init_src4();
|
|
97539
97831
|
init_errors();
|
|
97540
97832
|
init_utils11();
|
|
97541
|
-
|
|
97833
|
+
logger65 = log.scope("ShopListingController");
|
|
97542
97834
|
list7 = requireAdmin(async (ctx) => {
|
|
97543
|
-
|
|
97835
|
+
logger65.debug("Listing shop listings", { userId: ctx.user.id });
|
|
97544
97836
|
return ctx.services.shopListing.list();
|
|
97545
97837
|
});
|
|
97546
97838
|
getById4 = requireAdmin(async (ctx) => {
|
|
@@ -97551,7 +97843,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97551
97843
|
if (!isValidUUID(listingId)) {
|
|
97552
97844
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
97553
97845
|
}
|
|
97554
|
-
|
|
97846
|
+
logger65.debug("Getting listing", { userId: ctx.user.id, listingId });
|
|
97555
97847
|
return ctx.services.shopListing.getById(listingId);
|
|
97556
97848
|
});
|
|
97557
97849
|
create5 = requireAdmin(async (ctx) => {
|
|
@@ -97562,12 +97854,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97562
97854
|
} catch (error2) {
|
|
97563
97855
|
if (error2 instanceof exports_external.ZodError) {
|
|
97564
97856
|
const details = formatZodError(error2);
|
|
97565
|
-
|
|
97857
|
+
logger65.warn("Create shop listing validation failed", { details });
|
|
97566
97858
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97567
97859
|
}
|
|
97568
97860
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97569
97861
|
}
|
|
97570
|
-
|
|
97862
|
+
logger65.debug("Creating listing", {
|
|
97571
97863
|
userId: ctx.user.id,
|
|
97572
97864
|
itemId: body2.itemId,
|
|
97573
97865
|
currencyId: body2.currencyId,
|
|
@@ -97590,12 +97882,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97590
97882
|
} catch (error2) {
|
|
97591
97883
|
if (error2 instanceof exports_external.ZodError) {
|
|
97592
97884
|
const details = formatZodError(error2);
|
|
97593
|
-
|
|
97885
|
+
logger65.warn("Update shop listing validation failed", { details });
|
|
97594
97886
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97595
97887
|
}
|
|
97596
97888
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97597
97889
|
}
|
|
97598
|
-
|
|
97890
|
+
logger65.debug("Updating listing", {
|
|
97599
97891
|
userId: ctx.user.id,
|
|
97600
97892
|
listingId,
|
|
97601
97893
|
price: body2.price,
|
|
@@ -97612,7 +97904,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97612
97904
|
if (!isValidUUID(listingId)) {
|
|
97613
97905
|
throw ApiError.unprocessableEntity("listingId must be a valid UUID format");
|
|
97614
97906
|
}
|
|
97615
|
-
|
|
97907
|
+
logger65.debug("Deleting listing", { userId: ctx.user.id, listingId });
|
|
97616
97908
|
await ctx.services.shopListing.delete(listingId);
|
|
97617
97909
|
});
|
|
97618
97910
|
listByGame2 = requireNonAnonymous(async (ctx) => {
|
|
@@ -97623,7 +97915,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97623
97915
|
if (!isValidUUID(gameId)) {
|
|
97624
97916
|
throw ApiError.unprocessableEntity("gameId must be a valid UUID format");
|
|
97625
97917
|
}
|
|
97626
|
-
|
|
97918
|
+
logger65.debug("Listing game listings", { userId: ctx.user.id, gameId });
|
|
97627
97919
|
return ctx.services.shopListing.listByGame(gameId, ctx.user);
|
|
97628
97920
|
});
|
|
97629
97921
|
getByGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -97638,7 +97930,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97638
97930
|
if (!isValidUUID(itemId)) {
|
|
97639
97931
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
97640
97932
|
}
|
|
97641
|
-
|
|
97933
|
+
logger65.debug("Getting game item listing", { userId: ctx.user.id, gameId, itemId });
|
|
97642
97934
|
return ctx.services.shopListing.getByGameItem(gameId, itemId, ctx.user);
|
|
97643
97935
|
});
|
|
97644
97936
|
createForGameItem = requireNonAnonymous(async (ctx) => {
|
|
@@ -97660,12 +97952,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97660
97952
|
} catch (error2) {
|
|
97661
97953
|
if (error2 instanceof exports_external.ZodError) {
|
|
97662
97954
|
const details = formatZodError(error2);
|
|
97663
|
-
|
|
97955
|
+
logger65.warn("Create game item listing validation failed", { details });
|
|
97664
97956
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97665
97957
|
}
|
|
97666
97958
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97667
97959
|
}
|
|
97668
|
-
|
|
97960
|
+
logger65.debug("Creating game item listing", {
|
|
97669
97961
|
userId: ctx.user.id,
|
|
97670
97962
|
gameId,
|
|
97671
97963
|
itemId,
|
|
@@ -97693,12 +97985,12 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97693
97985
|
} catch (error2) {
|
|
97694
97986
|
if (error2 instanceof exports_external.ZodError) {
|
|
97695
97987
|
const details = formatZodError(error2);
|
|
97696
|
-
|
|
97988
|
+
logger65.warn("Update game item listing validation failed", { details });
|
|
97697
97989
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97698
97990
|
}
|
|
97699
97991
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97700
97992
|
}
|
|
97701
|
-
|
|
97993
|
+
logger65.debug("Updating game item listing", {
|
|
97702
97994
|
userId: ctx.user.id,
|
|
97703
97995
|
gameId,
|
|
97704
97996
|
itemId,
|
|
@@ -97720,7 +98012,7 @@ var init_shop_listing_controller = __esm(() => {
|
|
|
97720
98012
|
if (!isValidUUID(itemId)) {
|
|
97721
98013
|
throw ApiError.unprocessableEntity("itemId must be a valid UUID format");
|
|
97722
98014
|
}
|
|
97723
|
-
|
|
98015
|
+
logger65.debug("Deleting game item listing", {
|
|
97724
98016
|
userId: ctx.user.id,
|
|
97725
98017
|
gameId,
|
|
97726
98018
|
itemId
|
|
@@ -97747,21 +98039,21 @@ async function getBySlug2(ctx) {
|
|
|
97747
98039
|
if (!slug2) {
|
|
97748
98040
|
throw ApiError.badRequest("Template slug is required");
|
|
97749
98041
|
}
|
|
97750
|
-
|
|
98042
|
+
logger66.debug("Getting sprite by slug", { slug: slug2 });
|
|
97751
98043
|
return ctx.services.sprite.getBySlug(slug2);
|
|
97752
98044
|
}
|
|
97753
|
-
var
|
|
98045
|
+
var logger66, sprites;
|
|
97754
98046
|
var init_sprite_controller = __esm(() => {
|
|
97755
98047
|
init_src2();
|
|
97756
98048
|
init_errors();
|
|
97757
|
-
|
|
98049
|
+
logger66 = log.scope("SpriteController");
|
|
97758
98050
|
sprites = {
|
|
97759
98051
|
getBySlug: getBySlug2
|
|
97760
98052
|
};
|
|
97761
98053
|
});
|
|
97762
98054
|
|
|
97763
98055
|
// ../api-core/src/controllers/timeback.controller.ts
|
|
97764
|
-
var
|
|
98056
|
+
var logger67, getTodayXp, getTotalXp, updateTodayXp, getXpHistory, populateStudent, getUser, getUserById, setupIntegration, getIntegrations, updateIntegration, getIntegrationConfig, verifyIntegration, getConfig2, deleteIntegrations, endActivity, heartbeat, advanceCourse, getStudentXp, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getActivityDetail, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, deleteAssessment, reorderAssessments, reorderQuestions, activateAssessment, deactivateAssessment, listQuestions, createQuestion, updateQuestion, deleteQuestion, getAssessmentBankStatus, destroyAssessmentBank, timeback2;
|
|
97765
98057
|
var init_timeback_controller = __esm(() => {
|
|
97766
98058
|
init_esm();
|
|
97767
98059
|
init_schemas_index();
|
|
@@ -97769,15 +98061,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
97769
98061
|
init_src4();
|
|
97770
98062
|
init_errors();
|
|
97771
98063
|
init_utils11();
|
|
97772
|
-
|
|
98064
|
+
logger67 = log.scope("TimebackController");
|
|
97773
98065
|
getTodayXp = requireNonAnonymous(async (ctx) => {
|
|
97774
98066
|
const date4 = ctx.url.searchParams.get("date") || undefined;
|
|
97775
98067
|
const tz = ctx.url.searchParams.get("tz") || undefined;
|
|
97776
|
-
|
|
98068
|
+
logger67.debug("Getting today XP", { userId: ctx.user.id, date: date4, tz });
|
|
97777
98069
|
return ctx.services.timeback.getTodayXp(ctx.user.id, date4, tz);
|
|
97778
98070
|
});
|
|
97779
98071
|
getTotalXp = requireNonAnonymous(async (ctx) => {
|
|
97780
|
-
|
|
98072
|
+
logger67.debug("Getting total XP", { userId: ctx.user.id });
|
|
97781
98073
|
return ctx.services.timeback.getTotalXp(ctx.user.id);
|
|
97782
98074
|
});
|
|
97783
98075
|
updateTodayXp = requireNonAnonymous(async (ctx) => {
|
|
@@ -97788,18 +98080,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
97788
98080
|
} catch (error2) {
|
|
97789
98081
|
if (error2 instanceof exports_external.ZodError) {
|
|
97790
98082
|
const details = formatZodError(error2);
|
|
97791
|
-
|
|
98083
|
+
logger67.warn("Update today XP validation failed", { details });
|
|
97792
98084
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97793
98085
|
}
|
|
97794
98086
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97795
98087
|
}
|
|
97796
|
-
|
|
98088
|
+
logger67.debug("Updating today XP", { userId: ctx.user.id, xp: body2.xp });
|
|
97797
98089
|
return ctx.services.timeback.updateTodayXp(ctx.user.id, body2);
|
|
97798
98090
|
});
|
|
97799
98091
|
getXpHistory = requireNonAnonymous(async (ctx) => {
|
|
97800
98092
|
const startDate = ctx.url.searchParams.get("startDate") || undefined;
|
|
97801
98093
|
const endDate = ctx.url.searchParams.get("endDate") || undefined;
|
|
97802
|
-
|
|
98094
|
+
logger67.debug("Getting XP history", { userId: ctx.user.id, startDate, endDate });
|
|
97803
98095
|
return ctx.services.timeback.getXpHistory(ctx.user.id, startDate, endDate);
|
|
97804
98096
|
});
|
|
97805
98097
|
populateStudent = requireNonAnonymous(async (ctx) => {
|
|
@@ -97810,18 +98102,18 @@ var init_timeback_controller = __esm(() => {
|
|
|
97810
98102
|
} catch (error2) {
|
|
97811
98103
|
if (error2 instanceof exports_external.ZodError) {
|
|
97812
98104
|
const details = formatZodError(error2);
|
|
97813
|
-
|
|
98105
|
+
logger67.warn("Populate student validation failed", { details });
|
|
97814
98106
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97815
98107
|
}
|
|
97816
98108
|
}
|
|
97817
|
-
|
|
98109
|
+
logger67.debug("Populating student", {
|
|
97818
98110
|
userId: ctx.user.id,
|
|
97819
98111
|
hasProvidedNames: Boolean(providedNames)
|
|
97820
98112
|
});
|
|
97821
98113
|
return ctx.services.timeback.populateStudent(ctx.user, providedNames);
|
|
97822
98114
|
});
|
|
97823
98115
|
getUser = requireNonAnonymous(async (ctx) => {
|
|
97824
|
-
|
|
98116
|
+
logger67.debug("Getting user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
97825
98117
|
return ctx.services.timeback.getUserData(ctx.user.id, ctx.gameId);
|
|
97826
98118
|
});
|
|
97827
98119
|
getUserById = requireNonAnonymous(async (ctx) => {
|
|
@@ -97829,7 +98121,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97829
98121
|
if (!timebackId) {
|
|
97830
98122
|
throw ApiError.badRequest("Missing timebackId parameter");
|
|
97831
98123
|
}
|
|
97832
|
-
|
|
98124
|
+
logger67.debug("Getting user by ID", { requesterId: ctx.user.id, timebackId });
|
|
97833
98125
|
return ctx.services.timeback.getUserDataByTimebackId(timebackId);
|
|
97834
98126
|
});
|
|
97835
98127
|
setupIntegration = requireDeveloper(async (ctx) => {
|
|
@@ -97840,12 +98132,12 @@ var init_timeback_controller = __esm(() => {
|
|
|
97840
98132
|
} catch (error2) {
|
|
97841
98133
|
if (error2 instanceof exports_external.ZodError) {
|
|
97842
98134
|
const details = formatZodError(error2);
|
|
97843
|
-
|
|
98135
|
+
logger67.warn("Setup integration validation failed", { details });
|
|
97844
98136
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97845
98137
|
}
|
|
97846
98138
|
throw ApiError.badRequest("Invalid JSON body");
|
|
97847
98139
|
}
|
|
97848
|
-
|
|
98140
|
+
logger67.debug("Setting up integration", {
|
|
97849
98141
|
userId: ctx.user.id,
|
|
97850
98142
|
gameId: body2.gameId
|
|
97851
98143
|
});
|
|
@@ -97859,9 +98151,37 @@ var init_timeback_controller = __esm(() => {
|
|
|
97859
98151
|
if (!isValidUUID(gameId)) {
|
|
97860
98152
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97861
98153
|
}
|
|
97862
|
-
|
|
98154
|
+
logger67.debug("Getting integrations", { userId: ctx.user.id, gameId });
|
|
97863
98155
|
return ctx.services.timeback.getIntegrations(gameId, ctx.user);
|
|
97864
98156
|
});
|
|
98157
|
+
updateIntegration = requireDeveloper(async (ctx) => {
|
|
98158
|
+
const { gameId, courseId } = ctx.params;
|
|
98159
|
+
if (!gameId || !courseId) {
|
|
98160
|
+
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98161
|
+
}
|
|
98162
|
+
if (!isValidUUID(gameId)) {
|
|
98163
|
+
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
98164
|
+
}
|
|
98165
|
+
const body2 = await parseRequestBody(ctx.request, UpdateGameTimebackIntegrationRequestSchema);
|
|
98166
|
+
logger67.debug("Updating integration", {
|
|
98167
|
+
userId: ctx.user.id,
|
|
98168
|
+
gameId,
|
|
98169
|
+
courseId,
|
|
98170
|
+
fields: Object.keys(body2)
|
|
98171
|
+
});
|
|
98172
|
+
return ctx.services.timeback.updateIntegration(gameId, courseId, ctx.user, body2);
|
|
98173
|
+
});
|
|
98174
|
+
getIntegrationConfig = requireGameManagementAccess(async (ctx) => {
|
|
98175
|
+
const { gameId, courseId } = ctx.params;
|
|
98176
|
+
if (!gameId || !courseId) {
|
|
98177
|
+
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98178
|
+
}
|
|
98179
|
+
if (!isValidUUID(gameId)) {
|
|
98180
|
+
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
98181
|
+
}
|
|
98182
|
+
logger67.debug("Getting integration config", { userId: ctx.user.id, gameId, courseId });
|
|
98183
|
+
return ctx.services.timeback.getIntegrationConfig(gameId, courseId, ctx.user);
|
|
98184
|
+
});
|
|
97865
98185
|
verifyIntegration = requireDeveloper(async (ctx) => {
|
|
97866
98186
|
const gameId = ctx.params.gameId;
|
|
97867
98187
|
if (!gameId) {
|
|
@@ -97870,7 +98190,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97870
98190
|
if (!isValidUUID(gameId)) {
|
|
97871
98191
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97872
98192
|
}
|
|
97873
|
-
|
|
98193
|
+
logger67.debug("Verifying integration", { userId: ctx.user.id, gameId });
|
|
97874
98194
|
return ctx.services.timeback.verifyIntegration(gameId, ctx.user);
|
|
97875
98195
|
});
|
|
97876
98196
|
getConfig2 = requireDeveloper(async (ctx) => {
|
|
@@ -97881,7 +98201,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97881
98201
|
if (!isValidUUID(gameId)) {
|
|
97882
98202
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97883
98203
|
}
|
|
97884
|
-
|
|
98204
|
+
logger67.debug("Getting config", { userId: ctx.user.id, gameId });
|
|
97885
98205
|
return ctx.services.timeback.getConfig(gameId, ctx.user);
|
|
97886
98206
|
});
|
|
97887
98207
|
deleteIntegrations = requireDeveloper(async (ctx) => {
|
|
@@ -97892,7 +98212,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97892
98212
|
if (!isValidUUID(gameId)) {
|
|
97893
98213
|
throw ApiError.unprocessableEntity("Invalid gameId format");
|
|
97894
98214
|
}
|
|
97895
|
-
|
|
98215
|
+
logger67.debug("Deleting integrations", { userId: ctx.user.id, gameId });
|
|
97896
98216
|
await ctx.services.timeback.deleteIntegrations(gameId, ctx.user);
|
|
97897
98217
|
});
|
|
97898
98218
|
endActivity = requireDeveloper(async (ctx) => {
|
|
@@ -97903,7 +98223,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97903
98223
|
} catch (error2) {
|
|
97904
98224
|
if (error2 instanceof exports_external.ZodError) {
|
|
97905
98225
|
const details = formatZodError(error2);
|
|
97906
|
-
|
|
98226
|
+
logger67.warn("End activity validation failed", { details });
|
|
97907
98227
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97908
98228
|
}
|
|
97909
98229
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -97921,7 +98241,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97921
98241
|
masteredUnits,
|
|
97922
98242
|
extensions
|
|
97923
98243
|
} = body2;
|
|
97924
|
-
|
|
98244
|
+
logger67.debug("Ending activity", { userId: ctx.user.id, gameId });
|
|
97925
98245
|
return ctx.services.timeback.endActivity({
|
|
97926
98246
|
gameId,
|
|
97927
98247
|
studentId,
|
|
@@ -97945,7 +98265,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97945
98265
|
} catch (error2) {
|
|
97946
98266
|
if (error2 instanceof exports_external.ZodError) {
|
|
97947
98267
|
const details = formatZodError(error2);
|
|
97948
|
-
|
|
98268
|
+
logger67.warn("Heartbeat validation failed", { details });
|
|
97949
98269
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
97950
98270
|
}
|
|
97951
98271
|
throw ApiError.badRequest("Invalid JSON body");
|
|
@@ -97961,7 +98281,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97961
98281
|
windowSequence,
|
|
97962
98282
|
isFinal
|
|
97963
98283
|
} = body2;
|
|
97964
|
-
|
|
98284
|
+
logger67.debug("Recording heartbeat", {
|
|
97965
98285
|
userId: ctx.user.id,
|
|
97966
98286
|
gameId,
|
|
97967
98287
|
runId,
|
|
@@ -97986,7 +98306,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
97986
98306
|
});
|
|
97987
98307
|
advanceCourse = requireDeveloper(async (ctx) => {
|
|
97988
98308
|
const body2 = await parseRequestBody(ctx.request, AdvanceCourseRequestSchema);
|
|
97989
|
-
|
|
98309
|
+
logger67.debug("Advancing student manually", {
|
|
97990
98310
|
userId: ctx.user.id,
|
|
97991
98311
|
gameId: body2.gameId,
|
|
97992
98312
|
studentId: body2.studentId,
|
|
@@ -98027,7 +98347,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98027
98347
|
perCourse: includeOptions.includes("percourse"),
|
|
98028
98348
|
today: includeOptions.includes("today")
|
|
98029
98349
|
};
|
|
98030
|
-
|
|
98350
|
+
logger67.debug("Getting student XP", {
|
|
98031
98351
|
requesterId: ctx.user.id,
|
|
98032
98352
|
timebackId,
|
|
98033
98353
|
gameId,
|
|
@@ -98049,7 +98369,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98049
98369
|
if (!gameId || !courseId) {
|
|
98050
98370
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98051
98371
|
}
|
|
98052
|
-
|
|
98372
|
+
logger67.debug("Getting course roster", {
|
|
98053
98373
|
requesterId: ctx.user.id,
|
|
98054
98374
|
gameId,
|
|
98055
98375
|
courseId,
|
|
@@ -98066,7 +98386,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98066
98386
|
if (!timebackId || !gameId) {
|
|
98067
98387
|
throw ApiError.badRequest("Missing timebackId parameter or gameId query parameter");
|
|
98068
98388
|
}
|
|
98069
|
-
|
|
98389
|
+
logger67.debug("Getting student overview", {
|
|
98070
98390
|
requesterId: ctx.user.id,
|
|
98071
98391
|
timebackId,
|
|
98072
98392
|
gameId,
|
|
@@ -98080,7 +98400,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98080
98400
|
if (!gameId || !timebackId) {
|
|
98081
98401
|
throw ApiError.badRequest("Missing gameId or timebackId path parameter");
|
|
98082
98402
|
}
|
|
98083
|
-
|
|
98403
|
+
logger67.debug("Getting game metrics", {
|
|
98084
98404
|
requesterId: ctx.user.id,
|
|
98085
98405
|
gameId,
|
|
98086
98406
|
timebackId
|
|
@@ -98098,7 +98418,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98098
98418
|
if (!timebackId || !courseId || !gameId) {
|
|
98099
98419
|
throw ApiError.badRequest("Missing timebackId or courseId path parameter, or gameId query parameter");
|
|
98100
98420
|
}
|
|
98101
|
-
|
|
98421
|
+
logger67.debug("Getting student activity", {
|
|
98102
98422
|
requesterId: ctx.user.id,
|
|
98103
98423
|
timebackId,
|
|
98104
98424
|
courseId,
|
|
@@ -98123,7 +98443,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98123
98443
|
if (!timebackId || !courseId || !activityId || !gameId) {
|
|
98124
98444
|
throw ApiError.badRequest("Missing timebackId, courseId, or activityId path parameter, or gameId query parameter");
|
|
98125
98445
|
}
|
|
98126
|
-
|
|
98446
|
+
logger67.debug("Getting activity detail", {
|
|
98127
98447
|
requesterId: ctx.user.id,
|
|
98128
98448
|
timebackId,
|
|
98129
98449
|
courseId,
|
|
@@ -98141,7 +98461,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98141
98461
|
});
|
|
98142
98462
|
grantXp = requireDeveloper(async (ctx) => {
|
|
98143
98463
|
const body2 = await parseRequestBody(ctx.request, GrantTimebackXpRequestSchema);
|
|
98144
|
-
|
|
98464
|
+
logger67.debug("Granting manual XP", {
|
|
98145
98465
|
requesterId: ctx.user.id,
|
|
98146
98466
|
gameId: body2.gameId,
|
|
98147
98467
|
courseId: body2.courseId,
|
|
@@ -98153,7 +98473,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98153
98473
|
});
|
|
98154
98474
|
adjustTime = requireDeveloper(async (ctx) => {
|
|
98155
98475
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackTimeRequestSchema);
|
|
98156
|
-
|
|
98476
|
+
logger67.debug("Adjusting time spent", {
|
|
98157
98477
|
requesterId: ctx.user.id,
|
|
98158
98478
|
gameId: body2.gameId,
|
|
98159
98479
|
courseId: body2.courseId,
|
|
@@ -98165,7 +98485,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98165
98485
|
});
|
|
98166
98486
|
adjustMastery = requireDeveloper(async (ctx) => {
|
|
98167
98487
|
const body2 = await parseRequestBody(ctx.request, AdjustTimebackMasteryRequestSchema);
|
|
98168
|
-
|
|
98488
|
+
logger67.debug("Adjusting mastered units", {
|
|
98169
98489
|
requesterId: ctx.user.id,
|
|
98170
98490
|
gameId: body2.gameId,
|
|
98171
98491
|
courseId: body2.courseId,
|
|
@@ -98175,6 +98495,22 @@ var init_timeback_controller = __esm(() => {
|
|
|
98175
98495
|
});
|
|
98176
98496
|
return ctx.services.timebackAdmin.adjustMasteredUnits(body2, ctx.user);
|
|
98177
98497
|
});
|
|
98498
|
+
reconcileMasteryForConfigChange = requireDeveloper(async (ctx) => {
|
|
98499
|
+
const body2 = await parseRequestBody(ctx.request, ReconcileMasteryForConfigChangeSchema);
|
|
98500
|
+
logger67.debug("Reconciling mastery completion for config change", {
|
|
98501
|
+
requesterId: ctx.user.id,
|
|
98502
|
+
gameId: body2.gameId,
|
|
98503
|
+
courseId: body2.courseId,
|
|
98504
|
+
oldMasterableUnits: body2.oldMasterableUnits,
|
|
98505
|
+
newMasterableUnits: body2.newMasterableUnits,
|
|
98506
|
+
affectedCount: body2.affectedStudentIds.length
|
|
98507
|
+
});
|
|
98508
|
+
return ctx.services.timebackAdmin.reconcileMasteryForConfigChange(body2.gameId, body2.courseId, ctx.user, {
|
|
98509
|
+
oldMasterableUnits: body2.oldMasterableUnits,
|
|
98510
|
+
newMasterableUnits: body2.newMasterableUnits,
|
|
98511
|
+
affectedStudentIds: body2.affectedStudentIds
|
|
98512
|
+
});
|
|
98513
|
+
});
|
|
98178
98514
|
searchStudents = requireGameManagementAccess(async (ctx) => {
|
|
98179
98515
|
const gameId = ctx.params.gameId;
|
|
98180
98516
|
const courseId = ctx.params.courseId;
|
|
@@ -98182,7 +98518,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98182
98518
|
if (!gameId || !courseId) {
|
|
98183
98519
|
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
98184
98520
|
}
|
|
98185
|
-
|
|
98521
|
+
logger67.debug("Searching students for enrollment", {
|
|
98186
98522
|
requesterId: ctx.user.id,
|
|
98187
98523
|
gameId,
|
|
98188
98524
|
courseId,
|
|
@@ -98192,7 +98528,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98192
98528
|
});
|
|
98193
98529
|
enrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
98194
98530
|
const body2 = await parseRequestBody(ctx.request, EnrollStudentRequestSchema);
|
|
98195
|
-
|
|
98531
|
+
logger67.debug("Enrolling student", {
|
|
98196
98532
|
requesterId: ctx.user.id,
|
|
98197
98533
|
gameId: body2.gameId,
|
|
98198
98534
|
courseId: body2.courseId,
|
|
@@ -98202,7 +98538,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98202
98538
|
});
|
|
98203
98539
|
unenrollStudent = requireGameManagementAccess(async (ctx) => {
|
|
98204
98540
|
const body2 = await parseRequestBody(ctx.request, UnenrollStudentRequestSchema);
|
|
98205
|
-
|
|
98541
|
+
logger67.debug("Unenrolling student", {
|
|
98206
98542
|
requesterId: ctx.user.id,
|
|
98207
98543
|
gameId: body2.gameId,
|
|
98208
98544
|
courseId: body2.courseId,
|
|
@@ -98212,7 +98548,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98212
98548
|
});
|
|
98213
98549
|
reactivateEnrollment = requireGameManagementAccess(async (ctx) => {
|
|
98214
98550
|
const body2 = await parseRequestBody(ctx.request, ReactivateEnrollmentRequestSchema);
|
|
98215
|
-
|
|
98551
|
+
logger67.debug("Reactivating enrollment", {
|
|
98216
98552
|
requesterId: ctx.user.id,
|
|
98217
98553
|
gameId: body2.gameId,
|
|
98218
98554
|
courseId: body2.courseId,
|
|
@@ -98352,6 +98688,8 @@ var init_timeback_controller = __esm(() => {
|
|
|
98352
98688
|
getUserById,
|
|
98353
98689
|
setupIntegration,
|
|
98354
98690
|
getIntegrations,
|
|
98691
|
+
updateIntegration,
|
|
98692
|
+
getIntegrationConfig,
|
|
98355
98693
|
verifyIntegration,
|
|
98356
98694
|
getConfig: getConfig2,
|
|
98357
98695
|
deleteIntegrations,
|
|
@@ -98367,6 +98705,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
98367
98705
|
grantXp,
|
|
98368
98706
|
adjustTime,
|
|
98369
98707
|
adjustMastery,
|
|
98708
|
+
reconcileMasteryForConfigChange,
|
|
98370
98709
|
searchStudents,
|
|
98371
98710
|
enrollStudent,
|
|
98372
98711
|
unenrollStudent,
|
|
@@ -98388,14 +98727,14 @@ var init_timeback_controller = __esm(() => {
|
|
|
98388
98727
|
});
|
|
98389
98728
|
|
|
98390
98729
|
// ../api-core/src/controllers/upload.controller.ts
|
|
98391
|
-
var
|
|
98730
|
+
var logger68, initiate;
|
|
98392
98731
|
var init_upload_controller = __esm(() => {
|
|
98393
98732
|
init_esm();
|
|
98394
98733
|
init_schemas_index();
|
|
98395
98734
|
init_src2();
|
|
98396
98735
|
init_errors();
|
|
98397
98736
|
init_utils11();
|
|
98398
|
-
|
|
98737
|
+
logger68 = log.scope("UploadController");
|
|
98399
98738
|
initiate = requireDeveloper(async (ctx) => {
|
|
98400
98739
|
let body2;
|
|
98401
98740
|
try {
|
|
@@ -98404,34 +98743,34 @@ var init_upload_controller = __esm(() => {
|
|
|
98404
98743
|
} catch (error2) {
|
|
98405
98744
|
if (error2 instanceof exports_external.ZodError) {
|
|
98406
98745
|
const details = formatZodError(error2);
|
|
98407
|
-
|
|
98746
|
+
logger68.warn("Initiate upload validation failed", { details });
|
|
98408
98747
|
throw ApiError.unprocessableEntity("Validation failed", details);
|
|
98409
98748
|
}
|
|
98410
98749
|
throw ApiError.badRequest("Invalid JSON body");
|
|
98411
98750
|
}
|
|
98412
|
-
|
|
98751
|
+
logger68.debug("Initiating upload", { userId: ctx.user.id, gameId: body2.gameId });
|
|
98413
98752
|
return ctx.services.upload.initiate(body2, ctx.user);
|
|
98414
98753
|
});
|
|
98415
98754
|
});
|
|
98416
98755
|
|
|
98417
98756
|
// ../api-core/src/controllers/user.controller.ts
|
|
98418
|
-
var
|
|
98757
|
+
var logger69, getMe, getDemoProfile, updateDemoProfile, users2;
|
|
98419
98758
|
var init_user_controller = __esm(() => {
|
|
98420
98759
|
init_schemas_index();
|
|
98421
98760
|
init_src2();
|
|
98422
98761
|
init_utils11();
|
|
98423
|
-
|
|
98762
|
+
logger69 = log.scope("UserController");
|
|
98424
98763
|
getMe = requireNonAnonymous(async (ctx) => {
|
|
98425
|
-
|
|
98764
|
+
logger69.debug("Getting current user", { userId: ctx.user.id, gameId: ctx.gameId });
|
|
98426
98765
|
return ctx.services.user.getMe(ctx.user, ctx.gameId);
|
|
98427
98766
|
});
|
|
98428
98767
|
getDemoProfile = requireAnonymous(async (ctx) => {
|
|
98429
|
-
|
|
98768
|
+
logger69.debug("Getting demo profile", { userId: ctx.user.id });
|
|
98430
98769
|
return ctx.services.user.getDemoProfile(ctx.user.id);
|
|
98431
98770
|
});
|
|
98432
98771
|
updateDemoProfile = requireAnonymous(async (ctx) => {
|
|
98433
98772
|
const body2 = await parseRequestBody(ctx.request, DemoProfileSchema);
|
|
98434
|
-
|
|
98773
|
+
logger69.debug("Updating demo profile", {
|
|
98435
98774
|
userId: ctx.user.id,
|
|
98436
98775
|
displayName: body2.displayName
|
|
98437
98776
|
});
|
|
@@ -98445,13 +98784,13 @@ var init_user_controller = __esm(() => {
|
|
|
98445
98784
|
});
|
|
98446
98785
|
|
|
98447
98786
|
// ../api-core/src/controllers/verify.controller.ts
|
|
98448
|
-
var
|
|
98787
|
+
var logger70;
|
|
98449
98788
|
var init_verify_controller = __esm(() => {
|
|
98450
98789
|
init_schemas_index();
|
|
98451
98790
|
init_src2();
|
|
98452
98791
|
init_errors();
|
|
98453
98792
|
init_utils11();
|
|
98454
|
-
|
|
98793
|
+
logger70 = log.scope("VerifyController");
|
|
98455
98794
|
});
|
|
98456
98795
|
|
|
98457
98796
|
// ../api-core/src/controllers/index.ts
|
|
@@ -98765,7 +99104,7 @@ var init_uploads = __esm(() => {
|
|
|
98765
99104
|
});
|
|
98766
99105
|
|
|
98767
99106
|
// src/routes/platform/games/deploy.ts
|
|
98768
|
-
var
|
|
99107
|
+
var logger71, gameDeployRouter;
|
|
98769
99108
|
var init_deploy = __esm(() => {
|
|
98770
99109
|
init_drizzle_orm();
|
|
98771
99110
|
init_dist4();
|
|
@@ -98775,7 +99114,7 @@ var init_deploy = __esm(() => {
|
|
|
98775
99114
|
init_src2();
|
|
98776
99115
|
init_api();
|
|
98777
99116
|
init_uploads();
|
|
98778
|
-
|
|
99117
|
+
logger71 = log.scope("SandboxDeploy");
|
|
98779
99118
|
gameDeployRouter = new Hono2;
|
|
98780
99119
|
gameDeployRouter.post("/:slug/deploy", async (c2) => {
|
|
98781
99120
|
const user = c2.get("user");
|
|
@@ -98901,7 +99240,7 @@ var init_deploy = __esm(() => {
|
|
|
98901
99240
|
completedAt: now2
|
|
98902
99241
|
};
|
|
98903
99242
|
const [insertedJob] = await db2.insert(gameDeployJobs).values([jobValues]).returning();
|
|
98904
|
-
|
|
99243
|
+
logger71.info("Mock deploy job completed", { jobId: insertedJob.id, slug: slug2 });
|
|
98905
99244
|
return c2.json({
|
|
98906
99245
|
id: insertedJob.id,
|
|
98907
99246
|
status: "succeeded",
|
|
@@ -99548,7 +99887,7 @@ function verifyMockToken(idToken) {
|
|
|
99548
99887
|
throw new Error("Invalid LTI token format");
|
|
99549
99888
|
}
|
|
99550
99889
|
}
|
|
99551
|
-
var
|
|
99890
|
+
var logger72, ltiRouter;
|
|
99552
99891
|
var init_lti = __esm(() => {
|
|
99553
99892
|
init_drizzle_orm();
|
|
99554
99893
|
init_dist4();
|
|
@@ -99558,7 +99897,7 @@ var init_lti = __esm(() => {
|
|
|
99558
99897
|
init_src2();
|
|
99559
99898
|
init_constants();
|
|
99560
99899
|
init_api();
|
|
99561
|
-
|
|
99900
|
+
logger72 = log.scope("SandboxLti");
|
|
99562
99901
|
ltiRouter = new Hono2;
|
|
99563
99902
|
ltiRouter.post("/launch", async (c2) => {
|
|
99564
99903
|
const db2 = c2.get("db");
|
|
@@ -99576,7 +99915,7 @@ var init_lti = __esm(() => {
|
|
|
99576
99915
|
claims = verifyMockToken(idToken);
|
|
99577
99916
|
} catch (error2) {
|
|
99578
99917
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
99579
|
-
|
|
99918
|
+
logger72.error("LTI token verification failed", { error: errorMessage });
|
|
99580
99919
|
return c2.json({
|
|
99581
99920
|
error: "invalid_token",
|
|
99582
99921
|
message: errorMessage
|
|
@@ -99584,7 +99923,7 @@ var init_lti = __esm(() => {
|
|
|
99584
99923
|
}
|
|
99585
99924
|
const validationError = validateLtiClaims(claims);
|
|
99586
99925
|
if (validationError) {
|
|
99587
|
-
|
|
99926
|
+
logger72.warn("LTI claims validation failed", {
|
|
99588
99927
|
error: validationError,
|
|
99589
99928
|
sub: claims.sub
|
|
99590
99929
|
});
|
|
@@ -99604,7 +99943,7 @@ var init_lti = __esm(() => {
|
|
|
99604
99943
|
createdAt: new Date,
|
|
99605
99944
|
updatedAt: new Date
|
|
99606
99945
|
});
|
|
99607
|
-
|
|
99946
|
+
logger72.info("LTI launch successful", { userId: user.id });
|
|
99608
99947
|
const targetUri = claims["https://purl.imsglobal.org/spec/lti/claim/target_link_uri"];
|
|
99609
99948
|
const currentHost = new URL(c2.req.url).hostname;
|
|
99610
99949
|
const redirectPath = extractRedirectPath(targetUri, currentHost);
|
|
@@ -99612,7 +99951,7 @@ var init_lti = __esm(() => {
|
|
|
99612
99951
|
return c2.redirect(redirectPath);
|
|
99613
99952
|
} catch (error2) {
|
|
99614
99953
|
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
99615
|
-
|
|
99954
|
+
logger72.error("Unexpected error during LTI launch", { error: errorMessage });
|
|
99616
99955
|
return c2.json({
|
|
99617
99956
|
error: "unexpected_error",
|
|
99618
99957
|
message: "An unexpected error occurred during LTI launch"
|