@lessonkit/core 1.3.0 → 1.4.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/dist/chunk-PEWFPVQ6.js +628 -0
- package/dist/index.cjs +285 -36
- package/dist/index.d.cts +16 -481
- package/dist/index.d.ts +16 -481
- package/dist/index.js +216 -535
- package/dist/testing-BhVGckZ5.d.cts +569 -0
- package/dist/testing-BhVGckZ5.d.ts +569 -0
- package/dist/testing.cjs +60 -0
- package/dist/testing.d.cts +1 -0
- package/dist/testing.d.ts +1 -0
- package/dist/testing.js +12 -0
- package/package.json +9 -4
- package/telemetry-catalog.v3.json +170 -14
package/dist/index.cjs
CHANGED
|
@@ -22,11 +22,13 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
ACCORDION_FORBIDDEN_CHILD_TYPES: () => ACCORDION_FORBIDDEN_CHILD_TYPES,
|
|
24
24
|
ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES: () => ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES,
|
|
25
|
+
BLOCKS_14_PAGE_SLIDE: () => BLOCKS_14_PAGE_SLIDE,
|
|
25
26
|
COMPOUND_MAX_NESTING_DEPTH: () => COMPOUND_MAX_NESTING_DEPTH,
|
|
26
27
|
COMPOUND_RESUME_SCHEMA_VERSION: () => COMPOUND_RESUME_SCHEMA_VERSION,
|
|
27
28
|
ID_MAX_LENGTH: () => ID_MAX_LENGTH,
|
|
28
29
|
ID_PATTERN: () => ID_PATTERN,
|
|
29
30
|
INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES: () => INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES,
|
|
31
|
+
INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES: () => INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES,
|
|
30
32
|
PAGE_ALLOWED_CHILD_TYPES: () => PAGE_ALLOWED_CHILD_TYPES,
|
|
31
33
|
SESSION_STORAGE_KEY: () => SESSION_STORAGE_KEY,
|
|
32
34
|
SLIDE_ALLOWED_CHILD_TYPES: () => SLIDE_ALLOWED_CHILD_TYPES,
|
|
@@ -34,6 +36,7 @@ __export(index_exports, {
|
|
|
34
36
|
TELEMETRY_EVENT_CATALOG: () => TELEMETRY_EVENT_CATALOG,
|
|
35
37
|
TELEMETRY_EVENT_CATALOG_V2: () => TELEMETRY_EVENT_CATALOG_V2,
|
|
36
38
|
TELEMETRY_EVENT_CATALOG_V3: () => TELEMETRY_EVENT_CATALOG_V3,
|
|
39
|
+
TIMED_CUE_ALLOWED_CHILD_TYPES: () => TIMED_CUE_ALLOWED_CHILD_TYPES,
|
|
37
40
|
assertNever: () => assertNever,
|
|
38
41
|
assertValidId: () => assertValidId,
|
|
39
42
|
buildCourseStartedTelemetryEvent: () => buildCourseStartedTelemetryEvent,
|
|
@@ -322,10 +325,23 @@ function clearCompoundState(storage, courseId, compoundId) {
|
|
|
322
325
|
}
|
|
323
326
|
|
|
324
327
|
// src/compoundAllowlists.ts
|
|
328
|
+
var PAGE_AND_SLIDE_14_BLOCKS = [
|
|
329
|
+
"Video",
|
|
330
|
+
"Summary",
|
|
331
|
+
"ImagePairing",
|
|
332
|
+
"ImageSequencing",
|
|
333
|
+
"MemoryGame",
|
|
334
|
+
"InformationWall",
|
|
335
|
+
"ParallaxSlideshow",
|
|
336
|
+
"Questionnaire",
|
|
337
|
+
"Essay",
|
|
338
|
+
"ArithmeticQuiz"
|
|
339
|
+
];
|
|
325
340
|
var PAGE_ALLOWED_CHILD_TYPES = [
|
|
326
341
|
"Text",
|
|
327
342
|
"Heading",
|
|
328
343
|
"Image",
|
|
344
|
+
"Video",
|
|
329
345
|
"Scenario",
|
|
330
346
|
"Reflection",
|
|
331
347
|
"Quiz",
|
|
@@ -335,6 +351,15 @@ var PAGE_ALLOWED_CHILD_TYPES = [
|
|
|
335
351
|
"DragAndDrop",
|
|
336
352
|
"DragTheWords",
|
|
337
353
|
"MarkTheWords",
|
|
354
|
+
"Summary",
|
|
355
|
+
"ImagePairing",
|
|
356
|
+
"ImageSequencing",
|
|
357
|
+
"MemoryGame",
|
|
358
|
+
"InformationWall",
|
|
359
|
+
"ParallaxSlideshow",
|
|
360
|
+
"Questionnaire",
|
|
361
|
+
"Essay",
|
|
362
|
+
"ArithmeticQuiz",
|
|
338
363
|
"Accordion",
|
|
339
364
|
"DialogCards",
|
|
340
365
|
"Flashcards",
|
|
@@ -349,6 +374,7 @@ var SLIDE_ALLOWED_CHILD_TYPES = [
|
|
|
349
374
|
"Text",
|
|
350
375
|
"Heading",
|
|
351
376
|
"Image",
|
|
377
|
+
"Video",
|
|
352
378
|
"Scenario",
|
|
353
379
|
"Reflection",
|
|
354
380
|
"Quiz",
|
|
@@ -358,6 +384,15 @@ var SLIDE_ALLOWED_CHILD_TYPES = [
|
|
|
358
384
|
"DragAndDrop",
|
|
359
385
|
"DragTheWords",
|
|
360
386
|
"MarkTheWords",
|
|
387
|
+
"Summary",
|
|
388
|
+
"ImagePairing",
|
|
389
|
+
"ImageSequencing",
|
|
390
|
+
"MemoryGame",
|
|
391
|
+
"InformationWall",
|
|
392
|
+
"ParallaxSlideshow",
|
|
393
|
+
"Questionnaire",
|
|
394
|
+
"Essay",
|
|
395
|
+
"ArithmeticQuiz",
|
|
361
396
|
"Accordion",
|
|
362
397
|
"DialogCards",
|
|
363
398
|
"Flashcards",
|
|
@@ -367,6 +402,22 @@ var SLIDE_ALLOWED_CHILD_TYPES = [
|
|
|
367
402
|
"ImageSlider"
|
|
368
403
|
];
|
|
369
404
|
var SLIDE_DECK_ALLOWED_CHILD_TYPES = ["Slide"];
|
|
405
|
+
var TIMED_CUE_ALLOWED_CHILD_TYPES = [
|
|
406
|
+
"Text",
|
|
407
|
+
"Heading",
|
|
408
|
+
"Image",
|
|
409
|
+
"Quiz",
|
|
410
|
+
"TrueFalse",
|
|
411
|
+
"FillInTheBlanks",
|
|
412
|
+
"Summary",
|
|
413
|
+
"ImagePairing",
|
|
414
|
+
"ImageSequencing",
|
|
415
|
+
"MemoryGame",
|
|
416
|
+
"Questionnaire",
|
|
417
|
+
"Essay",
|
|
418
|
+
"ArithmeticQuiz"
|
|
419
|
+
];
|
|
420
|
+
var INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES = ["TimedCue"];
|
|
370
421
|
var ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES = [
|
|
371
422
|
"TrueFalse",
|
|
372
423
|
"FillInTheBlanks",
|
|
@@ -376,13 +427,20 @@ var ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES = [
|
|
|
376
427
|
"Quiz",
|
|
377
428
|
"KnowledgeCheck",
|
|
378
429
|
"FindHotspot",
|
|
379
|
-
"FindMultipleHotspots"
|
|
430
|
+
"FindMultipleHotspots",
|
|
431
|
+
"Summary",
|
|
432
|
+
"ImagePairing",
|
|
433
|
+
"ImageSequencing",
|
|
434
|
+
"ArithmeticQuiz",
|
|
435
|
+
"Essay"
|
|
380
436
|
];
|
|
381
437
|
var ALLOWLISTS = {
|
|
382
438
|
Page: PAGE_ALLOWED_CHILD_TYPES,
|
|
383
439
|
InteractiveBook: INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES,
|
|
384
440
|
Slide: SLIDE_ALLOWED_CHILD_TYPES,
|
|
385
441
|
SlideDeck: SLIDE_DECK_ALLOWED_CHILD_TYPES,
|
|
442
|
+
TimedCue: TIMED_CUE_ALLOWED_CHILD_TYPES,
|
|
443
|
+
InteractiveVideo: INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES,
|
|
386
444
|
AssessmentSequence: ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES
|
|
387
445
|
};
|
|
388
446
|
var COMPOUND_MAX_NESTING_DEPTH = {
|
|
@@ -390,6 +448,8 @@ var COMPOUND_MAX_NESTING_DEPTH = {
|
|
|
390
448
|
InteractiveBook: 2,
|
|
391
449
|
Slide: 1,
|
|
392
450
|
SlideDeck: 2,
|
|
451
|
+
TimedCue: 1,
|
|
452
|
+
InteractiveVideo: 2,
|
|
393
453
|
AssessmentSequence: 1
|
|
394
454
|
};
|
|
395
455
|
function getAllowedChildTypes(parent) {
|
|
@@ -399,6 +459,7 @@ function isChildTypeAllowed(parent, childType) {
|
|
|
399
459
|
return ALLOWLISTS[parent].includes(childType);
|
|
400
460
|
}
|
|
401
461
|
var ACCORDION_FORBIDDEN_CHILD_TYPES = ["Accordion"];
|
|
462
|
+
var BLOCKS_14_PAGE_SLIDE = PAGE_AND_SLIDE_14_BLOCKS;
|
|
402
463
|
|
|
403
464
|
// src/telemetryCatalog.ts
|
|
404
465
|
var telemetryCatalogVersion = 1;
|
|
@@ -554,6 +615,54 @@ var TELEMETRY_EVENT_CATALOG_V3 = [
|
|
|
554
615
|
dataFields: ["blockId", "slideIndex"],
|
|
555
616
|
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
556
617
|
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
name: "video_cue_reached",
|
|
621
|
+
description: "Learner reached a timed cue in an Interactive Video",
|
|
622
|
+
requiredFields: ["courseId", "lessonId", "sessionId", "timestamp"],
|
|
623
|
+
dataFields: ["blockId", "cueIndex", "atSeconds", "cueLabel"],
|
|
624
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
625
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
name: "video_segment_completed",
|
|
629
|
+
description: "Learner completed a timed segment in an Interactive Video",
|
|
630
|
+
requiredFields: ["courseId", "lessonId", "sessionId", "timestamp"],
|
|
631
|
+
dataFields: ["blockId", "segmentIndex", "atSeconds", "segmentLabel"],
|
|
632
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/completed",
|
|
633
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
name: "memory_card_flipped",
|
|
637
|
+
description: "Learner flipped a memory game card",
|
|
638
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
639
|
+
dataFields: ["blockId", "cardIndex", "face"],
|
|
640
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
641
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
name: "information_wall_search",
|
|
645
|
+
description: "Learner searched an information wall",
|
|
646
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
647
|
+
dataFields: ["blockId", "query", "resultCount"],
|
|
648
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
649
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
name: "parallax_slide_viewed",
|
|
653
|
+
description: "Learner viewed a slide in a parallax slideshow",
|
|
654
|
+
requiredFields: ["courseId", "sessionId", "timestamp"],
|
|
655
|
+
dataFields: ["blockId", "slideIndex"],
|
|
656
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/experienced",
|
|
657
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
658
|
+
},
|
|
659
|
+
{
|
|
660
|
+
name: "questionnaire_submitted",
|
|
661
|
+
description: "Learner submitted an unscored questionnaire",
|
|
662
|
+
requiredFields: ["courseId", "lessonId", "sessionId", "timestamp"],
|
|
663
|
+
dataFields: ["blockId", "fieldCount"],
|
|
664
|
+
xapiVerb: "http://adlnet.gov/expapi/verbs/completed",
|
|
665
|
+
urnPattern: "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
557
666
|
}
|
|
558
667
|
];
|
|
559
668
|
function buildTelemetryCatalogV3() {
|
|
@@ -561,6 +670,18 @@ function buildTelemetryCatalogV3() {
|
|
|
561
670
|
}
|
|
562
671
|
|
|
563
672
|
// src/internal/sinkInvoke.ts
|
|
673
|
+
async function invokeTrackingSinkWithResult(sink, event) {
|
|
674
|
+
try {
|
|
675
|
+
const result = sink(event);
|
|
676
|
+
if (result != null && typeof result.then === "function") {
|
|
677
|
+
await result;
|
|
678
|
+
}
|
|
679
|
+
return true;
|
|
680
|
+
} catch (err) {
|
|
681
|
+
warnDev("[lessonkit] tracking sink failed:", err);
|
|
682
|
+
return false;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
564
685
|
function invokeTrackingSink(sink, event) {
|
|
565
686
|
let result;
|
|
566
687
|
try {
|
|
@@ -607,7 +728,17 @@ function createTrackingClient(opts) {
|
|
|
607
728
|
return {
|
|
608
729
|
track: (event) => {
|
|
609
730
|
if (disposed2) return;
|
|
610
|
-
if (sink)
|
|
731
|
+
if (sink) {
|
|
732
|
+
try {
|
|
733
|
+
invokeTrackingSink(sink, event);
|
|
734
|
+
} catch {
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
deliver: async (event) => {
|
|
739
|
+
if (disposed2) return false;
|
|
740
|
+
if (!sink) return true;
|
|
741
|
+
return invokeTrackingSinkWithResult(sink, event);
|
|
611
742
|
},
|
|
612
743
|
dispose: () => {
|
|
613
744
|
disposed2 = true;
|
|
@@ -620,12 +751,14 @@ function createTrackingClient(opts) {
|
|
|
620
751
|
}
|
|
621
752
|
const buffer = [];
|
|
622
753
|
let flushInFlight = null;
|
|
754
|
+
let inflightExitBatch = null;
|
|
623
755
|
let disposed = false;
|
|
624
756
|
let disposing = false;
|
|
625
757
|
let intervalId;
|
|
626
758
|
const runFlush = () => {
|
|
627
759
|
if (!buffer.length) return Promise.resolve(true);
|
|
628
760
|
const events = buffer.splice(0, buffer.length);
|
|
761
|
+
inflightExitBatch = events;
|
|
629
762
|
let succeeded = false;
|
|
630
763
|
return Promise.resolve().then(async () => {
|
|
631
764
|
if (batchSink) {
|
|
@@ -650,6 +783,8 @@ function createTrackingClient(opts) {
|
|
|
650
783
|
return runFlush();
|
|
651
784
|
}
|
|
652
785
|
return succeeded;
|
|
786
|
+
}).finally(() => {
|
|
787
|
+
inflightExitBatch = null;
|
|
653
788
|
});
|
|
654
789
|
};
|
|
655
790
|
const flush = () => {
|
|
@@ -680,23 +815,44 @@ function createTrackingClient(opts) {
|
|
|
680
815
|
};
|
|
681
816
|
intervalId = flushIntervalMs > 0 ? globalThis.setInterval(() => void flush(), flushIntervalMs) : void 0;
|
|
682
817
|
intervalId?.unref?.();
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
);
|
|
693
|
-
}
|
|
694
|
-
return;
|
|
818
|
+
const track = (event) => {
|
|
819
|
+
if (disposed || disposing) return;
|
|
820
|
+
if (buffer.length >= maxBufferSize) {
|
|
821
|
+
opts?.onBufferDrop?.();
|
|
822
|
+
if (!warnedBufferCap && isDevEnvironment()) {
|
|
823
|
+
warnedBufferCap = true;
|
|
824
|
+
console.warn(
|
|
825
|
+
`[lessonkit] telemetry batch buffer capped at ${maxBufferSize} events; new events are dropped until the buffer drains.`
|
|
826
|
+
);
|
|
695
827
|
}
|
|
696
|
-
|
|
697
|
-
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
buffer.push(event);
|
|
831
|
+
if (buffer.length >= maxBatchSize) void flush();
|
|
832
|
+
};
|
|
833
|
+
return {
|
|
834
|
+
track,
|
|
835
|
+
deliver: async (event) => {
|
|
836
|
+
track(event);
|
|
837
|
+
return flush();
|
|
698
838
|
},
|
|
699
839
|
flush,
|
|
840
|
+
flushOnExit: opts?.exitBatchSink ? () => {
|
|
841
|
+
const fromBuffer = buffer.splice(0, buffer.length);
|
|
842
|
+
const fromInflight = inflightExitBatch ? [...inflightExitBatch] : [];
|
|
843
|
+
const events = [...fromInflight, ...fromBuffer];
|
|
844
|
+
if (!events.length) return;
|
|
845
|
+
try {
|
|
846
|
+
const result = opts.exitBatchSink(events);
|
|
847
|
+
if (result != null && typeof result.catch === "function") {
|
|
848
|
+
void result.catch(() => {
|
|
849
|
+
buffer.unshift(...events);
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
} catch {
|
|
853
|
+
buffer.unshift(...events);
|
|
854
|
+
}
|
|
855
|
+
} : void 0,
|
|
700
856
|
dispose: () => {
|
|
701
857
|
if (disposed || disposing) return Promise.resolve();
|
|
702
858
|
disposing = true;
|
|
@@ -920,6 +1076,81 @@ var TELEMETRY_EVENT_REGISTRY = {
|
|
|
920
1076
|
data: opts.data
|
|
921
1077
|
};
|
|
922
1078
|
}
|
|
1079
|
+
},
|
|
1080
|
+
video_cue_reached: {
|
|
1081
|
+
requiresLessonId: true,
|
|
1082
|
+
build: (opts, base) => {
|
|
1083
|
+
if (opts.name !== "video_cue_reached") throw new Error("unexpected event");
|
|
1084
|
+
const lessonId = opts.lessonId;
|
|
1085
|
+
if (!lessonId) throw new Error("video_cue_reached requires active lessonId");
|
|
1086
|
+
return {
|
|
1087
|
+
name: "video_cue_reached",
|
|
1088
|
+
...base,
|
|
1089
|
+
lessonId,
|
|
1090
|
+
data: opts.data
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
},
|
|
1094
|
+
video_segment_completed: {
|
|
1095
|
+
requiresLessonId: true,
|
|
1096
|
+
build: (opts, base) => {
|
|
1097
|
+
if (opts.name !== "video_segment_completed") throw new Error("unexpected event");
|
|
1098
|
+
const lessonId = opts.lessonId;
|
|
1099
|
+
if (!lessonId) throw new Error("video_segment_completed requires active lessonId");
|
|
1100
|
+
return {
|
|
1101
|
+
name: "video_segment_completed",
|
|
1102
|
+
...base,
|
|
1103
|
+
lessonId,
|
|
1104
|
+
data: opts.data
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
1108
|
+
memory_card_flipped: {
|
|
1109
|
+
build: (opts, base) => {
|
|
1110
|
+
if (opts.name !== "memory_card_flipped") throw new Error("unexpected event");
|
|
1111
|
+
return {
|
|
1112
|
+
name: "memory_card_flipped",
|
|
1113
|
+
...base,
|
|
1114
|
+
lessonId: opts.lessonId,
|
|
1115
|
+
data: opts.data
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
},
|
|
1119
|
+
information_wall_search: {
|
|
1120
|
+
build: (opts, base) => {
|
|
1121
|
+
if (opts.name !== "information_wall_search") throw new Error("unexpected event");
|
|
1122
|
+
return {
|
|
1123
|
+
name: "information_wall_search",
|
|
1124
|
+
...base,
|
|
1125
|
+
lessonId: opts.lessonId,
|
|
1126
|
+
data: opts.data
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
},
|
|
1130
|
+
parallax_slide_viewed: {
|
|
1131
|
+
build: (opts, base) => {
|
|
1132
|
+
if (opts.name !== "parallax_slide_viewed") throw new Error("unexpected event");
|
|
1133
|
+
return {
|
|
1134
|
+
name: "parallax_slide_viewed",
|
|
1135
|
+
...base,
|
|
1136
|
+
lessonId: opts.lessonId,
|
|
1137
|
+
data: opts.data
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
},
|
|
1141
|
+
questionnaire_submitted: {
|
|
1142
|
+
requiresLessonId: true,
|
|
1143
|
+
build: (opts, base) => {
|
|
1144
|
+
if (opts.name !== "questionnaire_submitted") throw new Error("unexpected event");
|
|
1145
|
+
const lessonId = opts.lessonId;
|
|
1146
|
+
if (!lessonId) throw new Error("questionnaire_submitted requires active lessonId");
|
|
1147
|
+
return {
|
|
1148
|
+
name: "questionnaire_submitted",
|
|
1149
|
+
...base,
|
|
1150
|
+
lessonId,
|
|
1151
|
+
data: opts.data
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
923
1154
|
}
|
|
924
1155
|
};
|
|
925
1156
|
function buildTelemetryEventFromRegistry(opts) {
|
|
@@ -1207,16 +1438,16 @@ function hasCourseStartedEmittedToTracking(storage, sessionId, courseId) {
|
|
|
1207
1438
|
return storage.getItem(courseStartedTrackingStorageKey(sessionId, courseId)) === "1";
|
|
1208
1439
|
}
|
|
1209
1440
|
function markCourseStartedEmittedToTracking(storage, sessionId, courseId) {
|
|
1210
|
-
if (!courseId) return;
|
|
1211
|
-
storage.setItem(courseStartedTrackingStorageKey(sessionId, courseId), "1");
|
|
1441
|
+
if (!courseId) return false;
|
|
1442
|
+
return storage.setItem(courseStartedTrackingStorageKey(sessionId, courseId), "1");
|
|
1212
1443
|
}
|
|
1213
1444
|
function hasCourseStartedPipelineDelivered(storage, sessionId, courseId) {
|
|
1214
1445
|
if (!courseId) return false;
|
|
1215
1446
|
return storage.getItem(courseStartedPipelineStorageKey(sessionId, courseId)) === "1";
|
|
1216
1447
|
}
|
|
1217
1448
|
function markCourseStartedPipelineDelivered(storage, sessionId, courseId) {
|
|
1218
|
-
if (!courseId) return;
|
|
1219
|
-
storage.setItem(courseStartedPipelineStorageKey(sessionId, courseId), "1");
|
|
1449
|
+
if (!courseId) return false;
|
|
1450
|
+
return storage.setItem(courseStartedPipelineStorageKey(sessionId, courseId), "1");
|
|
1220
1451
|
}
|
|
1221
1452
|
function resetSharedVolatileSessionIdForTests() {
|
|
1222
1453
|
sharedVolatileSessionId = null;
|
|
@@ -1238,19 +1469,29 @@ function migrateCourseStartedMark(storage, fromSessionId, toSessionId, courseId)
|
|
|
1238
1469
|
}
|
|
1239
1470
|
|
|
1240
1471
|
// src/runtime/courseLifecycle.ts
|
|
1472
|
+
var courseStartedEmitFlights = /* @__PURE__ */ new Set();
|
|
1241
1473
|
function tryEmitCourseStarted(ctx, deps, alreadyEmittedToSink) {
|
|
1474
|
+
const flightKey = `${ctx.sessionId}:${ctx.courseId}`;
|
|
1242
1475
|
const marked = hasCourseStarted(ctx.storage, ctx.sessionId, ctx.courseId);
|
|
1243
1476
|
if (alreadyEmittedToSink) {
|
|
1244
1477
|
return { emitted: true, marked };
|
|
1245
1478
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1479
|
+
if (courseStartedEmitFlights.has(flightKey)) {
|
|
1480
|
+
return { emitted: false, marked };
|
|
1481
|
+
}
|
|
1482
|
+
courseStartedEmitFlights.add(flightKey);
|
|
1483
|
+
try {
|
|
1484
|
+
const emitted = deps.emitCourseStartedEvent(ctx);
|
|
1485
|
+
if (emitted && !marked) {
|
|
1486
|
+
markCourseStarted(ctx.storage, ctx.sessionId, ctx.courseId);
|
|
1487
|
+
}
|
|
1488
|
+
return {
|
|
1489
|
+
emitted,
|
|
1490
|
+
marked: hasCourseStarted(ctx.storage, ctx.sessionId, ctx.courseId)
|
|
1491
|
+
};
|
|
1492
|
+
} finally {
|
|
1493
|
+
courseStartedEmitFlights.delete(flightKey);
|
|
1249
1494
|
}
|
|
1250
|
-
return {
|
|
1251
|
-
emitted,
|
|
1252
|
-
marked: hasCourseStarted(ctx.storage, ctx.sessionId, ctx.courseId)
|
|
1253
|
-
};
|
|
1254
1495
|
}
|
|
1255
1496
|
function buildCourseStartedTelemetryEvent(ctx) {
|
|
1256
1497
|
return buildTelemetryEvent({
|
|
@@ -1488,11 +1729,13 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1488
1729
|
if (next.courseId !== void 0 && next.courseId !== previousCourseId) {
|
|
1489
1730
|
progress = createProgressController();
|
|
1490
1731
|
}
|
|
1491
|
-
if (next.plugins !== void 0 && next.plugins !==
|
|
1732
|
+
if (next.plugins !== void 0 && next.plugins !== configSnapshot.plugins) {
|
|
1492
1733
|
pluginHost?.disposeAll();
|
|
1493
1734
|
configSnapshot.plugins = next.plugins;
|
|
1494
1735
|
pluginHost = resolvePluginHost(configSnapshot.plugins);
|
|
1495
|
-
|
|
1736
|
+
if (!configSnapshot.deferPluginSetup) {
|
|
1737
|
+
pluginHost?.setupAll(getPluginCtx());
|
|
1738
|
+
}
|
|
1496
1739
|
} else if (next.session !== void 0 && sessionKeyBefore !== sessionKeyAfter && pluginHost && !configSnapshot.deferPluginSetup) {
|
|
1497
1740
|
pluginHost.disposeAll();
|
|
1498
1741
|
pluginHost.setupAll(getPluginCtx());
|
|
@@ -1502,17 +1745,17 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1502
1745
|
const wrapped = wrapEmitFn(emitFn);
|
|
1503
1746
|
const current = progress.getState();
|
|
1504
1747
|
if (current.activeLessonId === lessonId) return;
|
|
1505
|
-
if (current.completedLessonIds.has(lessonId)) {
|
|
1506
|
-
progress.setActiveLesson(lessonId, clock.nowMs());
|
|
1507
|
-
return;
|
|
1508
|
-
}
|
|
1509
1748
|
const previous = current.activeLessonId;
|
|
1510
|
-
if (previous && previous !== lessonId) {
|
|
1749
|
+
if (previous && previous !== lessonId && !current.completedLessonIds.has(previous)) {
|
|
1511
1750
|
const completed = progress.completeLesson(previous, clock.nowMs());
|
|
1512
1751
|
if (completed.didComplete) {
|
|
1513
1752
|
emitLessonCompletedEvents(previous, completed.durationMs, wrapped);
|
|
1514
1753
|
}
|
|
1515
1754
|
}
|
|
1755
|
+
if (current.completedLessonIds.has(lessonId)) {
|
|
1756
|
+
progress.setActiveLesson(lessonId, clock.nowMs());
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1516
1759
|
progress.setActiveLesson(lessonId, clock.nowMs());
|
|
1517
1760
|
wrapped("lesson_started", { lessonId }, lessonId);
|
|
1518
1761
|
},
|
|
@@ -1533,9 +1776,12 @@ function createLessonkitRuntime(config, ports = {}) {
|
|
|
1533
1776
|
});
|
|
1534
1777
|
},
|
|
1535
1778
|
track,
|
|
1536
|
-
scoreAssessment(input,
|
|
1779
|
+
scoreAssessment(input, lessonId) {
|
|
1537
1780
|
if (!pluginHost) return null;
|
|
1538
|
-
return pluginHost.scoreAssessment(
|
|
1781
|
+
return pluginHost.scoreAssessment(
|
|
1782
|
+
{ ...input, lessonId: input.lessonId ?? lessonId },
|
|
1783
|
+
getPluginCtx()
|
|
1784
|
+
);
|
|
1539
1785
|
},
|
|
1540
1786
|
resetForCourseChange(nextCourseId) {
|
|
1541
1787
|
configSnapshot.courseId = nextCourseId;
|
|
@@ -1562,11 +1808,13 @@ function defineLifecyclePlugin(plugin) {
|
|
|
1562
1808
|
0 && (module.exports = {
|
|
1563
1809
|
ACCORDION_FORBIDDEN_CHILD_TYPES,
|
|
1564
1810
|
ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES,
|
|
1811
|
+
BLOCKS_14_PAGE_SLIDE,
|
|
1565
1812
|
COMPOUND_MAX_NESTING_DEPTH,
|
|
1566
1813
|
COMPOUND_RESUME_SCHEMA_VERSION,
|
|
1567
1814
|
ID_MAX_LENGTH,
|
|
1568
1815
|
ID_PATTERN,
|
|
1569
1816
|
INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES,
|
|
1817
|
+
INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES,
|
|
1570
1818
|
PAGE_ALLOWED_CHILD_TYPES,
|
|
1571
1819
|
SESSION_STORAGE_KEY,
|
|
1572
1820
|
SLIDE_ALLOWED_CHILD_TYPES,
|
|
@@ -1574,6 +1822,7 @@ function defineLifecyclePlugin(plugin) {
|
|
|
1574
1822
|
TELEMETRY_EVENT_CATALOG,
|
|
1575
1823
|
TELEMETRY_EVENT_CATALOG_V2,
|
|
1576
1824
|
TELEMETRY_EVENT_CATALOG_V3,
|
|
1825
|
+
TIMED_CUE_ALLOWED_CHILD_TYPES,
|
|
1577
1826
|
assertNever,
|
|
1578
1827
|
assertValidId,
|
|
1579
1828
|
buildCourseStartedTelemetryEvent,
|