@playcademy/sandbox 0.5.1-beta.2 → 0.5.1-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.
Files changed (3) hide show
  1. package/dist/cli.js +23 -56
  2. package/dist/server.js +23 -56
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1078,7 +1078,7 @@ var package_default;
1078
1078
  var init_package = __esm(() => {
1079
1079
  package_default = {
1080
1080
  name: "@playcademy/sandbox",
1081
- version: "0.5.1-beta.2",
1081
+ version: "0.5.1-beta.4",
1082
1082
  description: "Local development server for Playcademy game development",
1083
1083
  type: "module",
1084
1084
  exports: {
@@ -32125,44 +32125,6 @@ function validateSessionData(sessionData) {
32125
32125
  throw new ConfigurationError("sensorUrl", 'Sensor URL is required for Caliper events. Provide it in sessionData.sensorUrl (e.g., "https://hub.playcademy.net/p/your-game")');
32126
32126
  }
32127
32127
  }
32128
- function getAttemptMultiplier(attemptNumber) {
32129
- switch (attemptNumber) {
32130
- case 1: {
32131
- return 1;
32132
- }
32133
- case 2: {
32134
- return 0.5;
32135
- }
32136
- case 3: {
32137
- return 0.25;
32138
- }
32139
- default: {
32140
- return 0;
32141
- }
32142
- }
32143
- }
32144
- function getAccuracyMultiplier(accuracy) {
32145
- if (!Number.isFinite(accuracy) || accuracy < 0) {
32146
- return 0;
32147
- }
32148
- if (accuracy >= PERFECT_ACCURACY_THRESHOLD) {
32149
- return 1.25;
32150
- } else if (accuracy >= 0.8) {
32151
- return 1;
32152
- } else {
32153
- return 0;
32154
- }
32155
- }
32156
- function calculateXp(durationSeconds, accuracy, attemptNumber) {
32157
- if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) {
32158
- return 0;
32159
- }
32160
- const durationMinutes = durationSeconds / 60;
32161
- const baseXp = Number(durationMinutes);
32162
- const accuracyMultiplier = getAccuracyMultiplier(accuracy);
32163
- const attemptMultiplier = getAttemptMultiplier(attemptNumber);
32164
- return Math.round(baseXp * accuracyMultiplier * attemptMultiplier * 10) / 10;
32165
- }
32166
32128
 
32167
32129
  class ProgressRecorder {
32168
32130
  studentResolver;
@@ -32181,10 +32143,15 @@ class ProgressRecorder {
32181
32143
  validateProgressData(progressData);
32182
32144
  const { ids, activityId, activityName, courseName, student } = await this.resolveContext(courseId, studentIdentifier, progressData);
32183
32145
  const { id: studentId, email: studentEmail } = student;
32184
- const { score, totalQuestions, correctQuestions, xpEarned, attemptNumber } = progressData;
32146
+ const {
32147
+ score,
32148
+ totalQuestions,
32149
+ correctQuestions,
32150
+ xpEarned = 0,
32151
+ attemptNumber
32152
+ } = progressData;
32185
32153
  const actualLineItemId = await this.resolveAssessmentLineItem(activityId, activityName, progressData.classId, ids);
32186
32154
  const currentAttemptNumber = await this.resolveAttemptNumber(attemptNumber, score, studentId, actualLineItemId);
32187
- const calculatedXp = this.calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, currentAttemptNumber);
32188
32155
  let extensions = progressData.extensions;
32189
32156
  const masteryProgress = await this.masteryTracker.checkProgress({
32190
32157
  studentId,
@@ -32215,7 +32182,7 @@ class ProgressRecorder {
32215
32182
  studentId,
32216
32183
  attemptNumber: currentAttemptNumber,
32217
32184
  score,
32218
- xp: calculatedXp,
32185
+ xp: xpEarned,
32219
32186
  scoreStatus,
32220
32187
  inProgress,
32221
32188
  appName: progressData.appName,
@@ -32254,7 +32221,7 @@ class ProgressRecorder {
32254
32221
  courseName,
32255
32222
  totalQuestions,
32256
32223
  correctQuestions,
32257
- xpEarned: calculatedXp,
32224
+ xpEarned,
32258
32225
  masteredUnits: effectiveMasteredUnits || undefined,
32259
32226
  attemptNumber: currentAttemptNumber,
32260
32227
  progressData,
@@ -32262,7 +32229,7 @@ class ProgressRecorder {
32262
32229
  runId: progressData.runId
32263
32230
  });
32264
32231
  return {
32265
- xpAwarded: calculatedXp,
32232
+ xpAwarded: xpEarned,
32266
32233
  attemptNumber: currentAttemptNumber,
32267
32234
  masteredUnitsApplied: effectiveMasteredUnits,
32268
32235
  pctCompleteApp,
@@ -32296,16 +32263,6 @@ class ProgressRecorder {
32296
32263
  }
32297
32264
  return 1;
32298
32265
  }
32299
- calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, attemptNumber) {
32300
- if (xpEarned !== undefined) {
32301
- return xpEarned;
32302
- }
32303
- if (progressData.durationSeconds && totalQuestions && correctQuestions) {
32304
- const accuracy = correctQuestions / totalQuestions;
32305
- return calculateXp(progressData.durationSeconds, accuracy, attemptNumber);
32306
- }
32307
- return 0;
32308
- }
32309
32266
  async getOrCreateLineItem(lineItemId, activityName, classId, ids) {
32310
32267
  try {
32311
32268
  const lineItem = await this.onerosterNamespace.assessmentLineItems.findOrCreate(lineItemId, {
@@ -32963,7 +32920,7 @@ var __defProp2, __export2 = (target, all) => {
32963
32920
  configurable: true,
32964
32921
  set: (newValue) => all[name3] = () => newValue
32965
32922
  });
32966
- }, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), TIMEBACK_API_URLS, QTI_API_URL = "https://qti.alpha-1edtech.ai/api", TIMEBACK_AUTH_URLS, CALIPER_API_URLS, ONEROSTER_ENDPOINTS, QTI_ENDPOINTS, CALIPER_ENDPOINTS, CALIPER_CONSTANTS, TIMEBACK_EVENT_TYPES, TIMEBACK_ACTIONS, TIMEBACK_TYPES, ACTIVITY_METRIC_TYPES, TIME_METRIC_TYPES, TIMEBACK_SUBJECTS, TIMEBACK_GRADE_LEVELS, TIMEBACK_GRADE_LEVEL_LABELS, CALIPER_SUBJECTS, ONEROSTER_STATUS, SCORE_STATUS, ENV_VARS, HTTP_DEFAULTS, AUTH_DEFAULTS, CACHE_DEFAULTS, CONFIG_DEFAULTS, PLAYCADEMY_DEFAULTS, RESOURCE_DEFAULTS, HTTP_STATUS, ERROR_NAMES, init_constants4, exports_verify, init_verify, TimebackError, TimebackApiError, TimebackAuthenticationError, StudentNotFoundError, ConfigurationError, ResourceNotFoundError, SUBJECT_VALUES, GRADE_VALUES, TimebackAuthError, UUID_PATTERN, storage, PERFECT_ACCURACY_THRESHOLD = 0.999999, EmailSchema, StudentSourcedIdSchema, StudentIdentifierSchema;
32923
+ }, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), TIMEBACK_API_URLS, QTI_API_URL = "https://qti.alpha-1edtech.ai/api", TIMEBACK_AUTH_URLS, CALIPER_API_URLS, ONEROSTER_ENDPOINTS, QTI_ENDPOINTS, CALIPER_ENDPOINTS, CALIPER_CONSTANTS, TIMEBACK_EVENT_TYPES, TIMEBACK_ACTIONS, TIMEBACK_TYPES, ACTIVITY_METRIC_TYPES, TIME_METRIC_TYPES, TIMEBACK_SUBJECTS, TIMEBACK_GRADE_LEVELS, TIMEBACK_GRADE_LEVEL_LABELS, CALIPER_SUBJECTS, ONEROSTER_STATUS, SCORE_STATUS, ENV_VARS, HTTP_DEFAULTS, AUTH_DEFAULTS, CACHE_DEFAULTS, CONFIG_DEFAULTS, PLAYCADEMY_DEFAULTS, RESOURCE_DEFAULTS, HTTP_STATUS, ERROR_NAMES, init_constants4, exports_verify, init_verify, TimebackError, TimebackApiError, TimebackAuthenticationError, StudentNotFoundError, ConfigurationError, ResourceNotFoundError, SUBJECT_VALUES, GRADE_VALUES, TimebackAuthError, UUID_PATTERN, storage, EmailSchema, StudentSourcedIdSchema, StudentIdentifierSchema;
32967
32924
  var init_dist2 = __esm(() => {
32968
32925
  init_src();
32969
32926
  init_src();
@@ -34494,7 +34451,7 @@ var init_schemas4 = __esm(() => {
34494
34451
  activeSeconds: exports_external.number().nonnegative(),
34495
34452
  inactiveSeconds: exports_external.number().nonnegative().optional()
34496
34453
  }).optional(),
34497
- xpEarned: exports_external.number().optional(),
34454
+ xpEarned: exports_external.number(),
34498
34455
  masteredUnits: exports_external.number().optional(),
34499
34456
  masteredUnitsAbsolute: exports_external.number().int().nonnegative().optional(),
34500
34457
  extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
@@ -98297,7 +98254,12 @@ var init_timeback7 = __esm(() => {
98297
98254
  const includePerCourse = includeOptions.includes("percourse");
98298
98255
  const includeToday = includeOptions.includes("today");
98299
98256
  const db2 = c2.get("db");
98257
+ const contextGameId = c2.get("gameId");
98258
+ const gameId = url2.searchParams.get("gameId") || (typeof contextGameId === "string" ? contextGameId : undefined);
98300
98259
  let enrollments = await getMockEnrollments(db2);
98260
+ if (gameId) {
98261
+ enrollments = filterEnrollmentsByGame(enrollments, gameId);
98262
+ }
98301
98263
  if (gradeParam !== null !== (subjectParam !== null)) {
98302
98264
  const error2 = ApiError.badRequest("Both grade and subject must be provided together");
98303
98265
  return c2.json(createErrorResponse(error2), error2.status);
@@ -98350,7 +98312,12 @@ var init_timeback7 = __esm(() => {
98350
98312
  const includeOptions = includeParam.split(",").map((opt) => opt.trim().toLowerCase());
98351
98313
  const includePerCourse = includeOptions.includes("percourse");
98352
98314
  const db2 = c2.get("db");
98315
+ const contextGameId = c2.get("gameId");
98316
+ const gameId = url2.searchParams.get("gameId") || (typeof contextGameId === "string" ? contextGameId : undefined);
98353
98317
  let enrollments = await getMockEnrollments(db2);
98318
+ if (gameId) {
98319
+ enrollments = filterEnrollmentsByGame(enrollments, gameId);
98320
+ }
98354
98321
  if (gradeParam !== null !== (subjectParam !== null)) {
98355
98322
  const error2 = ApiError.badRequest("Both grade and subject must be provided together");
98356
98323
  return c2.json(createErrorResponse(error2), error2.status);
package/dist/server.js CHANGED
@@ -1077,7 +1077,7 @@ var package_default;
1077
1077
  var init_package = __esm(() => {
1078
1078
  package_default = {
1079
1079
  name: "@playcademy/sandbox",
1080
- version: "0.5.1-beta.2",
1080
+ version: "0.5.1-beta.4",
1081
1081
  description: "Local development server for Playcademy game development",
1082
1082
  type: "module",
1083
1083
  exports: {
@@ -32124,44 +32124,6 @@ function validateSessionData(sessionData) {
32124
32124
  throw new ConfigurationError("sensorUrl", 'Sensor URL is required for Caliper events. Provide it in sessionData.sensorUrl (e.g., "https://hub.playcademy.net/p/your-game")');
32125
32125
  }
32126
32126
  }
32127
- function getAttemptMultiplier(attemptNumber) {
32128
- switch (attemptNumber) {
32129
- case 1: {
32130
- return 1;
32131
- }
32132
- case 2: {
32133
- return 0.5;
32134
- }
32135
- case 3: {
32136
- return 0.25;
32137
- }
32138
- default: {
32139
- return 0;
32140
- }
32141
- }
32142
- }
32143
- function getAccuracyMultiplier(accuracy) {
32144
- if (!Number.isFinite(accuracy) || accuracy < 0) {
32145
- return 0;
32146
- }
32147
- if (accuracy >= PERFECT_ACCURACY_THRESHOLD) {
32148
- return 1.25;
32149
- } else if (accuracy >= 0.8) {
32150
- return 1;
32151
- } else {
32152
- return 0;
32153
- }
32154
- }
32155
- function calculateXp(durationSeconds, accuracy, attemptNumber) {
32156
- if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) {
32157
- return 0;
32158
- }
32159
- const durationMinutes = durationSeconds / 60;
32160
- const baseXp = Number(durationMinutes);
32161
- const accuracyMultiplier = getAccuracyMultiplier(accuracy);
32162
- const attemptMultiplier = getAttemptMultiplier(attemptNumber);
32163
- return Math.round(baseXp * accuracyMultiplier * attemptMultiplier * 10) / 10;
32164
- }
32165
32127
 
32166
32128
  class ProgressRecorder {
32167
32129
  studentResolver;
@@ -32180,10 +32142,15 @@ class ProgressRecorder {
32180
32142
  validateProgressData(progressData);
32181
32143
  const { ids, activityId, activityName, courseName, student } = await this.resolveContext(courseId, studentIdentifier, progressData);
32182
32144
  const { id: studentId, email: studentEmail } = student;
32183
- const { score, totalQuestions, correctQuestions, xpEarned, attemptNumber } = progressData;
32145
+ const {
32146
+ score,
32147
+ totalQuestions,
32148
+ correctQuestions,
32149
+ xpEarned = 0,
32150
+ attemptNumber
32151
+ } = progressData;
32184
32152
  const actualLineItemId = await this.resolveAssessmentLineItem(activityId, activityName, progressData.classId, ids);
32185
32153
  const currentAttemptNumber = await this.resolveAttemptNumber(attemptNumber, score, studentId, actualLineItemId);
32186
- const calculatedXp = this.calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, currentAttemptNumber);
32187
32154
  let extensions = progressData.extensions;
32188
32155
  const masteryProgress = await this.masteryTracker.checkProgress({
32189
32156
  studentId,
@@ -32214,7 +32181,7 @@ class ProgressRecorder {
32214
32181
  studentId,
32215
32182
  attemptNumber: currentAttemptNumber,
32216
32183
  score,
32217
- xp: calculatedXp,
32184
+ xp: xpEarned,
32218
32185
  scoreStatus,
32219
32186
  inProgress,
32220
32187
  appName: progressData.appName,
@@ -32253,7 +32220,7 @@ class ProgressRecorder {
32253
32220
  courseName,
32254
32221
  totalQuestions,
32255
32222
  correctQuestions,
32256
- xpEarned: calculatedXp,
32223
+ xpEarned,
32257
32224
  masteredUnits: effectiveMasteredUnits || undefined,
32258
32225
  attemptNumber: currentAttemptNumber,
32259
32226
  progressData,
@@ -32261,7 +32228,7 @@ class ProgressRecorder {
32261
32228
  runId: progressData.runId
32262
32229
  });
32263
32230
  return {
32264
- xpAwarded: calculatedXp,
32231
+ xpAwarded: xpEarned,
32265
32232
  attemptNumber: currentAttemptNumber,
32266
32233
  masteredUnitsApplied: effectiveMasteredUnits,
32267
32234
  pctCompleteApp,
@@ -32295,16 +32262,6 @@ class ProgressRecorder {
32295
32262
  }
32296
32263
  return 1;
32297
32264
  }
32298
- calculateXpForProgress(progressData, totalQuestions, correctQuestions, xpEarned, attemptNumber) {
32299
- if (xpEarned !== undefined) {
32300
- return xpEarned;
32301
- }
32302
- if (progressData.durationSeconds && totalQuestions && correctQuestions) {
32303
- const accuracy = correctQuestions / totalQuestions;
32304
- return calculateXp(progressData.durationSeconds, accuracy, attemptNumber);
32305
- }
32306
- return 0;
32307
- }
32308
32265
  async getOrCreateLineItem(lineItemId, activityName, classId, ids) {
32309
32266
  try {
32310
32267
  const lineItem = await this.onerosterNamespace.assessmentLineItems.findOrCreate(lineItemId, {
@@ -32962,7 +32919,7 @@ var __defProp2, __export2 = (target, all) => {
32962
32919
  configurable: true,
32963
32920
  set: (newValue) => all[name3] = () => newValue
32964
32921
  });
32965
- }, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), TIMEBACK_API_URLS, QTI_API_URL = "https://qti.alpha-1edtech.ai/api", TIMEBACK_AUTH_URLS, CALIPER_API_URLS, ONEROSTER_ENDPOINTS, QTI_ENDPOINTS, CALIPER_ENDPOINTS, CALIPER_CONSTANTS, TIMEBACK_EVENT_TYPES, TIMEBACK_ACTIONS, TIMEBACK_TYPES, ACTIVITY_METRIC_TYPES, TIME_METRIC_TYPES, TIMEBACK_SUBJECTS, TIMEBACK_GRADE_LEVELS, TIMEBACK_GRADE_LEVEL_LABELS, CALIPER_SUBJECTS, ONEROSTER_STATUS, SCORE_STATUS, ENV_VARS, HTTP_DEFAULTS, AUTH_DEFAULTS, CACHE_DEFAULTS, CONFIG_DEFAULTS, PLAYCADEMY_DEFAULTS, RESOURCE_DEFAULTS, HTTP_STATUS, ERROR_NAMES, init_constants4, exports_verify, init_verify, TimebackError, TimebackApiError, TimebackAuthenticationError, StudentNotFoundError, ConfigurationError, ResourceNotFoundError, SUBJECT_VALUES, GRADE_VALUES, TimebackAuthError, UUID_PATTERN, storage, PERFECT_ACCURACY_THRESHOLD = 0.999999, EmailSchema, StudentSourcedIdSchema, StudentIdentifierSchema;
32922
+ }, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), TIMEBACK_API_URLS, QTI_API_URL = "https://qti.alpha-1edtech.ai/api", TIMEBACK_AUTH_URLS, CALIPER_API_URLS, ONEROSTER_ENDPOINTS, QTI_ENDPOINTS, CALIPER_ENDPOINTS, CALIPER_CONSTANTS, TIMEBACK_EVENT_TYPES, TIMEBACK_ACTIONS, TIMEBACK_TYPES, ACTIVITY_METRIC_TYPES, TIME_METRIC_TYPES, TIMEBACK_SUBJECTS, TIMEBACK_GRADE_LEVELS, TIMEBACK_GRADE_LEVEL_LABELS, CALIPER_SUBJECTS, ONEROSTER_STATUS, SCORE_STATUS, ENV_VARS, HTTP_DEFAULTS, AUTH_DEFAULTS, CACHE_DEFAULTS, CONFIG_DEFAULTS, PLAYCADEMY_DEFAULTS, RESOURCE_DEFAULTS, HTTP_STATUS, ERROR_NAMES, init_constants4, exports_verify, init_verify, TimebackError, TimebackApiError, TimebackAuthenticationError, StudentNotFoundError, ConfigurationError, ResourceNotFoundError, SUBJECT_VALUES, GRADE_VALUES, TimebackAuthError, UUID_PATTERN, storage, EmailSchema, StudentSourcedIdSchema, StudentIdentifierSchema;
32966
32923
  var init_dist2 = __esm(() => {
32967
32924
  init_src();
32968
32925
  init_src();
@@ -34493,7 +34450,7 @@ var init_schemas4 = __esm(() => {
34493
34450
  activeSeconds: exports_external.number().nonnegative(),
34494
34451
  inactiveSeconds: exports_external.number().nonnegative().optional()
34495
34452
  }).optional(),
34496
- xpEarned: exports_external.number().optional(),
34453
+ xpEarned: exports_external.number(),
34497
34454
  masteredUnits: exports_external.number().optional(),
34498
34455
  masteredUnitsAbsolute: exports_external.number().int().nonnegative().optional(),
34499
34456
  extensions: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
@@ -98296,7 +98253,12 @@ var init_timeback7 = __esm(() => {
98296
98253
  const includePerCourse = includeOptions.includes("percourse");
98297
98254
  const includeToday = includeOptions.includes("today");
98298
98255
  const db2 = c2.get("db");
98256
+ const contextGameId = c2.get("gameId");
98257
+ const gameId = url2.searchParams.get("gameId") || (typeof contextGameId === "string" ? contextGameId : undefined);
98299
98258
  let enrollments = await getMockEnrollments(db2);
98259
+ if (gameId) {
98260
+ enrollments = filterEnrollmentsByGame(enrollments, gameId);
98261
+ }
98300
98262
  if (gradeParam !== null !== (subjectParam !== null)) {
98301
98263
  const error2 = ApiError.badRequest("Both grade and subject must be provided together");
98302
98264
  return c2.json(createErrorResponse(error2), error2.status);
@@ -98349,7 +98311,12 @@ var init_timeback7 = __esm(() => {
98349
98311
  const includeOptions = includeParam.split(",").map((opt) => opt.trim().toLowerCase());
98350
98312
  const includePerCourse = includeOptions.includes("percourse");
98351
98313
  const db2 = c2.get("db");
98314
+ const contextGameId = c2.get("gameId");
98315
+ const gameId = url2.searchParams.get("gameId") || (typeof contextGameId === "string" ? contextGameId : undefined);
98352
98316
  let enrollments = await getMockEnrollments(db2);
98317
+ if (gameId) {
98318
+ enrollments = filterEnrollmentsByGame(enrollments, gameId);
98319
+ }
98353
98320
  if (gradeParam !== null !== (subjectParam !== null)) {
98354
98321
  const error2 = ApiError.badRequest("Both grade and subject must be provided together");
98355
98322
  return c2.json(createErrorResponse(error2), error2.status);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/sandbox",
3
- "version": "0.5.1-beta.2",
3
+ "version": "0.5.1-beta.4",
4
4
  "description": "Local development server for Playcademy game development",
5
5
  "type": "module",
6
6
  "exports": {