@playcademy/vite-plugin 0.2.22-beta.3 → 0.2.22-beta.4
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 +171 -46
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25334,7 +25334,7 @@ var package_default;
|
|
|
25334
25334
|
var init_package = __esm(() => {
|
|
25335
25335
|
package_default = {
|
|
25336
25336
|
name: "@playcademy/sandbox",
|
|
25337
|
-
version: "0.3.16-beta.
|
|
25337
|
+
version: "0.3.16-beta.4",
|
|
25338
25338
|
description: "Local development server for Playcademy game development",
|
|
25339
25339
|
type: "module",
|
|
25340
25340
|
exports: {
|
|
@@ -54095,16 +54095,7 @@ function mapAssessmentResultToRecentActivity(assessment, relevantCourseIds, cour
|
|
|
54095
54095
|
return null;
|
|
54096
54096
|
}
|
|
54097
54097
|
if (isMasteryCompletionEntry(assessment)) {
|
|
54098
|
-
|
|
54099
|
-
const isResume = Boolean(metadata3?.resumedAt);
|
|
54100
|
-
return {
|
|
54101
|
-
id: assessment.sourcedId || `${assessment.assessmentLineItem.sourcedId}:${assessment.scoreDate}`,
|
|
54102
|
-
kind: "admin-completion",
|
|
54103
|
-
occurredAt: assessment.scoreDate,
|
|
54104
|
-
courseId,
|
|
54105
|
-
title: isResume ? "Course resumed" : "Course marked complete",
|
|
54106
|
-
reason: metadata3?.adminAction ? "Admin action" : undefined
|
|
54107
|
-
};
|
|
54098
|
+
return null;
|
|
54108
54099
|
}
|
|
54109
54100
|
const metadata2 = isRecord2(assessment.metadata) ? assessment.metadata : undefined;
|
|
54110
54101
|
const activityName = getStringValue(metadata2?.activityName);
|
|
@@ -54137,6 +54128,7 @@ function parseCaliperEventContext(event, relevantCourseIds) {
|
|
|
54137
54128
|
courseId,
|
|
54138
54129
|
occurredAt,
|
|
54139
54130
|
eventKind: getStringValue(playcademy?.eventKind),
|
|
54131
|
+
source: getStringValue(playcademy?.source),
|
|
54140
54132
|
reason: getStringValue(playcademy?.reason),
|
|
54141
54133
|
titleFromEvent: getStringValue(event.object.activity?.name),
|
|
54142
54134
|
appName: getStringValue(event.object.app?.name),
|
|
@@ -54160,30 +54152,59 @@ function mapTimeSpentRemediation(event, ctx) {
|
|
|
54160
54152
|
};
|
|
54161
54153
|
}
|
|
54162
54154
|
function mapActivityRemediation(event, ctx) {
|
|
54163
|
-
let kind;
|
|
54164
54155
|
if (ctx.eventKind === "remediation-xp") {
|
|
54165
|
-
|
|
54166
|
-
|
|
54167
|
-
|
|
54168
|
-
|
|
54169
|
-
|
|
54156
|
+
return {
|
|
54157
|
+
id: event.externalId,
|
|
54158
|
+
kind: "remediation-xp",
|
|
54159
|
+
occurredAt: ctx.occurredAt,
|
|
54160
|
+
courseId: ctx.courseId,
|
|
54161
|
+
title: "XP Adjustment",
|
|
54162
|
+
activityId: ctx.activityId,
|
|
54163
|
+
appName: ctx.appName,
|
|
54164
|
+
reason: ctx.reason,
|
|
54165
|
+
xpDelta: getGeneratedMetricValue(event, "xpEarned"),
|
|
54166
|
+
masteredUnitsDelta: getGeneratedMetricValue(event, "masteredUnits")
|
|
54167
|
+
};
|
|
54170
54168
|
}
|
|
54171
|
-
|
|
54172
|
-
|
|
54173
|
-
|
|
54174
|
-
|
|
54175
|
-
|
|
54176
|
-
|
|
54177
|
-
|
|
54178
|
-
|
|
54179
|
-
|
|
54180
|
-
|
|
54181
|
-
|
|
54182
|
-
|
|
54183
|
-
|
|
54184
|
-
|
|
54185
|
-
|
|
54186
|
-
|
|
54169
|
+
if (ctx.eventKind === "remediation-mastery") {
|
|
54170
|
+
return {
|
|
54171
|
+
id: event.externalId,
|
|
54172
|
+
kind: "remediation-mastery",
|
|
54173
|
+
occurredAt: ctx.occurredAt,
|
|
54174
|
+
courseId: ctx.courseId,
|
|
54175
|
+
title: "Mastery Adjustment",
|
|
54176
|
+
activityId: ctx.activityId,
|
|
54177
|
+
appName: ctx.appName,
|
|
54178
|
+
reason: ctx.reason,
|
|
54179
|
+
xpDelta: getGeneratedMetricValue(event, "xpEarned"),
|
|
54180
|
+
masteredUnitsDelta: getGeneratedMetricValue(event, "masteredUnits")
|
|
54181
|
+
};
|
|
54182
|
+
}
|
|
54183
|
+
if (ctx.eventKind === "course-completed") {
|
|
54184
|
+
return {
|
|
54185
|
+
id: event.externalId,
|
|
54186
|
+
kind: "course-completed",
|
|
54187
|
+
occurredAt: ctx.occurredAt,
|
|
54188
|
+
courseId: ctx.courseId,
|
|
54189
|
+
title: ctx.source === "admin" ? "Course marked complete" : "Course completed",
|
|
54190
|
+
activityId: ctx.activityId,
|
|
54191
|
+
appName: ctx.appName,
|
|
54192
|
+
reason: ctx.reason
|
|
54193
|
+
};
|
|
54194
|
+
}
|
|
54195
|
+
if (ctx.eventKind === "course-resumed") {
|
|
54196
|
+
return {
|
|
54197
|
+
id: event.externalId,
|
|
54198
|
+
kind: "course-resumed",
|
|
54199
|
+
occurredAt: ctx.occurredAt,
|
|
54200
|
+
courseId: ctx.courseId,
|
|
54201
|
+
title: "Course resumed",
|
|
54202
|
+
activityId: ctx.activityId,
|
|
54203
|
+
appName: ctx.appName,
|
|
54204
|
+
reason: ctx.reason
|
|
54205
|
+
};
|
|
54206
|
+
}
|
|
54207
|
+
return null;
|
|
54187
54208
|
}
|
|
54188
54209
|
function mapCaliperEventToRemediationActivity(event, relevantCourseIds) {
|
|
54189
54210
|
const ctx = parseCaliperEventContext(event, relevantCourseIds);
|
|
@@ -54204,6 +54225,7 @@ var init_timeback_util = __esm(() => {
|
|
|
54204
54225
|
|
|
54205
54226
|
class TimebackAdminService {
|
|
54206
54227
|
deps;
|
|
54228
|
+
static XP_PRECISION_FACTOR = 10;
|
|
54207
54229
|
static RECENT_ACTIVITY_LIMIT = 20;
|
|
54208
54230
|
static MAX_STUDENT_ACTIVITY_LIMIT = 200;
|
|
54209
54231
|
static MAX_STUDENT_ACTIVITY_OFFSET = 1000;
|
|
@@ -54215,6 +54237,10 @@ class TimebackAdminService {
|
|
|
54215
54237
|
constructor(deps) {
|
|
54216
54238
|
this.deps = deps;
|
|
54217
54239
|
}
|
|
54240
|
+
static roundXpToTenths(value) {
|
|
54241
|
+
const rounded = Math.round(value * TimebackAdminService.XP_PRECISION_FACTOR) / TimebackAdminService.XP_PRECISION_FACTOR;
|
|
54242
|
+
return Object.is(rounded, -0) ? 0 : rounded;
|
|
54243
|
+
}
|
|
54218
54244
|
requireClient() {
|
|
54219
54245
|
if (!this.deps.timeback) {
|
|
54220
54246
|
logger16.error("Timeback client not available in context");
|
|
@@ -54222,6 +54248,17 @@ class TimebackAdminService {
|
|
|
54222
54248
|
}
|
|
54223
54249
|
return this.deps.timeback;
|
|
54224
54250
|
}
|
|
54251
|
+
async recordCourseCompletionHistory(client, data) {
|
|
54252
|
+
await client.recordAdminCourseCompletionChange(data).catch((error) => {
|
|
54253
|
+
logger16.error("Failed to record admin course completion history event", {
|
|
54254
|
+
gameId: data.gameId,
|
|
54255
|
+
courseId: data.courseId,
|
|
54256
|
+
studentId: data.studentId,
|
|
54257
|
+
action: data.action,
|
|
54258
|
+
error: error instanceof Error ? error.message : String(error)
|
|
54259
|
+
});
|
|
54260
|
+
});
|
|
54261
|
+
}
|
|
54225
54262
|
async resolveAdminMutationContext(gameId, courseId, user, studentId) {
|
|
54226
54263
|
const client = this.requireClient();
|
|
54227
54264
|
await this.deps.validateDeveloperAccess(user, gameId);
|
|
@@ -54261,8 +54298,8 @@ class TimebackAdminService {
|
|
|
54261
54298
|
}
|
|
54262
54299
|
const today = formatDateYMD();
|
|
54263
54300
|
const history = [];
|
|
54264
|
-
let
|
|
54265
|
-
let
|
|
54301
|
+
let totalXpRaw = 0;
|
|
54302
|
+
let todayXpRaw = 0;
|
|
54266
54303
|
let activeTimeSeconds = 0;
|
|
54267
54304
|
let masteredUnits = 0;
|
|
54268
54305
|
for (const [date3, subjectFacts] of Object.entries(facts)) {
|
|
@@ -54279,15 +54316,16 @@ class TimebackAdminService {
|
|
|
54279
54316
|
masteredUnitsForDay += masteredUnitsFromFact;
|
|
54280
54317
|
}
|
|
54281
54318
|
}
|
|
54282
|
-
|
|
54319
|
+
const roundedXpForDay = TimebackAdminService.roundXpToTenths(xpForDay);
|
|
54320
|
+
totalXpRaw += xpForDay;
|
|
54283
54321
|
activeTimeSeconds += activeSecondsForDay;
|
|
54284
54322
|
masteredUnits += masteredUnitsForDay;
|
|
54285
54323
|
if (date3 === today) {
|
|
54286
|
-
|
|
54324
|
+
todayXpRaw += xpForDay;
|
|
54287
54325
|
}
|
|
54288
54326
|
history.push({
|
|
54289
54327
|
date: date3,
|
|
54290
|
-
xpEarned:
|
|
54328
|
+
xpEarned: roundedXpForDay,
|
|
54291
54329
|
activeTimeSeconds: activeSecondsForDay,
|
|
54292
54330
|
masteredUnits: masteredUnitsForDay
|
|
54293
54331
|
});
|
|
@@ -54295,8 +54333,8 @@ class TimebackAdminService {
|
|
|
54295
54333
|
history.sort((a, b) => a.date.localeCompare(b.date));
|
|
54296
54334
|
return {
|
|
54297
54335
|
analyticsAvailable: true,
|
|
54298
|
-
totalXp,
|
|
54299
|
-
todayXp,
|
|
54336
|
+
totalXp: TimebackAdminService.roundXpToTenths(totalXpRaw),
|
|
54337
|
+
todayXp: TimebackAdminService.roundXpToTenths(todayXpRaw),
|
|
54300
54338
|
activeTimeSeconds,
|
|
54301
54339
|
masteredUnits,
|
|
54302
54340
|
history
|
|
@@ -54638,6 +54676,7 @@ class TimebackAdminService {
|
|
|
54638
54676
|
}
|
|
54639
54677
|
async toggleCourseCompletion(data, user) {
|
|
54640
54678
|
const { client, sensorUrl, appName, actor } = await this.resolveAdminMutationContext(data.gameId, data.courseId, user, data.studentId);
|
|
54679
|
+
const historyClient = client;
|
|
54641
54680
|
const ids = deriveSourcedIds(data.courseId);
|
|
54642
54681
|
const lineItemId = `${ids.course}-mastery-completion-assessment`;
|
|
54643
54682
|
const resultId = `${lineItemId}:${data.studentId}:completion`;
|
|
@@ -54688,11 +54727,19 @@ class TimebackAdminService {
|
|
|
54688
54727
|
inProgress: "false",
|
|
54689
54728
|
metadata: {
|
|
54690
54729
|
isMasteryCompletion: true,
|
|
54691
|
-
completedAt: new Date().toISOString(),
|
|
54692
54730
|
adminAction: true,
|
|
54693
54731
|
appName
|
|
54694
54732
|
}
|
|
54695
54733
|
});
|
|
54734
|
+
await this.recordCourseCompletionHistory(historyClient, {
|
|
54735
|
+
gameId: data.gameId,
|
|
54736
|
+
courseId: data.courseId,
|
|
54737
|
+
studentId: data.studentId,
|
|
54738
|
+
action: "complete",
|
|
54739
|
+
actor,
|
|
54740
|
+
appName,
|
|
54741
|
+
sensorUrl
|
|
54742
|
+
});
|
|
54696
54743
|
} else {
|
|
54697
54744
|
await client.oneroster.assessmentResults.upsert(resultId, {
|
|
54698
54745
|
sourcedId: resultId,
|
|
@@ -54705,11 +54752,19 @@ class TimebackAdminService {
|
|
|
54705
54752
|
inProgress: "true",
|
|
54706
54753
|
metadata: {
|
|
54707
54754
|
isMasteryCompletion: true,
|
|
54708
|
-
resumedAt: new Date().toISOString(),
|
|
54709
54755
|
adminAction: true,
|
|
54710
54756
|
appName
|
|
54711
54757
|
}
|
|
54712
54758
|
});
|
|
54759
|
+
await this.recordCourseCompletionHistory(historyClient, {
|
|
54760
|
+
gameId: data.gameId,
|
|
54761
|
+
courseId: data.courseId,
|
|
54762
|
+
studentId: data.studentId,
|
|
54763
|
+
action: "resume",
|
|
54764
|
+
actor,
|
|
54765
|
+
appName,
|
|
54766
|
+
sensorUrl
|
|
54767
|
+
});
|
|
54713
54768
|
}
|
|
54714
54769
|
return { status: "ok" };
|
|
54715
54770
|
}
|
|
@@ -58934,7 +58989,8 @@ function buildAdminEventMetadata({
|
|
|
58934
58989
|
return {
|
|
58935
58990
|
playcademy: {
|
|
58936
58991
|
eventKind,
|
|
58937
|
-
reason
|
|
58992
|
+
reason,
|
|
58993
|
+
source: "admin"
|
|
58938
58994
|
}
|
|
58939
58995
|
};
|
|
58940
58996
|
}
|
|
@@ -59050,6 +59106,30 @@ class AdminEventRecorder {
|
|
|
59050
59106
|
eventExtensions: ctx.metadata
|
|
59051
59107
|
});
|
|
59052
59108
|
}
|
|
59109
|
+
async recordCourseCompletionChange(data) {
|
|
59110
|
+
const isResume = data.action === "resume";
|
|
59111
|
+
const ctx = await this.prepareAdminEvent({
|
|
59112
|
+
...data,
|
|
59113
|
+
defaultActivityId: isResume ? "playcademy-admin-course-resumed" : "playcademy-admin-course-completed",
|
|
59114
|
+
reason: "Admin action",
|
|
59115
|
+
eventKind: isResume ? "course-resumed" : "course-completed"
|
|
59116
|
+
});
|
|
59117
|
+
await this.caliper.emitActivityEvent({
|
|
59118
|
+
studentId: ctx.student.id,
|
|
59119
|
+
studentEmail: ctx.student.email,
|
|
59120
|
+
activityId: ctx.activityId,
|
|
59121
|
+
activityName: isResume ? "Course resumed" : "Course marked complete",
|
|
59122
|
+
courseId: data.courseId,
|
|
59123
|
+
courseName: ctx.courseContext.courseName,
|
|
59124
|
+
subject: ctx.courseContext.subject,
|
|
59125
|
+
appName: ctx.appName,
|
|
59126
|
+
sensorUrl: ctx.sensorUrl,
|
|
59127
|
+
process: false,
|
|
59128
|
+
includeAttempt: false,
|
|
59129
|
+
generatedExtensions: ctx.metadata,
|
|
59130
|
+
eventExtensions: ctx.metadata
|
|
59131
|
+
});
|
|
59132
|
+
}
|
|
59053
59133
|
}
|
|
59054
59134
|
|
|
59055
59135
|
class TimebackCache {
|
|
@@ -59263,7 +59343,7 @@ class MasteryTracker {
|
|
|
59263
59343
|
const totalMastered = historicalMasteredUnits + masteredUnits;
|
|
59264
59344
|
const rawPct = totalMastered / masterableUnits * 100;
|
|
59265
59345
|
const pctCompleteApp = Math.min(100, Math.max(0, Math.round(rawPct)));
|
|
59266
|
-
const masteryAchieved = totalMastered >= masterableUnits;
|
|
59346
|
+
const masteryAchieved = historicalMasteredUnits < masterableUnits && totalMastered >= masterableUnits;
|
|
59267
59347
|
return { pctCompleteApp, masteryAchieved };
|
|
59268
59348
|
}
|
|
59269
59349
|
async createCompletionEntry(studentId, courseId, classId, appName) {
|
|
@@ -59289,7 +59369,6 @@ class MasteryTracker {
|
|
|
59289
59369
|
inProgress: "false",
|
|
59290
59370
|
metadata: {
|
|
59291
59371
|
isMasteryCompletion: true,
|
|
59292
|
-
completedAt: new Date().toISOString(),
|
|
59293
59372
|
appName
|
|
59294
59373
|
}
|
|
59295
59374
|
});
|
|
@@ -59505,6 +59584,16 @@ class ProgressRecorder {
|
|
|
59505
59584
|
}
|
|
59506
59585
|
if (masteryAchieved) {
|
|
59507
59586
|
await this.masteryTracker.createCompletionEntry(studentId, courseId, progressData.classId, progressData.appName);
|
|
59587
|
+
await this.emitCourseCompletionHistoryEvent({
|
|
59588
|
+
studentId,
|
|
59589
|
+
studentEmail,
|
|
59590
|
+
activityId,
|
|
59591
|
+
courseId: ids.course,
|
|
59592
|
+
courseName,
|
|
59593
|
+
subject: progressData.subject,
|
|
59594
|
+
appName: progressData.appName,
|
|
59595
|
+
sensorUrl: progressData.sensorUrl
|
|
59596
|
+
});
|
|
59508
59597
|
}
|
|
59509
59598
|
await this.emitCaliperEvent({
|
|
59510
59599
|
studentId,
|
|
@@ -59679,6 +59768,38 @@ class ProgressRecorder {
|
|
|
59679
59768
|
log.error("[ProgressRecorder] Failed to emit activity event", { error });
|
|
59680
59769
|
});
|
|
59681
59770
|
}
|
|
59771
|
+
async emitCourseCompletionHistoryEvent(data) {
|
|
59772
|
+
await this.caliperNamespace.emitActivityEvent({
|
|
59773
|
+
studentId: data.studentId,
|
|
59774
|
+
studentEmail: data.studentEmail,
|
|
59775
|
+
activityId: data.activityId,
|
|
59776
|
+
activityName: "Course completed",
|
|
59777
|
+
courseId: data.courseId,
|
|
59778
|
+
courseName: data.courseName,
|
|
59779
|
+
subject: data.subject,
|
|
59780
|
+
appName: data.appName,
|
|
59781
|
+
sensorUrl: data.sensorUrl,
|
|
59782
|
+
process: false,
|
|
59783
|
+
includeAttempt: false,
|
|
59784
|
+
eventExtensions: {
|
|
59785
|
+
playcademy: {
|
|
59786
|
+
eventKind: "course-completed",
|
|
59787
|
+
source: "gameplay"
|
|
59788
|
+
}
|
|
59789
|
+
},
|
|
59790
|
+
generatedExtensions: {
|
|
59791
|
+
playcademy: {
|
|
59792
|
+
eventKind: "course-completed",
|
|
59793
|
+
source: "gameplay",
|
|
59794
|
+
activityId: data.activityId
|
|
59795
|
+
}
|
|
59796
|
+
}
|
|
59797
|
+
}).catch((error) => {
|
|
59798
|
+
log.error("[ProgressRecorder] Failed to emit course completion history event", {
|
|
59799
|
+
error
|
|
59800
|
+
});
|
|
59801
|
+
});
|
|
59802
|
+
}
|
|
59682
59803
|
}
|
|
59683
59804
|
|
|
59684
59805
|
class SessionRecorder {
|
|
@@ -60073,6 +60194,10 @@ class TimebackClient {
|
|
|
60073
60194
|
await this._ensureAuthenticated();
|
|
60074
60195
|
return this.adminEventRecorder.recordMasteryAdjustment(data);
|
|
60075
60196
|
}
|
|
60197
|
+
async recordAdminCourseCompletionChange(data) {
|
|
60198
|
+
await this._ensureAuthenticated();
|
|
60199
|
+
return this.adminEventRecorder.recordCourseCompletionChange(data);
|
|
60200
|
+
}
|
|
60076
60201
|
clearCaches() {
|
|
60077
60202
|
this.cacheManager.clearAll();
|
|
60078
60203
|
}
|
|
@@ -124862,7 +124987,7 @@ var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
|
124862
124987
|
// package.json
|
|
124863
124988
|
var package_default2 = {
|
|
124864
124989
|
name: "@playcademy/vite-plugin",
|
|
124865
|
-
version: "0.2.22-beta.
|
|
124990
|
+
version: "0.2.22-beta.4",
|
|
124866
124991
|
type: "module",
|
|
124867
124992
|
exports: {
|
|
124868
124993
|
".": {
|