@lessonkit/core 1.5.0 → 1.6.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-KFXFQ6B2.js → chunk-NGCHHJSM.js} +134 -12
- package/dist/index.cjs +353 -33
- package/dist/index.d.cts +94 -11
- package/dist/index.d.ts +94 -11
- package/dist/index.js +218 -22
- package/dist/{testing-BFr8oEfw.d.cts → testing-CzgxF1Ru.d.cts} +148 -2
- package/dist/{testing-BFr8oEfw.d.ts → testing-CzgxF1Ru.d.ts} +148 -2
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
- package/telemetry-catalog.v3.json +140 -0
|
@@ -21,7 +21,7 @@ declare const ID_PATTERN: RegExp;
|
|
|
21
21
|
declare const ID_MAX_LENGTH = 64;
|
|
22
22
|
|
|
23
23
|
/** H5P-aligned interaction kinds for assessment telemetry and xAPI. */
|
|
24
|
-
type AssessmentInteractionType = "mcq" | "trueFalse" | "fillInBlanks" | "markTheWords" | "dragTheWords" | "dragAndDrop" | "assessmentSequence" | "findHotspot" | "findMultipleHotspots" | "summary" | "imagePairing" | "imageSequencing" | "essay" | "arithmeticQuiz" | "memoryGame";
|
|
24
|
+
type AssessmentInteractionType = "mcq" | "trueFalse" | "fillInBlanks" | "markTheWords" | "dragTheWords" | "dragAndDrop" | "assessmentSequence" | "findHotspot" | "findMultipleHotspots" | "summary" | "imagePairing" | "imageSequencing" | "essay" | "arithmeticQuiz" | "memoryGame" | "combinationLock" | "crossword" | "wordSearch";
|
|
25
25
|
/** Serializable resume blob for a single assessment block. */
|
|
26
26
|
type AssessmentResumeState = Record<string, unknown>;
|
|
27
27
|
/** Behaviour flags aligned with H5P question types. */
|
|
@@ -65,7 +65,7 @@ type McqAssessmentProps = AssessmentBaseProps & {
|
|
|
65
65
|
answer: string;
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
type TelemetryEventName = "course_started" | "course_completed" | "lesson_started" | "lesson_completed" | "lesson_time_on_task" | "quiz_answered" | "quiz_completed" | "assessment_answered" | "assessment_completed" | "interaction" | "book_page_viewed" | "slide_viewed" | "compound_page_viewed" | "hotspot_opened" | "accordion_section_toggled" | "flashcard_flipped" | "image_slider_changed" | "video_cue_reached" | "video_segment_completed" | "memory_card_flipped" | "information_wall_search" | "parallax_slide_viewed" | "questionnaire_submitted" | "branch_node_viewed" | "branch_selected";
|
|
68
|
+
type TelemetryEventName = "course_started" | "course_completed" | "lesson_started" | "lesson_completed" | "lesson_time_on_task" | "quiz_answered" | "quiz_completed" | "assessment_answered" | "assessment_completed" | "interaction" | "book_page_viewed" | "slide_viewed" | "compound_page_viewed" | "hotspot_opened" | "accordion_section_toggled" | "flashcard_flipped" | "image_slider_changed" | "video_cue_reached" | "video_segment_completed" | "memory_card_flipped" | "information_wall_search" | "parallax_slide_viewed" | "questionnaire_submitted" | "branch_node_viewed" | "branch_selected" | "image_juxtaposition_changed" | "timeline_event_viewed" | "image_sequence_changed" | "audio_recording_started" | "audio_recording_completed" | "qr_content_revealed" | "advent_door_opened" | "map_stage_viewed" | "map_exit_selected";
|
|
69
69
|
type TelemetryUser = {
|
|
70
70
|
id?: string;
|
|
71
71
|
email?: string;
|
|
@@ -196,6 +196,42 @@ type BranchSelectedData = {
|
|
|
196
196
|
label: string;
|
|
197
197
|
scoreWeight?: number;
|
|
198
198
|
};
|
|
199
|
+
type ImageJuxtapositionChangedData = {
|
|
200
|
+
blockId: BlockId;
|
|
201
|
+
position: number;
|
|
202
|
+
};
|
|
203
|
+
type TimelineEventViewedData = {
|
|
204
|
+
blockId: BlockId;
|
|
205
|
+
eventId: string;
|
|
206
|
+
};
|
|
207
|
+
type ImageSequenceChangedData = {
|
|
208
|
+
blockId: BlockId;
|
|
209
|
+
frameIndex: number;
|
|
210
|
+
};
|
|
211
|
+
type AudioRecordingData = {
|
|
212
|
+
blockId: BlockId;
|
|
213
|
+
};
|
|
214
|
+
type QrContentRevealedData = {
|
|
215
|
+
blockId: BlockId;
|
|
216
|
+
};
|
|
217
|
+
type AdventDoorOpenedData = {
|
|
218
|
+
blockId: BlockId;
|
|
219
|
+
doorId: string;
|
|
220
|
+
day: number;
|
|
221
|
+
};
|
|
222
|
+
type MapStageViewedData = {
|
|
223
|
+
blockId: BlockId;
|
|
224
|
+
stageId: string;
|
|
225
|
+
stageIndex: number;
|
|
226
|
+
stageLabel?: string;
|
|
227
|
+
};
|
|
228
|
+
type MapExitSelectedData = {
|
|
229
|
+
blockId: BlockId;
|
|
230
|
+
fromStageId: string;
|
|
231
|
+
toStageId: string;
|
|
232
|
+
label: string;
|
|
233
|
+
scoreWeight?: number;
|
|
234
|
+
};
|
|
199
235
|
type TelemetryEvent = (TelemetryEventBase & {
|
|
200
236
|
name: "course_started";
|
|
201
237
|
lessonId?: LessonId;
|
|
@@ -296,6 +332,42 @@ type TelemetryEvent = (TelemetryEventBase & {
|
|
|
296
332
|
name: "branch_selected";
|
|
297
333
|
lessonId: LessonId;
|
|
298
334
|
data: BranchSelectedData;
|
|
335
|
+
}) | (TelemetryEventBase & {
|
|
336
|
+
name: "image_juxtaposition_changed";
|
|
337
|
+
lessonId?: LessonId;
|
|
338
|
+
data: ImageJuxtapositionChangedData;
|
|
339
|
+
}) | (TelemetryEventBase & {
|
|
340
|
+
name: "timeline_event_viewed";
|
|
341
|
+
lessonId?: LessonId;
|
|
342
|
+
data: TimelineEventViewedData;
|
|
343
|
+
}) | (TelemetryEventBase & {
|
|
344
|
+
name: "image_sequence_changed";
|
|
345
|
+
lessonId?: LessonId;
|
|
346
|
+
data: ImageSequenceChangedData;
|
|
347
|
+
}) | (TelemetryEventBase & {
|
|
348
|
+
name: "audio_recording_started";
|
|
349
|
+
lessonId?: LessonId;
|
|
350
|
+
data: AudioRecordingData;
|
|
351
|
+
}) | (TelemetryEventBase & {
|
|
352
|
+
name: "audio_recording_completed";
|
|
353
|
+
lessonId?: LessonId;
|
|
354
|
+
data: AudioRecordingData;
|
|
355
|
+
}) | (TelemetryEventBase & {
|
|
356
|
+
name: "qr_content_revealed";
|
|
357
|
+
lessonId?: LessonId;
|
|
358
|
+
data: QrContentRevealedData;
|
|
359
|
+
}) | (TelemetryEventBase & {
|
|
360
|
+
name: "advent_door_opened";
|
|
361
|
+
lessonId?: LessonId;
|
|
362
|
+
data: AdventDoorOpenedData;
|
|
363
|
+
}) | (TelemetryEventBase & {
|
|
364
|
+
name: "map_stage_viewed";
|
|
365
|
+
lessonId: LessonId;
|
|
366
|
+
data: MapStageViewedData;
|
|
367
|
+
}) | (TelemetryEventBase & {
|
|
368
|
+
name: "map_exit_selected";
|
|
369
|
+
lessonId: LessonId;
|
|
370
|
+
data: MapExitSelectedData;
|
|
299
371
|
});
|
|
300
372
|
/** Payload shape for a telemetry event name. */
|
|
301
373
|
type TelemetryDataFor<N extends TelemetryEventName> = Extract<TelemetryEvent, {
|
|
@@ -446,6 +518,42 @@ type BuildTelemetryEventInput = (BuildTelemetryEventContext & {
|
|
|
446
518
|
name: "branch_selected";
|
|
447
519
|
lessonId?: LessonId;
|
|
448
520
|
data: BranchSelectedData;
|
|
521
|
+
}) | (BuildTelemetryEventContext & {
|
|
522
|
+
name: "image_juxtaposition_changed";
|
|
523
|
+
lessonId?: LessonId;
|
|
524
|
+
data: ImageJuxtapositionChangedData;
|
|
525
|
+
}) | (BuildTelemetryEventContext & {
|
|
526
|
+
name: "timeline_event_viewed";
|
|
527
|
+
lessonId?: LessonId;
|
|
528
|
+
data: TimelineEventViewedData;
|
|
529
|
+
}) | (BuildTelemetryEventContext & {
|
|
530
|
+
name: "image_sequence_changed";
|
|
531
|
+
lessonId?: LessonId;
|
|
532
|
+
data: ImageSequenceChangedData;
|
|
533
|
+
}) | (BuildTelemetryEventContext & {
|
|
534
|
+
name: "audio_recording_started";
|
|
535
|
+
lessonId?: LessonId;
|
|
536
|
+
data: AudioRecordingData;
|
|
537
|
+
}) | (BuildTelemetryEventContext & {
|
|
538
|
+
name: "audio_recording_completed";
|
|
539
|
+
lessonId?: LessonId;
|
|
540
|
+
data: AudioRecordingData;
|
|
541
|
+
}) | (BuildTelemetryEventContext & {
|
|
542
|
+
name: "qr_content_revealed";
|
|
543
|
+
lessonId?: LessonId;
|
|
544
|
+
data: QrContentRevealedData;
|
|
545
|
+
}) | (BuildTelemetryEventContext & {
|
|
546
|
+
name: "advent_door_opened";
|
|
547
|
+
lessonId?: LessonId;
|
|
548
|
+
data: AdventDoorOpenedData;
|
|
549
|
+
}) | (BuildTelemetryEventContext & {
|
|
550
|
+
name: "map_stage_viewed";
|
|
551
|
+
lessonId?: LessonId;
|
|
552
|
+
data: MapStageViewedData;
|
|
553
|
+
}) | (BuildTelemetryEventContext & {
|
|
554
|
+
name: "map_exit_selected";
|
|
555
|
+
lessonId?: LessonId;
|
|
556
|
+
data: MapExitSelectedData;
|
|
449
557
|
});
|
|
450
558
|
|
|
451
559
|
/** Reset dev-warning state (tests only). */
|
|
@@ -453,6 +561,18 @@ declare function resetTelemetryBuilderWarningsForTests(): void;
|
|
|
453
561
|
/**
|
|
454
562
|
* Build a typed telemetry event from a catalog event name and context.
|
|
455
563
|
* Validates lesson-scoped events require `lessonId`.
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```ts
|
|
567
|
+
* import { buildTelemetryEvent } from "@lessonkit/core";
|
|
568
|
+
*
|
|
569
|
+
* const event = buildTelemetryEvent({
|
|
570
|
+
* name: "lesson_completed",
|
|
571
|
+
* courseId: "sec-101",
|
|
572
|
+
* lessonId: "phishing-101",
|
|
573
|
+
* sessionId: "tab-abc",
|
|
574
|
+
* });
|
|
575
|
+
* ```
|
|
456
576
|
*/
|
|
457
577
|
declare function buildTelemetryEvent(opts: BuildTelemetryEventInput): TelemetryEvent;
|
|
458
578
|
/**
|
|
@@ -592,12 +712,38 @@ declare function tryEmitCourseStarted(ctx: CourseLifecycleContext, deps: CourseL
|
|
|
592
712
|
}>;
|
|
593
713
|
declare function buildCourseStartedTelemetryEvent(ctx: CourseLifecycleContext): TelemetryEvent;
|
|
594
714
|
type LessonCompletionEmitter = (lessonId: LessonId, durationMs?: number) => void;
|
|
715
|
+
/**
|
|
716
|
+
* Mark a lesson complete in progress state and emit `lesson_completed` when newly completed.
|
|
717
|
+
*
|
|
718
|
+
* @example
|
|
719
|
+
* ```ts
|
|
720
|
+
* completeLessonWithTelemetry({
|
|
721
|
+
* progress,
|
|
722
|
+
* lessonId: "lesson-1",
|
|
723
|
+
* nowMs: Date.now(),
|
|
724
|
+
* emitLessonCompleted: (id, durationMs) => track("lesson_completed", { lessonId: id, durationMs }),
|
|
725
|
+
* });
|
|
726
|
+
* ```
|
|
727
|
+
*/
|
|
595
728
|
declare function completeLessonWithTelemetry(opts: {
|
|
596
729
|
progress: ProgressController;
|
|
597
730
|
lessonId: LessonId;
|
|
598
731
|
nowMs: number;
|
|
599
732
|
emitLessonCompleted: LessonCompletionEmitter;
|
|
600
733
|
}): boolean;
|
|
734
|
+
/**
|
|
735
|
+
* Complete the active lesson (if any), then mark the course complete and emit `course_completed`.
|
|
736
|
+
*
|
|
737
|
+
* @example
|
|
738
|
+
* ```ts
|
|
739
|
+
* completeCourseWithTelemetry({
|
|
740
|
+
* progress,
|
|
741
|
+
* nowMs: Date.now(),
|
|
742
|
+
* emitLessonCompleted: (id) => track("lesson_completed", { lessonId: id }),
|
|
743
|
+
* emitCourseCompleted: () => track("course_completed", {}),
|
|
744
|
+
* });
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
601
747
|
declare function completeCourseWithTelemetry(opts: {
|
|
602
748
|
progress: ProgressController;
|
|
603
749
|
nowMs: number;
|
package/dist/testing.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { aE as resetCourseStartedEmitFlightForTests, ay as resetSharedVolatileSessionIdForTests, az as resetStoragePortForTests, aA as resetTelemetryBuilderWarningsForTests } from './testing-
|
|
1
|
+
export { aE as resetCourseStartedEmitFlightForTests, ay as resetSharedVolatileSessionIdForTests, az as resetStoragePortForTests, aA as resetTelemetryBuilderWarningsForTests } from './testing-CzgxF1Ru.cjs';
|
package/dist/testing.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { aE as resetCourseStartedEmitFlightForTests, ay as resetSharedVolatileSessionIdForTests, az as resetStoragePortForTests, aA as resetTelemetryBuilderWarningsForTests } from './testing-
|
|
1
|
+
export { aE as resetCourseStartedEmitFlightForTests, ay as resetSharedVolatileSessionIdForTests, az as resetStoragePortForTests, aA as resetTelemetryBuilderWarningsForTests } from './testing-CzgxF1Ru.js';
|
package/dist/testing.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
resetSharedVolatileSessionIdForTests,
|
|
4
4
|
resetStoragePortForTests,
|
|
5
5
|
resetTelemetryBuilderWarningsForTests
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NGCHHJSM.js";
|
|
7
7
|
export {
|
|
8
8
|
resetCourseStartedEmitFlightForTests,
|
|
9
9
|
resetSharedVolatileSessionIdForTests,
|
package/package.json
CHANGED
|
@@ -249,6 +249,146 @@
|
|
|
249
249
|
],
|
|
250
250
|
"xapiVerb": "http://adlnet.gov/expapi/verbs/answered",
|
|
251
251
|
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}:node:{toNodeId}"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"name": "image_juxtaposition_changed",
|
|
255
|
+
"description": "Learner adjusted the before/after divider",
|
|
256
|
+
"requiredFields": [
|
|
257
|
+
"courseId",
|
|
258
|
+
"sessionId",
|
|
259
|
+
"timestamp"
|
|
260
|
+
],
|
|
261
|
+
"dataFields": [
|
|
262
|
+
"blockId",
|
|
263
|
+
"position"
|
|
264
|
+
],
|
|
265
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/interacted",
|
|
266
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"name": "timeline_event_viewed",
|
|
270
|
+
"description": "Learner focused a timeline event",
|
|
271
|
+
"requiredFields": [
|
|
272
|
+
"courseId",
|
|
273
|
+
"sessionId",
|
|
274
|
+
"timestamp"
|
|
275
|
+
],
|
|
276
|
+
"dataFields": [
|
|
277
|
+
"blockId",
|
|
278
|
+
"eventId"
|
|
279
|
+
],
|
|
280
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/experienced",
|
|
281
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"name": "image_sequence_changed",
|
|
285
|
+
"description": "Learner changed the image sequence frame",
|
|
286
|
+
"requiredFields": [
|
|
287
|
+
"courseId",
|
|
288
|
+
"sessionId",
|
|
289
|
+
"timestamp"
|
|
290
|
+
],
|
|
291
|
+
"dataFields": [
|
|
292
|
+
"blockId",
|
|
293
|
+
"frameIndex"
|
|
294
|
+
],
|
|
295
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/interacted",
|
|
296
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"name": "audio_recording_started",
|
|
300
|
+
"description": "Learner started an audio recording",
|
|
301
|
+
"requiredFields": [
|
|
302
|
+
"courseId",
|
|
303
|
+
"sessionId",
|
|
304
|
+
"timestamp"
|
|
305
|
+
],
|
|
306
|
+
"dataFields": [
|
|
307
|
+
"blockId"
|
|
308
|
+
],
|
|
309
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/interacted",
|
|
310
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
"name": "audio_recording_completed",
|
|
314
|
+
"description": "Learner completed an audio recording",
|
|
315
|
+
"requiredFields": [
|
|
316
|
+
"courseId",
|
|
317
|
+
"sessionId",
|
|
318
|
+
"timestamp"
|
|
319
|
+
],
|
|
320
|
+
"dataFields": [
|
|
321
|
+
"blockId"
|
|
322
|
+
],
|
|
323
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/completed",
|
|
324
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"name": "qr_content_revealed",
|
|
328
|
+
"description": "Learner revealed QR hidden content",
|
|
329
|
+
"requiredFields": [
|
|
330
|
+
"courseId",
|
|
331
|
+
"sessionId",
|
|
332
|
+
"timestamp"
|
|
333
|
+
],
|
|
334
|
+
"dataFields": [
|
|
335
|
+
"blockId"
|
|
336
|
+
],
|
|
337
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/experienced",
|
|
338
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"name": "advent_door_opened",
|
|
342
|
+
"description": "Learner opened an advent calendar door",
|
|
343
|
+
"requiredFields": [
|
|
344
|
+
"courseId",
|
|
345
|
+
"sessionId",
|
|
346
|
+
"timestamp"
|
|
347
|
+
],
|
|
348
|
+
"dataFields": [
|
|
349
|
+
"blockId",
|
|
350
|
+
"doorId",
|
|
351
|
+
"day"
|
|
352
|
+
],
|
|
353
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/interacted",
|
|
354
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}"
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
"name": "map_stage_viewed",
|
|
358
|
+
"description": "Learner viewed a stage in a GameMap",
|
|
359
|
+
"requiredFields": [
|
|
360
|
+
"courseId",
|
|
361
|
+
"lessonId",
|
|
362
|
+
"sessionId",
|
|
363
|
+
"timestamp"
|
|
364
|
+
],
|
|
365
|
+
"dataFields": [
|
|
366
|
+
"blockId",
|
|
367
|
+
"stageId",
|
|
368
|
+
"stageIndex",
|
|
369
|
+
"stageLabel"
|
|
370
|
+
],
|
|
371
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/experienced",
|
|
372
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}:stage:{stageId}"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"name": "map_exit_selected",
|
|
376
|
+
"description": "Learner selected a map exit in a GameMap",
|
|
377
|
+
"requiredFields": [
|
|
378
|
+
"courseId",
|
|
379
|
+
"lessonId",
|
|
380
|
+
"sessionId",
|
|
381
|
+
"timestamp"
|
|
382
|
+
],
|
|
383
|
+
"dataFields": [
|
|
384
|
+
"blockId",
|
|
385
|
+
"fromStageId",
|
|
386
|
+
"toStageId",
|
|
387
|
+
"label",
|
|
388
|
+
"scoreWeight"
|
|
389
|
+
],
|
|
390
|
+
"xapiVerb": "http://adlnet.gov/expapi/verbs/answered",
|
|
391
|
+
"urnPattern": "urn:lessonkit:course:{courseId}:lesson:{lessonId}:block:{blockId}:stage:{toStageId}"
|
|
252
392
|
}
|
|
253
393
|
]
|
|
254
394
|
}
|