@playcademy/vite-plugin 1.2.1-beta.20 → 1.2.1-beta.22
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 +288 -6
- 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.22",
|
|
24319
24319
|
type: "module",
|
|
24320
24320
|
exports: {
|
|
24321
24321
|
".": {
|
|
@@ -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.21",
|
|
25925
25925
|
description: "Local development server for Playcademy game development",
|
|
25926
25926
|
type: "module",
|
|
25927
25927
|
exports: {
|
|
@@ -34476,6 +34476,12 @@ function responseValues(value) {
|
|
|
34476
34476
|
return Array.isArray(value) ? value : [value];
|
|
34477
34477
|
}
|
|
34478
34478
|
function assessmentResponseValidationMessage(assessment, responses) {
|
|
34479
|
+
return responseValidationMessage(assessment, responses, false);
|
|
34480
|
+
}
|
|
34481
|
+
function assessmentDraftResponseValidationMessage(assessment, responses) {
|
|
34482
|
+
return responseValidationMessage(assessment, responses, true);
|
|
34483
|
+
}
|
|
34484
|
+
function responseValidationMessage(assessment, responses, allowIncomplete) {
|
|
34479
34485
|
const items = new Map(assessment.items.map((item) => [item.identifier, item]));
|
|
34480
34486
|
for (const [itemIdentifier, itemResponses] of Object.entries(responses)) {
|
|
34481
34487
|
const item = items.get(itemIdentifier);
|
|
@@ -34492,7 +34498,7 @@ function assessmentResponseValidationMessage(assessment, responses) {
|
|
|
34492
34498
|
if (!interaction) {
|
|
34493
34499
|
return `Response for ${itemIdentifier} uses unknown identifier ${responseIdentifier}.`;
|
|
34494
34500
|
}
|
|
34495
|
-
const message = interactionResponseValidationMessage(itemIdentifier, interaction, responseValue);
|
|
34501
|
+
const message = interactionResponseValidationMessage(itemIdentifier, interaction, responseValue, allowIncomplete);
|
|
34496
34502
|
if (message) {
|
|
34497
34503
|
return message;
|
|
34498
34504
|
}
|
|
@@ -34535,7 +34541,7 @@ function undirectedPairsValidationMessage(itemIdentifier, values, interaction) {
|
|
|
34535
34541
|
}
|
|
34536
34542
|
return null;
|
|
34537
34543
|
}
|
|
34538
|
-
function interactionResponseValidationMessage(itemIdentifier, interaction, responseValue) {
|
|
34544
|
+
function interactionResponseValidationMessage(itemIdentifier, interaction, responseValue, allowIncomplete) {
|
|
34539
34545
|
if (!isAssessmentResponseValue(responseValue)) {
|
|
34540
34546
|
return `Response for ${itemIdentifier} is not a usable value: non-empty text, at most ${TIMEBACK_ASSESSMENT_RESPONSE_VALUE_MAX_LENGTH} characters.`;
|
|
34541
34547
|
}
|
|
@@ -34606,7 +34612,7 @@ function interactionResponseValidationMessage(itemIdentifier, interaction, respo
|
|
|
34606
34612
|
allowed = new Set(interaction.segments.flatMap((segment) => segment.selectable && segment.identifier ? [segment.identifier] : []));
|
|
34607
34613
|
maximum = interaction.maxChoices;
|
|
34608
34614
|
}
|
|
34609
|
-
if (values.length < minimum || maximum !== 0 && values.length > maximum || new Set(values).size !== values.length || allowed && values.some((value) => !allowed.has(value))) {
|
|
34615
|
+
if (!allowIncomplete && values.length < minimum || maximum !== 0 && values.length > maximum || new Set(values).size !== values.length || allowed && values.some((value) => !allowed.has(value))) {
|
|
34610
34616
|
return `Response for ${itemIdentifier} is not valid for its interaction.`;
|
|
34611
34617
|
}
|
|
34612
34618
|
return null;
|
|
@@ -64246,6 +64252,8 @@ var AssessmentStandardRefSchema2;
|
|
|
64246
64252
|
var CreateAssessmentRequestSchema;
|
|
64247
64253
|
var UpdateAssessmentRequestSchema;
|
|
64248
64254
|
var CopyAssessmentRequestSchema;
|
|
64255
|
+
var AssessmentAssociationImportEntrySchema;
|
|
64256
|
+
var AttachExistingAssessmentsRequestSchema;
|
|
64249
64257
|
var ReorderAssessmentsRequestSchema;
|
|
64250
64258
|
var ReorderQuestionsRequestSchema;
|
|
64251
64259
|
var init_schemas4 = __esm(() => {
|
|
@@ -64514,6 +64522,43 @@ var init_schemas4 = __esm(() => {
|
|
|
64514
64522
|
purpose: AssessmentPurposeSchema,
|
|
64515
64523
|
standard: AssessmentStandardRefSchema2.optional()
|
|
64516
64524
|
}).superRefine(requireMasteryStandard);
|
|
64525
|
+
AssessmentAssociationImportEntrySchema = exports_external.object({
|
|
64526
|
+
qtiTestIdentifier: exports_external.string().trim().min(1, "Assessment identifier is required"),
|
|
64527
|
+
purpose: AssessmentPurposeSchema,
|
|
64528
|
+
standard: AssessmentStandardRefSchema2.optional(),
|
|
64529
|
+
sortOrder: exports_external.number().int().nonnegative().nullable()
|
|
64530
|
+
}).superRefine((input, context2) => {
|
|
64531
|
+
requireMasteryStandard(input, context2);
|
|
64532
|
+
if (input.purpose !== "mastery" && input.standard !== undefined) {
|
|
64533
|
+
context2.addIssue({
|
|
64534
|
+
code: "custom",
|
|
64535
|
+
path: ["standard"],
|
|
64536
|
+
message: "Only mastery assessments may have a quiz-level standard"
|
|
64537
|
+
});
|
|
64538
|
+
}
|
|
64539
|
+
});
|
|
64540
|
+
AttachExistingAssessmentsRequestSchema = exports_external.object({
|
|
64541
|
+
version: exports_external.literal(1),
|
|
64542
|
+
sourceGameId: exports_external.string().trim().min(1),
|
|
64543
|
+
sourceGameSlug: exports_external.string().trim().min(1).optional(),
|
|
64544
|
+
sourceIntegrationId: exports_external.string().trim().min(1),
|
|
64545
|
+
subject: TimebackSubjectSchema,
|
|
64546
|
+
grade: TimebackGradeSchema,
|
|
64547
|
+
targetStatus: exports_external.enum(["draft", "live"]),
|
|
64548
|
+
assessments: exports_external.array(AssessmentAssociationImportEntrySchema).min(1, "At least one assessment is required").max(500, "A bulk import can contain at most 500 assessments")
|
|
64549
|
+
}).superRefine((input, context2) => {
|
|
64550
|
+
const seen = new Set;
|
|
64551
|
+
input.assessments.forEach((assessment, index2) => {
|
|
64552
|
+
if (seen.has(assessment.qtiTestIdentifier)) {
|
|
64553
|
+
context2.addIssue({
|
|
64554
|
+
code: "custom",
|
|
64555
|
+
path: ["assessments", index2, "qtiTestIdentifier"],
|
|
64556
|
+
message: "Assessment identifiers must be unique"
|
|
64557
|
+
});
|
|
64558
|
+
}
|
|
64559
|
+
seen.add(assessment.qtiTestIdentifier);
|
|
64560
|
+
});
|
|
64561
|
+
});
|
|
64517
64562
|
ReorderAssessmentsRequestSchema = exports_external.object({
|
|
64518
64563
|
purpose: AssessmentPurposeSchema,
|
|
64519
64564
|
testIdentifiers: exports_external.array(exports_external.string().trim().min(1, "Assessment identifier is required")).min(1, "At least one assessment is required")
|
|
@@ -117245,6 +117290,12 @@ function validateAssessmentResponses(assessment, responses) {
|
|
|
117245
117290
|
throw new AssessmentRuntimeError("INVALID_RESPONSE", message);
|
|
117246
117291
|
}
|
|
117247
117292
|
}
|
|
117293
|
+
function validateAssessmentDraftResponses(assessment, responses) {
|
|
117294
|
+
const message = assessmentDraftResponseValidationMessage(assessment, responses);
|
|
117295
|
+
if (message) {
|
|
117296
|
+
throw new AssessmentRuntimeError("INVALID_RESPONSE", message);
|
|
117297
|
+
}
|
|
117298
|
+
}
|
|
117248
117299
|
function assessmentScoringRequests(assessment, responses) {
|
|
117249
117300
|
return assessment.items.map((item) => ({
|
|
117250
117301
|
itemIdentifier: item.identifier,
|
|
@@ -117698,7 +117749,7 @@ class TimebackAssessmentRuntimeService {
|
|
|
117698
117749
|
}
|
|
117699
117750
|
validateAssessmentResponseUpdate(assessment, input.responses);
|
|
117700
117751
|
const responses = applyAssessmentResponseUpdate(attempt.metadata.responses, input.responses);
|
|
117701
|
-
|
|
117752
|
+
validateAssessmentDraftResponses(assessment, responses);
|
|
117702
117753
|
const metadata2 = {
|
|
117703
117754
|
...attempt.metadata,
|
|
117704
117755
|
responses,
|
|
@@ -120002,6 +120053,74 @@ var init_timeback_qti_authoring_util = __esm(() => {
|
|
|
120002
120053
|
buildMatchQuestionXml
|
|
120003
120054
|
];
|
|
120004
120055
|
});
|
|
120056
|
+
function assertPlayableAssessmentImportQuestions(targetStatus, questions) {
|
|
120057
|
+
if (targetStatus === "draft") {
|
|
120058
|
+
return;
|
|
120059
|
+
}
|
|
120060
|
+
for (const question of questions) {
|
|
120061
|
+
assertPlayableQtiQuestion(question);
|
|
120062
|
+
}
|
|
120063
|
+
}
|
|
120064
|
+
function assertAssessmentImportCourseMatches(manifest, integration) {
|
|
120065
|
+
if (integration.subject !== manifest.subject || integration.grade !== manifest.grade) {
|
|
120066
|
+
throw new ValidationError(`This manifest is for ${manifest.subject} grade ${manifest.grade}, not ${integration.subject} grade ${integration.grade}.`);
|
|
120067
|
+
}
|
|
120068
|
+
}
|
|
120069
|
+
function associationMetadataMatches(row, entry2) {
|
|
120070
|
+
return row.purpose === entry2.purpose && (row.standardFramework ?? undefined) === entry2.standard?.framework && (row.standardIdentifier ?? undefined) === entry2.standard?.identifier;
|
|
120071
|
+
}
|
|
120072
|
+
function targetStatusSatisfied(row, targetStatus) {
|
|
120073
|
+
return row.status === targetStatus || targetStatus === "draft" && row.status === "live";
|
|
120074
|
+
}
|
|
120075
|
+
function classifyExistingAssessmentImport(row, entry2, targetStatus) {
|
|
120076
|
+
if (!associationMetadataMatches(row, entry2)) {
|
|
120077
|
+
return {
|
|
120078
|
+
status: "failed",
|
|
120079
|
+
message: "Already attached with different purpose or standard metadata."
|
|
120080
|
+
};
|
|
120081
|
+
}
|
|
120082
|
+
if (targetStatusSatisfied(row, targetStatus)) {
|
|
120083
|
+
return { status: "skipped", message: `Already attached as ${row.status}.` };
|
|
120084
|
+
}
|
|
120085
|
+
if (row.status === "archived") {
|
|
120086
|
+
return {
|
|
120087
|
+
status: "failed",
|
|
120088
|
+
message: "Already attached as archived and cannot be imported again."
|
|
120089
|
+
};
|
|
120090
|
+
}
|
|
120091
|
+
if (targetStatus === "live" && row.status === "draft") {
|
|
120092
|
+
return {
|
|
120093
|
+
status: "failed",
|
|
120094
|
+
message: "Already attached as a draft. Publish it from the assessment editor before retrying."
|
|
120095
|
+
};
|
|
120096
|
+
}
|
|
120097
|
+
return {
|
|
120098
|
+
status: "failed",
|
|
120099
|
+
message: `Already attached as ${row.status}, which does not match the requested ${targetStatus} status.`
|
|
120100
|
+
};
|
|
120101
|
+
}
|
|
120102
|
+
function attachedAssessmentImportMessage(targetStatus, editable) {
|
|
120103
|
+
if (targetStatus === "live") {
|
|
120104
|
+
return editable ? "Attached live." : "Attached live. QTI content is read-only because another app owns it.";
|
|
120105
|
+
}
|
|
120106
|
+
return editable ? "Attached as a draft." : "Attached as a read-only draft owned by another app.";
|
|
120107
|
+
}
|
|
120108
|
+
function liveReviewAssessmentImportFailures(targetStatus, candidates, existingRows) {
|
|
120109
|
+
if (targetStatus === "draft") {
|
|
120110
|
+
return new Map;
|
|
120111
|
+
}
|
|
120112
|
+
const reviews = candidates.filter((candidate) => candidate.purpose === "review");
|
|
120113
|
+
const hasExistingLiveReview = existingRows.some((row) => row.purpose === "review" && row.status === "live");
|
|
120114
|
+
if (reviews.length <= 1 && !hasExistingLiveReview) {
|
|
120115
|
+
return new Map;
|
|
120116
|
+
}
|
|
120117
|
+
const message = hasExistingLiveReview ? "Another review assessment is already live for this course." : "Only one review assessment can be imported live at a time.";
|
|
120118
|
+
return new Map(reviews.map((review) => [review.qtiTestIdentifier, message]));
|
|
120119
|
+
}
|
|
120120
|
+
var init_timeback_assessment_import_util = __esm(() => {
|
|
120121
|
+
init_errors2();
|
|
120122
|
+
init_timeback_qti_authoring_util();
|
|
120123
|
+
});
|
|
120005
120124
|
function newPlaycademyTestIdentifier() {
|
|
120006
120125
|
return `${PLAYCADEMY_QTI_SOURCE_PREFIX}${crypto.randomUUID()}`;
|
|
120007
120126
|
}
|
|
@@ -120148,6 +120267,150 @@ class TimebackAssessmentsService {
|
|
|
120148
120267
|
throw error88;
|
|
120149
120268
|
}
|
|
120150
120269
|
}
|
|
120270
|
+
async attachExistingAssessments(integrationId, manifest) {
|
|
120271
|
+
const client2 = this.requireClient();
|
|
120272
|
+
const { integration, gameSlug } = await this.requireQtiTestOwnershipContext(integrationId);
|
|
120273
|
+
assertAssessmentImportCourseMatches(manifest, integration);
|
|
120274
|
+
validateUniqueAssessmentIdentifiers(manifest.assessments.map((assessment) => assessment.qtiTestIdentifier));
|
|
120275
|
+
const entries = manifest.assessments.map((assessment, index2) => ({
|
|
120276
|
+
...assessment,
|
|
120277
|
+
index: index2,
|
|
120278
|
+
standard: this.requirePurposeStandard(assessment.purpose, assessment.standard)
|
|
120279
|
+
}));
|
|
120280
|
+
const existingRows = await this.deps.db.query.gameTimebackAssessmentTests.findMany({
|
|
120281
|
+
where: eq(gameTimebackAssessmentTests.integrationId, integrationId)
|
|
120282
|
+
});
|
|
120283
|
+
const existingByIdentifier = new Map(existingRows.map((row) => [row.qtiTestIdentifier, row]));
|
|
120284
|
+
const validated = await runWithConcurrency(entries, QTI_HYDRATION_CONCURRENCY, async (entry2) => {
|
|
120285
|
+
try {
|
|
120286
|
+
const loaded = await loadHydratedQtiTest(client2, entry2.qtiTestIdentifier);
|
|
120287
|
+
assertAssessmentHasQuestions(loaded.questions.questions);
|
|
120288
|
+
assertPlayableAssessmentImportQuestions(manifest.targetStatus, loaded.questions.questions.map(({ question }) => question));
|
|
120289
|
+
if (entry2.purpose === "review") {
|
|
120290
|
+
assertReviewAssessmentHasStandards(loaded.questions.questions.map(({ question }) => qtiAssessmentStandardRefsFromMetadata2(question.metadata).filter((standard) => canonicalReviewStandardRef(standard) !== null).length));
|
|
120291
|
+
}
|
|
120292
|
+
return { entry: entry2, test: loaded.test };
|
|
120293
|
+
} catch (error88) {
|
|
120294
|
+
return { entry: entry2, error: error88 };
|
|
120295
|
+
}
|
|
120296
|
+
});
|
|
120297
|
+
const results = [];
|
|
120298
|
+
const pending = [];
|
|
120299
|
+
for (const validation of validated) {
|
|
120300
|
+
const { entry: entry2 } = validation;
|
|
120301
|
+
const { index: index2 } = entry2;
|
|
120302
|
+
const base = {
|
|
120303
|
+
qtiTestIdentifier: entry2.qtiTestIdentifier,
|
|
120304
|
+
purpose: entry2.purpose,
|
|
120305
|
+
...entry2.standard ? { standard: entry2.standard } : {},
|
|
120306
|
+
sourceSortOrder: entry2.sortOrder
|
|
120307
|
+
};
|
|
120308
|
+
if ("error" in validation) {
|
|
120309
|
+
results[index2] = {
|
|
120310
|
+
...base,
|
|
120311
|
+
status: "failed",
|
|
120312
|
+
message: `QTI validation failed: ${errorMessage2(validation.error)}`
|
|
120313
|
+
};
|
|
120314
|
+
} else {
|
|
120315
|
+
const existing = existingByIdentifier.get(entry2.qtiTestIdentifier);
|
|
120316
|
+
const editable = isQtiTestOwnedByGame(validation.test, gameSlug);
|
|
120317
|
+
const hydratedBase = { ...base, title: validation.test.title, editable };
|
|
120318
|
+
if (!existing) {
|
|
120319
|
+
pending.push({ entry: entry2, test: validation.test });
|
|
120320
|
+
} else {
|
|
120321
|
+
const decision = classifyExistingAssessmentImport(existing, {
|
|
120322
|
+
purpose: entry2.purpose,
|
|
120323
|
+
...entry2.standard ? { standard: entry2.standard } : {}
|
|
120324
|
+
}, manifest.targetStatus);
|
|
120325
|
+
results[index2] = {
|
|
120326
|
+
...hydratedBase,
|
|
120327
|
+
status: decision.status,
|
|
120328
|
+
association: this.associationImportSummary(existing),
|
|
120329
|
+
message: decision.message
|
|
120330
|
+
};
|
|
120331
|
+
}
|
|
120332
|
+
}
|
|
120333
|
+
}
|
|
120334
|
+
const liveReviewFailures = liveReviewAssessmentImportFailures(manifest.targetStatus, pending.map(({ entry: entry2 }) => entry2), existingRows);
|
|
120335
|
+
for (const { entry: entry2, test } of pending) {
|
|
120336
|
+
const message = liveReviewFailures.get(entry2.qtiTestIdentifier);
|
|
120337
|
+
if (message) {
|
|
120338
|
+
results[entry2.index] = {
|
|
120339
|
+
qtiTestIdentifier: entry2.qtiTestIdentifier,
|
|
120340
|
+
title: test.title,
|
|
120341
|
+
purpose: entry2.purpose,
|
|
120342
|
+
...entry2.standard ? { standard: entry2.standard } : {},
|
|
120343
|
+
sourceSortOrder: entry2.sortOrder,
|
|
120344
|
+
editable: isQtiTestOwnedByGame(test, gameSlug),
|
|
120345
|
+
status: "failed",
|
|
120346
|
+
message
|
|
120347
|
+
};
|
|
120348
|
+
}
|
|
120349
|
+
}
|
|
120350
|
+
const attachablePending = pending.filter(({ entry: entry2 }) => !liveReviewFailures.has(entry2.qtiTestIdentifier));
|
|
120351
|
+
for (const validation of attachablePending) {
|
|
120352
|
+
const { entry: entry2, test } = validation;
|
|
120353
|
+
const { index: index2 } = entry2;
|
|
120354
|
+
const base = {
|
|
120355
|
+
qtiTestIdentifier: entry2.qtiTestIdentifier,
|
|
120356
|
+
title: test.title,
|
|
120357
|
+
purpose: entry2.purpose,
|
|
120358
|
+
...entry2.standard ? { standard: entry2.standard } : {},
|
|
120359
|
+
sourceSortOrder: entry2.sortOrder,
|
|
120360
|
+
editable: isQtiTestOwnedByGame(test, gameSlug)
|
|
120361
|
+
};
|
|
120362
|
+
try {
|
|
120363
|
+
const [row] = await this.deps.db.insert(gameTimebackAssessmentTests).values({
|
|
120364
|
+
integrationId,
|
|
120365
|
+
qtiTestIdentifier: entry2.qtiTestIdentifier,
|
|
120366
|
+
purpose: entry2.purpose,
|
|
120367
|
+
status: manifest.targetStatus,
|
|
120368
|
+
sortOrder: entry2.sortOrder,
|
|
120369
|
+
standardFramework: entry2.standard?.framework,
|
|
120370
|
+
standardIdentifier: entry2.standard?.identifier
|
|
120371
|
+
}).returning();
|
|
120372
|
+
if (!row) {
|
|
120373
|
+
throw new Error("Assessment association create returned no row");
|
|
120374
|
+
}
|
|
120375
|
+
results[index2] = {
|
|
120376
|
+
...base,
|
|
120377
|
+
status: "created",
|
|
120378
|
+
association: this.associationImportSummary(row),
|
|
120379
|
+
message: attachedAssessmentImportMessage(manifest.targetStatus, base.editable)
|
|
120380
|
+
};
|
|
120381
|
+
} catch (error88) {
|
|
120382
|
+
results[index2] = {
|
|
120383
|
+
...base,
|
|
120384
|
+
status: "failed",
|
|
120385
|
+
message: `Association attach failed: ${errorMessage2(error88)}`
|
|
120386
|
+
};
|
|
120387
|
+
if (isUniqueViolation(error88)) {
|
|
120388
|
+
let concurrentAssociation;
|
|
120389
|
+
try {
|
|
120390
|
+
concurrentAssociation = await this.deps.db.query.gameTimebackAssessmentTests.findFirst({
|
|
120391
|
+
where: and(eq(gameTimebackAssessmentTests.integrationId, integrationId), eq(gameTimebackAssessmentTests.qtiTestIdentifier, entry2.qtiTestIdentifier))
|
|
120392
|
+
});
|
|
120393
|
+
} catch {}
|
|
120394
|
+
if (concurrentAssociation) {
|
|
120395
|
+
const decision = classifyExistingAssessmentImport(concurrentAssociation, {
|
|
120396
|
+
purpose: entry2.purpose,
|
|
120397
|
+
...entry2.standard ? { standard: entry2.standard } : {}
|
|
120398
|
+
}, manifest.targetStatus);
|
|
120399
|
+
results[index2] = {
|
|
120400
|
+
...base,
|
|
120401
|
+
status: decision.status,
|
|
120402
|
+
association: this.associationImportSummary(concurrentAssociation),
|
|
120403
|
+
message: decision.message
|
|
120404
|
+
};
|
|
120405
|
+
}
|
|
120406
|
+
}
|
|
120407
|
+
}
|
|
120408
|
+
}
|
|
120409
|
+
setAttribute("app.assessment.operation", "bulk_attach_existing");
|
|
120410
|
+
setAttribute("app.assessment.bulk_attach.target_status", manifest.targetStatus);
|
|
120411
|
+
setAttribute("app.assessment.bulk_attach.created", results.filter((result) => result.status === "created").length);
|
|
120412
|
+
return { results };
|
|
120413
|
+
}
|
|
120151
120414
|
async updateAssessment(integrationId, qtiTestIdentifier, input) {
|
|
120152
120415
|
try {
|
|
120153
120416
|
return await this.withLockedAssessmentAssociations(integrationId, qtiTestIdentifier, async (row, tx, associations) => {
|
|
@@ -120661,6 +120924,13 @@ class TimebackAssessmentsService {
|
|
|
120661
120924
|
updatedAt: row.updatedAt
|
|
120662
120925
|
};
|
|
120663
120926
|
}
|
|
120927
|
+
associationImportSummary(row) {
|
|
120928
|
+
return {
|
|
120929
|
+
...this.associationSummary(row),
|
|
120930
|
+
createdAt: row.createdAt.toISOString(),
|
|
120931
|
+
updatedAt: row.updatedAt.toISOString()
|
|
120932
|
+
};
|
|
120933
|
+
}
|
|
120664
120934
|
canonicalAssessmentStandard(input) {
|
|
120665
120935
|
const standard = canonicalReviewStandardRef(input);
|
|
120666
120936
|
if (!standard) {
|
|
@@ -120707,6 +120977,7 @@ var init_timeback_assessments_service = __esm(async () => {
|
|
|
120707
120977
|
init_qti();
|
|
120708
120978
|
init_timeback3();
|
|
120709
120979
|
init_errors2();
|
|
120980
|
+
init_timeback_assessment_import_util();
|
|
120710
120981
|
init_timeback_assessment_rules_util();
|
|
120711
120982
|
init_timeback_qti_authoring_util();
|
|
120712
120983
|
init_timeback_qti_hydration_util();
|
|
@@ -183323,6 +183594,7 @@ var unenrollStudent;
|
|
|
183323
183594
|
var reactivateEnrollment;
|
|
183324
183595
|
var listAssessments;
|
|
183325
183596
|
var createAssessment;
|
|
183597
|
+
var attachExistingAssessments;
|
|
183326
183598
|
var updateAssessment;
|
|
183327
183599
|
var reorderAssessments;
|
|
183328
183600
|
var reorderQuestions;
|
|
@@ -183989,6 +184261,15 @@ var init_timeback_controller = __esm(() => {
|
|
|
183989
184261
|
qtiTestIdentifier
|
|
183990
184262
|
});
|
|
183991
184263
|
});
|
|
184264
|
+
attachExistingAssessments = requireDeveloper(async (ctx) => {
|
|
184265
|
+
const { gameId, courseId } = ctx.params;
|
|
184266
|
+
if (!gameId || !courseId) {
|
|
184267
|
+
throw ApiError.badRequest("Missing gameId or courseId parameter");
|
|
184268
|
+
}
|
|
184269
|
+
const manifest = await parseRequestBody(ctx.request, AttachExistingAssessmentsRequestSchema);
|
|
184270
|
+
const integrationId = await ctx.services.timebackAssessments.resolveIntegrationId(gameId, courseId, ctx.user);
|
|
184271
|
+
return ctx.services.timebackAssessments.attachExistingAssessments(integrationId, manifest);
|
|
184272
|
+
});
|
|
183992
184273
|
updateAssessment = requireDeveloper(async (ctx) => {
|
|
183993
184274
|
const { gameId, courseId, testIdentifier } = ctx.params;
|
|
183994
184275
|
if (!gameId || !courseId || !testIdentifier) {
|
|
@@ -184138,6 +184419,7 @@ var init_timeback_controller = __esm(() => {
|
|
|
184138
184419
|
reactivateEnrollment,
|
|
184139
184420
|
listAssessments,
|
|
184140
184421
|
createAssessment,
|
|
184422
|
+
attachExistingAssessments,
|
|
184141
184423
|
updateAssessment,
|
|
184142
184424
|
reorderAssessments,
|
|
184143
184425
|
removeAssessment,
|
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.22",
|
|
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.22"
|
|
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.21",
|
|
29
|
+
"@playcademy/sdk": "0.16.1-beta.21",
|
|
30
30
|
"@playcademy/types": "0.0.1",
|
|
31
31
|
"@playcademy/utils": "0.0.1",
|
|
32
32
|
"@types/archiver": "^6.0.3",
|