@lxpack/runtime 0.1.1 → 0.2.1

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.
Files changed (52) hide show
  1. package/README.md +67 -11
  2. package/dist/client.js +2250 -1673
  3. package/dist/core/completion-evaluator.d.ts +13 -0
  4. package/dist/core/completion-evaluator.d.ts.map +1 -0
  5. package/dist/core/progress-state.d.ts +20 -0
  6. package/dist/core/progress-state.d.ts.map +1 -0
  7. package/dist/flow-conditions.d.ts +4 -0
  8. package/dist/flow-conditions.d.ts.map +1 -0
  9. package/dist/flow.d.ts +14 -0
  10. package/dist/flow.d.ts.map +1 -0
  11. package/dist/lms/bridge.d.ts +11 -0
  12. package/dist/lms/bridge.d.ts.map +1 -0
  13. package/dist/lms/completion-state.d.ts +10 -0
  14. package/dist/lms/completion-state.d.ts.map +1 -0
  15. package/dist/lms/factory.d.ts +5 -0
  16. package/dist/lms/factory.d.ts.map +1 -0
  17. package/dist/lms/local-bridge.d.ts +15 -0
  18. package/dist/lms/local-bridge.d.ts.map +1 -0
  19. package/dist/lms/scorm12-bridge.d.ts +15 -0
  20. package/dist/lms/scorm12-bridge.d.ts.map +1 -0
  21. package/dist/lms/scorm2004-bridge.d.ts +15 -0
  22. package/dist/lms/scorm2004-bridge.d.ts.map +1 -0
  23. package/dist/{progress-persist.d.ts → progress/codec.d.ts} +2 -3
  24. package/dist/progress/codec.d.ts.map +1 -0
  25. package/dist/progress/constants.d.ts +3 -0
  26. package/dist/progress/constants.d.ts.map +1 -0
  27. package/dist/progress/size-policy.d.ts +4 -0
  28. package/dist/progress/size-policy.d.ts.map +1 -0
  29. package/dist/quiz/host.d.ts +9 -0
  30. package/dist/quiz/host.d.ts.map +1 -0
  31. package/dist/quiz/score.d.ts +6 -0
  32. package/dist/quiz/score.d.ts.map +1 -0
  33. package/dist/runtime.d.ts +13 -12
  34. package/dist/runtime.d.ts.map +1 -1
  35. package/dist/runtime.js +288 -377
  36. package/dist/scorm-api.d.ts +1 -1
  37. package/dist/scorm-api.d.ts.map +1 -1
  38. package/dist/scorm12-DpGWvsHb.js +375 -0
  39. package/dist/scorm12.d.ts +3 -0
  40. package/dist/scorm12.d.ts.map +1 -0
  41. package/dist/scorm12.js +11 -0
  42. package/dist/scorm2004-api.d.ts +57 -0
  43. package/dist/scorm2004-api.d.ts.map +1 -0
  44. package/dist/scorm2004.d.ts +2 -0
  45. package/dist/scorm2004.d.ts.map +1 -0
  46. package/dist/scorm2004.js +153 -0
  47. package/dist/types.d.ts +5 -2
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/variables.d.ts +7 -0
  50. package/dist/variables.d.ts.map +1 -0
  51. package/package.json +11 -3
  52. package/dist/progress-persist.d.ts.map +0 -1
