@lessonkit/lxpack 0.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/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @lessonkit/lxpack
2
+
3
+ LXPack export adapter for LessonKit — write `lessonkit.json` + `course.yaml`, copy SPA builds, and package to SCORM / standalone / xAPI / cmi5 via [`@lxpack/api`](https://www.npmjs.com/package/@lxpack/api).
4
+
5
+ Requires **Node.js 20+**.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @lessonkit/lxpack @lxpack/api
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```ts
16
+ import { packageLessonkitCourse } from "@lessonkit/lxpack";
17
+ import { goldenCourseDescriptor } from "./course.descriptor";
18
+
19
+ const result = await packageLessonkitCourse({
20
+ descriptor: goldenCourseDescriptor,
21
+ outDir: ".lxpack/course",
22
+ spaDistDir: "dist",
23
+ target: "scorm12",
24
+ output: ".lxpack/out/course-scorm12.zip",
25
+ });
26
+
27
+ if (!result.ok) throw new Error("packaging failed");
28
+ ```
29
+
30
+ See [`docs/PACKAGING.md`](../../docs/PACKAGING.md) and [`examples/lxpack-golden`](../../examples/lxpack-golden).
31
+
32
+ ## Browser bridge
33
+
34
+ When your React app runs inside an LXPack iframe:
35
+
36
+ ```ts
37
+ import { notifyLxpackLessonComplete } from "@lessonkit/lxpack/bridge";
38
+ ```
39
+
40
+ `@lessonkit/react` forwards `lesson_completed`, `course_completed`, and `quiz_completed` automatically when `window.parent.lxpackBridge.v1` is present (`config.lxpack.bridge: "off"` to disable).
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/bridge.ts
21
+ var bridge_exports = {};
22
+ __export(bridge_exports, {
23
+ createLxpackBridge: () => createLxpackBridge,
24
+ normalizeAssessmentPassingScore: () => normalizeAssessmentPassingScore,
25
+ normalizeAssessmentScore: () => normalizeAssessmentScore,
26
+ notifyLxpackAssessment: () => notifyLxpackAssessment,
27
+ notifyLxpackCourseComplete: () => notifyLxpackCourseComplete,
28
+ notifyLxpackLessonComplete: () => notifyLxpackLessonComplete
29
+ });
30
+ module.exports = __toCommonJS(bridge_exports);
31
+ function normalizeAssessmentScore(opts) {
32
+ if (typeof opts.score !== "number" || !Number.isFinite(opts.score)) {
33
+ return null;
34
+ }
35
+ const maxScore = typeof opts.maxScore === "number" && opts.maxScore > 0 ? opts.maxScore : 1;
36
+ return opts.score / maxScore;
37
+ }
38
+ function normalizeAssessmentPassingScore(passingScore) {
39
+ return typeof passingScore === "number" && passingScore > 0 ? passingScore : 1;
40
+ }
41
+ function getBridge() {
42
+ if (typeof window === "undefined") return null;
43
+ const parent = window.parent;
44
+ if (!parent || parent === window) return null;
45
+ return parent.lxpackBridge?.v1 ?? parent.lxpack ?? null;
46
+ }
47
+ function createLxpackBridge() {
48
+ return getBridge();
49
+ }
50
+ function notifyLxpackLessonComplete(lessonId) {
51
+ const bridge = getBridge();
52
+ if (!bridge?.completeLesson) return false;
53
+ bridge.completeLesson(lessonId);
54
+ return true;
55
+ }
56
+ function notifyLxpackCourseComplete() {
57
+ const bridge = getBridge();
58
+ if (!bridge?.completeCourse) return false;
59
+ bridge.completeCourse();
60
+ return true;
61
+ }
62
+ function notifyLxpackAssessment(payload) {
63
+ const bridge = getBridge();
64
+ if (!bridge?.submitAssessment) return false;
65
+ bridge.submitAssessment(payload);
66
+ return true;
67
+ }
68
+ // Annotate the CommonJS export names for ESM import in node:
69
+ 0 && (module.exports = {
70
+ createLxpackBridge,
71
+ normalizeAssessmentPassingScore,
72
+ normalizeAssessmentScore,
73
+ notifyLxpackAssessment,
74
+ notifyLxpackCourseComplete,
75
+ notifyLxpackLessonComplete
76
+ });
@@ -0,0 +1,46 @@
1
+ import { LessonId, CheckId } from '@lessonkit/core';
2
+
3
+ type LxpackBridgeV1 = {
4
+ completeLesson?: (lessonId: LessonId) => void;
5
+ completeCourse?: () => void;
6
+ submitAssessment?: (payload: {
7
+ id: string;
8
+ score: number;
9
+ passingScore?: number;
10
+ }) => void;
11
+ track?: (payload: {
12
+ type: string;
13
+ id: string;
14
+ data?: Record<string, unknown>;
15
+ }) => void;
16
+ };
17
+ type LxpackBridgeHost = {
18
+ lxpackBridge?: {
19
+ v1?: LxpackBridgeV1;
20
+ };
21
+ lxpack?: LxpackBridgeV1;
22
+ };
23
+ /**
24
+ * Scale a raw quiz score to 0–1 for the LXPack parent bridge.
25
+ * Returns null when `score` is missing or not finite (caller should skip submit).
26
+ */
27
+ declare function normalizeAssessmentScore(opts: {
28
+ score?: number;
29
+ maxScore?: number;
30
+ }): number | null;
31
+ /** Bridge passing threshold (0–1 scale). Defaults to 1 when omitted or invalid. */
32
+ declare function normalizeAssessmentPassingScore(passingScore?: number): number;
33
+ declare function createLxpackBridge(): LxpackBridgeV1 | null;
34
+ declare function notifyLxpackLessonComplete(lessonId: LessonId): boolean;
35
+ declare function notifyLxpackCourseComplete(): boolean;
36
+ /**
37
+ * Submit assessment results to the parent LXPack bridge.
38
+ * `score` must already be on a 0–1 scale (use `normalizeAssessmentScore` for raw points).
39
+ */
40
+ declare function notifyLxpackAssessment(payload: {
41
+ id: CheckId;
42
+ score: number;
43
+ passingScore?: number;
44
+ }): boolean;
45
+
46
+ export { type LxpackBridgeHost, type LxpackBridgeV1, createLxpackBridge, normalizeAssessmentPassingScore, normalizeAssessmentScore, notifyLxpackAssessment, notifyLxpackCourseComplete, notifyLxpackLessonComplete };
@@ -0,0 +1,46 @@
1
+ import { LessonId, CheckId } from '@lessonkit/core';
2
+
3
+ type LxpackBridgeV1 = {
4
+ completeLesson?: (lessonId: LessonId) => void;
5
+ completeCourse?: () => void;
6
+ submitAssessment?: (payload: {
7
+ id: string;
8
+ score: number;
9
+ passingScore?: number;
10
+ }) => void;
11
+ track?: (payload: {
12
+ type: string;
13
+ id: string;
14
+ data?: Record<string, unknown>;
15
+ }) => void;
16
+ };
17
+ type LxpackBridgeHost = {
18
+ lxpackBridge?: {
19
+ v1?: LxpackBridgeV1;
20
+ };
21
+ lxpack?: LxpackBridgeV1;
22
+ };
23
+ /**
24
+ * Scale a raw quiz score to 0–1 for the LXPack parent bridge.
25
+ * Returns null when `score` is missing or not finite (caller should skip submit).
26
+ */
27
+ declare function normalizeAssessmentScore(opts: {
28
+ score?: number;
29
+ maxScore?: number;
30
+ }): number | null;
31
+ /** Bridge passing threshold (0–1 scale). Defaults to 1 when omitted or invalid. */
32
+ declare function normalizeAssessmentPassingScore(passingScore?: number): number;
33
+ declare function createLxpackBridge(): LxpackBridgeV1 | null;
34
+ declare function notifyLxpackLessonComplete(lessonId: LessonId): boolean;
35
+ declare function notifyLxpackCourseComplete(): boolean;
36
+ /**
37
+ * Submit assessment results to the parent LXPack bridge.
38
+ * `score` must already be on a 0–1 scale (use `normalizeAssessmentScore` for raw points).
39
+ */
40
+ declare function notifyLxpackAssessment(payload: {
41
+ id: CheckId;
42
+ score: number;
43
+ passingScore?: number;
44
+ }): boolean;
45
+
46
+ export { type LxpackBridgeHost, type LxpackBridgeV1, createLxpackBridge, normalizeAssessmentPassingScore, normalizeAssessmentScore, notifyLxpackAssessment, notifyLxpackCourseComplete, notifyLxpackLessonComplete };
package/dist/bridge.js ADDED
@@ -0,0 +1,46 @@
1
+ // src/bridge.ts
2
+ function normalizeAssessmentScore(opts) {
3
+ if (typeof opts.score !== "number" || !Number.isFinite(opts.score)) {
4
+ return null;
5
+ }
6
+ const maxScore = typeof opts.maxScore === "number" && opts.maxScore > 0 ? opts.maxScore : 1;
7
+ return opts.score / maxScore;
8
+ }
9
+ function normalizeAssessmentPassingScore(passingScore) {
10
+ return typeof passingScore === "number" && passingScore > 0 ? passingScore : 1;
11
+ }
12
+ function getBridge() {
13
+ if (typeof window === "undefined") return null;
14
+ const parent = window.parent;
15
+ if (!parent || parent === window) return null;
16
+ return parent.lxpackBridge?.v1 ?? parent.lxpack ?? null;
17
+ }
18
+ function createLxpackBridge() {
19
+ return getBridge();
20
+ }
21
+ function notifyLxpackLessonComplete(lessonId) {
22
+ const bridge = getBridge();
23
+ if (!bridge?.completeLesson) return false;
24
+ bridge.completeLesson(lessonId);
25
+ return true;
26
+ }
27
+ function notifyLxpackCourseComplete() {
28
+ const bridge = getBridge();
29
+ if (!bridge?.completeCourse) return false;
30
+ bridge.completeCourse();
31
+ return true;
32
+ }
33
+ function notifyLxpackAssessment(payload) {
34
+ const bridge = getBridge();
35
+ if (!bridge?.submitAssessment) return false;
36
+ bridge.submitAssessment(payload);
37
+ return true;
38
+ }
39
+ export {
40
+ createLxpackBridge,
41
+ normalizeAssessmentPassingScore,
42
+ normalizeAssessmentScore,
43
+ notifyLxpackAssessment,
44
+ notifyLxpackCourseComplete,
45
+ notifyLxpackLessonComplete
46
+ };