@playcademy/sandbox 0.8.1-beta.2 → 0.8.1-beta.3

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 +18 -103
  2. package/dist/server.js +18 -103
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1128,7 +1128,7 @@ var package_default;
1128
1128
  var init_package = __esm(() => {
1129
1129
  package_default = {
1130
1130
  name: "@playcademy/sandbox",
1131
- version: "0.8.1-beta.2",
1131
+ version: "0.8.1-beta.3",
1132
1132
  description: "Local development server for Playcademy game development",
1133
1133
  type: "module",
1134
1134
  exports: {
@@ -10767,39 +10767,21 @@ function compareNewestCompletedAssessmentAttempt(left, right) {
10767
10767
  return newestAttempt(left, right, "scoreDate");
10768
10768
  }
10769
10769
  function compareAssessmentCatalogOrder(left, right) {
10770
- if (left.sortOrder !== null || right.sortOrder !== null) {
10771
- if (left.sortOrder === null) {
10772
- return 1;
10773
- }
10774
- if (right.sortOrder === null) {
10775
- return -1;
10776
- }
10777
- const orderDifference = left.sortOrder - right.sortOrder;
10778
- if (orderDifference) {
10779
- return orderDifference;
10780
- }
10781
- }
10782
- const leftUpdatedAt = Date.parse(left.updatedAt);
10783
- const rightUpdatedAt = Date.parse(right.updatedAt);
10784
- const leftHasValidDate = Number.isFinite(leftUpdatedAt);
10785
- const rightHasValidDate = Number.isFinite(rightUpdatedAt);
10786
- if (leftHasValidDate && rightHasValidDate) {
10787
- const updatedDifference = leftUpdatedAt - rightUpdatedAt;
10788
- if (updatedDifference) {
10789
- return updatedDifference;
10790
- }
10791
- } else if (leftHasValidDate !== rightHasValidDate) {
10792
- return leftHasValidDate ? -1 : 1;
10793
- }
10794
10770
  if (left.assessmentKey !== null && right.assessmentKey !== null) {
10795
- const keyDifference = left.assessmentKey.localeCompare(right.assessmentKey);
10771
+ const keyDifference = compareCodePoints(left.assessmentKey, right.assessmentKey);
10796
10772
  if (keyDifference) {
10797
10773
  return keyDifference;
10798
10774
  }
10799
10775
  } else if (left.assessmentKey !== null || right.assessmentKey !== null) {
10800
10776
  return left.assessmentKey === null ? 1 : -1;
10801
10777
  }
10802
- return left.qtiTestIdentifier.localeCompare(right.qtiTestIdentifier);
10778
+ return compareCodePoints(left.qtiTestIdentifier, right.qtiTestIdentifier);
10779
+ }
10780
+ function compareCodePoints(left, right) {
10781
+ if (left === right) {
10782
+ return 0;
10783
+ }
10784
+ return left < right ? -1 : 1;
10803
10785
  }
10804
10786
  function orderRuntimeAssessmentTests(tests) {
10805
10787
  return [...tests].toSorted(compareAssessmentCatalogOrder);
@@ -11583,7 +11565,7 @@ function playcademyDiagnosticAssessmentItemResultMetadata(value) {
11583
11565
  const normalized = metadata2.responses === undefined ? { ...metadata2, responses: {} } : metadata2;
11584
11566
  return isPlaycademyDiagnosticAssessmentItemResultMetadataV1(normalized) ? normalized : null;
11585
11567
  }
11586
- var SCRIPT_SCHEMES, DATA_RASTER_IMAGE_PATTERN, QTI_MATHML_ALLOWED_TAGS, metadataSymbol, parser, SUPPORTED_QTI_INTERACTION_TYPES, URL_ATTRIBUTES, IMAGE_URL_ATTRIBUTES, INTERACTION_TYPES, EMPHASIS_TAGS, STRONG_TAGS, CONTENT_SKIPPED_TAGS, BLOCK_CONTENT_KINDS, GAP_MATCH_TOKEN_TAGS, STAGE_GRAPHIC_EXCLUDED_CONTAINERS, BLANK_SENTINEL = "￿", MARKED_BLANK_PATTERN, MARKED_BLANK_GLOBAL_PATTERN, MATCH_CORRECT_TEMPLATE = "http://www.imsglobal.org/question/qti_v3p0/rptemplates/match_correct", MAP_RESPONSE_TEMPLATE = "https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/map_response", MAP_RESPONSE_TEMPLATES, RESPONSE_PROCESSING_TEMPLATES, VOID_BODY_ELEMENTS, URL_ATTRIBUTES2, IMAGE_URL_ATTRIBUTES2, VOID_CHOICE_ELEMENTS, NUMERIC_COMPARISON_ATTRIBUTES, RESPONSE_CARDINALITIES, RESPONSE_BASE_TYPES, POINT_INTERACTION_TYPES, INDEPENDENT_PROCESSING_TAGS, UUID_PATTERN, COMMON_CORE_MATH_FRAMEWORK_ALIASES, COMMON_CORE_ELA_FRAMEWORK_ALIASES, COMMON_CORE_FRAMEWORK_ALIASES, ASSESSMENT_ATTEMPT_OPEN, ASSESSMENT_ATTEMPT_COMPLETED, ASSESSMENT_ATTEMPT_AWAITING_AWARD, ASSESSMENT_ATTEMPT_SUPERSEDED, ASSESSMENT_RUNTIME_ERROR_STATUS, ROUTING_KEY_MAX_LENGTH = 128, ROUTING_RESULT_KEY_MAX_LENGTH = 256, ROUTING_STAGE_LIMIT = 32, ROUTING_TRACK_LIMIT = 128, ROUTING_NODE_LIMIT = 1000, ROUTING_TERMINAL_LIMIT = 1000, ROUTING_GROUP_LIMIT = 128, ROUTING_PREDICATE_DEPTH_LIMIT = 8, ROUTING_EXPLORATION_STATE_LIMIT = 200000, RoutingKeySchema, RoutingResultKeySchema, DiagnosticTrackOutcomeSchema, DiagnosticActivationPredicateSchema, DiagnosticRoutingTransitionSchema, DiagnosticRoutingManifestV1Schema, GRADE_VALUES, POINT_RESPONSE_PATTERN, REVIEW_SELECTION_POLICY_VERSION = "unseen-first-least-recently-delivered-v1", PLAYCADEMY_REVIEW_BANK_MANIFEST_METADATA_KEY = "playcademyReviewBank", PLAYCADEMY_REVIEW_BANK_MANIFEST_VERSION = 1, DEFAULT_REVIEW_SELECTION_POLICY, ASSESSMENT_RUNTIME_FIXTURE_BUNDLE_VERSION = 7, RuntimeSubjectSchema, RuntimeGradeSchema, OptionalQueryGradeSchema, AssessmentResponseValueSchema, AssessmentRuntimeIdentitySchema, ResponseKeySchema, StartAssessmentBaseSchema, AssessmentStandardRefSchema, LatestAssessmentFilterBaseSchema, LatestAssessmentFiltersSchema, LatestRuntimeAssessmentQuerySchema, StartAssessmentBodySchema, SaveAssessmentBodySchema, SubmitAssessmentItemBodySchema, SubmitAssessmentBodySchema, FinalizeAssessmentBodySchema, StartRuntimeAssessmentRequestSchema, SaveRuntimeAssessmentRequestSchema, SubmitAssessmentItemRuntimeRequestSchema, SubmitRuntimeAssessmentRequestSchema, FinalizeRuntimeAssessmentRequestSchema;
11568
+ var SCRIPT_SCHEMES, DATA_RASTER_IMAGE_PATTERN, QTI_MATHML_ALLOWED_TAGS, metadataSymbol, parser, SUPPORTED_QTI_INTERACTION_TYPES, URL_ATTRIBUTES, IMAGE_URL_ATTRIBUTES, INTERACTION_TYPES, EMPHASIS_TAGS, STRONG_TAGS, CONTENT_SKIPPED_TAGS, BLOCK_CONTENT_KINDS, GAP_MATCH_TOKEN_TAGS, STAGE_GRAPHIC_EXCLUDED_CONTAINERS, BLANK_SENTINEL = "￿", MARKED_BLANK_PATTERN, MARKED_BLANK_GLOBAL_PATTERN, MATCH_CORRECT_TEMPLATE = "http://www.imsglobal.org/question/qti_v3p0/rptemplates/match_correct", MAP_RESPONSE_TEMPLATE = "https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/map_response", MAP_RESPONSE_TEMPLATES, RESPONSE_PROCESSING_TEMPLATES, VOID_BODY_ELEMENTS, URL_ATTRIBUTES2, IMAGE_URL_ATTRIBUTES2, VOID_CHOICE_ELEMENTS, NUMERIC_COMPARISON_ATTRIBUTES, RESPONSE_CARDINALITIES, RESPONSE_BASE_TYPES, POINT_INTERACTION_TYPES, INDEPENDENT_PROCESSING_TAGS, UUID_PATTERN, COMMON_CORE_MATH_FRAMEWORK_ALIASES, COMMON_CORE_ELA_FRAMEWORK_ALIASES, COMMON_CORE_FRAMEWORK_ALIASES, ASSESSMENT_ATTEMPT_OPEN, ASSESSMENT_ATTEMPT_COMPLETED, ASSESSMENT_ATTEMPT_AWAITING_AWARD, ASSESSMENT_ATTEMPT_SUPERSEDED, ASSESSMENT_RUNTIME_ERROR_STATUS, ROUTING_KEY_MAX_LENGTH = 128, ROUTING_RESULT_KEY_MAX_LENGTH = 256, ROUTING_STAGE_LIMIT = 32, ROUTING_TRACK_LIMIT = 128, ROUTING_NODE_LIMIT = 1000, ROUTING_TERMINAL_LIMIT = 1000, ROUTING_GROUP_LIMIT = 128, ROUTING_PREDICATE_DEPTH_LIMIT = 8, ROUTING_EXPLORATION_STATE_LIMIT = 200000, RoutingKeySchema, RoutingResultKeySchema, DiagnosticTrackOutcomeSchema, DiagnosticActivationPredicateSchema, DiagnosticRoutingTransitionSchema, DiagnosticRoutingManifestV1Schema, GRADE_VALUES, POINT_RESPONSE_PATTERN, REVIEW_SELECTION_POLICY_VERSION = "unseen-first-least-recently-delivered-v1", PLAYCADEMY_REVIEW_BANK_MANIFEST_METADATA_KEY = "playcademyReviewBank", PLAYCADEMY_REVIEW_BANK_MANIFEST_VERSION = 1, DEFAULT_REVIEW_SELECTION_POLICY, ASSESSMENT_RUNTIME_FIXTURE_BUNDLE_VERSION = 8, RuntimeSubjectSchema, RuntimeGradeSchema, OptionalQueryGradeSchema, AssessmentResponseValueSchema, AssessmentRuntimeIdentitySchema, ResponseKeySchema, StartAssessmentBaseSchema, AssessmentStandardRefSchema, LatestAssessmentFilterBaseSchema, LatestAssessmentFiltersSchema, LatestRuntimeAssessmentQuerySchema, StartAssessmentBodySchema, SaveAssessmentBodySchema, SubmitAssessmentItemBodySchema, SubmitAssessmentBodySchema, FinalizeAssessmentBodySchema, StartRuntimeAssessmentRequestSchema, SaveRuntimeAssessmentRequestSchema, SubmitAssessmentItemRuntimeRequestSchema, SubmitRuntimeAssessmentRequestSchema, FinalizeRuntimeAssessmentRequestSchema;
11587
11569
  var init_assessment_runtime2 = __esm(() => {
11588
11570
  init_timeback3();
11589
11571
  init_timeback3();
@@ -47142,7 +47124,7 @@ function rejectSystemManagedReview(input, context2) {
47142
47124
  });
47143
47125
  }
47144
47126
  }
47145
- var TimebackGradeSchema, TimebackSubjectSchema, CourseGoalsSchema, UpdateGameTimebackIntegrationRequestSchema, CreateGameTimebackIntegrationRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameRunMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, UnenrollCourseRequestSchema, 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, VerifyTimebackMetricDiscrepancyRequestSchema, AssessmentPurposeSchema, AssessmentStatusSchema, AssessmentKeySchema, DiagnosticKeySchema, DiagnosticRoutingManifestSchema, DiagnosticAssessmentDefinitionInputSchema, AssessmentStandardRefSchema2, CreateAssessmentRequestSchema, UpdateAssessmentRequestSchema, CopyAssessmentRequestSchema, AssessmentAssociationImportEntrySchema, AttachExistingAssessmentsRequestSchema, ReorderAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
47127
+ var TimebackGradeSchema, TimebackSubjectSchema, CourseGoalsSchema, UpdateGameTimebackIntegrationRequestSchema, CreateGameTimebackIntegrationRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameRunMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, UnenrollCourseRequestSchema, 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, VerifyTimebackMetricDiscrepancyRequestSchema, AssessmentPurposeSchema, AssessmentStatusSchema, AssessmentKeySchema, DiagnosticKeySchema, DiagnosticRoutingManifestSchema, DiagnosticAssessmentDefinitionInputSchema, AssessmentStandardRefSchema2, CreateAssessmentRequestSchema, UpdateAssessmentRequestSchema, CopyAssessmentRequestSchema, AssessmentAssociationImportEntrySchema, AttachExistingAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
47146
47128
  var init_schemas4 = __esm(() => {
47147
47129
  init_esm();
47148
47130
  init_src();
@@ -47429,8 +47411,7 @@ var init_schemas4 = __esm(() => {
47429
47411
  assessmentKey: AssessmentKeySchema,
47430
47412
  qtiTestIdentifier: exports_external.string().trim().min(1, "Assessment identifier is required"),
47431
47413
  purpose: AssessmentPurposeSchema,
47432
- standard: AssessmentStandardRefSchema2.optional(),
47433
- sortOrder: exports_external.number().int().nonnegative().nullable()
47414
+ standard: AssessmentStandardRefSchema2.optional()
47434
47415
  }).superRefine((input, context2) => {
47435
47416
  requireMasteryStandard(input, context2);
47436
47417
  rejectSystemManagedReview(input, context2);
@@ -47480,10 +47461,6 @@ var init_schemas4 = __esm(() => {
47480
47461
  seenKeys.add(assessment.assessmentKey);
47481
47462
  });
47482
47463
  });
47483
- ReorderAssessmentsRequestSchema = exports_external.object({
47484
- purpose: AssessmentPurposeSchema,
47485
- testIdentifiers: exports_external.array(exports_external.string().trim().min(1, "Assessment identifier is required")).min(1, "At least one assessment is required")
47486
- }).superRefine(rejectSystemManagedReview);
47487
47464
  ReorderQuestionsRequestSchema = exports_external.object({
47488
47465
  items: exports_external.array(exports_external.object({
47489
47466
  identifier: exports_external.string().min(1),
@@ -100924,9 +100901,6 @@ function buildAssessmentAssociationUpdates(row, input) {
100924
100901
  updates.standardFramework = null;
100925
100902
  updates.standardIdentifier = null;
100926
100903
  }
100927
- if (row.status === "live" && input.purpose !== row.purpose) {
100928
- updates.sortOrder = null;
100929
- }
100930
100904
  }
100931
100905
  if (input.standard !== undefined) {
100932
100906
  updates.standardFramework = input.standard.framework;
@@ -100934,9 +100908,6 @@ function buildAssessmentAssociationUpdates(row, input) {
100934
100908
  }
100935
100909
  if (input.status !== undefined) {
100936
100910
  updates.status = input.status;
100937
- if (input.status === "archived") {
100938
- updates.sortOrder = null;
100939
- }
100940
100911
  }
100941
100912
  return updates;
100942
100913
  }
@@ -100945,24 +100916,8 @@ function assessmentStandardForRow(row) {
100945
100916
  }
100946
100917
  function validateUniqueAssessmentIdentifiers(testIdentifiers) {
100947
100918
  if (new Set(testIdentifiers).size !== testIdentifiers.length) {
100948
- throw new ValidationError("Assessment order must contain unique identifiers");
100949
- }
100950
- }
100951
- function assertAssessmentOrderUpdateSucceeded(updatedRow) {
100952
- if (!updatedRow) {
100953
- throw new ValidationError("Assessment order changed while it was being saved. Refresh and try again.");
100919
+ throw new ValidationError("Assessment manifests must contain unique QTI test identifiers");
100954
100920
  }
100955
- return updatedRow;
100956
- }
100957
- function lockOrderAssessmentRows(rows) {
100958
- return rows.toSorted((left, right) => left.id.localeCompare(right.id));
100959
- }
100960
- function orderLiveAssessmentRows(liveRows, purpose, testIdentifiers) {
100961
- const rowsByIdentifier = new Map(liveRows.map((row) => [row.qtiTestIdentifier, row]));
100962
- if (liveRows.length !== testIdentifiers.length || testIdentifiers.some((identifier) => !rowsByIdentifier.has(identifier))) {
100963
- throw new ValidationError(`Assessment order must include every live ${purpose} assessment exactly once`);
100964
- }
100965
- return testIdentifiers.map((identifier) => rowsByIdentifier.get(identifier));
100966
100921
  }
100967
100922
  var init_timeback_assessment_rules_util = __esm(() => {
100968
100923
  init_errors2();
@@ -102471,8 +102426,6 @@ var init_timeback_assessment_runtime_service = __esm(async () => {
102471
102426
  id: row.id,
102472
102427
  assessmentKey: row.assessmentKey,
102473
102428
  qtiTestIdentifier: row.qtiTestIdentifier,
102474
- sortOrder: row.sortOrder,
102475
- updatedAt: row.updatedAt.toISOString(),
102476
102429
  standard: assessmentStandardForRow(row)
102477
102430
  })).filter((test) => !matchesMasteryStandard || matchesMasteryStandard(test.standard));
102478
102431
  }
@@ -104090,7 +104043,6 @@ class TimebackAssessmentsService {
104090
104043
  ...test ? { title: test.title } : {},
104091
104044
  purpose: entry.purpose,
104092
104045
  ...entry.standard ? { standard: entry.standard } : {},
104093
- sourceSortOrder: entry.sortOrder,
104094
104046
  ...test && gameSlug ? { editable: isQtiTestOwnedByGame(test, gameSlug) } : {}
104095
104047
  };
104096
104048
  }
@@ -104150,7 +104102,6 @@ class TimebackAssessmentsService {
104150
104102
  qtiTestIdentifier: entry.qtiTestIdentifier,
104151
104103
  purpose: entry.purpose,
104152
104104
  status: input.targetStatus,
104153
- sortOrder: entry.sortOrder,
104154
104105
  standardFramework: entry.standard?.framework,
104155
104106
  standardIdentifier: entry.standard?.identifier
104156
104107
  }).onConflictDoNothing().returning();
@@ -104283,7 +104234,7 @@ class TimebackAssessmentsService {
104283
104234
  if (plan.kind === "delete") {
104284
104235
  await tx.delete(gameTimebackAssessmentTests).where(eq(gameTimebackAssessmentTests.id, row.id));
104285
104236
  } else if (plan.kind === "archive") {
104286
- await tx.update(gameTimebackAssessmentTests).set({ status: "archived", sortOrder: null, updatedAt: new Date }).where(eq(gameTimebackAssessmentTests.id, row.id));
104237
+ await tx.update(gameTimebackAssessmentTests).set({ status: "archived", updatedAt: new Date }).where(eq(gameTimebackAssessmentTests.id, row.id));
104287
104238
  }
104288
104239
  if (plan.kind !== "none") {
104289
104240
  setAttribute("app.assessment.operation", plan.operation);
@@ -104291,27 +104242,6 @@ class TimebackAssessmentsService {
104291
104242
  return { action: plan.action };
104292
104243
  });
104293
104244
  }
104294
- async reorderAssessments(integrationId, purpose, testIdentifiers) {
104295
- if (purpose === "review") {
104296
- throw new ValidationError("The review bank is system-managed and cannot be reordered.");
104297
- }
104298
- await this.requireIntegration(integrationId);
104299
- validateUniqueAssessmentIdentifiers(testIdentifiers);
104300
- const updatedAt = new Date;
104301
- await this.deps.db.transaction(async (tx) => {
104302
- const liveRows = await tx.query.gameTimebackAssessmentTests.findMany({
104303
- where: and(eq(gameTimebackAssessmentTests.integrationId, integrationId), eq(gameTimebackAssessmentTests.purpose, purpose), eq(gameTimebackAssessmentTests.status, "live"))
104304
- });
104305
- const orderedRows = orderLiveAssessmentRows(liveRows, purpose, testIdentifiers);
104306
- const positionByRowId = new Map(orderedRows.map((row, index2) => [row.id, index2 + 1]));
104307
- for (const row of lockOrderAssessmentRows(orderedRows)) {
104308
- const testIdentifier = row.qtiTestIdentifier;
104309
- const [updatedRow] = await tx.update(gameTimebackAssessmentTests).set({ sortOrder: positionByRowId.get(row.id), updatedAt }).where(and(eq(gameTimebackAssessmentTests.id, row.id), eq(gameTimebackAssessmentTests.integrationId, integrationId), eq(gameTimebackAssessmentTests.qtiTestIdentifier, testIdentifier), eq(gameTimebackAssessmentTests.purpose, purpose), eq(gameTimebackAssessmentTests.status, "live"))).returning({ id: gameTimebackAssessmentTests.id });
104310
- assertAssessmentOrderUpdateSucceeded(updatedRow);
104311
- }
104312
- });
104313
- setAttribute("app.assessment.operation", "reorder_live_assessments");
104314
- }
104315
104245
  async listQuestions(integrationId, qtiTestIdentifier) {
104316
104246
  const client2 = this.requireClient();
104317
104247
  await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
@@ -104774,15 +104704,14 @@ class TimebackAssessmentsService {
104774
104704
  if (reservedKeyOwner && reservedKeyOwner.purpose !== "review") {
104775
104705
  throw new ValidationError("The reserved review-bank assessment key is already in use.");
104776
104706
  }
104777
- const singletonCurrent = Boolean(singleton && singleton.assessmentKey === input.sinkIdentifier && singleton.status === "live" && singleton.sortOrder === null && singleton.standardFramework === null && singleton.standardIdentifier === null && singleton.diagnosticKey === null && singleton.diagnosticRoutingManifest === null);
104778
- const legacyCurrent = legacyReviews.every((association) => association.status === "archived" && association.sortOrder === null && association.assessmentKey !== input.sinkIdentifier);
104707
+ const singletonCurrent = Boolean(singleton && singleton.assessmentKey === input.sinkIdentifier && singleton.status === "live" && singleton.standardFramework === null && singleton.standardIdentifier === null && singleton.diagnosticKey === null && singleton.diagnosticRoutingManifest === null);
104708
+ const legacyCurrent = legacyReviews.every((association) => association.status === "archived" && association.assessmentKey !== input.sinkIdentifier);
104779
104709
  const changed = !singletonCurrent || !legacyCurrent;
104780
104710
  await input.beforeInstall();
104781
104711
  for (const legacy of legacyReviews) {
104782
- if (legacy.status !== "archived" || legacy.sortOrder !== null || legacy.assessmentKey === input.sinkIdentifier) {
104712
+ if (legacy.status !== "archived" || legacy.assessmentKey === input.sinkIdentifier) {
104783
104713
  await input.tx.update(gameTimebackAssessmentTests).set({
104784
104714
  status: "archived",
104785
- sortOrder: null,
104786
104715
  ...legacy.assessmentKey === input.sinkIdentifier ? { assessmentKey: null } : {},
104787
104716
  updatedAt: new Date
104788
104717
  }).where(eq(gameTimebackAssessmentTests.id, legacy.id));
@@ -104796,7 +104725,6 @@ class TimebackAssessmentsService {
104796
104725
  assessmentKey: input.sinkIdentifier,
104797
104726
  purpose: "review",
104798
104727
  status: "live",
104799
- sortOrder: null,
104800
104728
  standardFramework: null,
104801
104729
  standardIdentifier: null,
104802
104730
  diagnosticKey: null,
@@ -104811,7 +104739,6 @@ class TimebackAssessmentsService {
104811
104739
  qtiTestIdentifier: input.sinkIdentifier,
104812
104740
  purpose: "review",
104813
104741
  status: "live",
104814
- sortOrder: null,
104815
104742
  standardFramework: null,
104816
104743
  standardIdentifier: null,
104817
104744
  diagnosticKey: null,
@@ -105014,7 +104941,6 @@ class TimebackAssessmentsService {
105014
104941
  qtiTestIdentifier: row.qtiTestIdentifier,
105015
104942
  purpose: row.purpose,
105016
104943
  status: row.status,
105017
- sortOrder: row.sortOrder,
105018
104944
  standard: assessmentStandardForRow(row),
105019
104945
  diagnostic: diagnosticDefinitionForRow(row),
105020
104946
  createdAt: row.createdAt,
@@ -165108,7 +165034,7 @@ function parseQtiLibraryParams(searchParams) {
165108
165034
  limit
165109
165035
  };
165110
165036
  }
165111
- var populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, getRemovedIntegrations, createIntegration, updateIntegration, deactivateCourse, reactivateCourse, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, startRuntimeAssessment, getRuntimeAssessment, getLatestRuntimeAssessment, saveRuntimeAssessment, submitRuntimeAssessmentItem, submitRuntimeAssessment, finalizeRuntimeAssessment, exportRuntimeAssessmentFixture, getStudentXp, getStudentMastery, getStudentHighestGradeMastered, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getGradeLevelTestResults, getGradeLevelTestReview, getActivityDetail, listMetricDiscrepancies, verifyMetricDiscrepancy, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, attachExistingAssessments, updateAssessment, synchronizeReviewBank, reorderAssessments, reorderQuestions, removeAssessment, listQuestions, listQuestionLibrary, listTestLibrary, copyAssessment, createQuestion, updateQuestion, removeQuestion, timeback2;
165037
+ var populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, getRemovedIntegrations, createIntegration, updateIntegration, deactivateCourse, reactivateCourse, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, startRuntimeAssessment, getRuntimeAssessment, getLatestRuntimeAssessment, saveRuntimeAssessment, submitRuntimeAssessmentItem, submitRuntimeAssessment, finalizeRuntimeAssessment, exportRuntimeAssessmentFixture, getStudentXp, getStudentMastery, getStudentHighestGradeMastered, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getGradeLevelTestResults, getGradeLevelTestReview, getActivityDetail, listMetricDiscrepancies, verifyMetricDiscrepancy, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, attachExistingAssessments, updateAssessment, synchronizeReviewBank, reorderQuestions, removeAssessment, listQuestions, listQuestionLibrary, listTestLibrary, copyAssessment, createQuestion, updateQuestion, removeQuestion, timeback2;
165112
165038
  var init_timeback_controller = __esm(() => {
165113
165039
  init_esm();
165114
165040
  init_src();
@@ -165814,16 +165740,6 @@ var init_timeback_controller = __esm(() => {
165814
165740
  const integrationId = await ctx.services.timebackAssessments.resolveIntegrationId(gameId, courseId, ctx.user);
165815
165741
  return ctx.services.timebackAssessments.synchronizeReviewBank(integrationId);
165816
165742
  });
165817
- reorderAssessments = requireDeveloper(async (ctx) => {
165818
- const { gameId, courseId } = ctx.params;
165819
- if (!gameId || !courseId) {
165820
- throw ApiError.badRequest("Missing gameId or courseId parameter");
165821
- }
165822
- const body2 = await parseRequestBody(ctx.request, ReorderAssessmentsRequestSchema);
165823
- const integrationId = await ctx.services.timebackAssessments.resolveIntegrationId(gameId, courseId, ctx.user);
165824
- await ctx.services.timebackAssessments.reorderAssessments(integrationId, body2.purpose, body2.testIdentifiers);
165825
- return { success: true };
165826
- });
165827
165743
  reorderQuestions = requireDeveloper(async (ctx) => {
165828
165744
  const { gameId, courseId, testIdentifier } = ctx.params;
165829
165745
  if (!gameId || !courseId || !testIdentifier) {
@@ -165964,7 +165880,6 @@ var init_timeback_controller = __esm(() => {
165964
165880
  attachExistingAssessments,
165965
165881
  updateAssessment,
165966
165882
  synchronizeReviewBank,
165967
- reorderAssessments,
165968
165883
  removeAssessment,
165969
165884
  reorderQuestions,
165970
165885
  listQuestions,
package/dist/server.js CHANGED
@@ -1127,7 +1127,7 @@ var package_default;
1127
1127
  var init_package = __esm(() => {
1128
1128
  package_default = {
1129
1129
  name: "@playcademy/sandbox",
1130
- version: "0.8.1-beta.2",
1130
+ version: "0.8.1-beta.3",
1131
1131
  description: "Local development server for Playcademy game development",
1132
1132
  type: "module",
1133
1133
  exports: {
@@ -10766,39 +10766,21 @@ function compareNewestCompletedAssessmentAttempt(left, right) {
10766
10766
  return newestAttempt(left, right, "scoreDate");
10767
10767
  }
10768
10768
  function compareAssessmentCatalogOrder(left, right) {
10769
- if (left.sortOrder !== null || right.sortOrder !== null) {
10770
- if (left.sortOrder === null) {
10771
- return 1;
10772
- }
10773
- if (right.sortOrder === null) {
10774
- return -1;
10775
- }
10776
- const orderDifference = left.sortOrder - right.sortOrder;
10777
- if (orderDifference) {
10778
- return orderDifference;
10779
- }
10780
- }
10781
- const leftUpdatedAt = Date.parse(left.updatedAt);
10782
- const rightUpdatedAt = Date.parse(right.updatedAt);
10783
- const leftHasValidDate = Number.isFinite(leftUpdatedAt);
10784
- const rightHasValidDate = Number.isFinite(rightUpdatedAt);
10785
- if (leftHasValidDate && rightHasValidDate) {
10786
- const updatedDifference = leftUpdatedAt - rightUpdatedAt;
10787
- if (updatedDifference) {
10788
- return updatedDifference;
10789
- }
10790
- } else if (leftHasValidDate !== rightHasValidDate) {
10791
- return leftHasValidDate ? -1 : 1;
10792
- }
10793
10769
  if (left.assessmentKey !== null && right.assessmentKey !== null) {
10794
- const keyDifference = left.assessmentKey.localeCompare(right.assessmentKey);
10770
+ const keyDifference = compareCodePoints(left.assessmentKey, right.assessmentKey);
10795
10771
  if (keyDifference) {
10796
10772
  return keyDifference;
10797
10773
  }
10798
10774
  } else if (left.assessmentKey !== null || right.assessmentKey !== null) {
10799
10775
  return left.assessmentKey === null ? 1 : -1;
10800
10776
  }
10801
- return left.qtiTestIdentifier.localeCompare(right.qtiTestIdentifier);
10777
+ return compareCodePoints(left.qtiTestIdentifier, right.qtiTestIdentifier);
10778
+ }
10779
+ function compareCodePoints(left, right) {
10780
+ if (left === right) {
10781
+ return 0;
10782
+ }
10783
+ return left < right ? -1 : 1;
10802
10784
  }
10803
10785
  function orderRuntimeAssessmentTests(tests) {
10804
10786
  return [...tests].toSorted(compareAssessmentCatalogOrder);
@@ -11582,7 +11564,7 @@ function playcademyDiagnosticAssessmentItemResultMetadata(value) {
11582
11564
  const normalized = metadata2.responses === undefined ? { ...metadata2, responses: {} } : metadata2;
11583
11565
  return isPlaycademyDiagnosticAssessmentItemResultMetadataV1(normalized) ? normalized : null;
11584
11566
  }
11585
- var SCRIPT_SCHEMES, DATA_RASTER_IMAGE_PATTERN, QTI_MATHML_ALLOWED_TAGS, metadataSymbol, parser, SUPPORTED_QTI_INTERACTION_TYPES, URL_ATTRIBUTES, IMAGE_URL_ATTRIBUTES, INTERACTION_TYPES, EMPHASIS_TAGS, STRONG_TAGS, CONTENT_SKIPPED_TAGS, BLOCK_CONTENT_KINDS, GAP_MATCH_TOKEN_TAGS, STAGE_GRAPHIC_EXCLUDED_CONTAINERS, BLANK_SENTINEL = "￿", MARKED_BLANK_PATTERN, MARKED_BLANK_GLOBAL_PATTERN, MATCH_CORRECT_TEMPLATE = "http://www.imsglobal.org/question/qti_v3p0/rptemplates/match_correct", MAP_RESPONSE_TEMPLATE = "https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/map_response", MAP_RESPONSE_TEMPLATES, RESPONSE_PROCESSING_TEMPLATES, VOID_BODY_ELEMENTS, URL_ATTRIBUTES2, IMAGE_URL_ATTRIBUTES2, VOID_CHOICE_ELEMENTS, NUMERIC_COMPARISON_ATTRIBUTES, RESPONSE_CARDINALITIES, RESPONSE_BASE_TYPES, POINT_INTERACTION_TYPES, INDEPENDENT_PROCESSING_TAGS, UUID_PATTERN, COMMON_CORE_MATH_FRAMEWORK_ALIASES, COMMON_CORE_ELA_FRAMEWORK_ALIASES, COMMON_CORE_FRAMEWORK_ALIASES, ASSESSMENT_ATTEMPT_OPEN, ASSESSMENT_ATTEMPT_COMPLETED, ASSESSMENT_ATTEMPT_AWAITING_AWARD, ASSESSMENT_ATTEMPT_SUPERSEDED, ASSESSMENT_RUNTIME_ERROR_STATUS, ROUTING_KEY_MAX_LENGTH = 128, ROUTING_RESULT_KEY_MAX_LENGTH = 256, ROUTING_STAGE_LIMIT = 32, ROUTING_TRACK_LIMIT = 128, ROUTING_NODE_LIMIT = 1000, ROUTING_TERMINAL_LIMIT = 1000, ROUTING_GROUP_LIMIT = 128, ROUTING_PREDICATE_DEPTH_LIMIT = 8, ROUTING_EXPLORATION_STATE_LIMIT = 200000, RoutingKeySchema, RoutingResultKeySchema, DiagnosticTrackOutcomeSchema, DiagnosticActivationPredicateSchema, DiagnosticRoutingTransitionSchema, DiagnosticRoutingManifestV1Schema, GRADE_VALUES, POINT_RESPONSE_PATTERN, REVIEW_SELECTION_POLICY_VERSION = "unseen-first-least-recently-delivered-v1", PLAYCADEMY_REVIEW_BANK_MANIFEST_METADATA_KEY = "playcademyReviewBank", PLAYCADEMY_REVIEW_BANK_MANIFEST_VERSION = 1, DEFAULT_REVIEW_SELECTION_POLICY, ASSESSMENT_RUNTIME_FIXTURE_BUNDLE_VERSION = 7, RuntimeSubjectSchema, RuntimeGradeSchema, OptionalQueryGradeSchema, AssessmentResponseValueSchema, AssessmentRuntimeIdentitySchema, ResponseKeySchema, StartAssessmentBaseSchema, AssessmentStandardRefSchema, LatestAssessmentFilterBaseSchema, LatestAssessmentFiltersSchema, LatestRuntimeAssessmentQuerySchema, StartAssessmentBodySchema, SaveAssessmentBodySchema, SubmitAssessmentItemBodySchema, SubmitAssessmentBodySchema, FinalizeAssessmentBodySchema, StartRuntimeAssessmentRequestSchema, SaveRuntimeAssessmentRequestSchema, SubmitAssessmentItemRuntimeRequestSchema, SubmitRuntimeAssessmentRequestSchema, FinalizeRuntimeAssessmentRequestSchema;
11567
+ var SCRIPT_SCHEMES, DATA_RASTER_IMAGE_PATTERN, QTI_MATHML_ALLOWED_TAGS, metadataSymbol, parser, SUPPORTED_QTI_INTERACTION_TYPES, URL_ATTRIBUTES, IMAGE_URL_ATTRIBUTES, INTERACTION_TYPES, EMPHASIS_TAGS, STRONG_TAGS, CONTENT_SKIPPED_TAGS, BLOCK_CONTENT_KINDS, GAP_MATCH_TOKEN_TAGS, STAGE_GRAPHIC_EXCLUDED_CONTAINERS, BLANK_SENTINEL = "￿", MARKED_BLANK_PATTERN, MARKED_BLANK_GLOBAL_PATTERN, MATCH_CORRECT_TEMPLATE = "http://www.imsglobal.org/question/qti_v3p0/rptemplates/match_correct", MAP_RESPONSE_TEMPLATE = "https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/map_response", MAP_RESPONSE_TEMPLATES, RESPONSE_PROCESSING_TEMPLATES, VOID_BODY_ELEMENTS, URL_ATTRIBUTES2, IMAGE_URL_ATTRIBUTES2, VOID_CHOICE_ELEMENTS, NUMERIC_COMPARISON_ATTRIBUTES, RESPONSE_CARDINALITIES, RESPONSE_BASE_TYPES, POINT_INTERACTION_TYPES, INDEPENDENT_PROCESSING_TAGS, UUID_PATTERN, COMMON_CORE_MATH_FRAMEWORK_ALIASES, COMMON_CORE_ELA_FRAMEWORK_ALIASES, COMMON_CORE_FRAMEWORK_ALIASES, ASSESSMENT_ATTEMPT_OPEN, ASSESSMENT_ATTEMPT_COMPLETED, ASSESSMENT_ATTEMPT_AWAITING_AWARD, ASSESSMENT_ATTEMPT_SUPERSEDED, ASSESSMENT_RUNTIME_ERROR_STATUS, ROUTING_KEY_MAX_LENGTH = 128, ROUTING_RESULT_KEY_MAX_LENGTH = 256, ROUTING_STAGE_LIMIT = 32, ROUTING_TRACK_LIMIT = 128, ROUTING_NODE_LIMIT = 1000, ROUTING_TERMINAL_LIMIT = 1000, ROUTING_GROUP_LIMIT = 128, ROUTING_PREDICATE_DEPTH_LIMIT = 8, ROUTING_EXPLORATION_STATE_LIMIT = 200000, RoutingKeySchema, RoutingResultKeySchema, DiagnosticTrackOutcomeSchema, DiagnosticActivationPredicateSchema, DiagnosticRoutingTransitionSchema, DiagnosticRoutingManifestV1Schema, GRADE_VALUES, POINT_RESPONSE_PATTERN, REVIEW_SELECTION_POLICY_VERSION = "unseen-first-least-recently-delivered-v1", PLAYCADEMY_REVIEW_BANK_MANIFEST_METADATA_KEY = "playcademyReviewBank", PLAYCADEMY_REVIEW_BANK_MANIFEST_VERSION = 1, DEFAULT_REVIEW_SELECTION_POLICY, ASSESSMENT_RUNTIME_FIXTURE_BUNDLE_VERSION = 8, RuntimeSubjectSchema, RuntimeGradeSchema, OptionalQueryGradeSchema, AssessmentResponseValueSchema, AssessmentRuntimeIdentitySchema, ResponseKeySchema, StartAssessmentBaseSchema, AssessmentStandardRefSchema, LatestAssessmentFilterBaseSchema, LatestAssessmentFiltersSchema, LatestRuntimeAssessmentQuerySchema, StartAssessmentBodySchema, SaveAssessmentBodySchema, SubmitAssessmentItemBodySchema, SubmitAssessmentBodySchema, FinalizeAssessmentBodySchema, StartRuntimeAssessmentRequestSchema, SaveRuntimeAssessmentRequestSchema, SubmitAssessmentItemRuntimeRequestSchema, SubmitRuntimeAssessmentRequestSchema, FinalizeRuntimeAssessmentRequestSchema;
11586
11568
  var init_assessment_runtime2 = __esm(() => {
11587
11569
  init_timeback3();
11588
11570
  init_timeback3();
@@ -47141,7 +47123,7 @@ function rejectSystemManagedReview(input, context2) {
47141
47123
  });
47142
47124
  }
47143
47125
  }
47144
- var TimebackGradeSchema, TimebackSubjectSchema, CourseGoalsSchema, UpdateGameTimebackIntegrationRequestSchema, CreateGameTimebackIntegrationRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameRunMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, UnenrollCourseRequestSchema, 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, VerifyTimebackMetricDiscrepancyRequestSchema, AssessmentPurposeSchema, AssessmentStatusSchema, AssessmentKeySchema, DiagnosticKeySchema, DiagnosticRoutingManifestSchema, DiagnosticAssessmentDefinitionInputSchema, AssessmentStandardRefSchema2, CreateAssessmentRequestSchema, UpdateAssessmentRequestSchema, CopyAssessmentRequestSchema, AssessmentAssociationImportEntrySchema, AttachExistingAssessmentsRequestSchema, ReorderAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
47126
+ var TimebackGradeSchema, TimebackSubjectSchema, CourseGoalsSchema, UpdateGameTimebackIntegrationRequestSchema, CreateGameTimebackIntegrationRequestSchema, TimebackActivityDataSchema, EndActivityRequestSchema, GameRunMetricsSchema, GameCourseMetricsSchema, GameMetricsResponseSchema, AdvanceCourseRequestSchema, UnenrollCourseRequestSchema, 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, VerifyTimebackMetricDiscrepancyRequestSchema, AssessmentPurposeSchema, AssessmentStatusSchema, AssessmentKeySchema, DiagnosticKeySchema, DiagnosticRoutingManifestSchema, DiagnosticAssessmentDefinitionInputSchema, AssessmentStandardRefSchema2, CreateAssessmentRequestSchema, UpdateAssessmentRequestSchema, CopyAssessmentRequestSchema, AssessmentAssociationImportEntrySchema, AttachExistingAssessmentsRequestSchema, ReorderQuestionsRequestSchema;
47145
47127
  var init_schemas4 = __esm(() => {
47146
47128
  init_esm();
47147
47129
  init_src();
@@ -47428,8 +47410,7 @@ var init_schemas4 = __esm(() => {
47428
47410
  assessmentKey: AssessmentKeySchema,
47429
47411
  qtiTestIdentifier: exports_external.string().trim().min(1, "Assessment identifier is required"),
47430
47412
  purpose: AssessmentPurposeSchema,
47431
- standard: AssessmentStandardRefSchema2.optional(),
47432
- sortOrder: exports_external.number().int().nonnegative().nullable()
47413
+ standard: AssessmentStandardRefSchema2.optional()
47433
47414
  }).superRefine((input, context2) => {
47434
47415
  requireMasteryStandard(input, context2);
47435
47416
  rejectSystemManagedReview(input, context2);
@@ -47479,10 +47460,6 @@ var init_schemas4 = __esm(() => {
47479
47460
  seenKeys.add(assessment.assessmentKey);
47480
47461
  });
47481
47462
  });
47482
- ReorderAssessmentsRequestSchema = exports_external.object({
47483
- purpose: AssessmentPurposeSchema,
47484
- testIdentifiers: exports_external.array(exports_external.string().trim().min(1, "Assessment identifier is required")).min(1, "At least one assessment is required")
47485
- }).superRefine(rejectSystemManagedReview);
47486
47463
  ReorderQuestionsRequestSchema = exports_external.object({
47487
47464
  items: exports_external.array(exports_external.object({
47488
47465
  identifier: exports_external.string().min(1),
@@ -100923,9 +100900,6 @@ function buildAssessmentAssociationUpdates(row, input) {
100923
100900
  updates.standardFramework = null;
100924
100901
  updates.standardIdentifier = null;
100925
100902
  }
100926
- if (row.status === "live" && input.purpose !== row.purpose) {
100927
- updates.sortOrder = null;
100928
- }
100929
100903
  }
100930
100904
  if (input.standard !== undefined) {
100931
100905
  updates.standardFramework = input.standard.framework;
@@ -100933,9 +100907,6 @@ function buildAssessmentAssociationUpdates(row, input) {
100933
100907
  }
100934
100908
  if (input.status !== undefined) {
100935
100909
  updates.status = input.status;
100936
- if (input.status === "archived") {
100937
- updates.sortOrder = null;
100938
- }
100939
100910
  }
100940
100911
  return updates;
100941
100912
  }
@@ -100944,24 +100915,8 @@ function assessmentStandardForRow(row) {
100944
100915
  }
100945
100916
  function validateUniqueAssessmentIdentifiers(testIdentifiers) {
100946
100917
  if (new Set(testIdentifiers).size !== testIdentifiers.length) {
100947
- throw new ValidationError("Assessment order must contain unique identifiers");
100948
- }
100949
- }
100950
- function assertAssessmentOrderUpdateSucceeded(updatedRow) {
100951
- if (!updatedRow) {
100952
- throw new ValidationError("Assessment order changed while it was being saved. Refresh and try again.");
100918
+ throw new ValidationError("Assessment manifests must contain unique QTI test identifiers");
100953
100919
  }
100954
- return updatedRow;
100955
- }
100956
- function lockOrderAssessmentRows(rows) {
100957
- return rows.toSorted((left, right) => left.id.localeCompare(right.id));
100958
- }
100959
- function orderLiveAssessmentRows(liveRows, purpose, testIdentifiers) {
100960
- const rowsByIdentifier = new Map(liveRows.map((row) => [row.qtiTestIdentifier, row]));
100961
- if (liveRows.length !== testIdentifiers.length || testIdentifiers.some((identifier) => !rowsByIdentifier.has(identifier))) {
100962
- throw new ValidationError(`Assessment order must include every live ${purpose} assessment exactly once`);
100963
- }
100964
- return testIdentifiers.map((identifier) => rowsByIdentifier.get(identifier));
100965
100920
  }
100966
100921
  var init_timeback_assessment_rules_util = __esm(() => {
100967
100922
  init_errors2();
@@ -102470,8 +102425,6 @@ var init_timeback_assessment_runtime_service = __esm(async () => {
102470
102425
  id: row.id,
102471
102426
  assessmentKey: row.assessmentKey,
102472
102427
  qtiTestIdentifier: row.qtiTestIdentifier,
102473
- sortOrder: row.sortOrder,
102474
- updatedAt: row.updatedAt.toISOString(),
102475
102428
  standard: assessmentStandardForRow(row)
102476
102429
  })).filter((test) => !matchesMasteryStandard || matchesMasteryStandard(test.standard));
102477
102430
  }
@@ -104089,7 +104042,6 @@ class TimebackAssessmentsService {
104089
104042
  ...test ? { title: test.title } : {},
104090
104043
  purpose: entry.purpose,
104091
104044
  ...entry.standard ? { standard: entry.standard } : {},
104092
- sourceSortOrder: entry.sortOrder,
104093
104045
  ...test && gameSlug ? { editable: isQtiTestOwnedByGame(test, gameSlug) } : {}
104094
104046
  };
104095
104047
  }
@@ -104149,7 +104101,6 @@ class TimebackAssessmentsService {
104149
104101
  qtiTestIdentifier: entry.qtiTestIdentifier,
104150
104102
  purpose: entry.purpose,
104151
104103
  status: input.targetStatus,
104152
- sortOrder: entry.sortOrder,
104153
104104
  standardFramework: entry.standard?.framework,
104154
104105
  standardIdentifier: entry.standard?.identifier
104155
104106
  }).onConflictDoNothing().returning();
@@ -104282,7 +104233,7 @@ class TimebackAssessmentsService {
104282
104233
  if (plan.kind === "delete") {
104283
104234
  await tx.delete(gameTimebackAssessmentTests).where(eq(gameTimebackAssessmentTests.id, row.id));
104284
104235
  } else if (plan.kind === "archive") {
104285
- await tx.update(gameTimebackAssessmentTests).set({ status: "archived", sortOrder: null, updatedAt: new Date }).where(eq(gameTimebackAssessmentTests.id, row.id));
104236
+ await tx.update(gameTimebackAssessmentTests).set({ status: "archived", updatedAt: new Date }).where(eq(gameTimebackAssessmentTests.id, row.id));
104286
104237
  }
104287
104238
  if (plan.kind !== "none") {
104288
104239
  setAttribute("app.assessment.operation", plan.operation);
@@ -104290,27 +104241,6 @@ class TimebackAssessmentsService {
104290
104241
  return { action: plan.action };
104291
104242
  });
104292
104243
  }
104293
- async reorderAssessments(integrationId, purpose, testIdentifiers) {
104294
- if (purpose === "review") {
104295
- throw new ValidationError("The review bank is system-managed and cannot be reordered.");
104296
- }
104297
- await this.requireIntegration(integrationId);
104298
- validateUniqueAssessmentIdentifiers(testIdentifiers);
104299
- const updatedAt = new Date;
104300
- await this.deps.db.transaction(async (tx) => {
104301
- const liveRows = await tx.query.gameTimebackAssessmentTests.findMany({
104302
- where: and(eq(gameTimebackAssessmentTests.integrationId, integrationId), eq(gameTimebackAssessmentTests.purpose, purpose), eq(gameTimebackAssessmentTests.status, "live"))
104303
- });
104304
- const orderedRows = orderLiveAssessmentRows(liveRows, purpose, testIdentifiers);
104305
- const positionByRowId = new Map(orderedRows.map((row, index2) => [row.id, index2 + 1]));
104306
- for (const row of lockOrderAssessmentRows(orderedRows)) {
104307
- const testIdentifier = row.qtiTestIdentifier;
104308
- const [updatedRow] = await tx.update(gameTimebackAssessmentTests).set({ sortOrder: positionByRowId.get(row.id), updatedAt }).where(and(eq(gameTimebackAssessmentTests.id, row.id), eq(gameTimebackAssessmentTests.integrationId, integrationId), eq(gameTimebackAssessmentTests.qtiTestIdentifier, testIdentifier), eq(gameTimebackAssessmentTests.purpose, purpose), eq(gameTimebackAssessmentTests.status, "live"))).returning({ id: gameTimebackAssessmentTests.id });
104309
- assertAssessmentOrderUpdateSucceeded(updatedRow);
104310
- }
104311
- });
104312
- setAttribute("app.assessment.operation", "reorder_live_assessments");
104313
- }
104314
104244
  async listQuestions(integrationId, qtiTestIdentifier) {
104315
104245
  const client2 = this.requireClient();
104316
104246
  await this.requireAssessmentRow(integrationId, qtiTestIdentifier);
@@ -104773,15 +104703,14 @@ class TimebackAssessmentsService {
104773
104703
  if (reservedKeyOwner && reservedKeyOwner.purpose !== "review") {
104774
104704
  throw new ValidationError("The reserved review-bank assessment key is already in use.");
104775
104705
  }
104776
- const singletonCurrent = Boolean(singleton && singleton.assessmentKey === input.sinkIdentifier && singleton.status === "live" && singleton.sortOrder === null && singleton.standardFramework === null && singleton.standardIdentifier === null && singleton.diagnosticKey === null && singleton.diagnosticRoutingManifest === null);
104777
- const legacyCurrent = legacyReviews.every((association) => association.status === "archived" && association.sortOrder === null && association.assessmentKey !== input.sinkIdentifier);
104706
+ const singletonCurrent = Boolean(singleton && singleton.assessmentKey === input.sinkIdentifier && singleton.status === "live" && singleton.standardFramework === null && singleton.standardIdentifier === null && singleton.diagnosticKey === null && singleton.diagnosticRoutingManifest === null);
104707
+ const legacyCurrent = legacyReviews.every((association) => association.status === "archived" && association.assessmentKey !== input.sinkIdentifier);
104778
104708
  const changed = !singletonCurrent || !legacyCurrent;
104779
104709
  await input.beforeInstall();
104780
104710
  for (const legacy of legacyReviews) {
104781
- if (legacy.status !== "archived" || legacy.sortOrder !== null || legacy.assessmentKey === input.sinkIdentifier) {
104711
+ if (legacy.status !== "archived" || legacy.assessmentKey === input.sinkIdentifier) {
104782
104712
  await input.tx.update(gameTimebackAssessmentTests).set({
104783
104713
  status: "archived",
104784
- sortOrder: null,
104785
104714
  ...legacy.assessmentKey === input.sinkIdentifier ? { assessmentKey: null } : {},
104786
104715
  updatedAt: new Date
104787
104716
  }).where(eq(gameTimebackAssessmentTests.id, legacy.id));
@@ -104795,7 +104724,6 @@ class TimebackAssessmentsService {
104795
104724
  assessmentKey: input.sinkIdentifier,
104796
104725
  purpose: "review",
104797
104726
  status: "live",
104798
- sortOrder: null,
104799
104727
  standardFramework: null,
104800
104728
  standardIdentifier: null,
104801
104729
  diagnosticKey: null,
@@ -104810,7 +104738,6 @@ class TimebackAssessmentsService {
104810
104738
  qtiTestIdentifier: input.sinkIdentifier,
104811
104739
  purpose: "review",
104812
104740
  status: "live",
104813
- sortOrder: null,
104814
104741
  standardFramework: null,
104815
104742
  standardIdentifier: null,
104816
104743
  diagnosticKey: null,
@@ -105013,7 +104940,6 @@ class TimebackAssessmentsService {
105013
104940
  qtiTestIdentifier: row.qtiTestIdentifier,
105014
104941
  purpose: row.purpose,
105015
104942
  status: row.status,
105016
- sortOrder: row.sortOrder,
105017
104943
  standard: assessmentStandardForRow(row),
105018
104944
  diagnostic: diagnosticDefinitionForRow(row),
105019
104945
  createdAt: row.createdAt,
@@ -165107,7 +165033,7 @@ function parseQtiLibraryParams(searchParams) {
165107
165033
  limit
165108
165034
  };
165109
165035
  }
165110
- var populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, getRemovedIntegrations, createIntegration, updateIntegration, deactivateCourse, reactivateCourse, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, startRuntimeAssessment, getRuntimeAssessment, getLatestRuntimeAssessment, saveRuntimeAssessment, submitRuntimeAssessmentItem, submitRuntimeAssessment, finalizeRuntimeAssessment, exportRuntimeAssessmentFixture, getStudentXp, getStudentMastery, getStudentHighestGradeMastered, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getGradeLevelTestResults, getGradeLevelTestReview, getActivityDetail, listMetricDiscrepancies, verifyMetricDiscrepancy, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, attachExistingAssessments, updateAssessment, synchronizeReviewBank, reorderAssessments, reorderQuestions, removeAssessment, listQuestions, listQuestionLibrary, listTestLibrary, copyAssessment, createQuestion, updateQuestion, removeQuestion, timeback2;
165036
+ var populateStudent, getUser, getUserEnrollments, getUserById, setupIntegration, getIntegrations, getRemovedIntegrations, createIntegration, updateIntegration, deactivateCourse, reactivateCourse, getIntegrationConfig, verifyIntegration, getConfig, deleteIntegrations, endActivity, heartbeat, advanceCourse, unenrollCourse, startRuntimeAssessment, getRuntimeAssessment, getLatestRuntimeAssessment, saveRuntimeAssessment, submitRuntimeAssessmentItem, submitRuntimeAssessment, finalizeRuntimeAssessment, exportRuntimeAssessmentFixture, getStudentXp, getStudentMastery, getStudentHighestGradeMastered, getRoster, getStudentOverview, getGameMetrics, getStudentActivity, getGradeLevelTestResults, getGradeLevelTestReview, getActivityDetail, listMetricDiscrepancies, verifyMetricDiscrepancy, grantXp, adjustTime, adjustMastery, reconcileMasteryForConfigChange, searchStudents, enrollStudent, unenrollStudent, reactivateEnrollment, listAssessments, createAssessment, attachExistingAssessments, updateAssessment, synchronizeReviewBank, reorderQuestions, removeAssessment, listQuestions, listQuestionLibrary, listTestLibrary, copyAssessment, createQuestion, updateQuestion, removeQuestion, timeback2;
165111
165037
  var init_timeback_controller = __esm(() => {
165112
165038
  init_esm();
165113
165039
  init_src();
@@ -165813,16 +165739,6 @@ var init_timeback_controller = __esm(() => {
165813
165739
  const integrationId = await ctx.services.timebackAssessments.resolveIntegrationId(gameId, courseId, ctx.user);
165814
165740
  return ctx.services.timebackAssessments.synchronizeReviewBank(integrationId);
165815
165741
  });
165816
- reorderAssessments = requireDeveloper(async (ctx) => {
165817
- const { gameId, courseId } = ctx.params;
165818
- if (!gameId || !courseId) {
165819
- throw ApiError.badRequest("Missing gameId or courseId parameter");
165820
- }
165821
- const body2 = await parseRequestBody(ctx.request, ReorderAssessmentsRequestSchema);
165822
- const integrationId = await ctx.services.timebackAssessments.resolveIntegrationId(gameId, courseId, ctx.user);
165823
- await ctx.services.timebackAssessments.reorderAssessments(integrationId, body2.purpose, body2.testIdentifiers);
165824
- return { success: true };
165825
- });
165826
165742
  reorderQuestions = requireDeveloper(async (ctx) => {
165827
165743
  const { gameId, courseId, testIdentifier } = ctx.params;
165828
165744
  if (!gameId || !courseId || !testIdentifier) {
@@ -165963,7 +165879,6 @@ var init_timeback_controller = __esm(() => {
165963
165879
  attachExistingAssessments,
165964
165880
  updateAssessment,
165965
165881
  synchronizeReviewBank,
165966
- reorderAssessments,
165967
165882
  removeAssessment,
165968
165883
  reorderQuestions,
165969
165884
  listQuestions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcademy/sandbox",
3
- "version": "0.8.1-beta.2",
3
+ "version": "0.8.1-beta.3",
4
4
  "description": "Local development server for Playcademy game development",
5
5
  "type": "module",
6
6
  "exports": {