@lessonkit/core 1.4.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/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { p as CourseId, E as LessonId, C as CheckId, B as BlockId, t as IdentityIdPath, v as IdentityValidationResult, N as LessonkitUrn, h as AssessmentResumeState, a0 as StoragePort, a5 as TelemetryEventName, a7 as TelemetrySink, a1 as TelemetryBatchSink, aa as TrackingClient, a3 as TelemetryEvent, a8 as TelemetryUser, J as LessonkitPlugin, U as PluginRegistry, V as ProgressController, S as PluginHost, W as ProgressState, a2 as TelemetryDataFor, i as AssessmentScoreInput, j as AssessmentScoreResult, n as ClockPort, g as AssessmentPlugin, O as LifecyclePlugin, a6 as TelemetryPlugin, K as LessonkitPluginContext } from './testing-BhVGckZ5.cjs';
2
- export { A as AccordionSectionToggledData, a as AssessmentAnsweredData, b as AssessmentBaseProps, c as AssessmentBehaviour, d as AssessmentCompletedData, e as AssessmentHandle, f as AssessmentInteractionType, k as AssessmentXAPIData, l as BookPageViewedData, m as BuildTelemetryEventInput, o as CompoundPageViewedData, q as CourseLifecycleContext, r as CourseLifecycleDeps, F as FlashcardFlippedData, H as HotspotOpenedData, I as ID_MAX_LENGTH, s as ID_PATTERN, u as IdentityValidationIssue, w as ImageSliderChangedData, x as InformationWallSearchData, y as InteractionBlockRegistration, z as InteractionData, D as InteractionPlugin, L as LessonCompletionEmitter, G as LessonLifecycleData, M as LessonkitPluginKind, P as McqAssessmentProps, Q as MemoryCardFlippedData, R as ParallaxSlideViewedData, T as PluginIdentity, X as QuestionnaireSubmittedData, Y as QuizAnsweredData, Z as QuizCompletedData, _ as SESSION_STORAGE_KEY, $ as SlideViewedData, a4 as TelemetryEventBase, a9 as TimerPort, ab as VideoCueReachedData, ac as VideoSegmentCompletedData, ad as buildCourseStartedTelemetryEvent, ae as buildTelemetryEvent, af as completeCourseWithTelemetry, ag as completeLessonWithTelemetry, ah as createDefaultClock, ai as createGlobalTimer, aj as createNoopStorage, ak as createProgressController, al as createSessionStoragePort, am as getTabSessionId, an as hasCourseStarted, ao as hasCourseStartedEmittedToTracking, ap as hasCourseStartedPipelineDelivered, aq as markCourseStarted, ar as markCourseStartedEmittedToTracking, as as markCourseStartedPipelineDelivered, at as migrateCourseStartedMark, av as resetSharedVolatileSessionIdForTests, aw as resetStoragePortForTests, ax as resetTelemetryBuilderWarningsForTests, ay as resolveSessionId, az as tryBuildTelemetryEvent, aA as tryEmitCourseStarted } from './testing-BhVGckZ5.cjs';
1
+ import { C as CourseId, L as LessonId, a as CheckId, B as BlockId, I as IdentityIdPath, b as IdentityValidationResult, c as LessonkitUrn, A as AssessmentResumeState, S as StoragePort, T as TelemetryEventName, d as TelemetrySink, e as TelemetryBatchSink, f as TrackingClient, g as TelemetryEvent, h as TelemetryUser, i as LessonkitPlugin, P as PluginRegistry, j as ProgressController, k as PluginHost, l as ProgressState, m as TelemetryDataFor, n as AssessmentScoreInput, o as AssessmentScoreResult, p as ClockPort, q as AssessmentPlugin, r as LifecyclePlugin, s as TelemetryPlugin, t as LessonkitPluginContext } from './testing-CzgxF1Ru.cjs';
2
+ export { u as AccordionSectionToggledData, v as AssessmentAnsweredData, w as AssessmentBaseProps, x as AssessmentBehaviour, y as AssessmentCompletedData, z as AssessmentHandle, D as AssessmentInteractionType, E as AssessmentXAPIData, F as BookPageViewedData, G as BranchNodeViewedData, H as BranchSelectedData, J as BuildTelemetryEventInput, K as CompoundPageViewedData, M as CourseLifecycleContext, N as CourseLifecycleDeps, O as FlashcardFlippedData, Q as HotspotOpenedData, R as ID_MAX_LENGTH, U as ID_PATTERN, V as IdentityValidationIssue, W as ImageSliderChangedData, X as InformationWallSearchData, Y as InteractionBlockRegistration, Z as InteractionData, _ as InteractionPlugin, $ as LessonCompletionEmitter, a0 as LessonLifecycleData, a1 as LessonkitPluginKind, a2 as McqAssessmentProps, a3 as MemoryCardFlippedData, a4 as ParallaxSlideViewedData, a5 as PluginIdentity, a6 as QuestionnaireSubmittedData, a7 as QuizAnsweredData, a8 as QuizCompletedData, a9 as SESSION_STORAGE_KEY, aa as SlideViewedData, ab as TelemetryEventBase, ac as TimerPort, ad as VideoCueReachedData, ae as VideoSegmentCompletedData, af as buildCourseStartedTelemetryEvent, ag as buildTelemetryEvent, ah as completeCourseWithTelemetry, ai as completeLessonWithTelemetry, aj as createDefaultClock, ak as createGlobalTimer, al as createNoopStorage, am as createProgressController, an as createSessionStoragePort, ao as getTabSessionId, ap as hasCourseStarted, aq as hasCourseStartedEmittedToTracking, ar as hasCourseStartedPipelineDelivered, as as hasCourseStartedXapiSent, at as markCourseStarted, au as markCourseStartedEmittedToTracking, av as markCourseStartedPipelineDelivered, aw as markCourseStartedXapiSent, ax as migrateCourseStartedMark, ay as resetSharedVolatileSessionIdForTests, az as resetStoragePortForTests, aA as resetTelemetryBuilderWarningsForTests, aB as resolveSessionId, aC as tryBuildTelemetryEvent, aD as tryEmitCourseStarted } from './testing-CzgxF1Ru.cjs';
3
3
 
4
4
  /**
5
5
  * Exhaustiveness helper for switch/default branches.
@@ -28,6 +28,7 @@ type LessonkitUrnParts = {
28
28
  lessonId?: LessonId;
29
29
  checkId?: CheckId;
30
30
  blockId?: BlockId;
31
+ nodeId?: string;
31
32
  };
32
33
  /**
33
34
  * Build a stable LessonKit URN for courses, lessons, checks, and blocks.
@@ -55,7 +56,12 @@ type CompoundResumeInput = {
55
56
  declare function createCompoundResumeState(input?: CompoundResumeInput): CompoundResumeState;
56
57
  /** Clamp page index to valid range for a compound with `pageCount` pages. */
