@playcademy/vite-plugin 0.3.3-beta.1 → 0.3.3-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/index.js +295 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23746,7 +23746,7 @@ import path from "node:path";
|
|
|
23746
23746
|
// package.json
|
|
23747
23747
|
var package_default = {
|
|
23748
23748
|
name: "@playcademy/vite-plugin",
|
|
23749
|
-
version: "0.3.3-beta.
|
|
23749
|
+
version: "0.3.3-beta.2",
|
|
23750
23750
|
type: "module",
|
|
23751
23751
|
exports: {
|
|
23752
23752
|
".": {
|
|
@@ -24339,6 +24339,8 @@ var TIMEBACK_COURSE_DEFAULTS;
|
|
|
24339
24339
|
var TIMEBACK_RESOURCE_DEFAULTS;
|
|
24340
24340
|
var TIMEBACK_COMPONENT_DEFAULTS;
|
|
24341
24341
|
var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS;
|
|
24342
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES;
|
|
24343
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE;
|
|
24342
24344
|
var init_timeback2 = __esm(() => {
|
|
24343
24345
|
TIMEBACK_ROUTES = {
|
|
24344
24346
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
@@ -24383,6 +24385,17 @@ var init_timeback2 = __esm(() => {
|
|
|
24383
24385
|
sortOrder: 1,
|
|
24384
24386
|
lessonType: "quiz"
|
|
24385
24387
|
};
|
|
24388
|
+
TIMEBACK_GAME_METRIC_DECIMAL_PLACES = {
|
|
24389
|
+
xp: 1,
|
|
24390
|
+
mastery: 0,
|
|
24391
|
+
score: 2
|
|
24392
|
+
};
|
|
24393
|
+
TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE = {
|
|
24394
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.xp,
|
|
24395
|
+
mastery: 0,
|
|
24396
|
+
time: 60,
|
|
24397
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES.score
|
|
24398
|
+
};
|
|
24386
24399
|
});
|
|
24387
24400
|
var WORKER_NAMING;
|
|
24388
24401
|
var SECRETS_PREFIX = "secrets_";
|
|
@@ -25177,7 +25190,7 @@ var package_default2;
|
|
|
25177
25190
|
var init_package = __esm(() => {
|
|
25178
25191
|
package_default2 = {
|
|
25179
25192
|
name: "@playcademy/sandbox",
|
|
25180
|
-
version: "0.4.1-beta.
|
|
25193
|
+
version: "0.4.1-beta.2",
|
|
25181
25194
|
description: "Local development server for Playcademy game development",
|
|
25182
25195
|
type: "module",
|
|
25183
25196
|
exports: {
|
|
@@ -53873,7 +53886,7 @@ var CourseGoalsSchema;
|
|
|
53873
53886
|
var UpdateGameTimebackIntegrationRequestSchema;
|
|
53874
53887
|
var TimebackActivityDataSchema;
|
|
53875
53888
|
var EndActivityRequestSchema;
|
|
53876
|
-
var
|
|
53889
|
+
var GameRunMetricsSchema;
|
|
53877
53890
|
var GameCourseMetricsSchema;
|
|
53878
53891
|
var GameMetricsResponseSchema;
|
|
53879
53892
|
var AdvanceCourseRequestSchema;
|
|
@@ -53972,22 +53985,22 @@ var init_schemas4 = __esm(() => {
|
|
|
53972
53985
|
message: "Cannot provide both masteredUnits and masteredUnitsAbsolute",
|
|
53973
53986
|
path: ["masteredUnitsAbsolute"]
|
|
53974
53987
|
});
|
|
53975
|
-
|
|
53988
|
+
GameRunMetricsSchema = exports_external.object({
|
|
53989
|
+
runId: exports_external.string().uuid(),
|
|
53976
53990
|
activityId: exports_external.string().min(1),
|
|
53977
53991
|
activityName: exports_external.string().optional(),
|
|
53978
|
-
totalXp: exports_external.number().nonnegative(),
|
|
53979
|
-
masteredUnits: exports_external.number().int().nonnegative(),
|
|
53980
|
-
activeTimeSeconds: exports_external.number().nonnegative(),
|
|
53981
|
-
|
|
53982
|
-
lastCompletedAt: exports_external.string().datetime().optional()
|
|
53992
|
+
totalXp: exports_external.number().nonnegative().optional(),
|
|
53993
|
+
masteredUnits: exports_external.number().int().nonnegative().optional(),
|
|
53994
|
+
activeTimeSeconds: exports_external.number().nonnegative().optional(),
|
|
53995
|
+
score: exports_external.number().min(0).max(100).optional()
|
|
53983
53996
|
});
|
|
53984
53997
|
GameCourseMetricsSchema = exports_external.object({
|
|
53985
53998
|
grade: TimebackGradeSchema,
|
|
53986
53999
|
subject: TimebackSubjectSchema,
|
|
53987
|
-
totalXp: exports_external.number().nonnegative(),
|
|
53988
|
-
masteredUnits: exports_external.number().int().nonnegative(),
|
|
53989
|
-
activeTimeSeconds: exports_external.number().nonnegative(),
|
|
53990
|
-
activities: exports_external.array(
|
|
54000
|
+
totalXp: exports_external.number().nonnegative().optional(),
|
|
54001
|
+
masteredUnits: exports_external.number().int().nonnegative().optional(),
|
|
54002
|
+
activeTimeSeconds: exports_external.number().nonnegative().optional(),
|
|
54003
|
+
activities: exports_external.array(GameRunMetricsSchema).optional()
|
|
53991
54004
|
});
|
|
53992
54005
|
GameMetricsResponseSchema = exports_external.object({
|
|
53993
54006
|
studentId: exports_external.string().min(1),
|
|
@@ -54257,6 +54270,122 @@ function compareEnrollmentsByRecency(a, b) {
|
|
|
54257
54270
|
var init_timeback_admin_util = __esm(() => {
|
|
54258
54271
|
init_errors();
|
|
54259
54272
|
});
|
|
54273
|
+
function createMetricRow(definition) {
|
|
54274
|
+
const { gameValue, kind, metric, timebackValue, tolerance } = definition;
|
|
54275
|
+
if (timebackValue === undefined && gameValue === undefined) {
|
|
54276
|
+
return null;
|
|
54277
|
+
}
|
|
54278
|
+
if (gameValue === undefined) {
|
|
54279
|
+
return {
|
|
54280
|
+
metric,
|
|
54281
|
+
kind,
|
|
54282
|
+
status: "not_reported_by_game",
|
|
54283
|
+
...timebackValue !== undefined ? { timebackValue } : {}
|
|
54284
|
+
};
|
|
54285
|
+
}
|
|
54286
|
+
if (timebackValue === undefined) {
|
|
54287
|
+
return {
|
|
54288
|
+
metric,
|
|
54289
|
+
kind,
|
|
54290
|
+
status: "not_recorded_by_timeback",
|
|
54291
|
+
gameValue
|
|
54292
|
+
};
|
|
54293
|
+
}
|
|
54294
|
+
const delta = gameValue - timebackValue;
|
|
54295
|
+
const isDiscrepant = tolerance === 0 ? delta !== 0 : Math.abs(delta) >= tolerance;
|
|
54296
|
+
return {
|
|
54297
|
+
metric,
|
|
54298
|
+
kind,
|
|
54299
|
+
status: isDiscrepant ? "discrepant" : "matched",
|
|
54300
|
+
timebackValue,
|
|
54301
|
+
gameValue,
|
|
54302
|
+
delta
|
|
54303
|
+
};
|
|
54304
|
+
}
|
|
54305
|
+
function createRunComparison(activity, gameRun) {
|
|
54306
|
+
const runId = activity.runId ?? "";
|
|
54307
|
+
if (!gameRun) {
|
|
54308
|
+
return {
|
|
54309
|
+
runId,
|
|
54310
|
+
status: "not_reported",
|
|
54311
|
+
discrepancyCount: 0,
|
|
54312
|
+
rows: []
|
|
54313
|
+
};
|
|
54314
|
+
}
|
|
54315
|
+
const rows = [
|
|
54316
|
+
createMetricRow({
|
|
54317
|
+
metric: "xp",
|
|
54318
|
+
kind: "number",
|
|
54319
|
+
timebackValue: activity.xpDelta,
|
|
54320
|
+
gameValue: gameRun.totalXp,
|
|
54321
|
+
tolerance: TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE.xp
|
|
54322
|
+
}),
|
|
54323
|
+
createMetricRow({
|
|
54324
|
+
metric: "mastery",
|
|
54325
|
+
kind: "number",
|
|
54326
|
+
timebackValue: activity.masteredUnitsDelta,
|
|
54327
|
+
gameValue: gameRun.masteredUnits,
|
|
54328
|
+
tolerance: TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE.mastery
|
|
54329
|
+
}),
|
|
54330
|
+
createMetricRow({
|
|
54331
|
+
metric: "time",
|
|
54332
|
+
kind: "time",
|
|
54333
|
+
timebackValue: activity.timeDeltaSeconds,
|
|
54334
|
+
gameValue: gameRun.activeTimeSeconds,
|
|
54335
|
+
tolerance: TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE.time
|
|
54336
|
+
}),
|
|
54337
|
+
createMetricRow({
|
|
54338
|
+
metric: "score",
|
|
54339
|
+
kind: "percent",
|
|
54340
|
+
timebackValue: activity.score,
|
|
54341
|
+
gameValue: gameRun.score,
|
|
54342
|
+
tolerance: TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE.score
|
|
54343
|
+
})
|
|
54344
|
+
].filter((row) => row !== null);
|
|
54345
|
+
const discrepancyCount = rows.filter((row) => row.status === "discrepant").length;
|
|
54346
|
+
return {
|
|
54347
|
+
runId,
|
|
54348
|
+
status: discrepancyCount > 0 ? "discrepant" : "matched",
|
|
54349
|
+
discrepancyCount,
|
|
54350
|
+
rows
|
|
54351
|
+
};
|
|
54352
|
+
}
|
|
54353
|
+
function summarizeGameRunMetricsComparison(comparison) {
|
|
54354
|
+
return {
|
|
54355
|
+
runId: comparison.runId,
|
|
54356
|
+
status: comparison.status,
|
|
54357
|
+
discrepancyCount: comparison.discrepancyCount,
|
|
54358
|
+
...comparison.reason ? { reason: comparison.reason } : {}
|
|
54359
|
+
};
|
|
54360
|
+
}
|
|
54361
|
+
function buildGameRunMetricComparisons(activities, course, response) {
|
|
54362
|
+
const activitiesWithRunIds = activities.filter((activity) => typeof activity.runId === "string" && activity.runId.length > 0);
|
|
54363
|
+
const comparisons = new Map;
|
|
54364
|
+
if (activitiesWithRunIds.length === 0) {
|
|
54365
|
+
return comparisons;
|
|
54366
|
+
}
|
|
54367
|
+
if (!response.supported) {
|
|
54368
|
+
for (const activity of activitiesWithRunIds) {
|
|
54369
|
+
comparisons.set(activity.runId, {
|
|
54370
|
+
runId: activity.runId,
|
|
54371
|
+
status: "unavailable",
|
|
54372
|
+
discrepancyCount: 0,
|
|
54373
|
+
reason: response.reason,
|
|
54374
|
+
rows: []
|
|
54375
|
+
});
|
|
54376
|
+
}
|
|
54377
|
+
return comparisons;
|
|
54378
|
+
}
|
|
54379
|
+
const gameCourseMetrics = response.metrics.courses.find((gameCourse) => gameCourse.grade === course.grade && gameCourse.subject === course.subject);
|
|
54380
|
+
const gameRunsById = new Map(gameCourseMetrics?.activities?.map((gameRun) => [gameRun.runId.toLowerCase(), gameRun]));
|
|
54381
|
+
for (const activity of activitiesWithRunIds) {
|
|
54382
|
+
comparisons.set(activity.runId, createRunComparison(activity, gameRunsById.get(activity.runId.toLowerCase())));
|
|
54383
|
+
}
|
|
54384
|
+
return comparisons;
|
|
54385
|
+
}
|
|
54386
|
+
var init_timeback_game_metrics_comparison_util = __esm(() => {
|
|
54387
|
+
init_src();
|
|
54388
|
+
});
|
|
54260
54389
|
async function upsertMasteryCompletionEntry(params) {
|
|
54261
54390
|
const { client, courseId, studentId, appName, action } = params;
|
|
54262
54391
|
const ids = deriveSourcedIds(courseId);
|
|
@@ -54643,6 +54772,8 @@ class TimebackAdminService {
|
|
|
54643
54772
|
static ANALYTICS_CONCURRENCY = 8;
|
|
54644
54773
|
static MASTERABLE_UNITS_CONCURRENCY = 4;
|
|
54645
54774
|
static GAME_METRICS_FETCH_TIMEOUT_MS = 1e4;
|
|
54775
|
+
static GAME_METRICS_LIST_FETCH_TIMEOUT_MS = 3000;
|
|
54776
|
+
static GAME_METRICS_RUN_IDS_PER_REQUEST = 50;
|
|
54646
54777
|
constructor(deps) {
|
|
54647
54778
|
this.deps = deps;
|
|
54648
54779
|
}
|
|
@@ -54652,13 +54783,42 @@ class TimebackAdminService {
|
|
|
54652
54783
|
}
|
|
54653
54784
|
return this.deps.config.localGameUrls[slug2] ?? deployedUrl;
|
|
54654
54785
|
}
|
|
54655
|
-
static resolveGameMetricsUrl(baseUrl) {
|
|
54786
|
+
static resolveGameMetricsUrl(baseUrl, runIds) {
|
|
54656
54787
|
try {
|
|
54657
|
-
|
|
54788
|
+
const url2 = new URL("/__playcademy/metrics", baseUrl);
|
|
54789
|
+
for (const runId of runIds ?? []) {
|
|
54790
|
+
url2.searchParams.append("runId", runId);
|
|
54791
|
+
}
|
|
54792
|
+
return url2;
|
|
54658
54793
|
} catch {
|
|
54659
54794
|
return null;
|
|
54660
54795
|
}
|
|
54661
54796
|
}
|
|
54797
|
+
static normalizeRunIds(runIds, limit = Number.POSITIVE_INFINITY) {
|
|
54798
|
+
const normalized = [];
|
|
54799
|
+
const seen = new Set;
|
|
54800
|
+
for (const runId of runIds ?? []) {
|
|
54801
|
+
const value = runId.trim().toLowerCase();
|
|
54802
|
+
if (isValidUUID(value) && !seen.has(value)) {
|
|
54803
|
+
seen.add(value);
|
|
54804
|
+
normalized.push(value);
|
|
54805
|
+
if (normalized.length >= limit) {
|
|
54806
|
+
break;
|
|
54807
|
+
}
|
|
54808
|
+
}
|
|
54809
|
+
}
|
|
54810
|
+
return normalized;
|
|
54811
|
+
}
|
|
54812
|
+
static chunkRunIds(runIds) {
|
|
54813
|
+
const chunks = [];
|
|
54814
|
+
for (let index2 = 0;index2 < runIds.length; index2 += this.GAME_METRICS_RUN_IDS_PER_REQUEST) {
|
|
54815
|
+
chunks.push(runIds.slice(index2, index2 + this.GAME_METRICS_RUN_IDS_PER_REQUEST));
|
|
54816
|
+
}
|
|
54817
|
+
return chunks;
|
|
54818
|
+
}
|
|
54819
|
+
static isAbortError(error) {
|
|
54820
|
+
return error instanceof Error && error.name === "AbortError";
|
|
54821
|
+
}
|
|
54662
54822
|
static roundXpToTenths(value) {
|
|
54663
54823
|
const rounded = Math.round(value * TimebackAdminService.XP_PRECISION_FACTOR) / TimebackAdminService.XP_PRECISION_FACTOR;
|
|
54664
54824
|
return Object.is(rounded, -0) ? 0 : rounded;
|
|
@@ -54819,6 +54979,56 @@ class TimebackAdminService {
|
|
|
54819
54979
|
const remediationItems = events.map((event) => mapCaliperEventToRemediationActivity(event, relevantCourseIds)).filter((item) => Boolean(item));
|
|
54820
54980
|
return [...groupedGameplayItems, ...remediationItems].toSorted((a, b) => b.occurredAt.localeCompare(a.occurredAt));
|
|
54821
54981
|
}
|
|
54982
|
+
async getGameMetricComparisonsForActivities(user, options) {
|
|
54983
|
+
const runIds = TimebackAdminService.normalizeRunIds(options.activities.map((activity) => activity.runId).filter((runId) => Boolean(runId)));
|
|
54984
|
+
if (runIds.length === 0) {
|
|
54985
|
+
return new Map;
|
|
54986
|
+
}
|
|
54987
|
+
const activitiesByRunId = new Map(options.activities.filter((activity) => typeof activity.runId === "string" && activity.runId.length > 0).map((activity) => [activity.runId.toLowerCase(), activity]));
|
|
54988
|
+
const comparisons = new Map;
|
|
54989
|
+
await Promise.all(TimebackAdminService.chunkRunIds(runIds).map(async (chunk) => {
|
|
54990
|
+
const activities = [];
|
|
54991
|
+
for (const runId of chunk) {
|
|
54992
|
+
const activity = activitiesByRunId.get(runId);
|
|
54993
|
+
if (activity) {
|
|
54994
|
+
activities.push(activity);
|
|
54995
|
+
}
|
|
54996
|
+
}
|
|
54997
|
+
if (activities.length === 0) {
|
|
54998
|
+
return;
|
|
54999
|
+
}
|
|
55000
|
+
let response;
|
|
55001
|
+
try {
|
|
55002
|
+
response = await this.getGameMetrics(options.gameId, options.studentId, user, {
|
|
55003
|
+
runIds: chunk,
|
|
55004
|
+
timeoutMs: options.timeoutMs
|
|
55005
|
+
});
|
|
55006
|
+
} catch (error) {
|
|
55007
|
+
response = {
|
|
55008
|
+
supported: false,
|
|
55009
|
+
reason: "fetch_failed",
|
|
55010
|
+
details: error instanceof Error ? error.message : String(error)
|
|
55011
|
+
};
|
|
55012
|
+
}
|
|
55013
|
+
for (const [runId, comparison] of buildGameRunMetricComparisons(activities, options.course, response)) {
|
|
55014
|
+
comparisons.set(runId, comparison);
|
|
55015
|
+
}
|
|
55016
|
+
}));
|
|
55017
|
+
return comparisons;
|
|
55018
|
+
}
|
|
55019
|
+
async attachGameMetricSummariesToActivities(user, options) {
|
|
55020
|
+
const comparisons = await this.getGameMetricComparisonsForActivities(user, options);
|
|
55021
|
+
if (comparisons.size === 0) {
|
|
55022
|
+
return [...options.activities];
|
|
55023
|
+
}
|
|
55024
|
+
return options.activities.map((activity) => {
|
|
55025
|
+
const comparison = activity.runId ? comparisons.get(activity.runId) : undefined;
|
|
55026
|
+
return comparison ? {
|
|
55027
|
+
...activity,
|
|
55028
|
+
gameMetricsComparison: summarizeGameRunMetricsComparison(comparison)
|
|
55029
|
+
} : activity;
|
|
55030
|
+
});
|
|
55031
|
+
}
|
|
54822
55032
|
async getStudentEnrollmentsByCourseId(client, studentId, courseIds, options) {
|
|
54823
55033
|
const enrollments = new Map;
|
|
54824
55034
|
const allEnrollments = new Map;
|
|
@@ -54978,7 +55188,7 @@ class TimebackAdminService {
|
|
|
54978
55188
|
});
|
|
54979
55189
|
return { gameId, courseId, students: deduped };
|
|
54980
55190
|
}
|
|
54981
|
-
async getGameMetrics(gameId, timebackId, user) {
|
|
55191
|
+
async getGameMetrics(gameId, timebackId, user, options) {
|
|
54982
55192
|
const client = this.requireClient();
|
|
54983
55193
|
await this.deps.validateGameManagementAccess(user, gameId);
|
|
54984
55194
|
const [targetUser, integrations, game2, deployment] = await Promise.all([
|
|
@@ -55013,7 +55223,8 @@ class TimebackAdminService {
|
|
|
55013
55223
|
if (!metricsBaseUrl) {
|
|
55014
55224
|
return { supported: false, reason: "no_active_deployment" };
|
|
55015
55225
|
}
|
|
55016
|
-
const
|
|
55226
|
+
const runIds = TimebackAdminService.normalizeRunIds(options?.runIds, TimebackAdminService.GAME_METRICS_RUN_IDS_PER_REQUEST);
|
|
55227
|
+
const metricsUrl = TimebackAdminService.resolveGameMetricsUrl(metricsBaseUrl, runIds);
|
|
55017
55228
|
if (!metricsUrl) {
|
|
55018
55229
|
return {
|
|
55019
55230
|
supported: false,
|
|
@@ -55023,7 +55234,7 @@ class TimebackAdminService {
|
|
|
55023
55234
|
}
|
|
55024
55235
|
const token = await this.deps.mintPlatformServiceToken(gameId, targetUser.id);
|
|
55025
55236
|
const controller = new AbortController;
|
|
55026
|
-
const timeout = setTimeout(() => controller.abort(), TimebackAdminService.GAME_METRICS_FETCH_TIMEOUT_MS);
|
|
55237
|
+
const timeout = setTimeout(() => controller.abort(), options?.timeoutMs ?? TimebackAdminService.GAME_METRICS_FETCH_TIMEOUT_MS);
|
|
55027
55238
|
let response;
|
|
55028
55239
|
try {
|
|
55029
55240
|
response = await fetch(metricsUrl, {
|
|
@@ -55035,10 +55246,19 @@ class TimebackAdminService {
|
|
|
55035
55246
|
signal: controller.signal
|
|
55036
55247
|
});
|
|
55037
55248
|
} catch (error) {
|
|
55249
|
+
const timedOut = TimebackAdminService.isAbortError(error);
|
|
55250
|
+
let details;
|
|
55251
|
+
if (timedOut) {
|
|
55252
|
+
details = "Game metrics request timed out";
|
|
55253
|
+
} else if (error instanceof Error) {
|
|
55254
|
+
details = error.message;
|
|
55255
|
+
} else {
|
|
55256
|
+
details = String(error);
|
|
55257
|
+
}
|
|
55038
55258
|
return {
|
|
55039
55259
|
supported: false,
|
|
55040
|
-
reason: "fetch_failed",
|
|
55041
|
-
details
|
|
55260
|
+
reason: timedOut ? "timeout" : "fetch_failed",
|
|
55261
|
+
details
|
|
55042
55262
|
};
|
|
55043
55263
|
} finally {
|
|
55044
55264
|
clearTimeout(timeout);
|
|
@@ -55142,7 +55362,14 @@ class TimebackAdminService {
|
|
|
55142
55362
|
const allActivities = await this.listRecentActivityForStudent(client, studentId, gameSource, relevantCourseIds, fetchLimit);
|
|
55143
55363
|
const activities = allActivities.slice(safeOffset, safeOffset + safeLimit);
|
|
55144
55364
|
const hasMore = allActivities.length > safeOffset + safeLimit;
|
|
55145
|
-
|
|
55365
|
+
const activitiesWithGameMetrics = await this.attachGameMetricSummariesToActivities(user, {
|
|
55366
|
+
gameId,
|
|
55367
|
+
studentId,
|
|
55368
|
+
course: { grade: integration.grade, subject: integration.subject },
|
|
55369
|
+
activities,
|
|
55370
|
+
timeoutMs: TimebackAdminService.GAME_METRICS_LIST_FETCH_TIMEOUT_MS
|
|
55371
|
+
});
|
|
55372
|
+
return { activities: activitiesWithGameMetrics, hasMore };
|
|
55146
55373
|
}
|
|
55147
55374
|
async getActivityDetail(user, options) {
|
|
55148
55375
|
const { gameId, studentId, courseId, activityId, runId } = options;
|
|
@@ -55178,7 +55405,22 @@ class TimebackAdminService {
|
|
|
55178
55405
|
if (!activity) {
|
|
55179
55406
|
throw new NotFoundError("Activity", activityId);
|
|
55180
55407
|
}
|
|
55181
|
-
|
|
55408
|
+
const comparisons = await this.getGameMetricComparisonsForActivities(user, {
|
|
55409
|
+
gameId,
|
|
55410
|
+
studentId,
|
|
55411
|
+
course: { grade: integration.grade, subject: integration.subject },
|
|
55412
|
+
activities: [activity]
|
|
55413
|
+
});
|
|
55414
|
+
const gameMetricsComparison = activity.runId ? comparisons.get(activity.runId) : undefined;
|
|
55415
|
+
const activityWithGameMetrics = gameMetricsComparison ? {
|
|
55416
|
+
...activity,
|
|
55417
|
+
gameMetricsComparison: summarizeGameRunMetricsComparison(gameMetricsComparison)
|
|
55418
|
+
} : activity;
|
|
55419
|
+
return {
|
|
55420
|
+
activity: activityWithGameMetrics,
|
|
55421
|
+
rawEvents: matchedEvents,
|
|
55422
|
+
...gameMetricsComparison ? { gameMetricsComparison } : {}
|
|
55423
|
+
};
|
|
55182
55424
|
}
|
|
55183
55425
|
async grantManualXp(data, user) {
|
|
55184
55426
|
const { client, sensorUrl, appName, actor } = await this.resolveAdminMutationContext(data.gameId, data.courseId, user, data.studentId);
|
|
@@ -55466,6 +55708,7 @@ var init_timeback_admin_service = __esm(() => {
|
|
|
55466
55708
|
init_errors();
|
|
55467
55709
|
init_timeback_admin_metrics_util();
|
|
55468
55710
|
init_timeback_admin_util();
|
|
55711
|
+
init_timeback_game_metrics_comparison_util();
|
|
55469
55712
|
init_timeback_mastery_completion_util();
|
|
55470
55713
|
init_timeback_util();
|
|
55471
55714
|
logger17 = log.scope("TimebackAdminService");
|
|
@@ -120916,15 +121159,19 @@ var init_timeback_controller = __esm(() => {
|
|
|
120916
121159
|
getGameMetrics = requireGameManagementAccess(async (ctx) => {
|
|
120917
121160
|
const gameId = ctx.params.gameId;
|
|
120918
121161
|
const timebackId = ctx.params.timebackId;
|
|
121162
|
+
const runIds = [
|
|
121163
|
+
...new Set(ctx.url.searchParams.getAll("runId").map((runId) => runId.trim().toLowerCase()).filter(isValidUUID))
|
|
121164
|
+
];
|
|
120919
121165
|
if (!gameId || !timebackId) {
|
|
120920
121166
|
throw ApiError.badRequest("Missing gameId or timebackId path parameter");
|
|
120921
121167
|
}
|
|
120922
121168
|
logger45.debug("Getting game metrics", {
|
|
120923
121169
|
requesterId: ctx.user.id,
|
|
120924
121170
|
gameId,
|
|
120925
|
-
timebackId
|
|
121171
|
+
timebackId,
|
|
121172
|
+
runIds
|
|
120926
121173
|
});
|
|
120927
|
-
return ctx.services.timebackAdmin.getGameMetrics(gameId, timebackId, ctx.user);
|
|
121174
|
+
return ctx.services.timebackAdmin.getGameMetrics(gameId, timebackId, ctx.user, { runIds });
|
|
120928
121175
|
});
|
|
120929
121176
|
getStudentActivity = requireGameManagementAccess(async (ctx) => {
|
|
120930
121177
|
const timebackId = ctx.params.timebackId;
|
|
@@ -122767,6 +123014,17 @@ var POSTHOG_CONFIG = {
|
|
|
122767
123014
|
var TIMEBACK_ORG_SOURCED_ID2 = "PLAYCADEMY";
|
|
122768
123015
|
var TIMEBACK_ORG_NAME2 = "Playcademy Studios";
|
|
122769
123016
|
var TIMEBACK_ORG_TYPE2 = "department";
|
|
123017
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES2 = {
|
|
123018
|
+
xp: 1,
|
|
123019
|
+
mastery: 0,
|
|
123020
|
+
score: 2
|
|
123021
|
+
};
|
|
123022
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE2 = {
|
|
123023
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES2.xp,
|
|
123024
|
+
mastery: 0,
|
|
123025
|
+
time: 60,
|
|
123026
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES2.score
|
|
123027
|
+
};
|
|
122770
123028
|
// src/lib/sandbox/timeback.ts
|
|
122771
123029
|
function detectTimebackOptions() {
|
|
122772
123030
|
if (process.env.TIMEBACK_LOCAL === "true") {
|
|
@@ -122983,6 +123241,8 @@ var TIMEBACK_COURSE_DEFAULTS2;
|
|
|
122983
123241
|
var TIMEBACK_RESOURCE_DEFAULTS2;
|
|
122984
123242
|
var TIMEBACK_COMPONENT_DEFAULTS2;
|
|
122985
123243
|
var TIMEBACK_COMPONENT_RESOURCE_DEFAULTS2;
|
|
123244
|
+
var TIMEBACK_GAME_METRIC_DECIMAL_PLACES3;
|
|
123245
|
+
var TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE3;
|
|
122986
123246
|
var init_timeback7 = __esm8(() => {
|
|
122987
123247
|
TIMEBACK_ROUTES2 = {
|
|
122988
123248
|
END_ACTIVITY: "/integrations/timeback/end-activity",
|
|
@@ -123027,6 +123287,17 @@ var init_timeback7 = __esm8(() => {
|
|
|
123027
123287
|
sortOrder: 1,
|
|
123028
123288
|
lessonType: "quiz"
|
|
123029
123289
|
};
|
|
123290
|
+
TIMEBACK_GAME_METRIC_DECIMAL_PLACES3 = {
|
|
123291
|
+
xp: 1,
|
|
123292
|
+
mastery: 0,
|
|
123293
|
+
score: 2
|
|
123294
|
+
};
|
|
123295
|
+
TIMEBACK_GAME_METRIC_COMPARISON_TOLERANCE3 = {
|
|
123296
|
+
xp: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES3.xp,
|
|
123297
|
+
mastery: 0,
|
|
123298
|
+
time: 60,
|
|
123299
|
+
score: 0.5 / 10 ** TIMEBACK_GAME_METRIC_DECIMAL_PLACES3.score
|
|
123300
|
+
};
|
|
123030
123301
|
});
|
|
123031
123302
|
var WORKER_NAMING2;
|
|
123032
123303
|
var init_cloudflare2 = __esm8(() => {
|