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