57
58
  declare function clampCompoundPageIndex(index: number, pageCount: number): number;
58
- declare function parseCompoundResumeState(raw: unknown): CompoundResumeState | null;
59
+ type ParseCompoundResumeStateOptions = {
60
+ onDroppedChildKeys?: (keys: string[]) => void;
61
+ /** When set, clamps `activePageIndex` to `[0, pageCount - 1]`. */
62
+ pageCount?: number;
63
+ };
64
+ declare function parseCompoundResumeState(raw: unknown, opts?: ParseCompoundResumeStateOptions): CompoundResumeState | null;
59
65
  /**
60
66
  * Imperative handle for compound containers (H5P compound analogue).
61
67
  * Parents aggregate child AssessmentHandle scores and persist navigation state.
@@ -74,20 +80,29 @@ type CompoundBaseProps = {
74
80
  };
75
81
 
76
82
  declare function compoundStateStorageKey(courseId: CourseId, compoundId: BlockId): string;
77
- declare function loadCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId): CompoundResumeState | null;
83
+ type LoadCompoundStateOptions = ParseCompoundResumeStateOptions & {
84
+ onCorrupt?: () => void;
85
+ };
86
+ declare function loadCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId, opts?: LoadCompoundStateOptions): CompoundResumeState | null;
78
87
  declare function saveCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId, state: CompoundResumeState): boolean;
79
88
  declare function clearCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId): void;
80
89
 
81
90
  /** Canonical compound child allowlists (H5P sub-content curation). */
82
- declare const PAGE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "ProgressTracker"];
91
+ declare const PAGE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar", "ProgressTracker"];
92
+ /** Branch node content (Page-like minus ProgressTracker). */
93
+ declare const BRANCH_NODE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar", "BranchChoice"];
94
+ declare const BRANCHING_SCENARIO_ALLOWED_CHILD_TYPES: readonly ["BranchNode"];
95
+ declare const GAME_MAP_ALLOWED_CHILD_TYPES: readonly ["MapStage"];
96
+ /** Map stage content (BranchNode parity; WordSearch excluded from compounds). */
97
+ declare const MAP_STAGE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar", "MapExit"];
83
98
  declare const INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES: readonly ["Page"];
84
99
  /** Per-slide content (H5P Course Presentation slide row). Excludes ProgressTracker. */
85
- declare const SLIDE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider"];
100
+ declare const SLIDE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar"];
86
101
  declare const SLIDE_DECK_ALLOWED_CHILD_TYPES: readonly ["Slide"];
87
102
  declare const TIMED_CUE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Quiz", "TrueFalse", "FillInTheBlanks", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "Questionnaire", "Essay", "ArithmeticQuiz"];
88
103
  declare const INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES: readonly ["TimedCue"];
89
104
  declare const ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES: readonly ["TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Quiz", "KnowledgeCheck", "FindHotspot", "FindMultipleHotspots", "Summary", "ImagePairing", "ImageSequencing", "ArithmeticQuiz", "Essay"];
90
- type CompoundParentType = "Page" | "InteractiveBook" | "Slide" | "SlideDeck" | "TimedCue" | "InteractiveVideo" | "AssessmentSequence";
105
+ type CompoundParentType = "Page" | "InteractiveBook" | "Slide" | "SlideDeck" | "TimedCue" | "InteractiveVideo" | "AssessmentSequence" | "BranchingScenario" | "BranchNode" | "GameMap" | "MapStage";
91
106
  declare const COMPOUND_MAX_NESTING_DEPTH: Record<CompoundParentType, number>;
92
107
  declare function getAllowedChildTypes(parent: CompoundParentType): readonly string[];
93
108
  declare function isChildTypeAllowed(parent: CompoundParentType, childType: string): boolean;
@@ -96,6 +111,24 @@ declare const ACCORDION_FORBIDDEN_CHILD_TYPES: readonly ["Accordion"];
96
111
  /** New 1.4 blocks added to Page and Slide allowlists (for docs/tests). */
