Changelog

Changelog

All notable changes to the LessonKit monorepo are documented here.

[Unreleased]

[1.7.4] - 2026-07-13

Framework 1.7.x patch — version alignment. All seven @lessonkit/* packages ship at 1.7.4. Additive release (no breaking API changes).

Changed

  • @lessonkit/cli: lessonkit init template pins ^1.7.4 on all @lessonkit/* dependencies

[1.7.3] - 2026-06-12

Framework 1.7.x patch — autoCheck retry feedback fixes, assessment resume telemetry replay, and terminal-attempt semantics. All seven @lessonkit/* packages ship at 1.7.3. Additive release (no breaking API changes).

Fixed

  • FillInTheBlanksautoCheck + enableRetry no longer keeps stale Correct UI after editing a blank to a wrong value (#185)

  • DragTheWords — same stale passed state fix when replacing zone words after a pass (#186)

  • Assessment resume replaytracking.replayResumeEvents now replays assessment_answered / assessment_completed for failed terminal attempts (not pass-only) on TrueFalse, ArithmeticQuiz, SortParagraphs, and ImageSequencing (#122, #123, #129, #172)

  • FindMultipleHotspots — resume replay correct uses passingScore threshold semantics (partial pass replays as correct when threshold met) (#92)

  • GuessTheAnswer / ImagePairing — same terminal replay pattern for consistency (drive-by)

  • Regression testsautocheck-stale-pass.test.tsx, resume replay coverage in compound.test.tsx, blocks-1.7.test.tsx, and blocks-tier-bcd.test.tsx

Changed

  • @lessonkit/cli: lessonkit init template pins ^1.7.3 on all @lessonkit/* dependencies

[1.7.2] - 2026-06-11

Framework 1.7.x patch — shared touch primitives, compound navigation, P1 block touch hardening, and mobile E2E coverage. All seven @lessonkit/* packages ship at 1.7.2. Additive release (no breaking API changes).

Added

  • CompoundNav — shared Prev/Next navigation with lk-button sizing for SlideDeck, InteractiveBook, AssessmentSequence, and SingleChoiceSet

  • TouchHint — reusable coarse-pointer pick-and-place hint for drag blocks

  • useDualModeDrag — composes useCoarsePointer, usePickAndPlace, and usePointerDrag for dual-mode drag assessments

  • mockMatchMedia — exported from @lessonkit/react/testing for coarse-pointer unit tests

  • Theme classes.lk-compound-nav, .lk-accordion-trigger, .lk-image-sequence-thumb, .lk-flip-card, .lk-memory-card

  • Mobile E2E — Playwright projects for compound nav, framework-12 showcase (FindHotspot), and expanded assessments-p0 touch flows

  • Block catalog v3a11y.touch metadata on touch-hardened blocks

  • Docs — Touch behavior sections on component reference pages; touch-and-mobile guide aligned to 1.7+

Changed

  • DragAndDrop / DragTheWords — refactored to useDualModeDrag + TouchHint

  • P1 blocks — touch targets and coarse-pointer patterns on FindMultipleHotspots, ImageSequencing, ImageSlider, Accordion, Questionnaire, AudioRecorder, ImageSequence, Flashcards, DialogCards, MemoryGame, ImagePairing, and ImageHotspots

  • TrueFalse / MultimediaChoicelk-quiz-choice row sizing; GuessTheAnswerlk-button on actions

  • @lessonkit/cli: lessonkit init template pins ^1.7.2 on all @lessonkit/* dependencies

Fixed

  • FindHotspot — toolbar pointer-events lets bottom-row hotspot targets receive taps through the overlay chrome

  • Interaction tests — expanded hook and block integration coverage with mockMatchMedia

[1.7.1] - 2026-06-10

Framework 1.7.x patch — touch-friendly web interactions, component documentation completions, and mobile E2E coverage. All seven @lessonkit/* packages ship at 1.7.1. Additive release (no breaking API changes).

Added

  • @lessonkit/react interaction hooksuseCoarsePointer, usePickAndPlace, usePointerDrag, and resolveDropTargetAtPoint for pointer-first drag on touch devices

  • Touch theme tokens--lk-touch-target-min, --lk-touch-spacing, and global .lk-button / control sizing in @lessonkit/themes

  • Mobile E2E — Playwright mobile-assessments-p0 project (Pixel 7) for drag-and-drop and assessment flows on coarse pointers

  • DocsTouch and mobile guide; Try it tabs and variant examples on SortParagraphs, GuessTheAnswer, MultimediaChoice, and SingleChoiceSet component pages

Changed

  • DragAndDrop / DragTheWords — pointer drag with coarse pick-and-place hints; HTML5 drag disabled on coarse pointers; keyboard resume key preserved

  • Assessment and content blocks — enlarged touch targets on grids, hotspots, quiz choices, summary controls, MarkTheWords, ImageHotspots, AdventCalendar, SortParagraphs, and TimedCue (allowOutsideClick on coarse)

  • @lessonkit/cli: lessonkit init template pins ^1.7.1 on all @lessonkit/* dependencies

Fixed

  • Docs buildtouch-and-mobile added to Sphinx toctree (warnings-as-errors)

  • E2E — mobile drag assertion uses [aria-live="polite"] to avoid ambiguous role="status" matches

[1.7.0] - 2026-06-08

Framework 1.7.x — four Tier B P1 assessment blocks plus Quiz multi-select/shuffle/feedback variants. All seven @lessonkit/* packages ship at 1.7.0. Additive release (no breaking API changes).

Added

  • SortParagraphs — reorder paragraphs with keyboard Up/Down; interactionType: "sortParagraphs"; SPA-only LXPack descriptor

  • GuessTheAnswer — scored text guess or unscored reveal-only mode; interactionType: "guessTheAnswer"

  • MultimediaChoice — MCQ with image/audio choices; requires altText on every option; injectable via MCQ shell (kind: "multimediaChoice")

  • SingleChoiceSet — sequential MCQ compound (Quiz / KnowledgeCheck children only); aggregated CompoundHandle scoring

  • Quiz / KnowledgeCheck variantsanswers multi-select, shuffleChoices / shuffleSeed, choiceFeedback; shared McqAssessmentProps in @lessonkit/core

  • @lessonkit/coresortParagraphs and guessTheAnswer interaction types; MCQ scoring helpers (scoreMcqSelection, shuffleChoiceIndices); SINGLE_CHOICE_SET_ALLOWED_CHILD_TYPES; compound allowlist updates

  • @lessonkit/lxpack — descriptor kinds sortParagraphs, guessTheAnswer, multimediaChoice; MCQ answers descriptor validation; multi-select MCQ is SPA-only for LMS shell until LXPack multi-correct support; manifest schema $defs

  • Block catalog v3 — four Tier B entries with H5P machine names

  • Storybook — stories for all four blocks plus Quiz variant stories (multi-select, shuffle, feedback)

  • Golden exampleexamples/assessments-p0 extended with 1.7.0 blocks

  • Tests — unit, compound, lxpack, integration SCORM, e2e smoke; Playwright assessments-p0-scorm12 project

  • DocsMIGRATION-1.6-to-1.7; capability map ✅ for four blocks; authors guide updates

  • Docs — LMS Go-Live as canonical shipping guide; backend proxy cookbook; npm run docs:build; TypeDoc @example on high-traffic APIs; adoption-path navigation cleanup

Changed

  • @lessonkit/lxpack: bump @lxpack/* dependencies to 0.7.0; inject multi-select MCQ (answers length > 1) and shuffleChoices into LMS shell quizzes via selectionMode: "multiple"; map choiceFeedback to shell showFeedback: "immediate" (per-choice feedback text remains SPA-only)

  • @lessonkit/cli: lessonkit init template pins ^1.7.0 on all @lessonkit/* dependencies

Fixed

  • @lessonkit/cli: reject unsafe dist/ contents (e.g. node_modules) in lessonkit dev and lessonkit package; init replaces stale node_modules / lockfiles before promote; --here --force backs up conflicting dotfiles to .lessonkit-init-backup/

  • @lessonkit/lxpack: validateManifestName() and reserved export path checks; reject absolute or out-of-outDir package output paths at validation (#55, #56)

  • @lessonkit/react: gate pipelineDelivered on xAPI outcome for course_started; compound getAnswerGiven respects answerPageIndex; ArithmeticQuiz timer no longer tied to runCheck; multi-select Quiz uses plugin scoring; TrueFalse telemetry reports factual correctness

  • @lessonkit/react: xAPI bootstrap flush() failures invoke onXapiTransportError; provider queue wires dead-letter persistence and overflow hooks

  • @lessonkit/xapi: persistDeadLetterStatement reports storage failures via onDeadLetterPersistError

  • @lessonkit/core: onInvalidSessionId observability when session ids are replaced

[1.6.0] - 2026-06-08

Framework 1.6.x — portable .lkcourse interchange, block registry CLI, Tier C–E content blocks, GameMap compound, and release-stabilization fixes across LMS scoring, packaging, telemetry, and assessments. All seven @lessonkit/* packages ship at 1.6.0. Additive release (no breaking API changes).

Added

  • .lkcourse archivelessonkit export produces zip with manifest.json (envelope), interchange.json, dist/, optional block-tree.json

  • @lessonkit/lxpackexportLkcourse(), validateLkcourse(), importLkcourse(), extractBlockTree(); schemas lkcourse-format.v1.json, block-tree.v1.json; fflate zip helpers with zip-slip guards

  • CLIlessonkit blocks list (--json, --category, --tier) over block-catalog.v3.json; lessonkit package --strict exposes lxpack strictBuild

  • Tier C/D blocksTable, ImageJuxtaposition, Timeline, ImageSequence, Collage, AudioRecorder

  • Tier E puzzlesCombinationLock, QrContent, Crossword, WordSearch, AdventCalendar

  • GameMap compoundMapStage, MapExit; spatial map UI; map_stage_viewed, map_exit_selected telemetry

  • Block catalog v3 — 14 new entries; WordSearch page-level only (excluded from compound allowlists); tier field restores lessonkit blocks list --tier

  • ObservabilityonCompoundDuplicateCheckId and onStoragePortChangeIgnored hooks; compound score contract documented

  • Docsinterchange reference, MIGRATION-1.5-to-1.6, plugin marketplace research; manifest layers in manifest reference; capability map ✅ for all 1.6.x blocks

  • Examplesframework-12-showcase content-wave lesson; presetAnalyticsPack plugin preset

  • Integration testlxpack-golden export → validate → import round-trip with lessonkit.json parity

  • Tests & CI — framework-12 e2e smoke; assessments-p0 FillInTheBlanks compound gating e2e; xAPI/cmi5 lesson completion assertions; golden axe-core a11y gate; blockTiers.ts canonical tier source

Fixed

  • LMS scoringnormalizeScore no longer mis-scales { score: 2, maxScore: 1 }; notifyLxpackAssessment normalizes raw points; LMS shell and bridge default passingScore is 1.0 (100%) when omitted, matching React SPA; bridge routes invalid assessment_completed scores through onBridgeMiss; Quiz UI/telemetry use factual answer correctness separate from plugin pass threshold

  • Packaging pathsspaDistDir and packaging outDir reject reserved directories (.git, node_modules, .github); descriptor spaDistDir validated at parse time; output must resolve inside outDir

  • Packaging pipelinewriteLxpackProject no longer blocks SPA-only assessment kinds; rejects non-injectable assessments; packageLessonkitCourse returns structured errors on staging failures; validation.ok aligned on warning builds; promote lock timeout increased; SPA-only assessment packaging errors include actionable hints

  • CLIlessonkit build rejects symlinked dist; init rollback surfaces failures; lessonkit dev strips passthrough --outDir

  • Core runtime — stable auto-resolved session IDs; explicit learner session swaps re-emit course_started; telemetry batch re-queues full batch on partial sink failure; course-started dedupe uses tracking mark; compound resume clamps activePageIndex when pageCount provided; telemetry track() dedupes during in-flight flush; course-started marks not cached when durable setItem fails

  • React assessments — Fill/Drag blocks require Check before Next in compounds; plugin scoring wired; scoreFromCustom fails closed on maxScore <= 0; duplicate checkId rejected in compounds; config.embed.strictHosts option; storage port cannot change after mount; assessment feedback/telemetry parity across Fill/Drag/DnD/FindMultipleHotspots/Quiz/Summary resume paths

  • Subtle audit (2nd pass) — MCQ shell injection marks trimmed answers correct; fillInBlanks rejects invalid blank entries; empty tracking.xapi: {} no longer forces activityIri; SCORM e2e requires LMS store status; CI e2e forces artifact rebuild

[1.5.0] - 2026-06-06

Framework 1.5.xBranchingScenario graph compound, Embed and Chart content blocks, branch telemetry, and useBranchingScenario(). All seven @lessonkit/* packages ship at 1.5.0.

Added

  • BranchingScenario, BranchNode, BranchChoice — H5P Branching Scenario–aligned graph navigation with visited-path scoring, session resume, optional path recap UI, and useBranchingScenario() hook

  • Embed — sandboxed iframe block (H5P.IFrameEmbed) with restrictive defaults

  • Chart — bar/pie chart with accessible data table fallback (H5P.Chart)

  • Telemetrybranch_node_viewed, branch_selected (catalog v3 + xAPI node IRIs)

  • Golden exampleexamples/branching-scenario; customer-service uses declarative branching

  • DocsMIGRATION-1.4-to-1.5.md; H5P capability map updates

  • DocsMIGRATION-1.x-to-2.0.md deprecation preview; LMS bridge mapping in telemetry docs

Fixed

  • @lessonkit/lxpack: forward assessment_answered (and quiz_answered) to the LMS bridge via bridge.track; assessment_completed regression coverage

  • @lessonkit/react: wire onLxpackBridgeError and onXapiMappingError through telemetry, course-started bootstrap, and init template observability

  • @lessonkit/xapi: stable statement IDs for assessment_completed / quiz_completed retries (idempotent LRS delivery)

  • @lessonkit/core: onCompoundResumeCorrupt observability when compound child resume state is stripped or corrupt

  • @lessonkit/lxpack: distinct manifest parity error when React source is missing but descriptor defines IDs

  • Release stabilization — provider dispose/StrictMode regressions, SCORM 1.2 parity, bridge origin allowlist hardening, compound resume integrity, telemetry pipeline observability, and packaging validation fixes from the 1.5.0 release audit pass

[1.4.0] - 2026-06-06

Framework 1.4.xInteractiveVideo (H5P Interactive Video), bundled Tier B/C/D blocks, Studio removal, production-hardening audit pass, and dependency/toolchain refresh. All seven @lessonkit/* packages ship at 1.4.0.

Added

  • @lessonkit/react: Video, TimedCue, InteractiveVideo; assessments Summary, ImagePairing, ImageSequencing, ArithmeticQuiz, Essay; content Questionnaire, MemoryGame, InformationWall, ParallaxSlideshow.

  • @lessonkit/core: compound allowlists for InteractiveVideo / TimedCue; telemetry catalog v3 events (video_cue_reached, video_segment_completed, memory_card_flipped, information_wall_search, parallax_slide_viewed, questionnaire_submitted); assessment interaction types for 1.4 blocks; McqAssessmentProps, LmsBridgeMode; ./testing subpath export for test reset helpers.

  • @lessonkit/react: assertProductionCourseConfig(); shouldEnforceProductionGuard(); onXapiTransportError observability hook; ./blocks and ./testing subpath exports; optional @lessonkit/lxpack peer dependency.

  • @lessonkit/xapi: xAPI mappers for new telemetry events; FetchHttpError; fetch transport skips retry on 4xx except 429.

  • @lessonkit/lxpack: LessonkitExportTarget alias for packaging targets.

  • CLI init template: src/courseConfig.ts with production transports, observability, .env.example, and lxpack.bridge: "off".

  • Examples: examples/interactive-video golden path; integration SCORM packaging test; Playwright smoke.

Changed

  • Block catalog v3: 38 entries (was 26); Slide allowlist includes Video and 1.4 blocks.

  • @lessonkit/react: QuizProps and KnowledgeCheckProps now use McqAssessmentProps from @lessonkit/core (was McqAssessmentDescriptor from lxpack).

  • @lessonkit/lxpack: @lxpack/* dependencies pinned to exact 0.6.4; LXPack compatibility matrix in LXPack interoperability; activityIri must be HTTPS for xAPI/cmi5 packaging targets.

  • @lessonkit/cli: exports field now includes TypeScript types; lessonkit init rewrites courseConfig.ts and activityIri; init template uses React 19, Vite 8, and @vitejs/plugin-react 6.

  • Dependencies: @lessonkit/react transitively installs @lessonkit/lxpack (and @lxpack/*) for LMS bridge telemetry at runtime; use @lessonkit/cli as a devDependency for packaging only; monorepo bumps ESLint 10, jsdom 29, @types/node 25, commander 15, and GitHub Actions (checkout/setup-node/setup-python v6, CodeQL v4, deploy-pages/upload-pages-artifact); npm overrides for React types and @testing-library/dom for RTL 16.

  • CI: checks run on Node 20 only (Vite 8 engine requirement); Dependabot for npm and GitHub Actions.

  • Docs: MIGRATION-1.3-to-1.4.md; H5P capability map rows marked ✅ at 1.4.0; SECURITY.md lists 1.4.x; README clarifies lxpack bundles @lxpack/*; onboarding docs (API subpaths, example READMEs, init template packaging scripts); production checklist documents conditional observability hooks (including required onXapiTransportError), shouldEnforceProductionGuard(), init template lxpack.bridge: "off", and .env.example.

  • Test reset helpers on main package entries are deprecated; use @lessonkit/core/testing and @lessonkit/react/testing.

Removed

  • Studio: Visual Studio authoring packages (packages/studio-*, apps/studio-web, examples/studio-minimal) removed from the monorepo. LessonKit is React-first only; historical studio-v* git tags remain for archaeology.

Fixed

  • @lessonkit/core: TrackingClient.deliver() settles non-batch sinks; scoreAssessment merges input.lessonId with the lessonId argument; deferPluginSetup honored when replacing plugins in createLessonkitRuntime.

  • @lessonkit/react: course_started delivery dedupe uses reference-equality flight cleanup; filtered telemetry counts as settled; production guard rejects tracking.enabled without a sink; xAPI queue reads fresh observability refs; removed redundant production observability warning from provider.

  • @lessonkit/xapi: fresh AbortSignal per fetch retry; pagehide aborts in-flight direct sends and delivers queued statements including flush head; skipXapi race fixed when tracking enables mid-flush.

  • @lessonkit/lxpack: SPA dist validation resolves symlinks via realpath; injectable assessments validated in staging; duplicate MCQ choice labels rejected; packageCourse injectable scope aligned with validateDescriptorForTarget; validation issue path uses tracking.xapi.activityIri; ESLint 10 preserve-caught-error in promote/spa dist validation.

[1.3.1] - 2026-06-05

Framework 1.3.x patch — production hardening and documentation. All seven @lessonkit/* packages ship at 1.3.1.

Added

  • @lessonkit/xapi: createFetchTransport and createFetchBatchSink (timeout, retry backoff, keepalive pagehide delivery); XAPIClient.flushOnExit().

  • @lessonkit/core: TrackingClient.flushOnExit() via optional exitBatchSink; wrapBatchSink routes batch failures to onTelemetrySinkError.

  • @lessonkit/lxpack: validateReactManifestParitylessonkit package fails when React src/ omits manifest courseId or checkId values.

  • @lessonkit/react: production observability warning when hooks are missing; pagehide calls flushOnExit before async flush.

Changed

  • @lessonkit/react: course_started tracking dedupe mark is written only after a successful flush.

  • @lessonkit/cli: lessonkit dev has no subprocess timeout; init template uses noop telemetry sinks (no console.log PII).

  • Docs: production checklist, telemetry/xAPI guides, Sphinx reference pages updated for 1.3.x observability and transport helpers.

Fixed

  • @lessonkit/react: batchSink failures now invoke onTelemetrySinkError.

  • @lessonkit/react: course_started dedupe is atomic under concurrent emit; backup path skips xAPI when primary flush fails; compound persistence waits for resume hydration before saving.

  • @lessonkit/react: autoCheck retry no longer locks out learners in DragTheWords and FillInTheBlanks; resume telemetry replay for drag, fill, and hotspot blocks.

  • @lessonkit/core: markCourseStarted returns a boolean; in-flight telemetry batches included in flushOnExit.

  • @lessonkit/xapi: successful queue delivery removes statements by id; flushOnExit skips in-flight head; fetch transport with timeout, retry, and keepalive pagehide delivery.

  • @lessonkit/lxpack: strict React manifest parity (comment stripping, .jsx/.js scan, constant indirection, fail on missing source); promote lock checks PID liveness before TTL expiry.

  • @lessonkit/accessibility / @lessonkit/themes: CSS selector escaping hardening, cloned theme presets, roving focus and trap filtering improvements.

[1.3.0] - 2026-06-04

Framework 1.3.xSlideDeck (H5P Course Presentation). @lessonkit/core, @lessonkit/react, @lessonkit/lxpack, @lessonkit/xapi, @lessonkit/themes, @lessonkit/accessibility, and @lessonkit/cli ship at 1.3.0.

Added

  • @lessonkit/core: SLIDE_ALLOWED_CHILD_TYPES, SLIDE_DECK_ALLOWED_CHILD_TYPES; slide_viewed in telemetry catalog v3.

  • @lessonkit/react: Slide, SlideDeck; useCompoundKeyboardNav (Arrow keys, Home, End); block catalog v3 entries for Course Presentation.

  • @lessonkit/xapi: xAPI mapping for slide_viewed.

  • Example: examples/slide-deck — golden path for slide navigation, scoring, and session resume.

  • Docs: MIGRATION-1.2-to-1.3.md; H5P capability map marks H5P.CoursePresentationSlideDeck as shipped.

Fixed

  • @lessonkit/core: compound resume accepts one-level string-key maps in child state (DragTheWords, FillInTheBlanks, DragAndDrop round-trip); shared volatile session ID across provider and compound hooks; course_started dedupe when session storage write fails; batched telemetry partial-flush redelivery and onTelemetryBufferDrop observability.

  • @lessonkit/react: duplicate assessment_answered on resume for drag/fill blocks; compound persistence merges live handle state on save; FindHotspot resets when props change; compound containers use provider StoragePort.

  • @lessonkit/xapi: queue no longer drops the oldest non-head event during flush; interaction xAPI mapping guards missing blockId.

  • @lessonkit/lxpack: symlink-aware path containment for packaging inputs; fail closed on error-severity build issues in CLI package; remapArtifactPaths throws on escape.

  • @lessonkit/cli: packaging warnings filter respects issue severity.

1.2.0 - 2026-06-03

Framework 1.2.x — Compound containers, resume state, and Tier C/D P0 blocks. @lessonkit/core, @lessonkit/react, @lessonkit/lxpack, @lessonkit/xapi, @lessonkit/themes, and @lessonkit/accessibility ship at 1.2.0.

Added

  • @lessonkit/core: CompoundHandle, CompoundResumeState, compound session storage v2, compoundAllowlists, telemetry catalog v3 (book_page_viewed, content interaction events).

  • @lessonkit/react: Page, InteractiveBook, Text, Heading, Image; Tier C/D blocks (Accordion, DialogCards, Flashcards, ImageHotspots, ImageSlider, FindHotspot, FindMultipleHotspots); AssessmentSequence implements CompoundHandle; block-catalog.v3.json (default buildBlockCatalog({ version: 3 })).

  • @lessonkit/lxpack: findHotspot / findMultipleHotspots assessment descriptor kinds.

  • Example: examples/interactive-book, examples/framework-12-showcase (full 1.2 catalog), examples/framework-11-showcase (full 1.1 foundation + P0 assessments).

  • Docs: MIGRATION-1.1-to-1.2.md; ROADMAP 1.2.x milestone; H5P capability map updates; onboarding funnel (Getting started in 5 minutes, Glossary, API reference index, ARCHITECTURE.md, CODE_OF_CONDUCT.md, good first contributions).

  • Library Skills remote installer: library-skills/install-remote.sh.

  • GitHub Actions workflow to publish Storybook to GitHub Pages (.github/workflows/storybook-pages.yml).

  • @lessonkit/core: Headless createLessonkitRuntime runs plugin telemetry hooks and scoreAssessment; buildPluginContext exported.

Changed

  • buildBlockCatalog() defaults to catalog v3 (use { version: 2 } to keep the 1.1.x shape).

  • AssessmentSequence implements CompoundHandle and may surface parent-level scores when using a ref.

  • persistCompoundState defaults to true; provide a unique blockId on each compound container to avoid shared sessionStorage keys.

  • runtimeVersion: "v1" logs a development deprecation warning; v2 remains the default.

  • README and quickstart: npm-first funnel, npm run dev, package install table, examples index.

  • npm package homepage fields point to Read the Docs.

  • lessonkit init template pins ^1.2.0 for @lessonkit/*; CLI template Vitest aligned to v4.x.

1.1.0 - 2026-06-03

Framework 1.1.x — Assessment contract and Tier B P0 blocks. All seven @lessonkit/* packages ship at 1.1.0.

Added

  • @lessonkit/core: AssessmentHandle, AssessmentBehaviour, AssessmentXAPIData, AssessmentInteractionType; telemetry events assessment_answered and assessment_completed; telemetry-catalog.v2.json and buildTelemetryCatalogV2().

  • @lessonkit/react: TrueFalse, FillInTheBlanks, DragAndDrop, DragTheWords, MarkTheWords, AssessmentSequence; useAssessmentState; block-catalog.v2.json and block-contract.v2.json (blockCatalogVersion 2 via buildBlockCatalog({ version: 2 }), default).

  • @lessonkit/xapi: xAPI mapping for assessment_answered / assessment_completed.

  • @lessonkit/lxpack: Discriminated AssessmentDescriptor (mcq, trueFalse, fillInBlanks); trueFalse converts to MCQ for LMS shell packaging; assessment_completed forwards to LXPack bridge.

  • Example: examples/assessments-p0 — golden path for P0 blocks and SCORM 1.2 packaging.

  • Docs: MIGRATION-1.0-to-1.1.md.

Changed

  • lessonkit init template pins ^1.1.0 for @lessonkit/*.

  • Quiz / KnowledgeCheck props remain McqAssessmentDescriptor (unchanged MCQ shape).

Fixed

  • @lessonkit/react: TrueFalse feedback respects plugin passed; passingScore applied in scoreFromCustom; autoCheck dedupes assessment_answered; empty FIB/DragTheWords templates and zero-token MarkTheWords show author-facing errors.

  • Docs / policy: Version badges, SECURITY supported versions, README migration link, broken CHANGELOG paths.

[1.0.2] - 2026-06-01

Patch release: telemetry and course-lifecycle correctness, contributor DX, integration test determinism, session storage hardening, and Vitest 4 security upgrade.

Fixed

  • @lessonkit/react: course_started tracking dedupe is marked only after tracking.flush() so batched batchSink delivery cannot be lost while session storage blocks retry.

  • @lessonkit/react: Lesson auto-complete on unmount no longer emits lesson_completed under the wrong courseId when the provider switches courses (conditional lesson trees / key={courseId}).

  • @lessonkit/react: course_started non-tracking pipeline awaits async extraSinks before marking pipeline delivery (failures retry).

  • @lessonkit/react: Dev-only <Quiz> outside <Lesson> no longer violates Rules of Hooks (wrapper + QuizInner).

  • @lessonkit/react: completeLesson accepts optional { courseId } and ignores completions when the live provider course differs.

  • @lessonkit/xapi: Duplicate send() while an in-flight statement fails schedules a retry after the flight completes (success path still dedupes in-flight sends).

  • @lessonkit/core: createTrackingClient() throws when batchSink is set with batch.enabled: false.

  • @lessonkit/core: createSessionStoragePort() falls back to in-memory storage when sessionStorage is null or throws on access (embedded / restricted contexts).

  • @lessonkit/lxpack: Bridge resolution falls back to parent.lxpackBridge.v1 when the SDK helper returns null.

  • @lessonkit/lxpack: Descriptor validation failures report courseDir as the staged course directory (outDir), not the packaging output path.

  • Integration tests: package --no-build failure test removes copied dist/ so a local fixture build cannot make the test pass spuriously.

Changed

  • Monorepo: Root pretest runs build:packages before npm test so workspace tests use current @lessonkit/* dist artifacts.

  • DevDependencies: Vitest and @vitest/coverage-v8 upgraded to 4.1.8 (addresses GHSA-5xrq-8626); removed deprecated coverage.all from Vitest configs.

  • lessonkit init template: Pins ^1.0.2 for @lessonkit/*.

[1.0.1] - 2026-05-31

Patch release: stronger TypeScript typing across the monorepo with no intended runtime API breaks.

Fixed

  • @lessonkit/react: Do not mark course_started as delivered to the tracking sink when a telemetry plugin filters the event; retries when tracking enables after xAPI bootstrap or when the filter is removed.

  • @lessonkit/react: Strict course_started delivery for lxpack bridge and extraSinks with a pipeline dedupe flag; retry bridge/extraSinks when session and tracking marks are set but pipeline delivery failed; honor telemetry plugins in xAPI bootstrap; avoid duplicate xAPI bootstrap after pipeline delivery.

  • @lessonkit/xapi: flush() awaits in-flight direct transport sends, not only the queued batch.

  • @lessonkit/lxpack: Validate outDir, manifest paths, output, and absolute --out overrides with realpath (blocks symlink escapes); harden promote with unique temp dirs and clear errors for legacy .bak / .tmp-promote artifacts.

  • @lessonkit/lxpack: Reject Windows drive-relative SPA paths (C:foo); coerce manifest schemaVersion: "1" (string); trim manifest name; reject paths.spaDistDir of . only.

  • @lessonkit/lxpack: Case-insensitive path-under-root checks and path.relative remapping for Windows-style artifact paths.

  • @lessonkit/cli: Forward extra Vite CLI args on lessonkit build; package --no-build fails fast when dist/ is missing; --force requires --here.

  • @lessonkit/core: hasCourseStartedPipelineDelivered / markCourseStartedPipelineDelivered session helpers (used by React provider retries).

  • Integration tests: Await golden-example Vite build in beforeAll so lessonkit package --target standalone does not race a missing dist/.

Changed

  • All @lessonkit/* packages: Discriminated telemetry/CLI result types, ID parse helpers, validateDescriptor(unknown), stricter theme validation, exported component prop types, and @typescript-eslint/no-explicit-any enforcement.

  • lessonkit init template: Pins ^1.0.1 for @lessonkit/*.

[1.0.0] - 2026-05-30

Stable public API. See MIGRATION-0.x-to-1.0.md.

Fixed

  • @lessonkit/react: Emit course_started to the tracking sink when xAPI bootstraps first and tracking is enabled later (without duplicating xAPI statements).

  • @lessonkit/core: Track course_started delivery to the tracking sink separately from xAPI/session dedupe marks.

  • @lessonkit/xapi: Coalesce concurrent flush() calls so queued statements are not sent twice.

  • @lessonkit/react: Default Quiz passingScore to the assessment plugin maxScore when the prop is omitted.

  • @lessonkit/lxpack: Fix cross-platform remapArtifactPaths prefix checks and Windows output path joining.

  • @lessonkit/lxpack: Restore staged package content when promote fails and outDir did not exist yet.

  • library-skills: Fix install.sh default (global only), validate.sh path in lessonkit-author, and packaging output path notes.

  • Tooling: Add ESLint (flat config) with CI lint step and library-skills install/validate smoke in packaging CI.

Post-release maintenance (1.0.0 line)

Shipped on main without a semver bump (packages remain 1.0.0): Node 18+ for LMS packaging; quiz/lesson/provider hardening; LXPack staging validation; library-skills and CI template parity; items previously listed here through the first 1.0.0 release.

Fixed (1.0.0 maintenance)

  • @lessonkit/core: Isolate sync and async telemetry sink failures so one sink cannot block others or crash callers.

  • @lessonkit/core: Catch async rejections from non-batch tracking.sink (dev warning).

  • @lessonkit/core: Skip duplicate lesson_started when re-activating an already completed lesson (headless runtime).

  • @lessonkit/react: Bootstrap xAPI course_started on new clients after remount (Strict Mode / transport swap).

  • @lessonkit/react: Reset headless runtime and progress when runtimeVersion toggles between v1 and v2.

  • @lessonkit/react: Skip duplicate lesson_started when remounting a completed lesson (v1 progress path).

  • @lessonkit/lxpack: Reject course arrays in parseLessonkitManifest (clear validation message).

  • @lessonkit/lxpack: Preserve failed promote builds as .lk-failed-promote-* when outDir already exists.

  • @lessonkit/lxpack: Resolve SPA and outputBaseDir paths with realpath under projectRoot.

  • @lessonkit/lxpack: Swallow host bridge throws when forwarding telemetry (dev warning).

  • @lessonkit/xapi: Map quiz_answered.correct to xAPI result.success.

  • @lessonkit/xapi: Skip duplicate in-flight send() calls for the same statement id.

  • @lessonkit/cli: Clarify --force help text; README points at bundled template source.

  • @lessonkit/xapi: Add Node 18+ engines; README notes header aligned with 1.0.0.

  • @lessonkit/react: Split course_started bootstrap so tracking dedupe is marked before xAPI/bridge pipeline retries (no duplicate tracking events on partial failure).

  • @lessonkit/react: Forward course_started to lxpack bridge and extraSinks when tracking enables after xAPI bootstrap.

  • @lessonkit/cli: Launch Vite via node …/vite/bin/vite.js so dev and build work on Windows (no .cmd spawn).

  • @lessonkit/lxpack: loadLessonkitManifestFromFile accepts optional projectRoot for path validation; trim manifest paths.* values; reject unsafe relative output without projectRoot.

  • @lessonkit/lxpack: Promote double-failure throws a recovery message listing .lk-backup-* and .lk-failed-promote-* paths.

  • Docs: Fix staged packaging example in docs/PACKAGING.md for 1.0 validatePackageInputs API.

Added

  • Library Skills (library-skills/) — Agent Skills (SKILL.md) for Cursor, Claude Code, and compatible agents: lessonkit-author, lessonkit-packaging, lessonkit-telemetry, lessonkit-migrate; install.sh and docs/guides/library-skills.md.

  • Storybook for @lessonkit/react (npm run storybook) — Course/Lesson layouts, Quiz states, block stories; CI build-storybook job.

  • Docs: Core reference, LXPack bridge reference; updated plugins, packaging, and migration guides.

Changed

  • runtimeVersion: "v2" is the default headless runtime in @lessonkit/react.

  • Monorepo packages bumped to 1.0.0; lessonkit init template pins ^1.0.0.

Removed (breaking)

  • buildTrackEvent / tryBuildTrackEvent — use buildTelemetryEvent / tryBuildTelemetryEvent.

  • defineLessonkitPlugin / createPluginHost — use segregated plugin helpers and createPluginRegistry.

  • setLxpackBridgeMode — bridge mode is per-call via @lessonkit/lxpack/bridge.

[1.0.0-beta.1] - 2026-05-29

SOLID monorepo refactor: headless runtime, telemetry pipeline, segregated plugins, LXPack manifest/packaging stages.

Added

  • @lessonkit/core: buildTelemetryEvent, TelemetryPipeline, segregated plugin types (TelemetryPlugin, AssessmentPlugin, LifecyclePlugin), createPluginRegistry, createLessonkitRuntime, shared ports / progress / session modules.

  • @lessonkit/lxpack: parseLessonkitManifest, dispatchBridgeAction, forwardTelemetryToBridge, packaging stages validatePackageInputs, buildStagingPackage, promoteStagingToOutDir.

  • Docs: MIGRATION-0.x-to-1.0.md.

Changed

  • @lessonkit/react: LessonkitProvider delegates to useLessonkitProviderRuntime; runtimeVersion: "v2" and sinks config; bridge via @lessonkit/lxpack/bridge.

  • @lessonkit/cli: Manifest parsing delegates to @lessonkit/lxpack.

  • Monorepo packages bumped to 1.0.0-beta.1.

Deprecated (removed in 1.0.0)

  • defineLessonkitPlugin / createPluginHost — use segregated plugin helpers and createPluginRegistry.

  • React-local buildTrackEvent — use buildTelemetryEvent from core.

  • Legacy tracking / xapi split config — use TelemetryPipelineSink[].

[0.9.3] - 2026-05-29

Changed

  • Monorepo packages bumped to 0.9.3.

  • Quiz / KnowledgeCheck: Optional passingScore prop (default 1) forwarded to telemetry and the LXPack bridge.

Fixed

  • @lessonkit/cli: lessonkit init uses @lessonkit/core slugifyId() so numeric or invalid directory names produce valid courseId values (e.g. 9th-gradeid-9th-grade).

  • @lessonkit/core: composeTrackingSink preserves stateful wrapper closures across events while still refreshing context when courseId / session changes.

  • @lessonkit/react: wrapTrackingSink no longer re-composes the sink on every telemetry event (fixes broken stateful analytics wrappers).

  • @lessonkit/react: Quiz resets answer state when courseId changes in-app.

  • @lessonkit/react: Provider unmount captures the xAPI client before async flush (avoids remount race).

  • @lessonkit/react: completeCourse() completes the active in-progress lesson before marking the course complete.

  • @lessonkit/lxpack: per-lesson-spa lessonSpaDirs paths are validated under projectRoot when set.

[0.9.2] - 2026-05-29

Added

  • @lessonkit/integration: Vitest integration workspace (npm run test:integration) — real CLI init / build / package pipeline, golden target matrix, descriptor parity guards.

  • E2E: Playwright launch specs for SCORM 2004 (API_1484_11 mock), xAPI, and cmi5 packages; global-setup packages all golden LMS artifacts.

  • CI: Integration (Node 20) job in .github/workflows/checks.yml.

Changed

  • Monorepo packages bumped to 0.9.2.

  • examples/lxpack-golden: tracking.xapi.activityIri for xAPI / cmi5 packaging and export parity.

Fixed

  • @lessonkit/react: Plugin onTelemetryBatch and wrapTrackingSink use fresh courseId / session context at delivery time (fixes stale context after in-app courseId changes with batched tracking).

  • @lessonkit/react: Flush batched telemetry before emitting course_started when courseId changes.

  • @lessonkit/react: Quiz feedback reflects scoreAssessment result (not only props.answer).

  • @lessonkit/react: scoreAssessment without explicit passed and with maxScore 0 or unset falls back to answer matching (no longer treats any score > 0 as pass).

  • @lessonkit/react: course_started session dedupe is marked only after a successful emit (sink failures can retry).

  • @lessonkit/cli: Stricter lessonkit.json validation (paths types, course.lessons / course.assessments arrays, course.spaDistDir vs paths.spaDistDir conflict).

  • @lessonkit/cli: react-vite package target uses INVALID_PROJECT when dist is missing after build.

  • @lessonkit/lxpack: Reject output paths outside projectRoot when projectRoot is set (direct API use).

  • @lessonkit/cli: lessonkit init resolves bundled template when CLI runs from dist/bin.js (fixes template path for published CLI).

[0.9.1] - 2026-05-29

Added

  • E2E telemetry harness (e2e/fixtures/telemetry-harness/): Playwright project for telemetry batching and xAPI queue behavior via window.__e2e.

  • E2E: Expanded keyboard coverage on golden Vite (lesson nav, knowledge check).

  • Docs: Conformance matrix table and CI job map in export parity guide; expanded e2e/README.md; contributing E2E section.

  • PluginHost.deliverTelemetryBatch: batch flush hook for events already filtered at emit time (avoids double onTelemetry passes).

Changed

  • Monorepo packages bumped to 0.9.1; 0.9.x conformance harness milestone complete per ROADMAP.

  • @lessonkit/core: TrackingClient.flush / dispose may return Promise<void>; batched dispose drains the buffer after in-flight flushes complete.

  • @lessonkit/react: Provider unmount awaits tracking flush/dispose; setActiveLesson flushes batched telemetry after auto-completing the previous lesson.

Fixed

  • @lessonkit/react: Duplicate course-level xAPI initialized when tracking starts disabled and is enabled later with a transport (bootstrap now marks course_started in session storage).

  • @lessonkit/react: Plugin batchSink no longer re-runs onTelemetry on buffered events (prevents silent drops from stateful plugins).

  • @lessonkit/react: Quiz / KnowledgeCheck honor scoreAssessment plugins from LessonkitProvider.

  • @lessonkit/react: Dev warning and flush when courseId changes with an injected config.xapi.client.

  • @lessonkit/lxpack: Validate outDir / outputBaseDir when projectRoot is set; allow ./dist-style paths; log promote restore failures.

  • @lessonkit/cli: Pass projectRoot into packaging; map unsafe --out paths to CliError (INVALID_PROJECT); harden lessonkit init JSX string escaping.

  • E2E: Telemetry harness batching spec drains startup lifecycle events before asserting quiz batch coalescing.

[0.9.0] - 2026-05-29

Added

  • Plugin architecture (v1) in @lessonkit/core / @lessonkit/react: LessonkitPlugin, createPluginHost, config.plugins on LessonkitProvider (telemetry hooks, sink wrapping, assessment scoring slot).

  • Docs: plugins reference, plugin cookbook, example consoleAnalyticsPlugin.

  • Conformance harness (e2e/): Playwright e2e for examples/lxpack-golden on Vite preview, standalone, and SCORM 1.2 (LMS API mock).

  • CI: @lxpack/conformance packaging matrix, golden package matrix, and test:e2e job (Node 20).

  • Docs: export parity guide, e2e/README.md, contributor notes for conformance.

Changed

  • Monorepo packages bumped to 0.9.0; focus milestone is export parity before framework 1.0.

Fixed

  • @lessonkit/react: Emit one course-level xAPI initialized statement when both tracking and xAPI transport are configured (removed duplicate bootstrap send on provider mount).

[0.8.2] - 2026-05-29

Changed

  • @lessonkit/lxpack: Bump @lxpack/api, @lxpack/spa-bridge, @lxpack/validators, and @lxpack/tracking-schema to ^0.6.0; packageLessonkitCourse() uses LXPack packageLessonkit() instead of hand-built YAML + separate validate/build.

  • @lessonkit/lxpack: descriptorToInterchange() includes runtime, assessments, and interchange types from @lxpack/validators; writeLxpackProject() delegates to materializeLessonkitProject() (removed local YAML emitters).

  • @lessonkit/lxpack/bridge: Re-export @lxpack/spa-bridge and mapLessonkitTelemetryToBridgeAction from @lxpack/tracking-schema; telemetryEventToLessonkit() adapts @lessonkit/core events.

  • @lessonkit/react: Forward telemetry to the LXPack bridge via the shared tracking map (replacing hand-rolled switch).

  • @lessonkit/lxpack: Export materializeLessonkitProject, parseLessonkitInterchange, and lessonkitInterchangeSchema for advanced tooling.

[0.8.1] - 2026-05-29

Fixed

  • @lessonkit/react: Reset progress synchronously on courseId change so child <Lesson> effects cannot emit completions under the wrong course id.

  • @lessonkit/react: Revert to tab/auto sessionId when session.sessionId is cleared from config.

  • @lessonkit/react: Skip course_started storage/delivery while tracking.enabled is false; emit when tracking is re-enabled.

  • @lessonkit/react: Reset Quiz state when answer or question changes; cancel pending dispose timers on provider remount.

  • @lessonkit/react: Remove stale course_started storage keys after session id migration.

  • @lessonkit/cli: Validate lessonkit.json paths.* and package --out stay under the project root.

  • @lessonkit/cli: init --force only allowed when the target directory is empty or contains dotfiles only; template uses {{courseId}} / {{courseTitle}} placeholders.

  • @lessonkit/lxpack: validateProjectPaths, resolveSafePackageOutputOverride; validate custom theme and completion threshold in validateDescriptor; writeLxpackProject resolves relative spaDistDir under optional projectRoot.

  • @lessonkit/lxpack/bridge: Scale passingScore to 0–1 when maxScore is provided (matches normalizeAssessmentScore); clamp normalized scores to 1.

  • @lessonkit/lxpack: Atomic promote of packaged outDir so a failed rename does not delete the previous course tree.

  • @lessonkit/lxpack: Validate passingScore as absolute points (not capped by choice count); remap nested build.outputPath / outputDir after staging promote.

  • @lessonkit/react: Emit course_started before lesson_started when courseId changes; reset xAPI queue on courseId change.

  • @lessonkit/react: Harden tracking client dispose on provider unmount.

  • @lessonkit/react: Skip xAPI client creation when no transport/client unless xapi.enabled: true; flush batched tracking on completeCourse; migrate course_started dedup when session.sessionId changes.

  • @lessonkit/cli: Honor --no-build for react-vite package target; clarify init --force (only with --here).

  • Examples: lessonkit.json for react-vite, data-privacy, and customer-service; golden course.descriptor.ts sync; examples/lxpack-golden/README.md documents single-spa lesson ids.

  • Docs: README license Apache-2.0; ROADMAP framework status 0.8.1.

  • @lessonkit/react: Migrate course_started dedup when session.sessionId is first supplied after a tab auto-id (including from stored tab session).

  • @lessonkit/react: Reset Quiz completion state when checkId changes on a mounted instance.

  • @lessonkit/react: Ignore stale xAPI flush work after transport/client/courseId layout effect cleanup.

  • Examples: react-vite manifest theme preset matches App (brand); lxpack-golden renames in-SPA lesson safety-signoff (distinct from assessment checkId) and aligns welcome lesson title with the app.

  • Docs: CLI and guide version callouts updated to 0.8.1.

[0.8.0] - 2026-05-28

Added

  • @lessonkit/react: Runtime block catalog v1 — buildBlockCatalog(), getBlockCatalogEntry(), BLOCK_CATALOG, blockCatalogVersion.

  • @lessonkit/react: Machine-readable @lessonkit/react/block-catalog.v1.json and JSON Schema @lessonkit/react/block-contract.v1.json.

  • Docs: docs/BLOCK_CATALOG.md and block catalog reference.

  • Examples: examples/lxpack-golden demonstrates every catalog block (KnowledgeCheck, optional blockId on Scenario/Reflection).

Changed

  • Monorepo packages bumped to 0.8.0.

  • Docs: Block catalog reference complete; vibe-coding and components guides link to block catalog.

[0.7.0] - 2026-05-28

Added

  • @lessonkit/cli: Real init, dev, build, and package commands with dual export (react-vite + LMS targets via @lessonkit/lxpack).

  • lessonkit.json v1: Canonical project manifest for packaging.

  • CLI: Structured errors, stable exit codes, --json output mode, --skip-install / --force for automation.

  • Template bundling: Vite + React starter copied into @lessonkit/cli for lessonkit init.

  • Docs: docs/CLI.md.

  • CI: CLI packaging smoke step on golden example.

Changed

  • Monorepo packages bumped to 0.7.0.

  • examples/lxpack-golden: Packaging scripts use lessonkit package instead of custom tsx script.

  • templates/vite-react and golden example include lessonkit.json.

  • Starter template: ThemeProvider defaults to preset="default" / mode="light" to match lessonkit.json.

Fixed

  • @lessonkit/cli: paths.outputBaseDir is honored when resolving package artifacts; lessonkit build passes Vite --outDir when paths.spaDistDir is not dist.

  • @lessonkit/cli: Project discovery requires schemaVersion: 1 (ignores LXPack interchange lessonkit.json under .lxpack/course).

  • @lessonkit/cli: lessonkit init patches src/App.tsx courseId and course title to match the manifest; rejects per-lesson-spa for lessonkit package.

  • @lessonkit/lxpack: Descriptor validation requires layout and validates theme.preset.

  • @lessonkit/react: completeLesson clears activeLessonId; provider unmount flushes pending lesson completions before disposing the active tracking client; courseId changes re-activate mounted lessons.

[0.6.0] - 2026-05-28

Added

  • @lessonkit/lxpack: New package — LessonkitCourseDescriptor, writeLxpackProject, packageLessonkitCourse, validateLessonkitProject, buildLessonkitProject; themeToLxpackRuntime; single-spa and per-lesson-spa layouts; assessment export; browser bridge (@lessonkit/lxpack/bridge).

  • @lessonkit/react: Forwards lesson_completed, course_completed, and quiz_completed to window.parent.lxpackBridge.v1 when embedded (config.lxpack.bridge, default auto).

  • Examples: examples/lxpack-golden — build + SCORM 1.2 / standalone packaging scripts.

  • CI: Node 20 packaging smoke job (golden example → SCORM ZIP).

  • Docs: docs/PACKAGING.md; LXPack id mapping in docs/IDENTITY.md; theme parity in docs/THEMING.md.

Changed

  • Monorepo packages bumped to 0.6.0.

  • Root build:packages includes @lessonkit/lxpack (requires Node 20+ for consumers of the adapter).

  • @lessonkit/react: Depends on @lessonkit/lxpack for shared LXPack bridge score normalization.

Fixed

  • @lessonkit/lxpack: Reject unsafe spaPath values and verify copy destinations stay inside the project root.

  • @lessonkit/lxpack: Normalize trimmed ids/titles in validated descriptors; validate spaLessonId, duplicate spaPath, and assessment passingScore / choices.

  • @lessonkit/lxpack: Clear stale SPA output before re-copy; stage packaging in a temp dir so failed runs do not overwrite a good outDir.

  • @lessonkit/lxpack: Export normalizeAssessmentScore / normalizeAssessmentPassingScore from @lessonkit/lxpack/bridge.

  • @lessonkit/react: LXPack bridge skips submitAssessment when quiz_completed has no finite score (no longer defaults to 100%).

  • @lessonkit/react: Lifecycle telemetry uses canonical lessonId when data.lessonId conflicts.

  • @lessonkit/react: Reset progress and emit course_started when courseId changes; send course_started to xAPI when the client is enabled after mount.

  • @lessonkit/xapi: Dev warning when xAPI transport fails and a statement is re-queued.

0.5.0 - 2026-05-28

Added

  • @lessonkit/core: Identity v1 — validateId, slugifyId, deriveId, buildLessonkitUrn; typed TelemetryEvent payloads; TELEMETRY_EVENT_CATALOG / telemetry-catalog.v1.json; identity-contract.v1.json.

  • @lessonkit/xapi: telemetryEventToXAPIStatement() — canonical mapping from telemetry to xAPI object URNs.

  • Docs: docs/IDENTITY.md, docs/TELEMETRY.md.

Changed

  • @lessonkit/react: xAPI emission goes through the telemetry mapper after each track() (single path for lifecycle and quiz events).

  • @lessonkit/xapi: createXAPIClient uses courseId and the mapper internally for lifecycle helpers.

Breaking

  • @lessonkit/react: courseId required on Course and LessonkitProvider; lessonId required on Lesson (removed useId() lesson fallback); checkId required on Quiz / KnowledgeCheck.

  • @lessonkit/react: useQuizState().answer / .complete require checkId in their payloads.

  • @lessonkit/react: Removed exported sanitizeLessonId.

  • @lessonkit/core: All telemetry events require courseId; event data shapes are discriminated by event name.

  • @lessonkit/xapi: Clients without courseId no longer emit lifecycle statements; default urn:lessonkit base id removed.

Fixed

  • @lessonkit/react: setActiveLesson completes the previously active lesson when switching ids (tab/programmatic navigation).

  • @lessonkit/react: <Lesson> defers completion on unmount so React Strict Mode does not emit spurious lesson_completed events in development.

  • @lessonkit/react: Progress state uses createProgressController() (single implementation shared with tests).

  • @lessonkit/react: Dev-only warnings for invalid courseId / lessonId / checkId; xAPI mapping skips invalid ids with a dev warning instead of throwing.

  • @lessonkit/core: Test asserts identity-contract.v1.json idPattern matches ID_PATTERN.

Migration

See docs/IDENTITY.md: add courseId, lessonId, and checkId to your components; preserve IDs in source when regenerating.

0.4.0 - 2026-05-28

Added

  • @lessonkit/themes: Token schema v1 (colors, spacing, typography, radius, shadows), validateTheme, mergeThemes, themeToCssVariables, presets (default, light, dark, brand), buildThemeCatalog, published theme-contract.v1.json / theme-catalog.v1.json, optional base.css.

  • @lessonkit/react: ThemeProvider, useTheme, and theme types; injects --lk-* CSS variables on :root or a scoped element.

  • Docs: docs/THEMING.md — CSS variable contract, merge precedence, generator catalog paths.

  • Examples/templates: Showcase theme toggle (light / dark / system); styles migrated to --lk-* variables.

Changed

  • @lessonkit/themes: LessonkitTheme is now an alias for the full LessonkitThemeV1 schema (breaking if you relied on the old partial shape without other token groups).

Fixed

  • @lessonkit/themes / @lessonkit/react: preset="brand" no longer forces dark palette colors when mode is light or system (brand merges brandThemeOverrides onto the active mode base).

  • @lessonkit/react: LessonkitProvider uses shared createXapiClientFromConfig from runtime/xapi (no duplicate factory logic).

  • Docs: Package READMEs and root example updated for 0.4.0; SPEC.md imports @lessonkit/react; theming docs clarify preset="default" vs defaultTheme.

0.3.1 - 2026-05-28

Fixed

  • @lessonkit/react: Use an isomorphic layout effect in LessonkitProvider to avoid SSR useLayoutEffect warnings while preserving client-side lifecycle behavior.

  • Repo: Make npm run typecheck deterministic by building workspace package declarations first.

  • @lessonkit/react: Silence expected React error output in the “missing provider” test while keeping the assertion.

  • @lessonkit/core: Call unref() on batched telemetry flush timers so Node test runners and CLIs can exit cleanly.

Changed

  • @lessonkit/core, @lessonkit/xapi, @lessonkit/react: Internal module split (types, tracking client, xAPI queue/client, runtime session ports) with no intended public API changes.

  • @lessonkit/react: Session and course-started persistence now go through a storage port (runtime/session).

0.3.0 - 2026-05-28

Fixed

  • @lessonkit/react: Move tracking and xAPI client lifecycle to useLayoutEffect (no dispose side effects in useMemo); stabilize batch config dependencies on primitive fields.

  • @lessonkit/react: Persist tab-scoped sessionId via sessionStorage when session.sessionId is omitted; dedupe course_started across React Strict Mode remounts.

  • @lessonkit/react: Flush shared xAPI queue when xapi.transport changes so queued statements are not dropped.

  • @lessonkit/react: Flush batched telemetry on provider unmount; idempotent completeLesson / completeCourse telemetry.

  • @lessonkit/react: Quiz emits quiz_completed on first correct answer; fieldset legend uses bundled visually-hidden styles (no .sr-only CSS required).

Added

  • @lessonkit/accessibility: visuallyHiddenStyle export for screen-reader-only UI without app CSS.

  • @lessonkit/react: Depends on @lessonkit/accessibility for Quiz legend styling.

Changed

  • Root build order builds @lessonkit/accessibility before @lessonkit/react.

  • Documentation updated for 0.3.0 (ROADMAP status, React README notes on lesson unmount and sessions).

[0.2.0] - (unreleased on npm; included in 0.3.0)

Analytics and tracking milestone (shipped in repo before 0.3.0 hardening):

  • Session-aware telemetry, optional batching (@lessonkit/core, @lessonkit/react).

  • LessonkitProvider runtime config (tracking sink, xapi.transport, session metadata).

  • xAPI in-memory queue, richer lesson completion results (@lessonkit/xapi).

  • Vite React example and template with telemetry/xAPI wiring.

[0.1.1] - 2026-05-27

Last version published to npm before 0.2.x.

  • Initial public packages: @lessonkit/core, @lessonkit/react, @lessonkit/xapi, @lessonkit/accessibility, @lessonkit/themes, @lessonkit/cli.

  • Tag-based publish workflow and CI checks (build, typecheck, test, coverage).