@playcademy/vite-plugin 1.2.1-beta.17 → 1.2.1-beta.18
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 +105 -69
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -24315,7 +24315,7 @@ import path2 from "node:path";
|
|
|
24315
24315
|
// package.json
|
|
24316
24316
|
var package_default = {
|
|
24317
24317
|
name: "@playcademy/vite-plugin",
|
|
24318
|
-
version: "1.2.1-beta.
|
|
24318
|
+
version: "1.2.1-beta.18",
|
|
24319
24319
|
type: "module",
|
|
24320
24320
|
exports: {
|
|
24321
24321
|
".": {
|
|
@@ -25076,7 +25076,7 @@ var init_timeback2 = __esm(() => {
|
|
|
25076
25076
|
ASSESSMENT_PURPOSES = ["end_of_course", "diagnostic", "review", "mastery"];
|
|
25077
25077
|
TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS = {
|
|
25078
25078
|
standards: 20,
|
|
25079
|
-
|
|
25079
|
+
candidateItemsPerStandard: 2,
|
|
25080
25080
|
standardFieldLength: 128
|
|
25081
25081
|
};
|
|
25082
25082
|
TIMEBACK_COURSE_DEFAULTS = {
|
|
@@ -25921,7 +25921,7 @@ var package_default2;
|
|
|
25921
25921
|
var init_package = __esm(() => {
|
|
25922
25922
|
package_default2 = {
|
|
25923
25923
|
name: "@playcademy/sandbox",
|
|
25924
|
-
version: "0.7.1-beta.
|
|
25924
|
+
version: "0.7.1-beta.17",
|
|
25925
25925
|
description: "Local development server for Playcademy game development",
|
|
25926
25926
|
type: "module",
|
|
25927
25927
|
exports: {
|
|
@@ -34614,6 +34614,12 @@ function interactionResponseValidationMessage(itemIdentifier, interaction, respo
|
|
|
34614
34614
|
function invalidResponse(message) {
|
|
34615
34615
|
return { code: "INVALID_RESPONSE", message };
|
|
34616
34616
|
}
|
|
34617
|
+
function administeredItemIdentifiers(itemSubmissions) {
|
|
34618
|
+
return new Set(itemSubmissions.map((submission) => submission.itemIdentifier));
|
|
34619
|
+
}
|
|
34620
|
+
function itemAdministration(itemSubmissions, itemIdentifier) {
|
|
34621
|
+
return itemSubmissions.find((submission) => submission.itemIdentifier === itemIdentifier);
|
|
34622
|
+
}
|
|
34617
34623
|
function responseValuesEqual(left, right) {
|
|
34618
34624
|
if (left === undefined || right === undefined) {
|
|
34619
34625
|
return left === right;
|
|
@@ -34664,15 +34670,20 @@ function prepareAssessmentItemSubmission(state, input) {
|
|
|
34664
34670
|
failure: assessmentResponseVersionConflict(input.expectedResponseVersion, state.responseVersion)
|
|
34665
34671
|
};
|
|
34666
34672
|
}
|
|
34667
|
-
const
|
|
34668
|
-
const
|
|
34669
|
-
const
|
|
34670
|
-
|
|
34673
|
+
const itemIndex = state.assessment.items.findIndex((item) => item.identifier === input.itemIdentifier);
|
|
34674
|
+
const committed = administeredItemIdentifiers(state.itemSubmissions);
|
|
34675
|
+
const expectedItemIndex = state.assessment.items.findIndex((item) => !committed.has(item.identifier));
|
|
34676
|
+
const previousItemIdentifier = state.itemSubmissions.at(-1)?.itemIdentifier;
|
|
34677
|
+
const previousItemIndex = state.assessment.items.findIndex((item) => item.identifier === previousItemIdentifier);
|
|
34678
|
+
const validOrder = state.purpose === "review" ? itemIndex > previousItemIndex : itemIndex === expectedItemIndex;
|
|
34679
|
+
if (itemIndex === -1 || !validOrder) {
|
|
34671
34680
|
return {
|
|
34672
34681
|
action: "reject",
|
|
34673
|
-
failure: assessmentFlowViolation("Items must be submitted once and in presentation order.", {
|
|
34682
|
+
failure: assessmentFlowViolation(state.purpose === "review" ? "Items must be submitted once and in candidate order." : "Items must be submitted once and in presentation order.", {
|
|
34674
34683
|
itemIdentifier: input.itemIdentifier,
|
|
34675
|
-
|
|
34684
|
+
...state.purpose === "review" ? { previousItemIdentifier: previousItemIdentifier ?? null } : {
|
|
34685
|
+
expectedItemIdentifier: state.assessment.items[expectedItemIndex]?.identifier ?? null
|
|
34686
|
+
},
|
|
34676
34687
|
flow
|
|
34677
34688
|
})
|
|
34678
34689
|
};
|
|
@@ -34695,10 +34706,11 @@ function prepareAssessmentItemSubmission(state, input) {
|
|
|
34695
34706
|
answered: Object.keys(responses[input.itemIdentifier] ?? {}).length > 0
|
|
34696
34707
|
};
|
|
34697
34708
|
}
|
|
34698
|
-
function completeAssessmentItemSubmission(state, input, prepared, scoring) {
|
|
34709
|
+
function completeAssessmentItemSubmission(state, input, prepared, scoring, submittedAt) {
|
|
34699
34710
|
const submission = {
|
|
34700
34711
|
submissionId: input.submissionId,
|
|
34701
34712
|
itemIdentifier: input.itemIdentifier,
|
|
34713
|
+
submittedAt,
|
|
34702
34714
|
responseVersion: prepared.responseVersion,
|
|
34703
34715
|
answered: prepared.answered,
|
|
34704
34716
|
score: scoring.score,
|
|
@@ -34712,8 +34724,8 @@ function completeAssessmentItemSubmission(state, input, prepared, scoring) {
|
|
|
34712
34724
|
};
|
|
34713
34725
|
}
|
|
34714
34726
|
function assessmentResponseUpdateFlowFailure(purpose, itemSubmissions, update) {
|
|
34715
|
-
const
|
|
34716
|
-
const committedUpdate = Object.keys(update).find((identifier) =>
|
|
34727
|
+
const administered = administeredItemIdentifiers(itemSubmissions);
|
|
34728
|
+
const committedUpdate = Object.keys(update).find((identifier) => administered.has(identifier));
|
|
34717
34729
|
return committedUpdate ? assessmentFlowViolation("A submitted item response cannot be edited.", {
|
|
34718
34730
|
itemIdentifier: committedUpdate,
|
|
34719
34731
|
flow: assessmentFlowForPurpose(purpose)
|
|
@@ -34721,11 +34733,18 @@ function assessmentResponseUpdateFlowFailure(purpose, itemSubmissions, update) {
|
|
|
34721
34733
|
}
|
|
34722
34734
|
function assessmentCompletionFlowFailure(purpose, itemSubmissions, itemCount) {
|
|
34723
34735
|
const flow = assessmentFlowForPurpose(purpose);
|
|
34724
|
-
|
|
34736
|
+
if (flow !== "item-submit") {
|
|
34737
|
+
return null;
|
|
34738
|
+
}
|
|
34739
|
+
const complete = purpose === "review" ? itemSubmissions.length > 0 && itemSubmissions.length <= itemCount : itemSubmissions.length === itemCount;
|
|
34740
|
+
if (complete) {
|
|
34741
|
+
return null;
|
|
34742
|
+
}
|
|
34743
|
+
return assessmentFlowViolation(purpose === "review" ? "At least one candidate must be administered before the review can be completed." : "Every item must be submitted before the attempt can be completed.", {
|
|
34725
34744
|
flow,
|
|
34726
34745
|
submittedItemCount: itemSubmissions.length,
|
|
34727
34746
|
itemCount
|
|
34728
|
-
})
|
|
34747
|
+
});
|
|
34729
34748
|
}
|
|
34730
34749
|
function selectAssessmentCourseCandidate(candidates, subjectSpecified) {
|
|
34731
34750
|
if (candidates.length === 0) {
|
|
@@ -34901,15 +34920,15 @@ function canonicalRequestStandards(standards) {
|
|
|
34901
34920
|
return [...canonical.values()].toSorted((left, right) => compareCodeUnits(assessmentStandardRefKey(left), assessmentStandardRefKey(right)));
|
|
34902
34921
|
}
|
|
34903
34922
|
function normalizeReviewRequest(request) {
|
|
34904
|
-
const
|
|
34905
|
-
if (!Number.isInteger(
|
|
34906
|
-
throw new RangeError(`
|
|
34923
|
+
const candidateItemsPerStandard = request.candidateItemsPerStandard ?? 1;
|
|
34924
|
+
if (!Number.isInteger(candidateItemsPerStandard) || candidateItemsPerStandard <= 0 || candidateItemsPerStandard > TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard) {
|
|
34925
|
+
throw new RangeError(`candidateItemsPerStandard must be a positive integer at most ${TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard}`);
|
|
34907
34926
|
}
|
|
34908
34927
|
const standards = canonicalRequestStandards(request.standards);
|
|
34909
34928
|
if (standards.length === 0) {
|
|
34910
34929
|
throw new Error("At least one review standard is required");
|
|
34911
34930
|
}
|
|
34912
|
-
return { standards,
|
|
34931
|
+
return { standards, candidateItemsPerStandard };
|
|
34913
34932
|
}
|
|
34914
34933
|
function reviewRequestFingerprint(request, policy) {
|
|
34915
34934
|
const normalized = normalizeReviewRequest(request);
|
|
@@ -34918,7 +34937,7 @@ function reviewRequestFingerprint(request, policy) {
|
|
|
34918
34937
|
policy: {
|
|
34919
34938
|
version: policy.version
|
|
34920
34939
|
},
|
|
34921
|
-
|
|
34940
|
+
candidateItemsPerStandard: normalized.candidateItemsPerStandard,
|
|
34922
34941
|
standardKeys: normalized.standards.map(assessmentStandardRefKey)
|
|
34923
34942
|
});
|
|
34924
34943
|
}
|
|
@@ -35018,7 +35037,7 @@ function rankedCandidatesByStandard(bank, exposures) {
|
|
|
35018
35037
|
return byStandard;
|
|
35019
35038
|
}
|
|
35020
35039
|
function reviewSlots(request) {
|
|
35021
|
-
return request.standards.flatMap((standard) => Array.from({ length: request.
|
|
35040
|
+
return request.standards.flatMap((standard) => Array.from({ length: request.candidateItemsPerStandard }, () => ({
|
|
35022
35041
|
standard,
|
|
35023
35042
|
standardKey: assessmentStandardRefKey(standard)
|
|
35024
35043
|
})));
|
|
@@ -35122,7 +35141,7 @@ function preferredDistinctMatching(slots, candidatesByStandard) {
|
|
|
35122
35141
|
return new Map(slotItemEdges.filter((candidate) => candidate.edge.capacity === 0).map((candidate) => [candidate.slotIndex, candidate.itemIdentifier]));
|
|
35123
35142
|
}
|
|
35124
35143
|
function fulfillment(request, candidatesByStandard, selections) {
|
|
35125
|
-
const requestedItemCount = request.standards.length * request.
|
|
35144
|
+
const requestedItemCount = request.standards.length * request.candidateItemsPerStandard;
|
|
35126
35145
|
const selectedByStandard = new Map;
|
|
35127
35146
|
for (const selection of selections) {
|
|
35128
35147
|
const key = assessmentStandardRefKey(selection.standard);
|
|
@@ -35131,10 +35150,10 @@ function fulfillment(request, candidatesByStandard, selections) {
|
|
|
35131
35150
|
const shortages = request.standards.flatMap((standard) => {
|
|
35132
35151
|
const key = assessmentStandardRefKey(standard);
|
|
35133
35152
|
const selected = selectedByStandard.get(key) ?? 0;
|
|
35134
|
-
return selected < request.
|
|
35153
|
+
return selected < request.candidateItemsPerStandard ? [
|
|
35135
35154
|
{
|
|
35136
35155
|
standard,
|
|
35137
|
-
requested: request.
|
|
35156
|
+
requested: request.candidateItemsPerStandard,
|
|
35138
35157
|
selected,
|
|
35139
35158
|
eligible: candidatesByStandard.get(key)?.length ?? 0
|
|
35140
35159
|
}
|
|
@@ -35176,9 +35195,9 @@ function projectReviewAssessment(assessment, bank, selections) {
|
|
|
35176
35195
|
throw new Error(`Review bank ${bank.bankRevision} was built from content revision ${bank.sourceContentRevision}, not ${assessment.contentRevision}`);
|
|
35177
35196
|
}
|
|
35178
35197
|
const selectedIdentifiers = new Set(selections.map((selection) => selection.itemIdentifier));
|
|
35179
|
-
const
|
|
35198
|
+
const itemByIdentifier = new Map(assessment.items.map((item) => [item.identifier, item]));
|
|
35180
35199
|
const indexedItems = new Map(bank.items.map((item) => [item.itemIdentifier, item]));
|
|
35181
|
-
const missingIdentifiers = [...selectedIdentifiers].filter((identifier) => !
|
|
35200
|
+
const missingIdentifiers = [...selectedIdentifiers].filter((identifier) => !itemByIdentifier.has(identifier) || !indexedItems.has(identifier));
|
|
35182
35201
|
if (missingIdentifiers.length > 0) {
|
|
35183
35202
|
throw new Error(`Selected review items are absent from the pinned bank: ${missingIdentifiers.join(", ")}`);
|
|
35184
35203
|
}
|
|
@@ -35194,7 +35213,7 @@ function projectReviewAssessment(assessment, bank, selections) {
|
|
|
35194
35213
|
return structuredClone({
|
|
35195
35214
|
...assessment,
|
|
35196
35215
|
contentRevision: bank.bankRevision,
|
|
35197
|
-
items:
|
|
35216
|
+
items: selections.map((selection) => itemByIdentifier.get(selection.itemIdentifier))
|
|
35198
35217
|
});
|
|
35199
35218
|
}
|
|
35200
35219
|
function assessmentItemCorrectness(verdicts) {
|
|
@@ -35253,10 +35272,10 @@ function isReviewItemOutcome(value) {
|
|
|
35253
35272
|
return isRecord(value) && typeof value.itemIdentifier === "string" && value.itemIdentifier.length > 0 && isAssessmentStandardRef(value.standard) && typeof value.answered === "boolean" && isAssessmentScore(value.score) && (value.isCorrect === null || typeof value.isCorrect === "boolean");
|
|
35254
35273
|
}
|
|
35255
35274
|
function isAssessmentItemSubmission(value) {
|
|
35256
|
-
return isRecord(value) && typeof value.submissionId === "string" && value.submissionId.length > 0 && typeof value.itemIdentifier === "string" && value.itemIdentifier.length > 0 && Number.isInteger(value.responseVersion) && typeof value.answered === "boolean" && isAssessmentScore(value.score) && (value.isCorrect === null || typeof value.isCorrect === "boolean");
|
|
35275
|
+
return isRecord(value) && typeof value.submissionId === "string" && value.submissionId.length > 0 && typeof value.itemIdentifier === "string" && value.itemIdentifier.length > 0 && typeof value.submittedAt === "string" && Number.isInteger(value.responseVersion) && typeof value.answered === "boolean" && isAssessmentScore(value.score) && (value.isCorrect === null || typeof value.isCorrect === "boolean");
|
|
35257
35276
|
}
|
|
35258
35277
|
function isReviewAttemptMetadata(value) {
|
|
35259
|
-
return isRecord(value) && typeof value.requestFingerprint === "string" && typeof value.bankRevision === "string" && Array.isArray(value.standards) && value.standards.every(isAssessmentStandardRef) && Number.isInteger(value.
|
|
35278
|
+
return isRecord(value) && typeof value.requestFingerprint === "string" && typeof value.bankRevision === "string" && Array.isArray(value.standards) && value.standards.every(isAssessmentStandardRef) && Number.isInteger(value.candidateItemsPerStandard) && Array.isArray(value.selections) && value.selections.every((selection) => isRecord(selection) && isAssessmentStandardRef(selection.standard) && typeof selection.itemIdentifier === "string") && isReviewFulfillment(value.fulfillment);
|
|
35260
35279
|
}
|
|
35261
35280
|
function isMasteryAttemptMetadata(value) {
|
|
35262
35281
|
return isRecord(value) && typeof value.requestFingerprint === "string" && isAssessmentStandardRef(value.standard);
|
|
@@ -35626,7 +35645,7 @@ var init_assessment_runtime = __esm(() => {
|
|
|
35626
35645
|
StartAssessmentBaseSchema.extend({
|
|
35627
35646
|
purpose: exports_external.literal("review"),
|
|
35628
35647
|
standards: exports_external.array(AssessmentStandardRefSchema).min(1).max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.standards),
|
|
35629
|
-
|
|
35648
|
+
candidateItemsPerStandard: exports_external.number().int().positive().max(TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS.candidateItemsPerStandard).optional()
|
|
35630
35649
|
}),
|
|
35631
35650
|
StartAssessmentBaseSchema.extend({
|
|
35632
35651
|
purpose: exports_external.literal("mastery"),
|
|
@@ -116804,6 +116823,10 @@ var init_timeback4 = __esm(() => {
|
|
|
116804
116823
|
init_assessment_runtime2();
|
|
116805
116824
|
});
|
|
116806
116825
|
function buildReviewItemResultMetadata(input) {
|
|
116826
|
+
const administration = itemAdministration(input.metadata.itemSubmissions, input.selection.itemIdentifier);
|
|
116827
|
+
if (!administration) {
|
|
116828
|
+
throw new Error(`Cannot create a review result for unadministered candidate ${input.selection.itemIdentifier}`);
|
|
116829
|
+
}
|
|
116807
116830
|
return {
|
|
116808
116831
|
version: PLAYCADEMY_ASSESSMENT_ITEM_RESULT_METADATA_VERSION,
|
|
116809
116832
|
parentAttemptId: input.parentAttemptId,
|
|
@@ -116813,7 +116836,7 @@ function buildReviewItemResultMetadata(input) {
|
|
|
116813
116836
|
bankRevision: input.metadata.review.bankRevision,
|
|
116814
116837
|
itemIdentifier: input.selection.itemIdentifier,
|
|
116815
116838
|
standard: input.selection.standard,
|
|
116816
|
-
deliveredAt:
|
|
116839
|
+
deliveredAt: administration.submittedAt,
|
|
116817
116840
|
responseVersion: input.responseVersion ?? input.metadata.responseVersion,
|
|
116818
116841
|
responses: input.metadata.responses[input.selection.itemIdentifier] ?? {},
|
|
116819
116842
|
...input.submissionId ? { submissionId: input.submissionId } : {},
|
|
@@ -116868,7 +116891,8 @@ function resolveReviewChildResult(input) {
|
|
|
116868
116891
|
}
|
|
116869
116892
|
const childMetadata = playcademyAssessmentItemResultMetadata(input.childResult.metadata);
|
|
116870
116893
|
const expectedResponses = input.parentMetadata.responses[input.selection.itemIdentifier] ?? {};
|
|
116871
|
-
|
|
116894
|
+
const administration = itemAdministration(input.parentMetadata.itemSubmissions, input.selection.itemIdentifier);
|
|
116895
|
+
if (input.childResult.assessmentLineItem.sourcedId !== input.childLineItemId || input.childResult.student.sourcedId !== input.parentResult.student.sourcedId || !childMetadata || childMetadata.parentAttemptId !== input.parentResult.sourcedId || childMetadata.activityId !== input.parentMetadata.activityId || childMetadata.integrationId !== input.parentMetadata.integrationId || childMetadata.enrollmentId !== input.parentMetadata.enrollmentId || childMetadata.bankRevision !== input.parentMetadata.review.bankRevision || childMetadata.itemIdentifier !== input.selection.itemIdentifier || childMetadata.standard.framework !== input.selection.standard.framework || childMetadata.standard.identifier !== input.selection.standard.identifier || childMetadata.deliveredAt !== administration?.submittedAt || childMetadata.responseVersion > input.parentMetadata.responseVersion || canonicalJson(childMetadata.responses) !== canonicalJson(expectedResponses)) {
|
|
116872
116896
|
return { action: "restore", reason: "incompatible" };
|
|
116873
116897
|
}
|
|
116874
116898
|
return input.childResult.status === "active" ? { action: "reuse", metadata: childMetadata } : { action: "restore", reason: "inactive" };
|
|
@@ -117556,7 +117580,7 @@ class TimebackAssessmentRuntimeService {
|
|
|
117556
117580
|
requestFingerprint,
|
|
117557
117581
|
bankRevision: source.bank.bankRevision,
|
|
117558
117582
|
standards: [...normalizedRequest.standards],
|
|
117559
|
-
|
|
117583
|
+
candidateItemsPerStandard: normalizedRequest.candidateItemsPerStandard,
|
|
117560
117584
|
selections: [...selected.selections],
|
|
117561
117585
|
fulfillment: selected.fulfillment
|
|
117562
117586
|
}
|
|
@@ -117688,9 +117712,6 @@ class TimebackAssessmentRuntimeService {
|
|
|
117688
117712
|
updatedAt: new Date().toISOString()
|
|
117689
117713
|
};
|
|
117690
117714
|
await this.putResultMetadata(attempt.result, metadata2);
|
|
117691
|
-
if (metadata2.purpose === "review") {
|
|
117692
|
-
await this.putReviewChildResponses(attempt.result, metadata2, new Set(Object.keys(input.responses)));
|
|
117693
|
-
}
|
|
117694
117715
|
return {
|
|
117695
117716
|
attemptId: attempt.result.sourcedId,
|
|
117696
117717
|
responseVersion: metadata2.responseVersion,
|
|
@@ -117758,13 +117779,14 @@ class TimebackAssessmentRuntimeService {
|
|
|
117758
117779
|
if (!preview.scoring) {
|
|
117759
117780
|
throw new Error("Prepared item submission is missing its score");
|
|
117760
117781
|
}
|
|
117761
|
-
const
|
|
117782
|
+
const submittedAt = new Date().toISOString();
|
|
117783
|
+
const completed = completeAssessmentItemSubmission(attempt.metadata, input, transition, preview.scoring, submittedAt);
|
|
117762
117784
|
const metadata2 = {
|
|
117763
117785
|
...attempt.metadata,
|
|
117764
117786
|
responses: completed.responses,
|
|
117765
117787
|
responseVersion: completed.responseVersion,
|
|
117766
117788
|
itemSubmissions: completed.itemSubmissions,
|
|
117767
|
-
updatedAt:
|
|
117789
|
+
updatedAt: submittedAt
|
|
117768
117790
|
};
|
|
117769
117791
|
await this.putResultMetadata(attempt.result, metadata2);
|
|
117770
117792
|
return {
|
|
@@ -117869,12 +117891,13 @@ class TimebackAssessmentRuntimeService {
|
|
|
117869
117891
|
async scoreSubmission(attempt) {
|
|
117870
117892
|
const assessment = await this.loadAttemptAssessment(attempt.metadata);
|
|
117871
117893
|
validateAssessmentResponses(assessment, attempt.metadata.responses);
|
|
117872
|
-
const
|
|
117894
|
+
const administeredItems = attempt.metadata.purpose === "review" ? administeredItemIdentifiers(attempt.metadata.itemSubmissions) : undefined;
|
|
117895
|
+
const itemResults = await this.scoreItems(assessment, attempt.metadata.responses, administeredItems);
|
|
117873
117896
|
return {
|
|
117874
117897
|
responseVersion: attempt.metadata.responseVersion,
|
|
117875
117898
|
assessment,
|
|
117876
117899
|
itemResults,
|
|
117877
|
-
score: aggregateAssessmentScore(itemResults.map((result) => result.score.earned),
|
|
117900
|
+
score: aggregateAssessmentScore(itemResults.map((result) => result.score.earned), itemResults.reduce((total, result) => total + result.score.possible, 0)),
|
|
117878
117901
|
correctQuestions: countCorrectQuestions(itemResults.map((result) => result.isCorrect))
|
|
117879
117902
|
};
|
|
117880
117903
|
}
|
|
@@ -117967,7 +117990,7 @@ class TimebackAssessmentRuntimeService {
|
|
|
117967
117990
|
submissionId: input.submissionId,
|
|
117968
117991
|
timestamp: timestamp6,
|
|
117969
117992
|
testName: assessment.title,
|
|
117970
|
-
totalQuestions:
|
|
117993
|
+
totalQuestions: itemResults.length,
|
|
117971
117994
|
correctQuestions,
|
|
117972
117995
|
...input.session ? { session: input.session } : {},
|
|
117973
117996
|
...reviewOutcomes ? { itemOutcomes: reviewOutcomes } : {}
|
|
@@ -117998,7 +118021,7 @@ class TimebackAssessmentRuntimeService {
|
|
|
117998
118021
|
testIdentifier: assessment.identifier,
|
|
117999
118022
|
testName: assessment.title,
|
|
118000
118023
|
score,
|
|
118001
|
-
totalQuestions:
|
|
118024
|
+
totalQuestions: itemResults.length,
|
|
118002
118025
|
correctQuestions,
|
|
118003
118026
|
submissionId: input.submissionId,
|
|
118004
118027
|
gameId: params.gameId,
|
|
@@ -118542,11 +118565,21 @@ class TimebackAssessmentRuntimeService {
|
|
|
118542
118565
|
if (physicalItems.size !== input.metadata.review.selections.length) {
|
|
118543
118566
|
throw new Error("MVP review selection must use each physical item at most once");
|
|
118544
118567
|
}
|
|
118568
|
+
const administeredItems = administeredItemIdentifiers(input.metadata.itemSubmissions);
|
|
118545
118569
|
await runWithConcurrency(input.metadata.review.selections, TimebackAssessmentRuntimeService.SCORING_CONCURRENCY, async (selection) => {
|
|
118546
118570
|
const item = itemByIdentifier.get(selection.itemIdentifier);
|
|
118547
118571
|
if (!item) {
|
|
118548
118572
|
throw new Error(`Review assessment is missing selected item ${selection.itemIdentifier}`);
|
|
118549
118573
|
}
|
|
118574
|
+
if (!administeredItems.has(selection.itemIdentifier)) {
|
|
118575
|
+
await this.ensureReviewQuestionLineItem({
|
|
118576
|
+
parentLineItemId: input.result.assessmentLineItem.sourcedId,
|
|
118577
|
+
integration: input.integration,
|
|
118578
|
+
bank: input.source.bank,
|
|
118579
|
+
item
|
|
118580
|
+
});
|
|
118581
|
+
return;
|
|
118582
|
+
}
|
|
118550
118583
|
const childLineItemId = await reviewQuestionLineItemId(input.result.assessmentLineItem.sourcedId, item.identifier);
|
|
118551
118584
|
const childResultId = await reviewQuestionResultId(input.result.sourcedId, childLineItemId);
|
|
118552
118585
|
const streamedChildResult = input.existingChildResults.get(childResultId);
|
|
@@ -118593,33 +118626,35 @@ class TimebackAssessmentRuntimeService {
|
|
|
118593
118626
|
});
|
|
118594
118627
|
});
|
|
118595
118628
|
}
|
|
118596
|
-
async
|
|
118597
|
-
|
|
118598
|
-
|
|
118599
|
-
|
|
118600
|
-
|
|
118601
|
-
|
|
118602
|
-
|
|
118603
|
-
|
|
118604
|
-
|
|
118605
|
-
|
|
118606
|
-
|
|
118607
|
-
|
|
118608
|
-
|
|
118609
|
-
|
|
118610
|
-
|
|
118611
|
-
|
|
118612
|
-
|
|
118613
|
-
|
|
118614
|
-
|
|
118615
|
-
|
|
118616
|
-
|
|
118617
|
-
|
|
118618
|
-
|
|
118619
|
-
|
|
118629
|
+
async putReviewChildResponse(result, metadata2, itemIdentifier) {
|
|
118630
|
+
const selection = metadata2.review.selections.find((candidate) => candidate.itemIdentifier === itemIdentifier);
|
|
118631
|
+
if (!selection) {
|
|
118632
|
+
return;
|
|
118633
|
+
}
|
|
118634
|
+
try {
|
|
118635
|
+
const childLineItemId = await reviewQuestionLineItemId(result.assessmentLineItem.sourcedId, selection.itemIdentifier);
|
|
118636
|
+
const childResultId = await reviewQuestionResultId(result.sourcedId, childLineItemId);
|
|
118637
|
+
const childMetadata = buildReviewItemResultMetadata({
|
|
118638
|
+
metadata: metadata2,
|
|
118639
|
+
selection,
|
|
118640
|
+
parentAttemptId: result.sourcedId
|
|
118641
|
+
});
|
|
118642
|
+
await this.requireClient().api.oneroster.assessmentResults.upsert(childResultId, buildOpenReviewChildResult({
|
|
118643
|
+
childLineItemId,
|
|
118644
|
+
student: result.student,
|
|
118645
|
+
metadata: childMetadata
|
|
118646
|
+
}));
|
|
118647
|
+
} catch (error88) {
|
|
118648
|
+
addEvent("assessment.review_child_response_projection_failed", {
|
|
118649
|
+
"app.assessment.attempt_id": result.sourcedId,
|
|
118650
|
+
"app.assessment.qti_item_identifier": selection.itemIdentifier,
|
|
118651
|
+
"exception.type": errorType(error88),
|
|
118652
|
+
"app.error.message": errorMessage2(error88)
|
|
118653
|
+
});
|
|
118654
|
+
}
|
|
118620
118655
|
}
|
|
118621
118656
|
async projectReviewItemResponse(params, projection) {
|
|
118622
|
-
await this.
|
|
118657
|
+
await this.putReviewChildResponse(projection.result, projection.metadata, projection.itemIdentifier);
|
|
118623
118658
|
try {
|
|
118624
118659
|
await this.crossAttemptLockBarrier(params.attemptId);
|
|
118625
118660
|
const latest = await this.peekAttempt(params);
|
|
@@ -118698,7 +118733,8 @@ class TimebackAssessmentRuntimeService {
|
|
|
118698
118733
|
}
|
|
118699
118734
|
async finalizeReviewChildResults(input) {
|
|
118700
118735
|
const resultByItem = new Map(input.itemResults.map((itemResult) => [itemResult.itemIdentifier, itemResult]));
|
|
118701
|
-
|
|
118736
|
+
const administeredItems = administeredItemIdentifiers(input.metadata.itemSubmissions);
|
|
118737
|
+
return runWithConcurrency(input.metadata.review.selections.filter((selection) => administeredItems.has(selection.itemIdentifier)), TimebackAssessmentRuntimeService.SCORING_CONCURRENCY, async (selection) => {
|
|
118702
118738
|
const itemResult = resultByItem.get(selection.itemIdentifier);
|
|
118703
118739
|
if (!itemResult) {
|
|
118704
118740
|
throw new Error(`Scoring omitted selected review item ${selection.itemIdentifier}`);
|
|
@@ -118814,7 +118850,7 @@ class TimebackAssessmentRuntimeService {
|
|
|
118814
118850
|
kind: "standards-review",
|
|
118815
118851
|
purpose: metadata2.purpose,
|
|
118816
118852
|
standards: [...metadata2.review.standards],
|
|
118817
|
-
|
|
118853
|
+
candidateItemsPerStandard: metadata2.review.candidateItemsPerStandard,
|
|
118818
118854
|
selections: [...metadata2.review.selections],
|
|
118819
118855
|
fulfillment: metadata2.review.fulfillment
|
|
118820
118856
|
};
|
|
@@ -185960,7 +185996,7 @@ var init_timeback9 = __esm3(() => {
|
|
|
185960
185996
|
ASSESSMENT_PURPOSES2 = ["end_of_course", "diagnostic", "review", "mastery"];
|
|
185961
185997
|
TIMEBACK_ASSESSMENT_REVIEW_REQUEST_LIMITS2 = {
|
|
185962
185998
|
standards: 20,
|
|
185963
|
-
|
|
185999
|
+
candidateItemsPerStandard: 2,
|
|
185964
186000
|
standardFieldLength: 128
|
|
185965
186001
|
};
|
|
185966
186002
|
TIMEBACK_COURSE_DEFAULTS2 = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcademy/vite-plugin",
|
|
3
|
-
"version": "1.2.1-beta.
|
|
3
|
+
"version": "1.2.1-beta.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"archiver": "^7.0.1",
|
|
21
21
|
"picocolors": "^1.1.1",
|
|
22
|
-
"playcademy": "0.28.1-beta.
|
|
22
|
+
"playcademy": "0.28.1-beta.18"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@electric-sql/pglite": "^0.3.16",
|
|
26
26
|
"@inquirer/prompts": "^7.8.6",
|
|
27
27
|
"@playcademy/constants": "0.0.1",
|
|
28
|
-
"@playcademy/sandbox": "0.7.1-beta.
|
|
29
|
-
"@playcademy/sdk": "0.16.1-beta.
|
|
28
|
+
"@playcademy/sandbox": "0.7.1-beta.17",
|
|
29
|
+
"@playcademy/sdk": "0.16.1-beta.17",
|
|
30
30
|
"@playcademy/types": "0.0.1",
|
|
31
31
|
"@playcademy/utils": "0.0.1",
|
|
32
32
|
"@types/archiver": "^6.0.3",
|