97
112
  declare const BLOCKS_14_PAGE_SLIDE: readonly ["Video", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz"];
98
113
 
114
+ type BranchGraphNodeInput = {
115
+ nodeId: string;
116
+ choices: readonly {
117
+ targetNodeId: string;
118
+ }[];
119
+ };
120
+ type BranchGraphValidationIssue = {
121
+ code: "duplicate_node_id" | "start_not_found" | "start_no_choices" | "unknown_target" | "unreachable_node" | "empty_graph";
122
+ message: string;
123
+ nodeId?: string;
124
+ };
125
+ type BranchGraphValidationResult = {
126
+ ok: boolean;
127
+ issues: BranchGraphValidationIssue[];
128
+ reachableNodeIds: string[];
129
+ };
130
+ declare function validateBranchGraph(startNodeId: string, nodes: readonly BranchGraphNodeInput[]): BranchGraphValidationResult;
131
+
99
132
  declare const telemetryCatalogVersion: 1;
100
133
  type TelemetryCatalogEntry = {
101
134
  name: TelemetryEventName;
@@ -121,7 +154,7 @@ declare const TELEMETRY_EVENT_CATALOG_V2: TelemetryCatalogV2Entry[];
121
154
  declare function buildTelemetryCatalogV2(): TelemetryCatalogV2Entry[];
122
155
 
123
156
  declare const telemetryCatalogV3Version: 3;
124
- type TelemetryCatalogV3EventName = Extract<TelemetryEventName, "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">;
157
+ type TelemetryCatalogV3EventName = Extract<TelemetryEventName, "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">;
125
158
  type TelemetryCatalogV3Entry = {
126
159
  name: TelemetryCatalogV3EventName;
127
160
  description: string;
@@ -133,6 +166,25 @@ type TelemetryCatalogV3Entry = {
133
166
  declare const TELEMETRY_EVENT_CATALOG_V3: TelemetryCatalogV3Entry[];
134
167
  declare function buildTelemetryCatalogV3(): TelemetryCatalogV3Entry[];
135
168
 
169
+ /**
170
+ * Creates a client that buffers telemetry and flushes in batches.
171
+ *
172
+ * **Delivery semantics:** batch mode is at-least-once. A failed flush re-queues the batch for
173
+ * retry; `flushOnExit` and periodic flushes may deliver the same events more than once unless
174
+ * the sink deduplicates. Events currently owned by an in-flight `batchSink` call are not included
175
+ * in `flushOnExit` to avoid duplicate delivery on page unload.
176
+ *
177
+ * @example
178
+ * ```ts
179
+ * import { createTrackingClient } from "@lessonkit/core";
180
+ *
181
+ * const tracking = createTrackingClient({
182
+ * sink: (event) => console.log(event.name, event),
183
+ * batch: { enabled: true, flushIntervalMs: 5000 },
184
+ * });
185
+ * tracking.track({ name: "course_started", courseId: "c1", sessionId: "s1" });
186
+ * ```
187
+ */
136
188
  declare function createTrackingClient(opts?: {
137
189
  sink?: TelemetrySink;
138
190
  batch?: {
@@ -165,6 +217,20 @@ type TelemetryPipeline = {
165
217
  readonly sinks: readonly TelemetryPipelineSink[];
166
218
  emit(event: TelemetryEvent, ctx?: EmitContext): void | Promise<void>;
167
219
  };
220
+ declare function isLifecycleTelemetryEvent(name: TelemetryEventName): boolean;
221
+ /**
222
+ * Compose multiple telemetry sinks behind a single `emit` call.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * import { createTelemetryPipeline, createTrackingPipelineSink } from "@lessonkit/core";
227
+ *
228
+ * const pipeline = createTelemetryPipeline([
229
+ * createTrackingPipelineSink("console", (e) => console.log(e.name)),
230
+ * ]);
231
+ * await pipeline.emit(event, { courseId: "c1", sessionId: "s1" });
232
+ * ```
233
+ */
168
234
  declare function createTelemetryPipeline(sinks: TelemetryPipelineSink[]): TelemetryPipeline;
169
235
  declare function createTrackingPipelineSink(id: string, track: (event: TelemetryEvent) => void): TelemetryPipelineSink;
170
236
 
@@ -178,6 +244,8 @@ type HeadlessLessonkitConfig = {
178
244
  attemptId?: string;
179
245
  user?: TelemetryUser;
180
246
  };
247
+ /** When true (default), switching lessons auto-completes the previous in-progress lesson. */
248
+ autoCompleteOnLessonSwitch?: boolean;
181
249
  /** Plugin list or registry; hooks run on {@link HeadlessLessonkitRuntime.track} and lifecycle emits. */
182
250
  plugins?: HeadlessLessonkitPlugins;
183
251
  /** When true, skip initial {@link PluginHost.setupAll}; host caller runs setup (React v2 provider). */
@@ -187,9 +255,8 @@ type HeadlessRuntimePorts = {
187
255
  storage?: StoragePort;
188
256
  clock?: ClockPort;
189
257
  };
190
- type TelemetryEmitFn = {
191
- <N extends TelemetryEventName>(name: N, data?: TelemetryDataFor<N>, lessonId?: LessonId): void;
192
- };
258
+ /** Delivers a fully-built lifecycle telemetry event (plugins already applied). */
259
+ type TelemetryEmitFn = (event: TelemetryEvent) => void;
193
260
  type HeadlessLessonkitRuntime = {
194
261
  readonly config: HeadlessLessonkitConfig;
195
262
  readonly progress: ProgressController;
@@ -201,6 +268,8 @@ type HeadlessLessonkitRuntime = {
201
268
  user?: TelemetryUser;
202
269
  };
203
270
  updateConfig: (next: Partial<HeadlessLessonkitConfig>) => void;
271
+ /** Move course-started dedupe marks between session ids (e.g. LMS anonymous → authenticated handoff). */
272
+ migrateSessionMarks: (fromSessionId: string, toSessionId: string) => void;
204
273
  setActiveLesson: (lessonId: LessonId, emit: TelemetryEmitFn) => void;
205
274
  completeLesson: (lessonId: LessonId, emit: TelemetryEmitFn) => void;
206
275
  completeCourse: (emit: TelemetryEmitFn) => void;
@@ -209,15 +278,73 @@ type HeadlessLessonkitRuntime = {
209
278
  resetForCourseChange: (courseId: CourseId) => void;
210
279
  dispose: () => void;
211
280
  };
281
+ /**
282
+ * Create a headless LessonKit runtime for non-React tooling and tests.
283
+ * Powers `LessonkitProvider` from `@lessonkit/react` when `runtimeVersion` is `"v2"` (default).
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * import { createLessonkitRuntime } from "@lessonkit/core";
288
+ *
289
+ * const runtime = createLessonkitRuntime({ courseId: "demo-course" });
290
+ * runtime.setActiveLesson("lesson-1");
291
+ * runtime.track("interaction", { label: "opened" }, { lessonId: "lesson-1" });
292
+ * ```
293
+ */
212
294
  declare function createLessonkitRuntime(config: HeadlessLessonkitConfig, ports?: HeadlessRuntimePorts): HeadlessLessonkitRuntime;
213
295
 
214
296
  declare function createPluginRegistry(plugins?: readonly LessonkitPlugin[]): PluginRegistry;
215
297
 
216
- /** Identity helper for telemetry plugins; does not validate or register at import time. */
298
+ /**
299
+ * Identity helper for telemetry plugins; does not validate or register at import time.
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * import { defineTelemetryPlugin } from "@lessonkit/core";
304
+ *
305
+ * const analytics = defineTelemetryPlugin({
306
+ * id: "console-analytics",
307
+ * kind: "telemetry",
308
+ * onEvent(event) {
309
+ * console.log(event.name);
310
+ * },
311
+ * });
312
+ * ```
313
+ */
217
314
  declare function defineTelemetryPlugin(plugin: TelemetryPlugin): LessonkitPlugin;
218
- /** Identity helper for assessment plugins; does not validate or register at import time. */
315
+ /**
316
+ * Identity helper for assessment plugins; does not validate or register at import time.
317
+ *
318
+ * @example
319
+ * ```ts
320
+ * import { defineAssessmentPlugin } from "@lessonkit/core";
321
+ *
322
+ * const grader = defineAssessmentPlugin({
323
+ * id: "essay-grader",
324
+ * kind: "assessment",
325
+ * score(input) {
326
+ * return { score: input.rawScore ?? 0, maxScore: 1, passed: true };
327
+ * },
328
+ * });
329
+ * ```
330
+ */
219
331
  declare function defineAssessmentPlugin(plugin: AssessmentPlugin): LessonkitPlugin;
220
- /** Identity helper for lifecycle plugins; does not validate or register at import time. */
332
+ /**
333
+ * Identity helper for lifecycle plugins; does not validate or register at import time.
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * import { defineLifecyclePlugin } from "@lessonkit/core";
338
+ *
339
+ * const onComplete = defineLifecyclePlugin({
340
+ * id: "completion-hook",
341
+ * kind: "lifecycle",
342
+ * onCourseCompleted() {
343
+ * window.parent.postMessage({ type: "course-done" }, "*");
344
+ * },
345
+ * });
346
+ * ```
347
+ */
221
348
  declare function defineLifecyclePlugin(plugin: LifecyclePlugin): LessonkitPlugin;
222
349
 
223
350
  declare function buildPluginContext(opts: {
@@ -227,4 +354,4 @@ declare function buildPluginContext(opts: {
227
354
  user?: TelemetryUser;
228
355
  }): LessonkitPluginContext;
229
356
 
230
- export { ACCORDION_FORBIDDEN_CHILD_TYPES, ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES, AssessmentPlugin, AssessmentResumeState, AssessmentScoreInput, AssessmentScoreResult, BLOCKS_14_PAGE_SLIDE, BlockId, COMPOUND_MAX_NESTING_DEPTH, COMPOUND_RESUME_SCHEMA_VERSION, CheckId, ClockPort, type CompoundBaseProps, type CompoundHandle, type CompoundParentType, type CompoundResumeInput, type CompoundResumeState, CourseId, type EmitContext, type HeadlessLessonkitConfig, type HeadlessLessonkitRuntime, type HeadlessRuntimePorts, INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES, INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES, IdentityIdPath, IdentityValidationResult, LessonId, LessonkitPlugin, LessonkitPluginContext, type LessonkitRuntimeVersion, LessonkitUrn, type LessonkitUrnParts, LifecyclePlugin, type LmsBridgeMode, PAGE_ALLOWED_CHILD_TYPES, PluginHost, PluginRegistry, ProgressController, ProgressState, SLIDE_ALLOWED_CHILD_TYPES, SLIDE_DECK_ALLOWED_CHILD_TYPES, StoragePort, TELEMETRY_EVENT_CATALOG, TELEMETRY_EVENT_CATALOG_V2, TELEMETRY_EVENT_CATALOG_V3, TIMED_CUE_ALLOWED_CHILD_TYPES, TelemetryBatchSink, type TelemetryCatalogEntry, type TelemetryCatalogV2Entry, type TelemetryCatalogV3Entry, TelemetryDataFor, type TelemetryEmitFn, TelemetryEvent, TelemetryEventName, type TelemetryPipeline, type TelemetryPipelineSink, TelemetryPlugin, TelemetrySink, TelemetryUser, TrackingClient, assertNever, assertValidId, buildLessonkitUrn, buildPluginContext, buildTelemetryCatalog, buildTelemetryCatalogV2, buildTelemetryCatalogV3, clampCompoundPageIndex, clearCompoundState, compoundStateStorageKey, createCompoundResumeState, createLessonkitRuntime, createPluginRegistry, createSessionId, createTelemetryPipeline, createTrackingClient, createTrackingPipelineSink, defineAssessmentPlugin, defineLifecyclePlugin, defineTelemetryPlugin, deriveId, getAllowedChildTypes, isChildTypeAllowed, loadCompoundState, nowIso, parseBlockId, parseCheckId, parseCompoundResumeState, parseCourseId, parseLessonId, saveCompoundState, slugifyId, telemetryCatalogV2Version, telemetryCatalogV3Version, telemetryCatalogVersion, validateId };
357
+ export { ACCORDION_FORBIDDEN_CHILD_TYPES, ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES, AssessmentPlugin, AssessmentResumeState, AssessmentScoreInput, AssessmentScoreResult, BLOCKS_14_PAGE_SLIDE, BRANCHING_SCENARIO_ALLOWED_CHILD_TYPES, BRANCH_NODE_ALLOWED_CHILD_TYPES, BlockId, type BranchGraphNodeInput, type BranchGraphValidationIssue, type BranchGraphValidationResult, COMPOUND_MAX_NESTING_DEPTH, COMPOUND_RESUME_SCHEMA_VERSION, CheckId, ClockPort, type CompoundBaseProps, type CompoundHandle, type CompoundParentType, type CompoundResumeInput, type CompoundResumeState, CourseId, type EmitContext, GAME_MAP_ALLOWED_CHILD_TYPES, type HeadlessLessonkitConfig, type HeadlessLessonkitRuntime, type HeadlessRuntimePorts, INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES, INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES, IdentityIdPath, IdentityValidationResult, LessonId, LessonkitPlugin, LessonkitPluginContext, type LessonkitRuntimeVersion, LessonkitUrn, type LessonkitUrnParts, LifecyclePlugin, type LmsBridgeMode, type LoadCompoundStateOptions, MAP_STAGE_ALLOWED_CHILD_TYPES, PAGE_ALLOWED_CHILD_TYPES, type ParseCompoundResumeStateOptions, PluginHost, PluginRegistry, ProgressController, ProgressState, SLIDE_ALLOWED_CHILD_TYPES, SLIDE_DECK_ALLOWED_CHILD_TYPES, StoragePort, TELEMETRY_EVENT_CATALOG, TELEMETRY_EVENT_CATALOG_V2, TELEMETRY_EVENT_CATALOG_V3, TIMED_CUE_ALLOWED_CHILD_TYPES, TelemetryBatchSink, type TelemetryCatalogEntry, type TelemetryCatalogV2Entry, type TelemetryCatalogV3Entry, TelemetryDataFor, type TelemetryEmitFn, TelemetryEvent, TelemetryEventName, type TelemetryPipeline, type TelemetryPipelineSink, TelemetryPlugin, TelemetrySink, TelemetryUser, TrackingClient, assertNever, assertValidId, buildLessonkitUrn, buildPluginContext, buildTelemetryCatalog, buildTelemetryCatalogV2, buildTelemetryCatalogV3, clampCompoundPageIndex, clearCompoundState, compoundStateStorageKey, createCompoundResumeState, createLessonkitRuntime, createPluginRegistry, createSessionId, createTelemetryPipeline, createTrackingClient, createTrackingPipelineSink, defineAssessmentPlugin, defineLifecyclePlugin, defineTelemetryPlugin, deriveId, getAllowedChildTypes, isChildTypeAllowed, isLifecycleTelemetryEvent, loadCompoundState, nowIso, parseBlockId, parseCheckId, parseCompoundResumeState, parseCourseId, parseLessonId, saveCompoundState, slugifyId, telemetryCatalogV2Version, telemetryCatalogV3Version, telemetryCatalogVersion, validateBranchGraph, validateId };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { p as CourseId, E as LessonId, C as CheckId, B as BlockId, t as IdentityIdPath, v as IdentityValidationResult, N as LessonkitUrn, h as AssessmentResumeState, a0 as StoragePort, a5 as TelemetryEventName, a7 as TelemetrySink, a1 as TelemetryBatchSink, aa as TrackingClient, a3 as TelemetryEvent, a8 as TelemetryUser, J as LessonkitPlugin, U as PluginRegistry, V as ProgressController, S as PluginHost, W as ProgressState, a2 as TelemetryDataFor, i as AssessmentScoreInput, j as AssessmentScoreResult, n as ClockPort, g as AssessmentPlugin, O as LifecyclePlugin, a6 as TelemetryPlugin, K as LessonkitPluginContext } from './testing-BhVGckZ5.js';
2
- export { A as AccordionSectionToggledData, a as AssessmentAnsweredData, b as AssessmentBaseProps, c as AssessmentBehaviour, d as AssessmentCompletedData, e as AssessmentHandle, f as AssessmentInteractionType, k as AssessmentXAPIData, l as BookPageViewedData, m as BuildTelemetryEventInput, o as CompoundPageViewedData, q as CourseLifecycleContext, r as CourseLifecycleDeps, F as FlashcardFlippedData, H as HotspotOpenedData, I as ID_MAX_LENGTH, s as ID_PATTERN, u as IdentityValidationIssue, w as ImageSliderChangedData, x as InformationWallSearchData, y as InteractionBlockRegistration, z as InteractionData, D as InteractionPlugin, L as LessonCompletionEmitter, G as LessonLifecycleData, M as LessonkitPluginKind, P as McqAssessmentProps, Q as MemoryCardFlippedData, R as ParallaxSlideViewedData, T as PluginIdentity, X as QuestionnaireSubmittedData, Y as QuizAnsweredData, Z as QuizCompletedData, _ as SESSION_STORAGE_KEY, $ as SlideViewedData, a4 as TelemetryEventBase, a9 as TimerPort, ab as VideoCueReachedData, ac as VideoSegmentCompletedData, ad as buildCourseStartedTelemetryEvent, ae as buildTelemetryEvent, af as completeCourseWithTelemetry, ag as completeLessonWithTelemetry, ah as createDefaultClock, ai as createGlobalTimer, aj as createNoopStorage, ak as createProgressController, al as createSessionStoragePort, am as getTabSessionId, an as hasCourseStarted, ao as hasCourseStartedEmittedToTracking, ap as hasCourseStartedPipelineDelivered, aq as markCourseStarted, ar as markCourseStartedEmittedToTracking, as as markCourseStartedPipelineDelivered, at as migrateCourseStartedMark, av as resetSharedVolatileSessionIdForTests, aw as resetStoragePortForTests, ax as resetTelemetryBuilderWarningsForTests, ay as resolveSessionId, az as tryBuildTelemetryEvent, aA as tryEmitCourseStarted } from './testing-BhVGckZ5.js';
1
+ import { C as CourseId, L as LessonId, a as CheckId, B as BlockId, I as IdentityIdPath, b as IdentityValidationResult, c as LessonkitUrn, A as AssessmentResumeState, S as StoragePort, T as TelemetryEventName, d as TelemetrySink, e as TelemetryBatchSink, f as TrackingClient, g as TelemetryEvent, h as TelemetryUser, i as LessonkitPlugin, P as PluginRegistry, j as ProgressController, k as PluginHost, l as ProgressState, m as TelemetryDataFor, n as AssessmentScoreInput, o as AssessmentScoreResult, p as ClockPort, q as AssessmentPlugin, r as LifecyclePlugin, s as TelemetryPlugin, t as LessonkitPluginContext } from './testing-CzgxF1Ru.js';
2
+ export { u as AccordionSectionToggledData, v as AssessmentAnsweredData, w as AssessmentBaseProps, x as AssessmentBehaviour, y as AssessmentCompletedData, z as AssessmentHandle, D as AssessmentInteractionType, E as AssessmentXAPIData, F as BookPageViewedData, G as BranchNodeViewedData, H as BranchSelectedData, J as BuildTelemetryEventInput, K as CompoundPageViewedData, M as CourseLifecycleContext, N as CourseLifecycleDeps, O as FlashcardFlippedData, Q as HotspotOpenedData, R as ID_MAX_LENGTH, U as ID_PATTERN, V as IdentityValidationIssue, W as ImageSliderChangedData, X as InformationWallSearchData, Y as InteractionBlockRegistration, Z as InteractionData, _ as InteractionPlugin, $ as LessonCompletionEmitter, a0 as LessonLifecycleData, a1 as LessonkitPluginKind, a2 as McqAssessmentProps, a3 as MemoryCardFlippedData, a4 as ParallaxSlideViewedData, a5 as PluginIdentity, a6 as QuestionnaireSubmittedData, a7 as QuizAnsweredData, a8 as QuizCompletedData, a9 as SESSION_STORAGE_KEY, aa as SlideViewedData, ab as TelemetryEventBase, ac as TimerPort, ad as VideoCueReachedData, ae as VideoSegmentCompletedData, af as buildCourseStartedTelemetryEvent, ag as buildTelemetryEvent, ah as completeCourseWithTelemetry, ai as completeLessonWithTelemetry, aj as createDefaultClock, ak as createGlobalTimer, al as createNoopStorage, am as createProgressController, an as createSessionStoragePort, ao as getTabSessionId, ap as hasCourseStarted, aq as hasCourseStartedEmittedToTracking, ar as hasCourseStartedPipelineDelivered, as as hasCourseStartedXapiSent, at as markCourseStarted, au as markCourseStartedEmittedToTracking, av as markCourseStartedPipelineDelivered, aw as markCourseStartedXapiSent, ax as migrateCourseStartedMark, ay as resetSharedVolatileSessionIdForTests, az as resetStoragePortForTests, aA as resetTelemetryBuilderWarningsForTests, aB as resolveSessionId, aC as tryBuildTelemetryEvent, aD as tryEmitCourseStarted } from './testing-CzgxF1Ru.js';
3
3
 
4
4
  /**
5
5
  * Exhaustiveness helper for switch/default branches.
@@ -28,6 +28,7 @@ type LessonkitUrnParts = {
28
28
  lessonId?: LessonId;
29
29
  checkId?: CheckId;
30
30
  blockId?: BlockId;
31
+ nodeId?: string;
31
32
  };
32
33
  /**
33
34
  * Build a stable LessonKit URN for courses, lessons, checks, and blocks.
@@ -55,7 +56,12 @@ type CompoundResumeInput = {
55
56
  declare function createCompoundResumeState(input?: CompoundResumeInput): CompoundResumeState;
56
57
  /** Clamp page index to valid range for a compound with `pageCount` pages. */
57
58
  declare function clampCompoundPageIndex(index: number, pageCount: number): number;
58
- declare function parseCompoundResumeState(raw: unknown): CompoundResumeState | null;
59
+ type ParseCompoundResumeStateOptions = {
60
+ onDroppedChildKeys?: (keys: string[]) => void;
61
+ /** When set, clamps `activePageIndex` to `[0, pageCount - 1]`. */
62
+ pageCount?: number;
63
+ };
64
+ declare function parseCompoundResumeState(raw: unknown, opts?: ParseCompoundResumeStateOptions): CompoundResumeState | null;
59
65
  /**
60
66
  * Imperative handle for compound containers (H5P compound analogue).
61
67
  * Parents aggregate child AssessmentHandle scores and persist navigation state.
@@ -74,20 +80,29 @@ type CompoundBaseProps = {
74
80
  };
75
81
 
76
82
  declare function compoundStateStorageKey(courseId: CourseId, compoundId: BlockId): string;
77
- declare function loadCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId): CompoundResumeState | null;
83
+ type LoadCompoundStateOptions = ParseCompoundResumeStateOptions & {
84
+ onCorrupt?: () => void;
85
+ };
86
+ declare function loadCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId, opts?: LoadCompoundStateOptions): CompoundResumeState | null;
78
87
  declare function saveCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId, state: CompoundResumeState): boolean;
79
88
  declare function clearCompoundState(storage: StoragePort, courseId: CourseId, compoundId: BlockId): void;
80
89
 
81
90
  /** Canonical compound child allowlists (H5P sub-content curation). */
82
- declare const PAGE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "ProgressTracker"];
91
+ declare const PAGE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar", "ProgressTracker"];
92
+ /** Branch node content (Page-like minus ProgressTracker). */
93
+ declare const BRANCH_NODE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar", "BranchChoice"];
94
+ declare const BRANCHING_SCENARIO_ALLOWED_CHILD_TYPES: readonly ["BranchNode"];
95
+ declare const GAME_MAP_ALLOWED_CHILD_TYPES: readonly ["MapStage"];
96
+ /** Map stage content (BranchNode parity; WordSearch excluded from compounds). */
97
+ declare const MAP_STAGE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar", "MapExit"];
83
98
  declare const INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES: readonly ["Page"];
84
99
  /** Per-slide content (H5P Course Presentation slide row). Excludes ProgressTracker. */
85
- declare const SLIDE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider"];
100
+ declare const SLIDE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Video", "Scenario", "Reflection", "Quiz", "KnowledgeCheck", "TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz", "Accordion", "DialogCards", "Flashcards", "ImageHotspots", "FindHotspot", "FindMultipleHotspots", "ImageSlider", "Embed", "Chart", "Table", "ImageJuxtaposition", "Timeline", "ImageSequence", "Collage", "AudioRecorder", "CombinationLock", "QrContent", "Crossword", "AdventCalendar"];
86
101
  declare const SLIDE_DECK_ALLOWED_CHILD_TYPES: readonly ["Slide"];
87
102
  declare const TIMED_CUE_ALLOWED_CHILD_TYPES: readonly ["Text", "Heading", "Image", "Quiz", "TrueFalse", "FillInTheBlanks", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "Questionnaire", "Essay", "ArithmeticQuiz"];
88
103
  declare const INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES: readonly ["TimedCue"];
89
104
  declare const ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES: readonly ["TrueFalse", "FillInTheBlanks", "DragAndDrop", "DragTheWords", "MarkTheWords", "Quiz", "KnowledgeCheck", "FindHotspot", "FindMultipleHotspots", "Summary", "ImagePairing", "ImageSequencing", "ArithmeticQuiz", "Essay"];
90
- type CompoundParentType = "Page" | "InteractiveBook" | "Slide" | "SlideDeck" | "TimedCue" | "InteractiveVideo" | "AssessmentSequence";
105
+ type CompoundParentType = "Page" | "InteractiveBook" | "Slide" | "SlideDeck" | "TimedCue" | "InteractiveVideo" | "AssessmentSequence" | "BranchingScenario" | "BranchNode" | "GameMap" | "MapStage";
91
106
  declare const COMPOUND_MAX_NESTING_DEPTH: Record<CompoundParentType, number>;
92
107
  declare function getAllowedChildTypes(parent: CompoundParentType): readonly string[];
93
108
  declare function isChildTypeAllowed(parent: CompoundParentType, childType: string): boolean;
@@ -96,6 +111,24 @@ declare const ACCORDION_FORBIDDEN_CHILD_TYPES: readonly ["Accordion"];
96
111
  /** New 1.4 blocks added to Page and Slide allowlists (for docs/tests). */
97
112
  declare const BLOCKS_14_PAGE_SLIDE: readonly ["Video", "Summary", "ImagePairing", "ImageSequencing", "MemoryGame", "InformationWall", "ParallaxSlideshow", "Questionnaire", "Essay", "ArithmeticQuiz"];
98
113
 
114
+ type BranchGraphNodeInput = {
115
+ nodeId: string;
116
+ choices: readonly {
117
+ targetNodeId: string;
118
+ }[];
119
+ };
120
+ type BranchGraphValidationIssue = {
121
+ code: "duplicate_node_id" | "start_not_found" | "start_no_choices" | "unknown_target" | "unreachable_node" | "empty_graph";
122
+ message: string;
123
+ nodeId?: string;
124
+ };
125
+ type BranchGraphValidationResult = {
126
+ ok: boolean;
127
+ issues: BranchGraphValidationIssue[];
128
+ reachableNodeIds: string[];
129
+ };
130
+ declare function validateBranchGraph(startNodeId: string, nodes: readonly BranchGraphNodeInput[]): BranchGraphValidationResult;
131
+
99
132
  declare const telemetryCatalogVersion: 1;
100
133
  type TelemetryCatalogEntry = {
101
134
  name: TelemetryEventName;
@@ -121,7 +154,7 @@ declare const TELEMETRY_EVENT_CATALOG_V2: TelemetryCatalogV2Entry[];
121
154
  declare function buildTelemetryCatalogV2(): TelemetryCatalogV2Entry[];
122
155
 
123
156
  declare const telemetryCatalogV3Version: 3;
124
- type TelemetryCatalogV3EventName = Extract<TelemetryEventName, "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">;
157
+ type TelemetryCatalogV3EventName = Extract<TelemetryEventName, "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">;
125
158
  type TelemetryCatalogV3Entry = {
126
159
  name: TelemetryCatalogV3EventName;
127
160
  description: string;
@@ -133,6 +166,25 @@ type TelemetryCatalogV3Entry = {
133
166
  declare const TELEMETRY_EVENT_CATALOG_V3: TelemetryCatalogV3Entry[];
134
167
  declare function buildTelemetryCatalogV3(): TelemetryCatalogV3Entry[];
135
168
 
169
+ /**
170
+ * Creates a client that buffers telemetry and flushes in batches.
171
+ *
172
+ * **Delivery semantics:** batch mode is at-least-once. A failed flush re-queues the batch for
173
+ * retry; `flushOnExit` and periodic flushes may deliver the same events more than once unless
174
+ * the sink deduplicates. Events currently owned by an in-flight `batchSink` call are not included
175
+ * in `flushOnExit` to avoid duplicate delivery on page unload.
176
+ *
177
+ * @example
178
+ * ```ts
179
+ * import { createTrackingClient } from "@lessonkit/core";
180
+ *
181
+ * const tracking = createTrackingClient({
182
+ * sink: (event) => console.log(event.name, event),
183
+ * batch: { enabled: true, flushIntervalMs: 5000 },
184
+ * });
185
+ * tracking.track({ name: "course_started", courseId: "c1", sessionId: "s1" });
186
+ * ```
187
+ */
136
188
  declare function createTrackingClient(opts?: {
137
189
  sink?: TelemetrySink;
138
190
  batch?: {
@@ -165,6 +217,20 @@ type TelemetryPipeline = {
165
217
  readonly sinks: readonly TelemetryPipelineSink[];
166
218
  emit(event: TelemetryEvent, ctx?: EmitContext): void | Promise<void>;
167
219
  };
220
+ declare function isLifecycleTelemetryEvent(name: TelemetryEventName): boolean;
221
+ /**
222
+ * Compose multiple telemetry sinks behind a single `emit` call.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * import { createTelemetryPipeline, createTrackingPipelineSink } from "@lessonkit/core";
227
+ *
228
+ * const pipeline = createTelemetryPipeline([
229
+ * createTrackingPipelineSink("console", (e) => console.log(e.name)),
230
+ * ]);
231
+ * await pipeline.emit(event, { courseId: "c1", sessionId: "s1" });
232
+ * ```
233
+ */
168
234
  declare function createTelemetryPipeline(sinks: TelemetryPipelineSink[]): TelemetryPipeline;
169
235
  declare function createTrackingPipelineSink(id: string, track: (event: TelemetryEvent) => void): TelemetryPipelineSink;
170
236
 
@@ -178,6 +244,8 @@ type HeadlessLessonkitConfig = {
178
244
  attemptId?: string;
179
245
  user?: TelemetryUser;
180
246
  };
247
+ /** When true (default), switching lessons auto-completes the previous in-progress lesson. */
248
+ autoCompleteOnLessonSwitch?: boolean;
181
249
  /** Plugin list or registry; hooks run on {@link HeadlessLessonkitRuntime.track} and lifecycle emits. */
182
250
  plugins?: HeadlessLessonkitPlugins;
183
251
  /** When true, skip initial {@link PluginHost.setupAll}; host caller runs setup (React v2 provider). */
@@ -187,9 +255,8 @@ type HeadlessRuntimePorts = {
187
255
  storage?: StoragePort;
188
256
  clock?: ClockPort;
189
257
  };
190
- type TelemetryEmitFn = {
191
- <N extends TelemetryEventName>(name: N, data?: TelemetryDataFor<N>, lessonId?: LessonId): void;
192
- };
258
+ /** Delivers a fully-built lifecycle telemetry event (plugins already applied). */
259
+ type TelemetryEmitFn = (event: TelemetryEvent) => void;
193
260
  type HeadlessLessonkitRuntime = {
194
261
  readonly config: HeadlessLessonkitConfig;
195
262
  readonly progress: ProgressController;
@@ -201,6 +268,8 @@ type HeadlessLessonkitRuntime = {
201
268
  user?: TelemetryUser;
202
269
  };
203
270
  updateConfig: (next: Partial<HeadlessLessonkitConfig>) => void;
271
+ /** Move course-started dedupe marks between session ids (e.g. LMS anonymous → authenticated handoff). */
272
+ migrateSessionMarks: (fromSessionId: string, toSessionId: string) => void;
204
273
  setActiveLesson: (lessonId: LessonId, emit: TelemetryEmitFn) => void;
205
274
  completeLesson: (lessonId: LessonId, emit: TelemetryEmitFn) => void;
206
275
  completeCourse: (emit: TelemetryEmitFn) => void;
@@ -209,15 +278,73 @@ type HeadlessLessonkitRuntime = {
209
278
  resetForCourseChange: (courseId: CourseId) => void;
210
279
  dispose: () => void;
211
280
  };
281
+ /**
282
+ * Create a headless LessonKit runtime for non-React tooling and tests.
283
+ * Powers `LessonkitProvider` from `@lessonkit/react` when `runtimeVersion` is `"v2"` (default).
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * import { createLessonkitRuntime } from "@lessonkit/core";
288
+ *
289
+ * const runtime = createLessonkitRuntime({ courseId: "demo-course" });
290
+ * runtime.setActiveLesson("lesson-1");
291
+ * runtime.track("interaction", { label: "opened" }, { lessonId: "lesson-1" });
292
+ * ```
293
+ */
212
294
  declare function createLessonkitRuntime(config: HeadlessLessonkitConfig, ports?: HeadlessRuntimePorts): HeadlessLessonkitRuntime;
213
295
 
214
296
  declare function createPluginRegistry(plugins?: readonly LessonkitPlugin[]): PluginRegistry;
215
297
 
216
- /** Identity helper for telemetry plugins; does not validate or register at import time. */
298
+ /**
299
+ * Identity helper for telemetry plugins; does not validate or register at import time.
300
+ *
301
+ * @example
302
+ * ```ts
303
+ * import { defineTelemetryPlugin } from "@lessonkit/core";
304
+ *
305
+ * const analytics = defineTelemetryPlugin({
306
+ * id: "console-analytics",
307
+ * kind: "telemetry",
308
+ * onEvent(event) {
309
+ * console.log(event.name);
310
+ * },
311
+ * });
312
+ * ```
313
+ */
217
314
  declare function defineTelemetryPlugin(plugin: TelemetryPlugin): LessonkitPlugin;
218
- /** Identity helper for assessment plugins; does not validate or register at import time. */
315
+ /**
316
+ * Identity helper for assessment plugins; does not validate or register at import time.
317
+ *
318
+ * @example
319
+ * ```ts
320
+ * import { defineAssessmentPlugin } from "@lessonkit/core";
321
+ *
322
+ * const grader = defineAssessmentPlugin({
323
+ * id: "essay-grader",
324
+ * kind: "assessment",
325
+ * score(input) {
326
+ * return { score: input.rawScore ?? 0, maxScore: 1, passed: true };
327
+ * },
328
+ * });
329
+ * ```
330
+ */
219
331
  declare function defineAssessmentPlugin(plugin: AssessmentPlugin): LessonkitPlugin;
220
- /** Identity helper for lifecycle plugins; does not validate or register at import time. */
332
+ /**
333
+ * Identity helper for lifecycle plugins; does not validate or register at import time.
334
+ *
335
+ * @example
336
+ * ```ts
337
+ * import { defineLifecyclePlugin } from "@lessonkit/core";
338
+ *
339
+ * const onComplete = defineLifecyclePlugin({
340
+ * id: "completion-hook",
341
+ * kind: "lifecycle",
342
+ * onCourseCompleted() {
343
+ * window.parent.postMessage({ type: "course-done" }, "*");
344
+ * },
345
+ * });
346
+ * ```
347
+ */
221
348
  declare function defineLifecyclePlugin(plugin: LifecyclePlugin): LessonkitPlugin;
222
349
 
223
350
  declare function buildPluginContext(opts: {
@@ -227,4 +354,4 @@ declare function buildPluginContext(opts: {
227
354
  user?: TelemetryUser;
228
355
  }): LessonkitPluginContext;
229
356
 
230
- export { ACCORDION_FORBIDDEN_CHILD_TYPES, ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES, AssessmentPlugin, AssessmentResumeState, AssessmentScoreInput, AssessmentScoreResult, BLOCKS_14_PAGE_SLIDE, BlockId, COMPOUND_MAX_NESTING_DEPTH, COMPOUND_RESUME_SCHEMA_VERSION, CheckId, ClockPort, type CompoundBaseProps, type CompoundHandle, type CompoundParentType, type CompoundResumeInput, type CompoundResumeState, CourseId, type EmitContext, type HeadlessLessonkitConfig, type HeadlessLessonkitRuntime, type HeadlessRuntimePorts, INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES, INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES, IdentityIdPath, IdentityValidationResult, LessonId, LessonkitPlugin, LessonkitPluginContext, type LessonkitRuntimeVersion, LessonkitUrn, type LessonkitUrnParts, LifecyclePlugin, type LmsBridgeMode, PAGE_ALLOWED_CHILD_TYPES, PluginHost, PluginRegistry, ProgressController, ProgressState, SLIDE_ALLOWED_CHILD_TYPES, SLIDE_DECK_ALLOWED_CHILD_TYPES, StoragePort, TELEMETRY_EVENT_CATALOG, TELEMETRY_EVENT_CATALOG_V2, TELEMETRY_EVENT_CATALOG_V3, TIMED_CUE_ALLOWED_CHILD_TYPES, TelemetryBatchSink, type TelemetryCatalogEntry, type TelemetryCatalogV2Entry, type TelemetryCatalogV3Entry, TelemetryDataFor, type TelemetryEmitFn, TelemetryEvent, TelemetryEventName, type TelemetryPipeline, type TelemetryPipelineSink, TelemetryPlugin, TelemetrySink, TelemetryUser, TrackingClient, assertNever, assertValidId, buildLessonkitUrn, buildPluginContext, buildTelemetryCatalog, buildTelemetryCatalogV2, buildTelemetryCatalogV3, clampCompoundPageIndex, clearCompoundState, compoundStateStorageKey, createCompoundResumeState, createLessonkitRuntime, createPluginRegistry, createSessionId, createTelemetryPipeline, createTrackingClient, createTrackingPipelineSink, defineAssessmentPlugin, defineLifecyclePlugin, defineTelemetryPlugin, deriveId, getAllowedChildTypes, isChildTypeAllowed, loadCompoundState, nowIso, parseBlockId, parseCheckId, parseCompoundResumeState, parseCourseId, parseLessonId, saveCompoundState, slugifyId, telemetryCatalogV2Version, telemetryCatalogV3Version, telemetryCatalogVersion, validateId };
357
+ export { ACCORDION_FORBIDDEN_CHILD_TYPES, ASSESSMENT_SEQUENCE_ALLOWED_CHILD_TYPES, AssessmentPlugin, AssessmentResumeState, AssessmentScoreInput, AssessmentScoreResult, BLOCKS_14_PAGE_SLIDE, BRANCHING_SCENARIO_ALLOWED_CHILD_TYPES, BRANCH_NODE_ALLOWED_CHILD_TYPES, BlockId, type BranchGraphNodeInput, type BranchGraphValidationIssue, type BranchGraphValidationResult, COMPOUND_MAX_NESTING_DEPTH, COMPOUND_RESUME_SCHEMA_VERSION, CheckId, ClockPort, type CompoundBaseProps, type CompoundHandle, type CompoundParentType, type CompoundResumeInput, type CompoundResumeState, CourseId, type EmitContext, GAME_MAP_ALLOWED_CHILD_TYPES, type HeadlessLessonkitConfig, type HeadlessLessonkitRuntime, type HeadlessRuntimePorts, INTERACTIVE_BOOK_ALLOWED_CHILD_TYPES, INTERACTIVE_VIDEO_ALLOWED_CHILD_TYPES, IdentityIdPath, IdentityValidationResult, LessonId, LessonkitPlugin, LessonkitPluginContext, type LessonkitRuntimeVersion, LessonkitUrn, type LessonkitUrnParts, LifecyclePlugin, type LmsBridgeMode, type LoadCompoundStateOptions, MAP_STAGE_ALLOWED_CHILD_TYPES, PAGE_ALLOWED_CHILD_TYPES, type ParseCompoundResumeStateOptions, PluginHost, PluginRegistry, ProgressController, ProgressState, SLIDE_ALLOWED_CHILD_TYPES, SLIDE_DECK_ALLOWED_CHILD_TYPES, StoragePort, TELEMETRY_EVENT_CATALOG, TELEMETRY_EVENT_CATALOG_V2, TELEMETRY_EVENT_CATALOG_V3, TIMED_CUE_ALLOWED_CHILD_TYPES, TelemetryBatchSink, type TelemetryCatalogEntry, type TelemetryCatalogV2Entry, type TelemetryCatalogV3Entry, TelemetryDataFor, type TelemetryEmitFn, TelemetryEvent, TelemetryEventName, type TelemetryPipeline, type TelemetryPipelineSink, TelemetryPlugin, TelemetrySink, TelemetryUser, TrackingClient, assertNever, assertValidId, buildLessonkitUrn, buildPluginContext, buildTelemetryCatalog, buildTelemetryCatalogV2, buildTelemetryCatalogV3, clampCompoundPageIndex, clearCompoundState, compoundStateStorageKey, createCompoundResumeState, createLessonkitRuntime, createPluginRegistry, createSessionId, createTelemetryPipeline, createTrackingClient, createTrackingPipelineSink, defineAssessmentPlugin, defineLifecyclePlugin, defineTelemetryPlugin, deriveId, getAllowedChildTypes, isChildTypeAllowed, isLifecycleTelemetryEvent, loadCompoundState, nowIso, parseBlockId, parseCheckId, parseCompoundResumeState, parseCourseId, parseLessonId, saveCompoundState, slugifyId, telemetryCatalogV2Version, telemetryCatalogV3Version, telemetryCatalogVersion, validateBranchGraph, validateId };