@lessonkit/core 1.5.0 → 1.7.0
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/README.md +1 -1
- package/dist/{chunk-KFXFQ6B2.js → chunk-DTJGIMUU.js} +216 -35
- package/dist/index.cjs +532 -60
- package/dist/index.d.cts +129 -13
- package/dist/index.d.ts +129 -13
- package/dist/index.js +308 -26
- package/dist/{testing-BFr8oEfw.d.cts → testing-CQ-ZsT7D.d.cts} +185 -5
- package/dist/{testing-BFr8oEfw.d.ts → testing-CQ-ZsT7D.d.ts} +185 -5
- package/dist/testing.cjs +2 -0
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +3 -3
- package/telemetry-catalog.v3.json +140 -0
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
tryEmitCourseStarted,
|
|
37
37
|
validateId,
|
|
38
38
|
warnDev
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-DTJGIMUU.js";
|
|
40
40
|
|
|
41
41
|
// src/assertNever.ts
|
|
42
42
|
function assertNever(value, message = "Unexpected value") {
|
|
@@ -117,7 +117,7 @@ function buildLessonkitUrn(parts) {
|
|
|
117
117
|
urn += `:block:${blockId}`;
|
|
118
118
|
}
|
|
119
119
|
if (parts.nodeId !== void 0) {
|
|
120
|
-
const nodeId = assertValidId(parts.nodeId, "
|
|
120
|
+
const nodeId = assertValidId(parts.nodeId, "nodeId");
|
|
121
121
|
if (parts.blockId === void 0) {
|
|
122
122
|
throw new Error("buildLessonkitUrn: nodeId requires blockId");
|
|
123
123
|
}
|
|
@@ -126,6 +126,69 @@ function buildLessonkitUrn(parts) {
|
|
|
126
126
|
return urn;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
// src/mcqAssessment.ts
|
|
130
|
+
function resolveMcqCorrectAnswers(props) {
|
|
131
|
+
if (props.answers && props.answers.length > 1) {
|
|
132
|
+
return new Set(props.answers.map((a) => a.trim()).filter(Boolean));
|
|
133
|
+
}
|
|
134
|
+
const single = props.answers?.[0]?.trim() ?? props.answer.trim();
|
|
135
|
+
return new Set(single ? [single] : []);
|
|
136
|
+
}
|
|
137
|
+
function isMultiSelectMcq(props) {
|
|
138
|
+
return (props.answers?.length ?? 0) > 1;
|
|
139
|
+
}
|
|
140
|
+
function scoreMcqSelection(selected, correct, multi, passingScore) {
|
|
141
|
+
const maxScore = multi ? Math.max(correct.size, 1) : 1;
|
|
142
|
+
if (!selected || Array.isArray(selected) && selected.length === 0) {
|
|
143
|
+
return {
|
|
144
|
+
score: 0,
|
|
145
|
+
maxScore,
|
|
146
|
+
exactMatch: false,
|
|
147
|
+
hasWrongSelection: false,
|
|
148
|
+
passedThreshold: false
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const selectedSet = new Set(
|
|
152
|
+
(Array.isArray(selected) ? selected : [selected]).map((s) => s.trim()).filter(Boolean)
|
|
153
|
+
);
|
|
154
|
+
let score = 0;
|
|
155
|
+
for (const label of selectedSet) {
|
|
156
|
+
if (correct.has(label)) score += 1;
|
|
157
|
+
}
|
|
158
|
+
const hasWrongSelection = [...selectedSet].some((label) => !correct.has(label));
|
|
159
|
+
const exactMatch = !hasWrongSelection && selectedSet.size === correct.size && [...correct].every((label) => selectedSet.has(label));
|
|
160
|
+
const threshold = passingScore ?? maxScore;
|
|
161
|
+
const passedThreshold = score >= threshold && !hasWrongSelection;
|
|
162
|
+
return { score, maxScore, exactMatch, hasWrongSelection, passedThreshold };
|
|
163
|
+
}
|
|
164
|
+
function hashSeedToNumber(seed) {
|
|
165
|
+
if (typeof seed === "number" && Number.isFinite(seed)) return Math.abs(Math.trunc(seed)) || 1;
|
|
166
|
+
let hash = 2166136261;
|
|
167
|
+
const text = String(seed);
|
|
168
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
169
|
+
hash ^= text.charCodeAt(i);
|
|
170
|
+
hash = Math.imul(hash, 16777619);
|
|
171
|
+
}
|
|
172
|
+
return hash >>> 0 || 1;
|
|
173
|
+
}
|
|
174
|
+
function shuffleChoiceIndices(length, seed) {
|
|
175
|
+
const indices = Array.from({ length }, (_, i) => i);
|
|
176
|
+
if (length <= 1) return indices;
|
|
177
|
+
let state = hashSeedToNumber(seed);
|
|
178
|
+
for (let i = length - 1; i > 0; i -= 1) {
|
|
179
|
+
state = Math.imul(state, 1664525) + 1013904223 >>> 0;
|
|
180
|
+
const j = state % (i + 1);
|
|
181
|
+
[indices[i], indices[j]] = [indices[j], indices[i]];
|
|
182
|
+
}
|
|
183
|
+
return indices;
|
|
184
|
+
}
|
|
185
|
+
function resolveMcqShuffleSeed(props) {
|
|
186
|
+
return props.shuffleSeed ?? props.checkId;
|
|
187
|
+
}
|
|
188
|
+
function orderChoicesByIndices(choices, orderIndices) {
|
|
189
|
+
return orderIndices.map((index) => choices[index] ?? "").filter((c) => c.length > 0);
|
|
190
|
+
}
|
|
191
|
+
|
|
129
192
|
// src/compound.ts
|
|
130
193
|
var COMPOUND_RESUME_SCHEMA_VERSION = 1;
|
|
131
194
|
function createCompoundResumeState(input = {}) {
|
|
@@ -187,9 +250,11 @@ function parseCompoundResumeState(raw, opts) {
|
|
|
187
250
|
opts?.onDroppedChildKeys?.(droppedChildKeys);
|
|
188
251
|
}
|
|
189
252
|
const activeChapterIndex = typeof obj.activeChapterIndex === "number" && Number.isFinite(obj.activeChapterIndex) ? obj.activeChapterIndex : void 0;
|
|
253
|
+
const rawPageIndex = Math.max(0, Math.floor(obj.activePageIndex));
|
|
254
|
+
const activePageIndex = typeof opts?.pageCount === "number" && opts.pageCount > 0 ? clampCompoundPageIndex(rawPageIndex, opts.pageCount) : rawPageIndex;
|
|
190
255
|
return {
|
|
191
256
|
schemaVersion: COMPOUND_RESUME_SCHEMA_VERSION,
|
|
192
|
-
activePageIndex
|
|
257
|
+
activePageIndex,
|
|
193
258
|
...activeChapterIndex !== void 0 ? { activeChapterIndex: Math.max(0, Math.floor(activeChapterIndex)) } : {},
|
|
194
259
|
childStates
|
|
195
260
|
};
|
|
@@ -229,6 +294,11 @@ function clearCompoundState(storage, courseId, compoundId) {
|
|
|
229
294
|
}
|
|
230
295
|
|
|
231
296
|
// src/compoundAllowlists.ts
|
|
297
|
+
var ASSESSMENT_17_CHILD_TYPES = [
|
|
298
|
+
"SortParagraphs",
|
|
299
|
+
"GuessTheAnswer",
|
|
300
|
+
"MultimediaChoice"
|
|
301
|
+
];
|
|
232
302
|
var PAGE_AND_SLIDE_14_BLOCKS = [
|
|
233
303
|
"Video",
|
|
234
304
|
"Summary",
|
|
@@ -273,7 +343,18 @@ var PAGE_ALLOWED_CHILD_TYPES = [
|
|
|
273
343
|
"ImageSlider",
|
|
274
344
|
"Embed",
|
|
275
345
|
"Chart",
|
|
276
|
-
"
|
|
346
|
+
"Table",
|
|
347
|
+
"ImageJuxtaposition",
|
|
348
|
+
"Timeline",
|
|
349
|
+
"ImageSequence",
|
|
350
|
+
"Collage",
|
|
351
|
+
"AudioRecorder",
|
|
352
|
+
"CombinationLock",
|
|
353
|
+
"QrContent",
|
|
354
|
+
"Crossword",
|
|
355
|
+
"AdventCalendar",
|
|
356
|
+
"ProgressTracker",
|
|
357
|
+
...ASSESSMENT_17_CHILD_TYPES
|
|
277
358
|
];
|
|
278
359
|
var BRANCH_NODE_ALLOWED_CHILD_TYPES = [
|
|
279
360
|
"Text",
|
|
@@ -307,9 +388,66 @@ var BRANCH_NODE_ALLOWED_CHILD_TYPES = [
|
|
|
307
388
|
"ImageSlider",
|
|
308
389
|
"Embed",
|
|
309
390
|
"Chart",
|
|
310
|
-
"
|
|
391
|
+
"Table",
|
|
392
|
+
"ImageJuxtaposition",
|
|
393
|
+
"Timeline",
|
|
394
|
+
"ImageSequence",
|
|
395
|
+
"Collage",
|
|
396
|
+
"AudioRecorder",
|
|
397
|
+
"CombinationLock",
|
|
398
|
+
"QrContent",
|
|
399
|
+
"Crossword",
|
|
400
|
+
"AdventCalendar",
|
|
401
|
+
"BranchChoice",
|
|
402
|
+
...ASSESSMENT_17_CHILD_TYPES
|
|
311
403
|
];
|
|
312
404
|
var BRANCHING_SCENARIO_ALLOWED_CHILD_TYPES = ["BranchNode"];
|
|
405
|
+
var GAME_MAP_ALLOWED_CHILD_TYPES = ["MapStage"];
|
|
406
|
+
var MAP_STAGE_ALLOWED_CHILD_TYPES = [
|
|
407
|
+
"Text",
|
|
408
|
+
"Heading",
|
|
409
|
+
"Image",
|
|
410
|
+
"Video",
|
|
411
|
+
"Scenario",
|
|
412
|
+
"Reflection",
|
|
413
|
+
"Quiz",
|
|
414
|
+
"KnowledgeCheck",
|
|
415
|
+
"TrueFalse",
|
|
416
|
+
"FillInTheBlanks",
|
|
417
|
+
"DragAndDrop",
|
|
418
|
+
"DragTheWords",
|
|
419
|
+
"MarkTheWords",
|
|
420
|
+
"Summary",
|
|
421
|
+
"ImagePairing",
|
|
422
|
+
"ImageSequencing",
|
|
423
|
+
"MemoryGame",
|
|
424
|
+
"InformationWall",
|
|
425
|
+
"ParallaxSlideshow",
|
|
426
|
+
"Questionnaire",
|
|
427
|
+
"Essay",
|
|
428
|
+
"ArithmeticQuiz",
|
|
429
|
+
"Accordion",
|
|
430
|
+
"DialogCards",
|
|
431
|
+
"Flashcards",
|
|
432
|
+
"ImageHotspots",
|
|
433
|
+
"FindHotspot",
|
|
434
|
+
"FindMultipleHotspots",
|
|
435
|
+
"ImageSlider",
|
|
436
|
+
"Embed",
|
|
437
|
+
"Chart",
|
|
438
|
+
"Table",
|
|
439
|
+
"ImageJuxtaposition",
|
|
440
|
+
"Timeline",
|
|
441
|
+
"ImageSequence",
|
|
442
|
+
"Collage",
|
|
443
|
+
"AudioRecorder",
|
|
444
|
+
"CombinationLock",
|
|
445
|
+
"QrContent",
|
|
446
|
+
"Crossword",
|
|
447
|
+
"AdventCalendar",
|
|
448
|
+
"MapExit",
|
|
449
|
+
...ASSESSMENT_17_CHILD_TYPES
|
|
450
|
+
];
|
|
313
451
|
var INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES = ["Page"];
|
|
314
452
|
var SLIDE_ALLOWED_CHILD_TYPES = [
|
|
315
453
|
"Text",
|
|
@@ -342,7 +480,18 @@ var SLIDE_ALLOWED_CHILD_TYPES = [
|
|
|
342
480
|
"FindMultipleHotspots",
|
|
343
481
|
"ImageSlider",
|
|
344
482
|
"Embed",
|
|
345
|
-
"Chart"
|
|
483
|
+
"Chart",
|
|
484
|
+
"Table",
|
|
485
|
+
"ImageJuxtaposition",
|
|
486
|
+
"Timeline",
|
|
487
|
+
"ImageSequence",
|
|
488
|
+
"Collage",
|
|
489
|
+
"AudioRecorder",
|
|
490
|
+
"CombinationLock",
|
|
491
|
+
"QrContent",
|
|
492
|
+
"Crossword",
|
|
493
|
+
"AdventCalendar",
|
|
494
|
+
...ASSESSMENT_17_CHILD_TYPES
|
|
346
495
|
];
|
|
347
496
|
var SLIDE_DECK_ALLOWED_CHILD_TYPES = ["Slide"];
|
|
348
497
|
var TIMED_CUE_ALLOWED_CHILD_TYPES = [
|
|
@@ -358,7 +507,9 @@ var TIMED_CUE_ALLOWED_CHILD_TYPES = [
|
|
|
358
507
|
"MemoryGame",
|
|
359
508
|
"Questionnaire",
|
|
360
509
|
"Essay",
|
|
361
|
-
"ArithmeticQuiz"
|
|
510
|
+
"ArithmeticQuiz",
|
|
511
|
+
"MultimediaChoice",
|
|
512
|
+
"GuessTheAnswer"
|
|
362
513
|
];
|
|
363
514
|
var INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES = ["TimedCue"];
|
|
364
515
|
var ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES = [
|
|
@@ -375,8 +526,10 @@ var ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES = [
|
|
|
375
526
|
"ImagePairing",
|
|
376
527
|
"ImageSequencing",
|
|
377
528
|
"ArithmeticQuiz",
|
|
378
|
-
"Essay"
|
|
529
|
+
"Essay",
|
|
530
|
+
...ASSESSMENT_17_CHILD_TYPES
|
|
379
531
|
];
|
|
532
|
+
var SINGLE_CHOICE_SET_ALLOWED_CHILD_TYPES = ["Quiz", "KnowledgeCheck"];
|
|
380
533
|
var ALLOWLISTS = {
|
|
381
534
|
Page: PAGE_ALLOWED_CHILD_TYPES,
|
|
382
535
|
InteractiveBook: INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES,
|
|
@@ -386,7 +539,10 @@ var ALLOWLISTS = {
|
|
|
386
539
|
InteractiveVideo: INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES,
|
|
387
540
|
AssessmentSequence: ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES,
|
|
388
541
|
BranchingScenario: BRANCHING_SCENARIO_ALLOWED_CHILD_TYPES,
|
|
389
|
-
BranchNode: BRANCH_NODE_ALLOWED_CHILD_TYPES
|
|
542
|
+
BranchNode: BRANCH_NODE_ALLOWED_CHILD_TYPES,
|
|
543
|
+
GameMap: GAME_MAP_ALLOWED_CHILD_TYPES,
|
|
544
|
+
MapStage: MAP_STAGE_ALLOWED_CHILD_TYPES,
|
|
545
|
+
SingleChoiceSet: SINGLE_CHOICE_SET_ALLOWED_CHILD_TYPES
|
|
390
546
|
};
|
|
391
547
|
var COMPOUND_MAX_NESTING_DEPTH = {
|
|
392
548
|
Page: 1,
|
|
@@ -397,7 +553,10 @@ var COMPOUND_MAX_NESTING_DEPTH = {
|
|
|
397
553
|
InteractiveVideo: 2,
|
|
398
554
|
AssessmentSequence: 1,
|
|
399
555
|
BranchingScenario: 2,
|
|
400
|
-
BranchNode: 1
|
|
556
|
+
BranchNode: 1,
|
|
557
|
+
GameMap: 2,
|
|
558
|
+
MapStage: 1,
|
|
559
|
+
SingleChoiceSet: 1
|
|
401
560
|
};
|
|
402
561
|
function getAllowedChildTypes(parent) {
|
|
403
562
|
return ALLOWLISTS[parent];
|
|
@@ -702,6 +861,78 @@ var TELEMETRY_EVENT_CATALOG_V3 = [
|
|
|
702
861
|
dataFields: ["blockId", "fromNodeId", "toNodeId", "label", "scoreWeight"],
|
|
703
862
|
xapiVerb: "http://adlnet.gov/expapi/verbs/answered",
|
|
704
863
|
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}:node:{toNodeId}"
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
name: "image_juxtaposition_changed",
|
|
867
|
+
description: "Learner adjusted the before/after divider",
|
|
868
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
869
|
+
dataFields: ["blockId", "position"],
|
|
870
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/interacted",
|
|
871
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
name: "timeline_event_viewed",
|
|
875
|
+
description: "Learner focused a timeline event",
|
|
876
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
877
|
+
dataFields: ["blockId", "eventId"],
|
|
878
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
879
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
name: "image_sequence_changed",
|
|
883
|
+
description: "Learner changed the image sequence frame",
|
|
884
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
885
|
+
dataFields: ["blockId", "frameIndex"],
|
|
886
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/interacted",
|
|
887
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
name: "audio_recording_started",
|
|
891
|
+
description: "Learner started an audio recording",
|
|
892
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
893
|
+
dataFields: ["blockId"],
|
|
894
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/interacted",
|
|
895
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
name: "audio_recording_completed",
|
|
899
|
+
description: "Learner completed an audio recording",
|
|
900
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
901
|
+
dataFields: ["blockId"],
|
|
902
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/completed",
|
|
903
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
name: "qr_content_revealed",
|
|
907
|
+
description: "Learner revealed QR hidden content",
|
|
908
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
909
|
+
dataFields: ["blockId"],
|
|
910
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
911
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
name: "advent_door_opened",
|
|
915
|
+
description: "Learner opened an advent calendar door",
|
|
916
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
917
|
+
dataFields: ["blockId", "doorId", "day"],
|
|
918
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/interacted",
|
|
919
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
name: "map_stage_viewed",
|
|
923
|
+
description: "Learner viewed a stage in a GameMap",
|
|
924
|
+
requiredFields: ["courseId", "lessonId", "sessionId", "timestamp"],
|
|
925
|
+
dataFields: ["blockId", "stageId", "stageIndex", "stageLabel"],
|
|
926
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
927
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}:stage:{stageId}"
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
name: "map_exit_selected",
|
|
931
|
+
description: "Learner selected a map exit in a GameMap",
|
|
932
|
+
requiredFields: ["courseId", "lessonId", "sessionId", "timestamp"],
|
|
933
|
+
dataFields: ["blockId", "fromStageId", "toStageId", "label", "scoreWeight"],
|
|
934
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/answered",
|
|
935
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}:stage:{toStageId}"
|
|
705
936
|
}
|
|
706
937
|
];
|
|
707
938
|
function buildTelemetryCatalogV3() {
|
|
@@ -798,6 +1029,10 @@ function createTrackingClient(opts) {
|
|
|
798
1029
|
const runFlush = () => {
|
|
799
1030
|
if (!buffer.length) return Promise.resolve(true);
|
|
800
1031
|
const events = buffer.splice(0, buffer.length);
|
|
1032
|
+
for (const event of events) {
|
|
1033
|
+
const key = eventDedupKey(event);
|
|
1034
|
+
if (key) pendingDeliverIds.add(key);
|
|
1035
|
+
}
|
|
801
1036
|
let succeeded = false;
|
|
802
1037
|
return Promise.resolve().then(async () => {
|
|
803
1038
|
if (batchSink) {
|
|
@@ -807,7 +1042,7 @@ function createTrackingClient(opts) {
|
|
|
807
1042
|
try {
|
|
808
1043
|
await sink?.(events[i]);
|
|
809
1044
|
} catch {
|
|
810
|
-
buffer.unshift(...events
|
|
1045
|
+
buffer.unshift(...events);
|
|
811
1046
|
return;
|
|
812
1047
|
}
|
|
813
1048
|
}
|
|
@@ -1142,6 +1377,10 @@ function resolvePluginHost(plugins) {
|
|
|
1142
1377
|
if (Array.isArray(plugins) && plugins.length > 0) return createPluginRegistry(plugins);
|
|
1143
1378
|
return null;
|
|
1144
1379
|
}
|
|
1380
|
+
function pluginListFingerprint(plugins) {
|
|
1381
|
+
if (!plugins || !Array.isArray(plugins)) return null;
|
|
1382
|
+
return plugins.map((p) => `${p.id}\0${p.version ?? ""}`).join("\n");
|
|
1383
|
+
}
|
|
1145
1384
|
function warnRuntimeV1Deprecated() {
|
|
1146
1385
|
const g = globalThis;
|
|
1147
1386
|
if (typeof g.process !== "undefined" && g.process.env?.NODE_ENV === "production") return;
|
|
@@ -1154,12 +1393,19 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1154
1393
|
const storage = ports.storage ?? createSessionStoragePort();
|
|
1155
1394
|
const clock = ports.clock ?? createDefaultClock();
|
|
1156
1395
|
const configSnapshot = { ...config };
|
|
1396
|
+
const hasExplicitSessionId = Boolean(configSnapshot.session?.sessionId?.trim());
|
|
1397
|
+
let autoSessionId;
|
|
1157
1398
|
let sessionId = resolveSessionId(storage, configSnapshot.session?.sessionId);
|
|
1399
|
+
if (!hasExplicitSessionId) {
|
|
1400
|
+
autoSessionId = sessionId;
|
|
1401
|
+
}
|
|
1158
1402
|
let attemptId = configSnapshot.session?.attemptId;
|
|
1159
1403
|
let user = configSnapshot.session?.user;
|
|
1160
1404
|
let courseId = configSnapshot.courseId;
|
|
1405
|
+
let configuredSessionId = configSnapshot.session?.sessionId;
|
|
1161
1406
|
let progress = createProgressController();
|
|
1162
1407
|
let pluginHost = resolvePluginHost(configSnapshot.plugins);
|
|
1408
|
+
let pluginFingerprint = pluginListFingerprint(configSnapshot.plugins);
|
|
1163
1409
|
let disposed = false;
|
|
1164
1410
|
const getPluginCtx = () => buildPluginContext({
|
|
1165
1411
|
courseId,
|
|
@@ -1171,12 +1417,6 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1171
1417
|
pluginHost?.setupAll(getPluginCtx());
|
|
1172
1418
|
}
|
|
1173
1419
|
const getSession = () => ({ sessionId, attemptId, user });
|
|
1174
|
-
const syncSessionFromConfig = (next) => {
|
|
1175
|
-
sessionId = resolveSessionId(storage, next.session?.sessionId);
|
|
1176
|
-
attemptId = next.session?.attemptId;
|
|
1177
|
-
user = next.session?.user;
|
|
1178
|
-
courseId = next.courseId;
|
|
1179
|
-
};
|
|
1180
1420
|
const applyPluginsToEvent = (event) => {
|
|
1181
1421
|
if (!pluginHost) return event;
|
|
1182
1422
|
return pluginHost.runTelemetry(event, getPluginCtx());
|
|
@@ -1198,7 +1438,6 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1198
1438
|
const event = buildAndApply(name, data, lessonId);
|
|
1199
1439
|
if (event) emitFn(event);
|
|
1200
1440
|
};
|
|
1201
|
-
syncSessionFromConfig(configSnapshot);
|
|
1202
1441
|
const track = (name, data, emit, lessonId) => {
|
|
1203
1442
|
if (disposed) return;
|
|
1204
1443
|
const event = buildAndApply(name, data, lessonId);
|
|
@@ -1240,21 +1479,52 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1240
1479
|
if (next.autoCompleteOnLessonSwitch !== void 0) {
|
|
1241
1480
|
configSnapshot.autoCompleteOnLessonSwitch = next.autoCompleteOnLessonSwitch;
|
|
1242
1481
|
}
|
|
1482
|
+
if (next.courseId !== void 0) {
|
|
1483
|
+
courseId = next.courseId;
|
|
1484
|
+
}
|
|
1243
1485
|
if (next.session !== void 0) {
|
|
1486
|
+
const previousSessionId = sessionId;
|
|
1244
1487
|
configSnapshot.session = { ...configSnapshot.session, ...next.session };
|
|
1488
|
+
const explicitSessionId = configSnapshot.session?.sessionId?.trim();
|
|
1489
|
+
if (explicitSessionId) {
|
|
1490
|
+
sessionId = resolveSessionId(storage, explicitSessionId);
|
|
1491
|
+
autoSessionId = void 0;
|
|
1492
|
+
} else {
|
|
1493
|
+
sessionId = autoSessionId ?? resolveSessionId(storage, void 0);
|
|
1494
|
+
if (!autoSessionId) autoSessionId = sessionId;
|
|
1495
|
+
}
|
|
1496
|
+
attemptId = configSnapshot.session?.attemptId;
|
|
1497
|
+
user = configSnapshot.session?.user;
|
|
1498
|
+
if (previousSessionId !== sessionId) {
|
|
1499
|
+
const prevExplicit = configuredSessionId?.trim();
|
|
1500
|
+
const nextExplicit = configSnapshot.session?.sessionId?.trim();
|
|
1501
|
+
const isExplicitLearnerSwap = Boolean(prevExplicit) && Boolean(nextExplicit) && prevExplicit !== nextExplicit;
|
|
1502
|
+
if (!isExplicitLearnerSwap) {
|
|
1503
|
+
migrateCourseStartedMark(storage, previousSessionId, sessionId, courseId);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
configuredSessionId = configSnapshot.session?.sessionId;
|
|
1245
1507
|
}
|
|
1246
|
-
syncSessionFromConfig(configSnapshot);
|
|
1247
1508
|
const sessionKeyAfter = JSON.stringify({ sessionId, attemptId, user });
|
|
1248
1509
|
if (next.courseId !== void 0 && next.courseId !== previousCourseId) {
|
|
1249
1510
|
progress = createProgressController();
|
|
1250
|
-
}
|
|
1251
|
-
if (next.plugins !== void 0 && next.plugins !== configSnapshot.plugins) {
|
|
1252
|
-
pluginHost?.disposeAll();
|
|
1253
|
-
configSnapshot.plugins = next.plugins;
|
|
1254
|
-
pluginHost = resolvePluginHost(configSnapshot.plugins);
|
|
1255
1511
|
if (!configSnapshot.deferPluginSetup) {
|
|
1512
|
+
pluginHost?.disposeAll();
|
|
1256
1513
|
pluginHost?.setupAll(getPluginCtx());
|
|
1257
1514
|
}
|
|
1515
|
+
}
|
|
1516
|
+
if (next.plugins !== void 0) {
|
|
1517
|
+
const nextFingerprint = pluginListFingerprint(next.plugins);
|
|
1518
|
+
const pluginsChanged = next.plugins !== configSnapshot.plugins || nextFingerprint !== null && nextFingerprint !== pluginFingerprint;
|
|
1519
|
+
if (pluginsChanged) {
|
|
1520
|
+
pluginHost?.disposeAll();
|
|
1521
|
+
configSnapshot.plugins = next.plugins;
|
|
1522
|
+
pluginFingerprint = nextFingerprint;
|
|
1523
|
+
pluginHost = resolvePluginHost(configSnapshot.plugins);
|
|
1524
|
+
if (!configSnapshot.deferPluginSetup) {
|
|
1525
|
+
pluginHost?.setupAll(getPluginCtx());
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1258
1528
|
} else if (next.session !== void 0 && sessionKeyBefore !== sessionKeyAfter && pluginHost && !configSnapshot.deferPluginSetup) {
|
|
1259
1529
|
pluginHost.disposeAll();
|
|
1260
1530
|
pluginHost.setupAll(getPluginCtx());
|
|
@@ -1309,15 +1579,17 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1309
1579
|
configSnapshot.courseId = nextCourseId;
|
|
1310
1580
|
courseId = nextCourseId;
|
|
1311
1581
|
progress = createProgressController();
|
|
1312
|
-
pluginHost?.disposeAll();
|
|
1313
1582
|
if (!configSnapshot.deferPluginSetup) {
|
|
1583
|
+
pluginHost?.disposeAll();
|
|
1314
1584
|
pluginHost?.setupAll(getPluginCtx());
|
|
1315
1585
|
}
|
|
1316
1586
|
},
|
|
1317
1587
|
dispose() {
|
|
1318
1588
|
if (disposed) return;
|
|
1319
1589
|
disposed = true;
|
|
1320
|
-
|
|
1590
|
+
if (!configSnapshot.deferPluginSetup) {
|
|
1591
|
+
pluginHost?.disposeAll();
|
|
1592
|
+
}
|
|
1321
1593
|
}
|
|
1322
1594
|
};
|
|
1323
1595
|
}
|
|
@@ -1334,18 +1606,22 @@ function defineLifecyclePlugin(plugin) {
|
|
|
1334
1606
|
}
|
|
1335
1607
|
export {
|
|
1336
1608
|
ACCORDION_FORBIDDEN_CHILD_TYPES,
|
|
1609
|
+
ASSESSMENT_17_CHILD_TYPES,
|
|
1337
1610
|
ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES,
|
|
1338
1611
|
BLOCKS_14_PAGE_SLIDE,
|
|
1339
1612
|
BRANCHING_SCENARIO_ALLOWED_CHILD_TYPES,
|
|
1340
1613
|
BRANCH_NODE_ALLOWED_CHILD_TYPES,
|
|
1341
1614
|
COMPOUND_MAX_NESTING_DEPTH,
|
|
1342
1615
|
COMPOUND_RESUME_SCHEMA_VERSION,
|
|
1616
|
+
GAME_MAP_ALLOWED_CHILD_TYPES,
|
|
1343
1617
|
ID_MAX_LENGTH,
|
|
1344
1618
|
ID_PATTERN,
|
|
1345
1619
|
INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES,
|
|
1346
1620
|
INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES,
|
|
1621
|
+
MAP_STAGE_ALLOWED_CHILD_TYPES,
|
|
1347
1622
|
PAGE_ALLOWED_CHILD_TYPES,
|
|
1348
1623
|
SESSION_STORAGE_KEY,
|
|
1624
|
+
SINGLE_CHOICE_SET_ALLOWED_CHILD_TYPES,
|
|
1349
1625
|
SLIDE_ALLOWED_CHILD_TYPES,
|
|
1350
1626
|
SLIDE_DECK_ALLOWED_CHILD_TYPES,
|
|
1351
1627
|
TELEMETRY_EVENT_CATALOG,
|
|
@@ -1390,6 +1666,7 @@ export {
|
|
|
1390
1666
|
hasCourseStartedXapiSent,
|
|
1391
1667
|
isChildTypeAllowed,
|
|
1392
1668
|
isLifecycleTelemetryEvent,
|
|
1669
|
+
isMultiSelectMcq,
|
|
1393
1670
|
loadCompoundState,
|
|
1394
1671
|
markCourseStarted,
|
|
1395
1672
|
markCourseStartedEmittedToTracking,
|
|
@@ -1397,6 +1674,7 @@ export {
|
|
|
1397
1674
|
markCourseStartedXapiSent,
|
|
1398
1675
|
migrateCourseStartedMark,
|
|
1399
1676
|
nowIso,
|
|
1677
|
+
orderChoicesByIndices,
|
|
1400
1678
|
parseBlockId,
|
|
1401
1679
|
parseCheckId,
|
|
1402
1680
|
parseCompoundResumeState,
|
|
@@ -1405,8 +1683,12 @@ export {
|
|
|
1405
1683
|
resetSharedVolatileSessionIdForTests,
|
|
1406
1684
|
resetStoragePortForTests,
|
|
1407
1685
|
resetTelemetryBuilderWarningsForTests,
|
|
1686
|
+
resolveMcqCorrectAnswers,
|
|
1687
|
+
resolveMcqShuffleSeed,
|
|
1408
1688
|
resolveSessionId,
|
|
1409
1689
|
saveCompoundState,
|
|
1690
|
+
scoreMcqSelection,
|
|
1691
|
+
shuffleChoiceIndices,
|
|
1410
1692
|
slugifyId,
|
|
1411
1693
|
telemetryCatalogV2Version,
|
|
1412
1694
|
telemetryCatalogV3Version,
|