package/dist/runtime.js CHANGED
@@ -1,414 +1,323 @@
1
- var f = Object.defineProperty;
2
- var g = (t, s, e) => s in t ? f(t, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[s] = e;
3
- var i = (t, s, e) => g(t, typeof s != "symbol" ? s + "" : s, e);
4
- const S = "lxpack_scorm12_preview";
5
- function _(t = 500) {
6
- let s = window, e = 0;
7
- for (; s && e < t; ) {
8
- try {
9
- const r = s.API;
10
- if (r && typeof r.LMSInitialize == "function")
11
- return r;
12
- } catch {
13
- }
14
- try {
15
- if (s.parent && s.parent !== s)
16
- s = s.parent;
17
- else if (s.opener && !s.opener.closed)
18
- s = s.opener;
19
- else
20
- break;
21
- } catch {
22
- break;
23
- }
24
- e++;
1
+ var M = Object.defineProperty;
2
+ var T = (t, s, e) => s in t ? M(t, s, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[s] = e;
3
+ var a = (t, s, e) => T(t, typeof s != "symbol" ? s + "" : s, e);
4
+ import { p as f, d as F, s as I } from "./scorm12-DpGWvsHb.js";
5
+ import { S as Q, a as W, b as Y, c as Z, f as ss, i as es, t as ts } from "./scorm12-DpGWvsHb.js";
6
+ import { createScorm2004Connection as N } from "./scorm2004.js";
7
+ const x = "v:";
8
+ function g(t) {
9
+ return `${x}${t}`;
10
+ }
11
+ function y(t, s) {
12
+ for (const [e, n] of Object.entries(t.variables ?? {})) {
13
+ const i = g(e);
14
+ s[i] === void 0 && (s[i] = n.default);
25
15
  }
16
+ }
17
+ function _(t, s) {
18
+ return t[g(s)];
19
+ }
20
+ function $(t, s, e) {
21
+ t[g(s)] = e;
22
+ }
23
+ const R = [
24
+ (t, s) => {
25
+ var e;
26
+ if ("variable" in t && ((e = t.variable) != null && e.eq)) {
27
+ const [n, i] = t.variable.eq;
28
+ return s.getVariable(n) === i;
29
+ }
30
+ return null;
31
+ },
32
+ (t, s) => {
33
+ var e;
34
+ return "assessment" in t && ((e = t.assessment) != null && e.passed) ? s.isAssessmentPassed(t.assessment.passed) : null;
35
+ },
36
+ (t, s) => {
37
+ var e;
38
+ return "interaction" in t && ((e = t.interaction) != null && e.done) ? s.isInteractionDone(t.interaction.done) : null;
39
+ },
40
+ (t, s) => "all" in t && t.all ? t.all.every((e) => d(e, s)) : null,
41
+ (t, s) => "any" in t && t.any ? t.any.some((e) => d(e, s)) : null
42
+ ];
43
+ function d(t, s) {
44
+ for (const e of R) {
45
+ const n = e(t, s);
46
+ if (n !== null)
47
+ return n;
48
+ }
49
+ return !1;
50
+ }
51
+ function k(t, s) {
52
+ const e = t.flow;
53
+ if (!(e != null && e.length)) return null;
54
+ for (const n of e)
55
+ if (d(n.when, s))
56
+ return n.goto;
26
57
  return null;
27
58
  }
28
- class L {
59
+ class G {
29
60
  constructor(s) {
30
- i(this, "api");
31
- i(this, "initialized", !1);
32
- i(this, "terminated", !1);
33
- i(this, "lastError", "0");
34
- this.api = s;
35
- }
36
- LMSInitialize() {
37
- if (this.initialized)
38
- return this.lastError = "301", "false";
39
- const s = this.api.LMSInitialize("");
40
- return s === "true" && (this.initialized = !0, this.terminated = !1, this.lastError = "0"), s;
61
+ this.connection = s;
62
+ }
63
+ init() {
64
+ this.connection.LMSInitialize();
65
+ }
66
+ restoreProgress(s) {
67
+ const e = this.connection.LMSGetValue("cmi.suspend_data");
68
+ if (e) {
69
+ const { progress: i, parsed: c } = f(e, s);
70
+ if (c) return i;
71
+ const r = this.connection.LMSGetValue("cmi.core.lesson_location");
72
+ return r ? { ...s, currentLessonId: r } : s;
73
+ }
74
+ const n = this.connection.LMSGetValue("cmi.core.lesson_location");
75
+ return n ? { ...s, currentLessonId: n } : s;
41
76
  }
42
- LMSFinish() {
43
- if (!this.initialized || this.terminated)
44
- return this.lastError = "302", "false";
45
- const s = this.api.LMSFinish("");
46
- return s === "true" && (this.terminated = !0, this.lastError = "0"), s;
77
+ persist(s, e) {
78
+ this.connection.setSuspendData(e), this.connection.LMSCommit();
47
79
  }
48
- LMSGetValue(s) {
49
- return !this.initialized || this.terminated ? (this.lastError = "301", "") : (this.lastError = "0", this.api.LMSGetValue(s));
80
+ setLocation(s) {
81
+ this.connection.setLessonLocation(s);
50
82
  }
51
- LMSSetValue(s, e) {
52
- return !this.initialized || this.terminated ? (this.lastError = "301", "false") : (this.lastError = "0", this.api.LMSSetValue(s, e));
83
+ applyCompletion(s) {
84
+ this.connection.setScore(s.scorePercent), s.anyAssessmentFailed ? this.connection.setLessonStatus("failed") : s.ratio >= s.completionThreshold && s.allLessonsComplete && s.allAssessmentsPassed ? this.connection.setLessonStatus(
85
+ s.hasAssessments ? "passed" : "completed"
86
+ ) : s.scorePercent > 0 && this.connection.setLessonStatus("incomplete");
53
87
  }
54
- LMSCommit() {
55
- return !this.initialized || this.terminated ? (this.lastError = "301", "false") : (this.lastError = "0", this.api.LMSCommit(""));
88
+ terminate() {
89
+ this.connection.LMSFinish();
56
90
  }
57
- LMSGetLastError() {
58
- return this.lastError;
91
+ }
92
+ class B {
93
+ constructor(s) {
94
+ this.connection = s;
95
+ }
96
+ init() {
97
+ this.connection.Initialize();
98
+ }
99
+ restoreProgress(s) {
100
+ const e = this.connection.GetValue("cmi.suspend_data");
101
+ if (e) {
102
+ const { progress: i, parsed: c } = f(e, s);
103
+ if (c) return i;
104
+ const r = this.connection.GetValue("cmi.location");
105
+ return r ? { ...s, currentLessonId: r } : s;
106
+ }
107
+ const n = this.connection.GetValue("cmi.location");
108
+ return n ? { ...s, currentLessonId: n } : s;
59
109
  }
60
- LMSGetErrorString(s) {
61
- const e = s ?? this.lastError;
62
- return e === "301" ? "Not initialized" : e === "302" ? "Already terminated" : this.api.LMSGetErrorString(e);
110
+ persist(s, e) {
111
+ this.connection.setSuspendData(e), this.connection.Commit();
63
112
  }
64
- LMSGetDiagnostic(s) {
65
- return this.api.LMSGetDiagnostic(s ?? this.lastError);
113
+ setLocation(s) {
114
+ this.connection.setLocation(s);
66
115
  }
67
- setLessonStatus(s) {
68
- this.LMSSetValue("cmi.core.lesson_status", s);
116
+ applyCompletion(s) {
117
+ this.connection.setScoreScaled(s.ratio), s.anyAssessmentFailed ? (this.connection.setSuccessStatus("failed"), this.connection.setCompletionStatus("completed")) : s.ratio >= s.completionThreshold && s.allLessonsComplete && s.allAssessmentsPassed ? (this.connection.setSuccessStatus("passed"), this.connection.setCompletionStatus("completed")) : s.ratio > 0 && (this.connection.setCompletionStatus("incomplete"), this.connection.setSuccessStatus("unknown"));
69
118
  }
70
- setScore(s, e = 100) {
71
- this.LMSSetValue("cmi.core.score.raw", String(s)), this.LMSSetValue("cmi.core.score.max", String(e)), this.LMSSetValue("cmi.core.score.min", "0");
119
+ terminate() {
120
+ this.connection.Terminate();
72
121
  }
73
- setSuspendData(s) {
74
- const e = m(s);
75
- this.LMSSetValue("cmi.suspend_data", e);
122
+ }
123
+ class D {
124
+ constructor(s) {
125
+ this.storageKey = s;
76
126
  }
77
- setLessonLocation(s) {
78
- this.LMSSetValue("cmi.core.lesson_location", s);
127
+ init() {
79
128
  }
80
- }
81
- class h {
82
- constructor(s = {}) {
83
- i(this, "data", {
84
- lessonStatus: "not attempted",
85
- scoreRaw: 0,
86
- scoreMin: 0,
87
- scoreMax: 100,
88
- suspendData: "",
89
- lessonLocation: "",
90
- entry: "ab-initio",
91
- exit: "",
92
- sessionTime: "00:00:00"
93
- });
94
- i(this, "initialized", !1);
95
- i(this, "terminated", !1);
96
- i(this, "lastError", "0");
97
- i(this, "persistToStorage");
98
- this.persistToStorage = s.persistToStorage ?? !1, s.initialData && (this.data = { ...this.data, ...s.initialData }), this.persistToStorage && this.loadFromStorage();
99
- }
100
- LMSInitialize() {
101
- return this.initialized ? (this.lastError = "301", "false") : (this.initialized = !0, this.terminated = !1, this.lastError = "0", "true");
102
- }
103
- LMSFinish() {
104
- return !this.initialized || this.terminated ? (this.lastError = "302", "false") : (this.data.exit = "suspend", this.terminated = !0, this.saveToStorage(), this.lastError = "0", "true");
105
- }
106
- LMSGetValue(s) {
107
- if (!this.initialized || this.terminated)
108
- return this.lastError = "301", "";
109
- switch (this.lastError = "0", s) {
110
- case "cmi.core.lesson_status":
111
- return this.data.lessonStatus;
112
- case "cmi.core.score.raw":
113
- return String(this.data.scoreRaw);
114
- case "cmi.core.score.min":
115
- return String(this.data.scoreMin);
116
- case "cmi.core.score.max":
117
- return String(this.data.scoreMax);
118
- case "cmi.suspend_data":
119
- return this.data.suspendData;
120
- case "cmi.core.lesson_location":
121
- return this.data.lessonLocation;
122
- case "cmi.core.student_id":
123
- return "lxpack-learner";
124
- case "cmi.core.student_name":
125
- return "LXPack Learner";
126
- case "cmi.core.entry":
127
- return this.data.entry;
128
- case "cmi.core.exit":
129
- return this.data.exit;
130
- case "cmi.core.session_time":
131
- return this.data.sessionTime;
132
- default:
133
- return "";
129
+ restoreProgress(s) {
130
+ try {
131
+ const e = localStorage.getItem(this.storageKey);
132
+ if (e) {
133
+ const { progress: n, parsed: i } = f(e, s);
134
+ if (i) return n;
135
+ }
136
+ } catch {
134
137
  }
138
+ return s;
135
139
  }
136
- LMSSetValue(s, e) {
137
- if (!this.initialized || this.terminated)
138
- return this.lastError = "301", "false";
139
- switch (this.lastError = "0", s) {
140
- case "cmi.core.lesson_status":
141
- this.data.lessonStatus = e;
142
- break;
143
- case "cmi.core.score.raw":
144
- this.data.scoreRaw = Number(e);
145
- break;
146
- case "cmi.core.score.min":
147
- this.data.scoreMin = Number(e);
148
- break;
149
- case "cmi.core.score.max":
150
- this.data.scoreMax = Number(e);
151
- break;
152
- case "cmi.suspend_data":
153
- this.data.suspendData = m(e);
154
- break;
155
- case "cmi.core.lesson_location":
156
- this.data.lessonLocation = e;
157
- break;
158
- case "cmi.core.exit":
159
- this.data.exit = e;
160
- break;
161
- case "cmi.core.session_time":
162
- this.data.sessionTime = e;
163
- break;
164
- default:
165
- return "false";
140
+ persist(s, e) {
141
+ try {
142
+ localStorage.setItem(this.storageKey, e);
143
+ } catch {
166
144
  }
167
- return this.saveToStorage(), "true";
168
145
  }
169
- LMSCommit() {
170
- return !this.initialized || this.terminated ? (this.lastError = "301", "false") : (this.saveToStorage(), this.lastError = "0", "true");
146
+ setLocation(s) {
171
147
  }
172
- LMSGetLastError() {
173
- return this.lastError;
148
+ applyCompletion(s) {
174
149
  }
175
- LMSGetErrorString(s) {
176
- const e = s ?? this.lastError;
177
- return e === "301" ? "Not initialized" : e === "302" ? "Already terminated" : "No error";
150
+ terminate() {
178
151
  }
179
- LMSGetDiagnostic() {
180
- return "";
152
+ }
153
+ function K(t, s) {
154
+ const e = `${t}::${s}`;
155
+ let n = 0;
156
+ for (let i = 0; i < e.length; i++)
157
+ n = (n << 5) - n + e.charCodeAt(i), n |= 0;
158
+ return `lxpack_progress_${Math.abs(n)}`;
159
+ }
160
+ function z(t, s) {
161
+ return t === "scorm12" ? new G(F("scorm12")) : t === "scorm2004" ? new B(N("scorm2004")) : t === "preview" || t === "standalone" ? new D(s) : new D(s);
162
+ }
163
+ function S(t, s) {
164
+ const e = t[`assessment_attempts_${s}`];
165
+ return typeof e == "number" ? e : typeof e == "string" && e !== "" && !Number.isNaN(Number(e)) ? Number(e) : 0;
166
+ }
167
+ function O(t, s) {
168
+ const e = S(t, s) + 1;
169
+ return t[`assessment_attempts_${s}`] = e, e;
170
+ }
171
+ class j {
172
+ constructor(s, e, n) {
173
+ a(this, "progress");
174
+ a(this, "passedAssessments", /* @__PURE__ */ new Set());
175
+ this.manifest = e, this.defaultPassingScores = n, this.progress = s, this.syncPassedAssessments();
181
176
  }
182
- setLessonStatus(s) {
183
- this.data.lessonStatus = s, this.saveToStorage();
177
+ getAssessmentPassingScore(s) {
178
+ const e = this.progress.suspendData[`assessment_passing_${s}`];
179
+ return typeof e == "number" ? e : s in this.defaultPassingScores ? this.defaultPassingScores[s] : 0.7;
184
180
  }
185
- setScore(s, e = 100) {
186
- this.data.scoreRaw = s, this.data.scoreMax = e, this.data.scoreMin = 0, this.saveToStorage();
181
+ syncPassedAssessments() {
182
+ this.passedAssessments.clear();
183
+ for (const [s, e] of Object.entries(this.progress.assessmentScores))
184
+ e >= this.getAssessmentPassingScore(s) && this.passedAssessments.add(s);
187
185
  }
188
- setSuspendData(s) {
189
- this.data.suspendData = m(s), this.saveToStorage();
186
+ applyAssessmentResult(s, e, n) {
187
+ this.progress.assessmentScores[s] = e, this.progress.suspendData[`assessment_passing_${s}`] = n, e >= n ? this.passedAssessments.add(s) : this.passedAssessments.delete(s);
190
188
  }
191
- setLessonLocation(s) {
192
- this.data.lessonLocation = s, this.saveToStorage();
189
+ recordAssessmentAttempt(s) {
190
+ return O(this.progress.suspendData, s);
193
191
  }
194
- loadFromStorage() {
195
- try {
196
- const s = localStorage.getItem(S);
197
- s && (this.data = { ...this.data, ...JSON.parse(s) });
198
- } catch {
199
- }
192
+ getAssessmentAttemptCount(s) {
193
+ return S(this.progress.suspendData, s);
200
194
  }
201
- saveToStorage() {
202
- if (this.persistToStorage)
203
- try {
204
- localStorage.setItem(S, JSON.stringify(this.data));
205
- } catch {
206
- }
195
+ completeLesson(s) {
196
+ new Set(this.manifest.lessons.map((n) => n.id)).has(s) && (this.progress.completedLessons.includes(s) || this.progress.completedLessons.push(s));
207
197
  }
208
- }
209
- class D extends h {
210
- constructor() {
211
- super({ persistToStorage: !0 });
198
+ setCurrentLesson(s) {
199
+ this.progress.currentLessonId = s;
212
200
  }
213
- }
214
- function m(t) {
215
- return t.length <= 4096 ? t : (console.warn(
216
- "[lxpack] suspend_data exceeds 4096 chars; truncating"
217
- ), t.slice(0, 4096));
218
- }
219
- function R(t) {
220
- if (t === "preview")
221
- return new h({ persistToStorage: !0 });
222
- if (t === "scorm12") {
223
- const s = _();
224
- return s ? new L(s) : (console.warn(
225
- "[lxpack] No LMS SCORM API found; using in-memory simulator (progress will not persist to LMS)"
226
- ), new h({ persistToStorage: !1 }));
227
- }
228
- return new h({ persistToStorage: !1 });
229
- }
230
- function C(t = "preview") {
231
- const s = R(t);
232
- if (t === "preview") {
233
- const e = window;
234
- e.API = s;
201
+ isLessonComplete(s) {
202
+ return this.progress.completedLessons.includes(s);
203
+ }
204
+ isAssessmentPassed(s) {
205
+ return this.passedAssessments.has(s);
206
+ }
207
+ getAssessmentPassingScoreForTrack(s) {
208
+ return this.getAssessmentPassingScore(s);
235
209
  }
236
- return s;
237
- }
238
- function d(t) {
239
- var e;
240
- const s = {
241
- c: t.currentLessonId,
242
- l: t.completedLessons,
243
- a: t.assessmentScores,
244
- s: t.suspendData
245
- };
246
- return (e = s.l) != null && e.length || delete s.l, (!s.a || !Object.keys(s.a).length) && delete s.a, (!s.s || !Object.keys(s.s).length) && delete s.s, s;
247
- }
248
- function E(t, s) {
249
- return {
250
- currentLessonId: t.c ?? s.currentLessonId,
251
- completedLessons: Array.isArray(t.l) ? t.l : s.completedLessons,
252
- assessmentScores: t.a && typeof t.a == "object" ? t.a : s.assessmentScores,
253
- suspendData: t.s && typeof t.s == "object" ? t.s : s.suspendData
254
- };
255
- }
256
- function O(t) {
257
- const s = { ...t.suspendData }, e = Object.keys(s).filter((r) => r.startsWith("interaction_")).sort();
258
- for (const r of e)
259
- if (delete s[r], JSON.stringify(d({ ...t, suspendData: s })).length <= 4096)
260
- return { ...t, suspendData: s };
261
- return { ...t, suspendData: s };
262
- }
263
- function M(t) {
264
- let s = JSON.stringify(d(t));
265
- if (s.length <= 4096)
266
- return s;
267
- const e = O(t);
268
- return s = JSON.stringify(d(e)), s.length <= 4096 ? s : (console.warn(
269
- "[lxpack] suspend_data exceeds 4096 chars; truncating"
270
- ), s.slice(0, 4096));
271
- }
272
- function A(t) {
273
- if (!t || typeof t != "object") return !1;
274
- const s = t;
275
- return "currentLessonId" in s || "completedLessons" in s || "assessmentScores" in s;
276
210
  }
277
- function N(t, s) {
211
+ function w(t, s) {
212
+ var A, L, C, P;
213
+ const { manifest: e, completionThreshold: n, passedAssessments: i } = s, c = e.lessons.length, r = ((A = e.assessments) == null ? void 0 : A.length) ?? 0, l = c + r, m = t.completedLessons.filter(
214
+ (o) => e.lessons.some((p) => p.id === o)
215
+ ).length, u = l === 0 ? 0 : (m + i.size) / l, h = e.lessons.every(
216
+ (o) => t.completedLessons.includes(o.id)
217
+ ), V = !((L = e.assessments) != null && L.length) || e.assessments.every((o) => i.has(o.id)), v = (C = e.assessments) == null ? void 0 : C.some((o) => {
218
+ var b;
219
+ if (!(o.id in t.assessmentScores) || i.has(o.id)) return !1;
220
+ const p = ((b = s.assessmentConfigs[o.id]) == null ? void 0 : b.maxAttempts) ?? 1;
221
+ return S(t.suspendData, o.id) >= p;
222
+ });
278
223
  return {
279
- currentLessonId: t.currentLessonId ?? s.currentLessonId,
280
- completedLessons: Array.isArray(t.completedLessons) ? t.completedLessons : s.completedLessons,
281
- assessmentScores: t.assessmentScores && typeof t.assessmentScores == "object" ? t.assessmentScores : s.assessmentScores,
282
- suspendData: t.suspendData && typeof t.suspendData == "object" ? t.suspendData : s.suspendData
224
+ ratio: u,
225
+ scorePercent: Math.round(u * 100),
226
+ allLessonsComplete: h,
227
+ allAssessmentsPassed: V,
228
+ anyAssessmentFailed: !!v,
229
+ hasAssessments: (((P = e.assessments) == null ? void 0 : P.length) ?? 0) > 0,
230
+ completionThreshold: n
283
231
  };
284
232
  }
285
- function p(t, s) {
286
- try {
287
- const e = JSON.parse(t);
288
- return A(e) ? {
289
- progress: N(e, s),
290
- parsed: !0
291
- } : { progress: E(e, s), parsed: !0 };
292
- } catch {
293
- return { progress: s, parsed: !1 };
294
- }
295
- }
296
- function I(t) {
297
- const s = `${t.title}::${t.version}`;
298
- let e = 0;
299
- for (let r = 0; r < s.length; r++)
300
- e = (e << 5) - e + s.charCodeAt(r), e |= 0;
301
- return `lxpack_progress_${Math.abs(e)}`;
302
- }
303
- class y {
233
+ class X {
304
234
  constructor(s) {
305
- i(this, "manifest");
306
- i(this, "progress");
307
- i(this, "scorm", null);
308
- i(this, "completionThreshold");
309
- i(this, "storageKey");
310
- i(this, "mode");
311
- i(this, "passedAssessments", /* @__PURE__ */ new Set());
312
- i(this, "defaultPassingScores");
313
- i(this, "terminated", !1);
314
- var r, a, o;
315
- this.manifest = s.manifest, this.mode = s.mode, this.completionThreshold = ((a = (r = s.manifest.tracking) == null ? void 0 : r.completion) == null ? void 0 : a.threshold) ?? 0.9, this.storageKey = I(s.manifest), this.defaultPassingScores = {};
316
- for (const [n, l] of Object.entries(s.assessments ?? {}))
317
- this.defaultPassingScores[n] = l.passingScore;
318
- const e = ((o = s.manifest.lessons[0]) == null ? void 0 : o.id) ?? "";
319
- this.progress = s.progress ?? {
320
- currentLessonId: e,
235
+ a(this, "manifest");
236
+ a(this, "state");
237
+ a(this, "bridge");
238
+ a(this, "completionThreshold");
239
+ a(this, "assessmentConfigs");
240
+ a(this, "defaultPassingScores");
241
+ a(this, "terminated", !1);
242
+ var r, l, m;
243
+ this.manifest = s.manifest, this.completionThreshold = ((l = (r = s.manifest.tracking) == null ? void 0 : r.completion) == null ? void 0 : l.threshold) ?? 0.9;
244
+ const e = K(
245
+ s.manifest.title,
246
+ s.manifest.version
247
+ );
248
+ this.bridge = z(s.mode, e), this.defaultPassingScores = {};
249
+ for (const [u, h] of Object.entries(s.assessments ?? {}))
250
+ this.defaultPassingScores[u] = h.passingScore;
251
+ this.assessmentConfigs = s.assessmentConfigs ?? {};
252
+ const n = s.activityId ?? ((m = s.manifest.lessons[0]) == null ? void 0 : m.id) ?? "", i = s.progress ?? {
253
+ currentLessonId: n,
321
254
  completedLessons: [],
322
255
  assessmentScores: {},
323
256
  suspendData: {}
324
- }, s.mode === "scorm12" ? (this.scorm = R("scorm12"), this.scorm.LMSInitialize(), this.restoreScormProgress()) : (s.mode === "preview" || s.mode === "standalone") && this.restoreLocalProgress();
325
- }
326
- restoreLessonLocation() {
327
- if (!this.scorm) return;
328
- const s = this.scorm.LMSGetValue("cmi.core.lesson_location");
329
- s && (this.progress.currentLessonId = s);
330
- }
331
- restoreScormProgress() {
332
- if (!this.scorm) return;
333
- const s = this.scorm.LMSGetValue("cmi.suspend_data");
334
- if (s) {
335
- const { progress: e, parsed: r } = p(s, this.progress);
336
- r ? this.progress = e : this.restoreLessonLocation();
337
- } else
338
- this.restoreLessonLocation();
339
- this.syncPassedAssessments();
340
- }
341
- restoreLocalProgress() {
342
- try {
343
- const s = localStorage.getItem(this.storageKey);
344
- if (s) {
345
- const { progress: e, parsed: r } = p(s, this.progress);
346
- r && (this.progress = e);
347
- }
348
- } catch {
349
- }
350
- this.syncPassedAssessments();
351
- }
352
- syncPassedAssessments() {
353
- this.passedAssessments.clear();
354
- for (const [s, e] of Object.entries(this.progress.assessmentScores))
355
- e >= this.getAssessmentPassingScore(s) && this.passedAssessments.add(s);
356
- }
357
- getAssessmentPassingScore(s) {
358
- const e = this.progress.suspendData[`assessment_passing_${s}`];
359
- return typeof e == "number" ? e : s in this.defaultPassingScores ? this.defaultPassingScores[s] : 0.7;
257
+ };
258
+ y(this.manifest, i.suspendData), this.bridge.init();
259
+ const c = this.bridge.restoreProgress(i);
260
+ this.state = new j(
261
+ c,
262
+ this.manifest,
263
+ this.defaultPassingScores
264
+ ), y(this.manifest, this.state.progress.suspendData), this.state.syncPassedAssessments(), s.activityId && this.state.setCurrentLesson(s.activityId);
360
265
  }
361
266
  getAPI() {
362
267
  return {
363
268
  track: (s) => this.track(s),
364
269
  completeLesson: (s) => this.completeLesson(s),
365
- getProgress: () => ({
366
- ...this.progress,
367
- completedLessons: [...this.progress.completedLessons],
368
- assessmentScores: { ...this.progress.assessmentScores },
369
- suspendData: { ...this.progress.suspendData }
370
- }),
270
+ getProgress: () => this.getProgress(),
371
271
  setVariable: (s, e) => {
372
- this.progress.suspendData[s] = e, this.persist();
272
+ this.manifest.variables && s in this.manifest.variables ? $(this.state.progress.suspendData, s, e) : this.state.progress.suspendData[s] = e, this.persist();
373
273
  },
374
- getVariable: (s) => this.progress.suspendData[s],
375
- submitAssessment: (s, e, r) => this.submitAssessment(s, e, r)
274
+ getVariable: (s) => this.manifest.variables && s in this.manifest.variables ? _(this.state.progress.suspendData, s) : this.state.progress.suspendData[s],
275
+ submitAssessment: (s, e, n) => this.submitAssessment(s, e, n)
376
276
  };
377
277
  }
378
278
  track(s, e) {
379
- var r, a;
380
- if (s.type === "interaction" && s.id && (this.progress.suspendData[`interaction_${s.id}`] = s.data ?? !0, console.debug("[lxpack] interaction:", s.id, s.data)), s.type === "assessment" && s.id) {
381
- const o = typeof ((r = s.data) == null ? void 0 : r.passingScore) == "number" ? Number(s.data.passingScore) : this.getAssessmentPassingScore(s.id), n = ((a = s.data) == null ? void 0 : a.score) != null ? Number(s.data.score) : void 0;
382
- if (n != null && !Number.isNaN(n)) {
383
- this.applyAssessmentResult(s.id, n, o), (e == null ? void 0 : e.persist) !== !1 && (this.updateCompletion(), this.persist());
279
+ var n, i;
280
+ if (s.type === "interaction" && s.id && (this.state.progress.suspendData[`interaction_${s.id}`] = s.data ?? !0, console.debug("[lxpack] interaction:", s.id, s.data)), s.type === "assessment" && s.id) {
281
+ const c = typeof ((n = s.data) == null ? void 0 : n.passingScore) == "number" ? Number(s.data.passingScore) : this.state.getAssessmentPassingScoreForTrack(s.id), r = ((i = s.data) == null ? void 0 : i.score) != null ? Number(s.data.score) : void 0;
282
+ if (r != null && !Number.isNaN(r)) {
283
+ this.state.applyAssessmentResult(s.id, r, c), (e == null ? void 0 : e.persist) !== !1 && (this.updateCompletion(), this.persist());
384
284
  return;
385
285
  }
386
286
  }
387
287
  (e == null ? void 0 : e.persist) !== !1 && this.persist();
388
288
  }
389
- applyAssessmentResult(s, e, r) {
390
- this.progress.assessmentScores[s] = e, this.progress.suspendData[`assessment_passing_${s}`] = r, e >= r ? this.passedAssessments.add(s) : this.passedAssessments.delete(s);
289
+ recordAssessmentAttempt(s) {
290
+ return this.state.recordAssessmentAttempt(s);
391
291
  }
392
- submitAssessment(s, e, r) {
393
- this.applyAssessmentResult(s, e, r), this.updateCompletion(), this.persist();
292
+ getAssessmentAttemptCount(s) {
293
+ return this.state.getAssessmentAttemptCount(s);
294
+ }
295
+ submitAssessment(s, e, n) {
296
+ this.state.recordAssessmentAttempt(s), this.state.applyAssessmentResult(s, e, n), this.updateCompletion(), this.persist();
394
297
  }
395
298
  completeLesson(s) {
396
- new Set(this.manifest.lessons.map((r) => r.id)).has(s) && (this.progress.completedLessons.includes(s) || this.progress.completedLessons.push(s), this.updateCompletion(), this.persist());
299
+ this.state.completeLesson(s), this.updateCompletion(), this.persist();
397
300
  }
398
301
  setCurrentLesson(s) {
399
- this.progress.currentLessonId = s, this.scorm && this.scorm.setLessonLocation(s), this.persist();
302
+ this.state.setCurrentLesson(s), this.bridge.setLocation(s), this.persist();
400
303
  }
401
304
  getProgress() {
402
- return this.getAPI().getProgress();
305
+ const s = this.state.progress;
306
+ return {
307
+ ...s,
308
+ completedLessons: [...s.completedLessons],
309
+ assessmentScores: { ...s.assessmentScores },
310
+ suspendData: { ...s.suspendData }
311
+ };
403
312
  }
404
313
  getManifest() {
405
314
  return this.manifest;
406
315
  }
407
316
  isLessonComplete(s) {
408
- return this.progress.completedLessons.includes(s);
317
+ return this.state.isLessonComplete(s);
409
318
  }
410
319
  isAssessmentPassed(s) {
411
- return this.passedAssessments.has(s);
320
+ return this.state.isAssessmentPassed(s);
412
321
  }
413
322
  getTotalUnits() {
414
323
  var e;
@@ -416,48 +325,50 @@ class y {
416
325
  return this.manifest.lessons.length + s;
417
326
  }
418
327
  getCompletionRatio() {
419
- var n;
420
- if (this.getTotalUnits() === 0) return 0;
421
- const e = this.manifest.lessons.length, r = ((n = this.manifest.assessments) == null ? void 0 : n.length) ?? 0, a = this.progress.completedLessons.filter(
422
- (l) => this.manifest.lessons.some((u) => u.id === l)
423
- ).length, o = this.passedAssessments.size;
424
- return (a + o) / (e + r);
328
+ return w(this.state.progress, {
329
+ manifest: this.manifest,
330
+ completionThreshold: this.completionThreshold,
331
+ assessmentConfigs: this.assessmentConfigs,
332
+ defaultPassingScores: this.defaultPassingScores,
333
+ passedAssessments: this.state.passedAssessments
334
+ }).ratio;
425
335
  }
426
336
  updateCompletion() {
427
- var r, a, o;
428
- const s = this.getCompletionRatio(), e = Math.round(s * 100);
429
- if (this.scorm) {
430
- this.scorm.setScore(e);
431
- const n = this.manifest.lessons.every(
432
- (c) => this.progress.completedLessons.includes(c.id)
433
- ), l = !((r = this.manifest.assessments) != null && r.length) || this.manifest.assessments.every((c) => this.passedAssessments.has(c.id));
434
- ((a = this.manifest.assessments) == null ? void 0 : a.some(
435
- (c) => c.id in this.progress.assessmentScores && !this.passedAssessments.has(c.id)
436
- )) ? this.scorm.setLessonStatus("failed") : s >= this.completionThreshold && n && l ? this.scorm.setLessonStatus(
437
- (((o = this.manifest.assessments) == null ? void 0 : o.length) ?? 0) > 0 ? "passed" : "completed"
438
- ) : e > 0 && this.scorm.setLessonStatus("incomplete");
439
- }
337
+ const s = w(this.state.progress, {
338
+ manifest: this.manifest,
339
+ completionThreshold: this.completionThreshold,
340
+ assessmentConfigs: this.assessmentConfigs,
341
+ defaultPassingScores: this.defaultPassingScores,
342
+ passedAssessments: this.state.passedAssessments
343
+ });
344
+ this.bridge.applyCompletion(s);
440
345
  }
441
346
  persist() {
442
- const s = M(this.progress);
443
- if (this.mode === "preview" || this.mode === "standalone")
444
- try {
445
- localStorage.setItem(this.storageKey, s);
446
- } catch {
447
- }
448
- this.scorm && (this.scorm.setSuspendData(s), this.scorm.LMSCommit());
347
+ const s = I(this.state.progress);
348
+ this.bridge.persist(this.state.progress, s);
349
+ }
350
+ getFlowContext() {
351
+ return {
352
+ getVariable: (s) => _(this.state.progress.suspendData, s),
353
+ isAssessmentPassed: (s) => this.isAssessmentPassed(s),
354
+ isInteractionDone: (s) => this.state.progress.suspendData[`interaction_${s}`] !== void 0
355
+ };
356
+ }
357
+ resolveFlowNavigation() {
358
+ return k(this.manifest, this.getFlowContext());
449
359
  }
450
360
  terminate() {
451
- this.terminated || (this.terminated = !0, this.scorm && this.scorm.LMSFinish());
361
+ this.terminated || (this.terminated = !0, this.bridge.terminate());
452
362
  }
453
363
  }
454
364
  export {
455
- y as LxpackRuntime,
456
- D as Scorm12API,
457
- L as Scorm12Adapter,
458
- h as Scorm12Simulator,
459
- R as createScormConnection,
460
- _ as findLmsApi,
461
- C as installScormAPI,
462
- m as trimSuspendData
365
+ X as LxpackRuntime,
366
+ Q as SCORM_SUSPEND_DATA_MAX,
367
+ W as Scorm12API,
368
+ Y as Scorm12Adapter,
369
+ Z as Scorm12Simulator,
370
+ F as createScormConnection,
371
+ ss as findLmsApi,
372
+ es as installScormAPI,
373
+ ts as trimSuspendData
463
374
  };