@lessonkit/lxpack 0.9.2 → 1.0.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 CHANGED
@@ -1,14 +1,12 @@
1
1
  # @lessonkit/lxpack
2
2
 
3
- [![Documentation](https://readthedocs.org/projects/lessonkit/badge/?version=latest)](https://lessonkit.readthedocs.io/en/latest/)
4
3
  [![npm](https://img.shields.io/npm/v/@lessonkit/lxpack.svg)](https://www.npmjs.com/package/@lessonkit/lxpack)
4
+ [![Documentation](https://readthedocs.org/projects/lessonkit/badge/?version=latest)](https://lessonkit.readthedocs.io/en/latest/reference/packaging.html)
5
5
  [![License](https://img.shields.io/github/license/eddiethedean/lessonkit)](https://github.com/eddiethedean/lessonkit/blob/main/LICENSE)
6
6
 
7
- LXPack export adapter for LessonKitwrite `lessonkit.json` + `course.yaml`, copy SPA builds, and package to SCORM / standalone / xAPI / cmi5 via [`@lxpack/api`](https://www.npmjs.com/package/@lxpack/api).
7
+ Package Vite SPAs for LMS delivery SCORM 1.2/2004, standalone, xAPI, and cmi5 via [`@lxpack/api`](https://www.npmjs.com/package/@lxpack/api).
8
8
 
9
- Requires **Node.js 20+**.
10
-
11
- **Docs:** [Packaging reference](https://lessonkit.readthedocs.io/en/latest/reference/packaging.html) · [Packaging & CLI guide](https://lessonkit.readthedocs.io/en/latest/guides/react-developers/packaging-and-cli.html) · [Live examples](https://lessonkit.readthedocs.io/en/latest/examples/index.html)
9
+ Requires Node.js **18+**.
12
10
 
13
11
  ## Install
14
12
 
@@ -16,14 +14,13 @@ Requires **Node.js 20+**.
16
14
  npm install @lessonkit/lxpack @lxpack/api
17
15
  ```
18
16
 
19
- ## Quick start
17
+ ## Usage
20
18
 
21
- ```ts
19
+ ```typescript
22
20
  import { packageLessonkitCourse } from "@lessonkit/lxpack";
23
- import { goldenCourseDescriptor } from "./course.descriptor";
24
21
 
25
22
  const result = await packageLessonkitCourse({
26
- descriptor: goldenCourseDescriptor,
23
+ descriptor: courseDescriptor,
27
24
  outDir: ".lxpack/course",
28
25
  spaDistDir: "dist",
29
26
  target: "scorm12",
@@ -33,16 +30,20 @@ const result = await packageLessonkitCourse({
33
30
  if (!result.ok) throw new Error("packaging failed");
34
31
  ```
35
32
 
36
- See the [packaging reference](https://lessonkit.readthedocs.io/en/latest/reference/packaging.html) and the [`examples/lxpack-golden`](https://github.com/eddiethedean/lessonkit/tree/main/examples/lxpack-golden) course.
33
+ Prefer the CLI: `lessonkit package --target scorm12` reads `lessonkit.json` and runs the same pipeline.
37
34
 
38
35
  ## Browser bridge
39
36
 
40
- When your React app runs inside an LXPack iframe:
37
+ When embedded in an LXPack iframe, `@lessonkit/react` forwards completion events to `window.parent.lxpackBridge.v1`. Direct API:
41
38
 
42
- ```ts
43
- import { notifyLxpackLessonComplete } from "@lessonkit/lxpack/bridge";
39
+ ```typescript
40
+ import { forwardTelemetryToBridge } from "@lessonkit/lxpack/bridge";
44
41
  ```
45
42
 
46
- `@lessonkit/react` forwards `lesson_completed`, `course_completed`, and `quiz_completed` automatically when `window.parent.lxpackBridge.v1` is present (`config.lxpack.bridge: "off"` to disable).
43
+ ## Docs
44
+
45
+ [Packaging reference](https://lessonkit.readthedocs.io/en/latest/reference/packaging.html) · [LXPack bridge](https://lessonkit.readthedocs.io/en/latest/reference/lxpack-bridge.html) · [Golden example](https://github.com/eddiethedean/lessonkit/tree/main/examples/lxpack-golden)
46
+
47
+ ## License
47
48
 
48
- For interoperability notes, see [LXPack upgrades](https://lessonkit.readthedocs.io/en/latest/reference/lxpack-upgrades.html). LXPack maintainers: [upgrade plan for maintainers](https://github.com/eddiethedean/lessonkit/blob/main/docs/LXPACK_UPGRADE_PLAN_FOR_MAINTAINERS.md).
49
+ Apache-2.0
package/dist/bridge.cjs CHANGED
@@ -25,6 +25,8 @@ __export(bridge_exports, {
25
25
  LXPACK_BRIDGE_VERSIONS: () => import_spa_bridge2.LXPACK_BRIDGE_VERSIONS,
26
26
  createLxpackBridge: () => createLxpackBridge,
27
27
  createLxpackBridgeHost: () => import_spa_bridge2.createLxpackBridgeHost,
28
+ dispatchBridgeAction: () => dispatchBridgeAction,
29
+ forwardTelemetryToBridge: () => forwardTelemetryToBridge,
28
30
  getLxpackBridge: () => import_spa_bridge2.getLxpackBridge,
29
31
  mapLessonkitTelemetryToBridgeAction: () => import_tracking_schema2.mapLessonkitTelemetryToBridgeAction,
30
32
  mapLessonkitTelemetryToLxpack: () => import_tracking_schema2.mapLessonkitTelemetryToLxpack,
@@ -42,6 +44,7 @@ module.exports = __toCommonJS(bridge_exports);
42
44
  var import_spa_bridge = require("@lxpack/spa-bridge");
43
45
  var import_spa_bridge2 = require("@lxpack/spa-bridge");
44
46
  var import_tracking_schema2 = require("@lxpack/tracking-schema");
47
+ var import_tracking_schema3 = require("@lxpack/tracking-schema");
45
48
 
46
49
  // src/telemetry.ts
47
50
  var import_tracking_schema = require("@lxpack/tracking-schema");
@@ -93,6 +96,65 @@ function getBridge(parentWindow) {
93
96
  if (!parent || parent === window) return null;
94
97
  return parent.lxpack ?? null;
95
98
  }
99
+ function isDevEnvironment() {
100
+ const g = globalThis;
101
+ return typeof g.process !== "undefined" && g.process.env?.NODE_ENV !== "production";
102
+ }
103
+ function dispatchBridgeAction(bridge, action) {
104
+ if (!action) return;
105
+ try {
106
+ dispatchBridgeActionInner(bridge, action);
107
+ } catch (err) {
108
+ if (isDevEnvironment()) {
109
+ console.warn(
110
+ "[lessonkit/lxpack] lxpack bridge action failed:",
111
+ err instanceof Error ? err.message : err
112
+ );
113
+ }
114
+ }
115
+ }
116
+ function dispatchBridgeActionInner(bridge, action) {
117
+ if (!action) return;
118
+ switch (action.kind) {
119
+ case "completeLesson":
120
+ bridge.completeLesson?.(action.lessonId);
121
+ return;
122
+ case "completeCourse":
123
+ bridge.completeCourse?.();
124
+ return;
125
+ case "submitAssessment": {
126
+ const scaled = (0, import_spa_bridge.normalizeScore)({
127
+ score: action.score,
128
+ maxScore: action.maxScore
129
+ });
130
+ if (scaled === null) return;
131
+ bridge.submitAssessment?.({
132
+ id: action.id,
133
+ score: scaled,
134
+ passingScore: (0, import_spa_bridge.normalizePassingThreshold)({
135
+ passingScore: action.passingScore,
136
+ maxScore: action.maxScore
137
+ }),
138
+ maxScore: action.maxScore
139
+ });
140
+ return;
141
+ }
142
+ case "track":
143
+ bridge.track?.(action.event);
144
+ return;
145
+ default:
146
+ return;
147
+ }
148
+ }
149
+ function forwardTelemetryToBridge(event, mode = "auto", parentWindow) {
150
+ if (mode === "off") return;
151
+ const bridge = getBridge(parentWindow);
152
+ if (!bridge) return;
153
+ const lessonkitEvent = telemetryEventToLessonkit(event);
154
+ if (!lessonkitEvent) return;
155
+ const action = (0, import_tracking_schema3.mapLessonkitTelemetryToBridgeAction)(lessonkitEvent);
156
+ dispatchBridgeAction(bridge, action);
157
+ }
96
158
  function createLxpackBridge() {
97
159
  return getBridge();
98
160
  }
@@ -121,6 +183,8 @@ function notifyLxpackAssessment(payload) {
121
183
  LXPACK_BRIDGE_VERSIONS,
122
184
  createLxpackBridge,
123
185
  createLxpackBridgeHost,
186
+ dispatchBridgeAction,
187
+ forwardTelemetryToBridge,
124
188
  getLxpackBridge,
125
189
  mapLessonkitTelemetryToBridgeAction,
126
190
  mapLessonkitTelemetryToLxpack,
package/dist/bridge.d.cts CHANGED
@@ -1,6 +1,7 @@
1
- import { CheckId, LessonId } from '@lessonkit/core';
1
+ import { TelemetryEvent, CheckId, LessonId } from '@lessonkit/core';
2
2
  import { LxpackBridgeV1, LxpackBridgeSubmitAssessmentPayload } from '@lxpack/spa-bridge';
3
3
  export { DEFAULT_BRIDGE_PASSING_SCORE, LXPACK_BRIDGE_VERSIONS, LxpackBridgeSubmitAssessmentPayload, LxpackBridgeV1, createLxpackBridgeHost, getLxpackBridge, normalizePassingThreshold, normalizeScore, supportedBridgeVersions } from '@lxpack/spa-bridge';
4
+ import { mapLessonkitTelemetryToBridgeAction } from '@lxpack/tracking-schema';
4
5
  export { LESSONKIT_TELEMETRY_EVENTS, LessonkitBridgeAction, LessonkitTelemetryEvent, LessonkitTelemetryEventName, TrackingSchemaEvent, mapLessonkitTelemetryToBridgeAction, mapLessonkitTelemetryToLxpack } from '@lxpack/tracking-schema';
5
6
  export { t as telemetryEventToLessonkit } from './telemetry-gCxlwc7I.cjs';
6
7
 
@@ -20,6 +21,11 @@ declare function normalizeAssessmentPassingScore(opts?: {
20
21
  passingScore?: number;
21
22
  maxScore?: number;
22
23
  }): number;
24
+ type LxpackBridgeMode = "auto" | "off";
25
+ /** Apply a mapped bridge action to an LXPack bridge instance. */
26
+ declare function dispatchBridgeAction(bridge: LxpackBridgeV1, action: ReturnType<typeof mapLessonkitTelemetryToBridgeAction>): void;
27
+ /** Resolve bridge and dispatch a telemetry-derived action. */
28
+ declare function forwardTelemetryToBridge(event: TelemetryEvent, mode?: LxpackBridgeMode, parentWindow?: Window): void;
23
29
  declare function createLxpackBridge(): LxpackBridgeV1 | null;
24
30
  declare function notifyLxpackLessonComplete(lessonId: LessonId): boolean;
25
31
  declare function notifyLxpackCourseComplete(): boolean;
@@ -31,4 +37,4 @@ declare function notifyLxpackAssessment(payload: LxpackBridgeSubmitAssessmentPay
31
37
  id: CheckId;
32
38
  }): boolean;
33
39
 
34
- export { createLxpackBridge, normalizeAssessmentPassingScore, normalizeAssessmentScore, notifyLxpackAssessment, notifyLxpackCourseComplete, notifyLxpackLessonComplete };
40
+ export { type LxpackBridgeMode, createLxpackBridge, dispatchBridgeAction, forwardTelemetryToBridge, normalizeAssessmentPassingScore, normalizeAssessmentScore, notifyLxpackAssessment, notifyLxpackCourseComplete, notifyLxpackLessonComplete };
package/dist/bridge.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { CheckId, LessonId } from '@lessonkit/core';
1
+ import { TelemetryEvent, CheckId, LessonId } from '@lessonkit/core';
2
2
  import { LxpackBridgeV1, LxpackBridgeSubmitAssessmentPayload } from '@lxpack/spa-bridge';
3
3
  export { DEFAULT_BRIDGE_PASSING_SCORE, LXPACK_BRIDGE_VERSIONS, LxpackBridgeSubmitAssessmentPayload, LxpackBridgeV1, createLxpackBridgeHost, getLxpackBridge, normalizePassingThreshold, normalizeScore, supportedBridgeVersions } from '@lxpack/spa-bridge';
4
+ import { mapLessonkitTelemetryToBridgeAction } from '@lxpack/tracking-schema';
4
5
  export { LESSONKIT_TELEMETRY_EVENTS, LessonkitBridgeAction, LessonkitTelemetryEvent, LessonkitTelemetryEventName, TrackingSchemaEvent, mapLessonkitTelemetryToBridgeAction, mapLessonkitTelemetryToLxpack } from '@lxpack/tracking-schema';
5
6
  export { t as telemetryEventToLessonkit } from './telemetry-gCxlwc7I.js';
6
7
 
@@ -20,6 +21,11 @@ declare function normalizeAssessmentPassingScore(opts?: {
20
21
  passingScore?: number;
21
22
  maxScore?: number;
22
23
  }): number;
24
+ type LxpackBridgeMode = "auto" | "off";
25
+ /** Apply a mapped bridge action to an LXPack bridge instance. */
26
+ declare function dispatchBridgeAction(bridge: LxpackBridgeV1, action: ReturnType<typeof mapLessonkitTelemetryToBridgeAction>): void;
27
+ /** Resolve bridge and dispatch a telemetry-derived action. */
28
+ declare function forwardTelemetryToBridge(event: TelemetryEvent, mode?: LxpackBridgeMode, parentWindow?: Window): void;
23
29
  declare function createLxpackBridge(): LxpackBridgeV1 | null;
24
30
  declare function notifyLxpackLessonComplete(lessonId: LessonId): boolean;
25
31
  declare function notifyLxpackCourseComplete(): boolean;
@@ -31,4 +37,4 @@ declare function notifyLxpackAssessment(payload: LxpackBridgeSubmitAssessmentPay
31
37
  id: CheckId;
32
38
  }): boolean;
33
39
 
34
- export { createLxpackBridge, normalizeAssessmentPassingScore, normalizeAssessmentScore, notifyLxpackAssessment, notifyLxpackCourseComplete, notifyLxpackLessonComplete };
40
+ export { type LxpackBridgeMode, createLxpackBridge, dispatchBridgeAction, forwardTelemetryToBridge, normalizeAssessmentPassingScore, normalizeAssessmentScore, notifyLxpackAssessment, notifyLxpackCourseComplete, notifyLxpackLessonComplete };
package/dist/bridge.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  normalizeScore
10
10
  } from "@lxpack/spa-bridge";
11
11
  import {
12
- createLxpackBridgeHost as createLxpackBridgeHost2,
12
+ createLxpackBridgeHost,
13
13
  DEFAULT_BRIDGE_PASSING_SCORE,
14
14
  getLxpackBridge,
15
15
  LXPACK_BRIDGE_VERSIONS,
@@ -22,6 +22,7 @@ import {
22
22
  mapLessonkitTelemetryToBridgeAction,
23
23
  mapLessonkitTelemetryToLxpack
24
24
  } from "@lxpack/tracking-schema";
25
+ import { mapLessonkitTelemetryToBridgeAction as mapLessonkitTelemetryToBridgeAction2 } from "@lxpack/tracking-schema";
25
26
  function normalizeAssessmentScore(opts) {
26
27
  if (typeof opts.score !== "number" || !Number.isFinite(opts.score)) {
27
28
  return null;
@@ -42,6 +43,65 @@ function getBridge(parentWindow) {
42
43
  if (!parent || parent === window) return null;
43
44
  return parent.lxpack ?? null;
44
45
  }
46
+ function isDevEnvironment() {
47
+ const g = globalThis;
48
+ return typeof g.process !== "undefined" && g.process.env?.NODE_ENV !== "production";
49
+ }
50
+ function dispatchBridgeAction(bridge, action) {
51
+ if (!action) return;
52
+ try {
53
+ dispatchBridgeActionInner(bridge, action);
54
+ } catch (err) {
55
+ if (isDevEnvironment()) {
56
+ console.warn(
57
+ "[lessonkit/lxpack] lxpack bridge action failed:",
58
+ err instanceof Error ? err.message : err
59
+ );
60
+ }
61
+ }
62
+ }
63
+ function dispatchBridgeActionInner(bridge, action) {
64
+ if (!action) return;
65
+ switch (action.kind) {
66
+ case "completeLesson":
67
+ bridge.completeLesson?.(action.lessonId);
68
+ return;
69
+ case "completeCourse":
70
+ bridge.completeCourse?.();
71
+ return;
72
+ case "submitAssessment": {
73
+ const scaled = normalizeScore({
74
+ score: action.score,
75
+ maxScore: action.maxScore
76
+ });
77
+ if (scaled === null) return;
78
+ bridge.submitAssessment?.({
79
+ id: action.id,
80
+ score: scaled,
81
+ passingScore: normalizePassingThreshold({
82
+ passingScore: action.passingScore,
83
+ maxScore: action.maxScore
84
+ }),
85
+ maxScore: action.maxScore
86
+ });
87
+ return;
88
+ }
89
+ case "track":
90
+ bridge.track?.(action.event);
91
+ return;
92
+ default:
93
+ return;
94
+ }
95
+ }
96
+ function forwardTelemetryToBridge(event, mode = "auto", parentWindow) {
97
+ if (mode === "off") return;
98
+ const bridge = getBridge(parentWindow);
99
+ if (!bridge) return;
100
+ const lessonkitEvent = telemetryEventToLessonkit(event);
101
+ if (!lessonkitEvent) return;
102
+ const action = mapLessonkitTelemetryToBridgeAction2(lessonkitEvent);
103
+ dispatchBridgeAction(bridge, action);
104
+ }
45
105
  function createLxpackBridge() {
46
106
  return getBridge();
47
107
  }
@@ -68,7 +128,9 @@ export {
68
128
  LESSONKIT_TELEMETRY_EVENTS,
69
129
  LXPACK_BRIDGE_VERSIONS,
70
130
  createLxpackBridge,
71
- createLxpackBridgeHost2 as createLxpackBridgeHost,
131
+ createLxpackBridgeHost,
132
+ dispatchBridgeAction,
133
+ forwardTelemetryToBridge,
72
134
  getLxpackBridge,
73
135
  mapLessonkitTelemetryToBridgeAction,
74
136
  mapLessonkitTelemetryToLxpack,