@contractspec/example.learning-journey-registry 0.0.0-canary-20260113170453

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 (63) hide show
  1. package/.turbo/turbo-build$colon$bundle.log +50 -0
  2. package/.turbo/turbo-build.log +51 -0
  3. package/CHANGELOG.md +612 -0
  4. package/LICENSE +21 -0
  5. package/README.md +25 -0
  6. package/dist/api-types.d.ts +41 -0
  7. package/dist/api-types.d.ts.map +1 -0
  8. package/dist/api-types.js +0 -0
  9. package/dist/api.d.ts +13 -0
  10. package/dist/api.d.ts.map +1 -0
  11. package/dist/api.js +171 -0
  12. package/dist/api.js.map +1 -0
  13. package/dist/docs/index.d.ts +1 -0
  14. package/dist/docs/index.js +1 -0
  15. package/dist/docs/learning-journey-registry.docblock.d.ts +1 -0
  16. package/dist/docs/learning-journey-registry.docblock.js +38 -0
  17. package/dist/docs/learning-journey-registry.docblock.js.map +1 -0
  18. package/dist/example.d.ts +7 -0
  19. package/dist/example.d.ts.map +1 -0
  20. package/dist/example.js +42 -0
  21. package/dist/example.js.map +1 -0
  22. package/dist/index.d.ts +8 -0
  23. package/dist/index.js +10 -0
  24. package/dist/learning-journey-registry.feature.d.ts +12 -0
  25. package/dist/learning-journey-registry.feature.d.ts.map +1 -0
  26. package/dist/learning-journey-registry.feature.js +75 -0
  27. package/dist/learning-journey-registry.feature.js.map +1 -0
  28. package/dist/presentations/index.d.ts +10 -0
  29. package/dist/presentations/index.d.ts.map +1 -0
  30. package/dist/presentations/index.js +71 -0
  31. package/dist/presentations/index.js.map +1 -0
  32. package/dist/progress-store.d.ts +11 -0
  33. package/dist/progress-store.d.ts.map +1 -0
  34. package/dist/progress-store.js +31 -0
  35. package/dist/progress-store.js.map +1 -0
  36. package/dist/tracks.d.ts +40 -0
  37. package/dist/tracks.d.ts.map +1 -0
  38. package/dist/tracks.js +48 -0
  39. package/dist/tracks.js.map +1 -0
  40. package/dist/ui/LearningMiniApp.d.ts +24 -0
  41. package/dist/ui/LearningMiniApp.d.ts.map +1 -0
  42. package/dist/ui/LearningMiniApp.js +80 -0
  43. package/dist/ui/LearningMiniApp.js.map +1 -0
  44. package/dist/ui/index.d.ts +2 -0
  45. package/dist/ui/index.js +3 -0
  46. package/example.ts +1 -0
  47. package/package.json +86 -0
  48. package/src/api-types.ts +43 -0
  49. package/src/api.test.ts +46 -0
  50. package/src/api.ts +301 -0
  51. package/src/docs/index.ts +1 -0
  52. package/src/docs/learning-journey-registry.docblock.ts +36 -0
  53. package/src/example.ts +31 -0
  54. package/src/index.ts +8 -0
  55. package/src/learning-journey-registry.feature.ts +64 -0
  56. package/src/presentations/index.ts +65 -0
  57. package/src/progress-store.ts +39 -0
  58. package/src/tracks.ts +91 -0
  59. package/src/ui/LearningMiniApp.tsx +121 -0
  60. package/src/ui/index.ts +5 -0
  61. package/tsconfig.json +9 -0
  62. package/tsconfig.tsbuildinfo +1 -0
  63. package/tsdown.config.js +17 -0
@@ -0,0 +1,41 @@
1
+ import { LearningJourneyTrackSpec } from "@contractspec/module.learning-journey/track-spec";
2
+
3
+ //#region src/api-types.d.ts
4
+ interface LearningEvent {
5
+ name: string;
6
+ version?: number;
7
+ sourceModule?: string;
8
+ payload?: Record<string, unknown>;
9
+ occurredAt?: Date;
10
+ learnerId: string;
11
+ trackId?: string;
12
+ }
13
+ type StepStatus = 'PENDING' | 'COMPLETED';
14
+ interface StepProgress {
15
+ id: string;
16
+ status: StepStatus;
17
+ xpEarned: number;
18
+ completedAt?: Date;
19
+ triggeringEvent?: string;
20
+ eventPayload?: Record<string, unknown>;
21
+ occurrences?: number;
22
+ counterStartedAt?: Date;
23
+ availableAt?: Date;
24
+ dueAt?: Date;
25
+ masteryCount?: number;
26
+ }
27
+ interface TrackProgress {
28
+ learnerId: string;
29
+ trackId: string;
30
+ progress: number;
31
+ isCompleted: boolean;
32
+ xpEarned: number;
33
+ startedAt?: Date;
34
+ completedAt?: Date;
35
+ lastActivityAt?: Date;
36
+ steps: StepProgress[];
37
+ }
38
+ type TrackResolver = (trackId: string) => LearningJourneyTrackSpec | undefined;
39
+ //#endregion
40
+ export { LearningEvent, StepProgress, StepStatus, TrackProgress, TrackResolver };
41
+ //# sourceMappingURL=api-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-types.d.ts","names":[],"sources":["../src/api-types.ts"],"sourcesContent":[],"mappings":";;;UAEiB,aAAA;;EAAA,OAAA,CAAA,EAAA,MAAa;EAUlB,YAAA,CAAU,EAAA,MAAA;EAEL,OAAA,CAAA,EARL,MAQiB,CAAA,MAAA,EAAA,OAAA,CAAA;EAEnB,UAAA,CAAA,EATK,IASL;EAEM,SAAA,EAAA,MAAA;EAEC,OAAA,CAAA,EAAA,MAAA;;AAGD,KAXJ,UAAA,GAWI,SAAA,GAAA,WAAA;AACN,UAVO,YAAA,CAUP;EAAI,EAAA,EAAA,MAAA;EAIG,MAAA,EAZP,UAYoB;EAMhB,QAAA,EAAA,MAAA;EACE,WAAA,CAAA,EAjBA,IAiBA;EACG,eAAA,CAAA,EAAA,MAAA;EACV,YAAA,CAAA,EAjBQ,MAiBR,CAAA,MAAA,EAAA,OAAA,CAAA;EAAY,WAAA,CAAA,EAAA,MAAA;EAGT,gBAAa,CAAA,EAlBJ,IAkBI;gBAjBT;UACN;;;UAIO,aAAA;;;;;;cAMH;gBACE;mBACG;SACV;;KAGG,aAAA,wBAEP"}
File without changes
package/dist/api.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { LearningEvent, TrackProgress } from "./api-types.js";
2
+ import { LearningJourneyTrackSpec } from "@contractspec/module.learning-journey/track-spec";
3
+
4
+ //#region src/api.d.ts
5
+ declare const listTracks: (learnerId?: string) => {
6
+ tracks: LearningJourneyTrackSpec[];
7
+ progress: TrackProgress[];
8
+ };
9
+ declare const getProgress: (trackId: string, learnerId: string) => TrackProgress | undefined;
10
+ declare const recordEvent: (event: LearningEvent) => TrackProgress[];
11
+ //#endregion
12
+ export { getProgress, listTracks, recordEvent };
13
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","names":[],"sources":["../src/api.ts"],"sourcesContent":[],"mappings":";;;;cAyLa;UAWZ;EAXY,QAAA,EAWZ,aAAA,EAAA;AAED,CAAA;AAUa,cAVA,WAUsB,EAAA,CAAA,OAAA,EAAA,MAAa,EAAA,SAAA,EAAA,MAAA,EAAA,GAVc,aAUd,GAAA,SAAA;cAAnC,qBAAsB,kBAAa"}
package/dist/api.js ADDED
@@ -0,0 +1,171 @@
1
+ import { learningJourneyTracks } from "./tracks.js";
2
+ import { getLearnerTracks, getTrackResolver, initProgress } from "./progress-store.js";
3
+
4
+ //#region src/api.ts
5
+ const getTrack = getTrackResolver(learningJourneyTracks);
6
+ const matchesFilter = (filter, payload) => {
7
+ if (!filter) return true;
8
+ if (!payload) return false;
9
+ return Object.entries(filter).every(([key, value]) => payload[key] === value);
10
+ };
11
+ const matchesBaseEvent = (condition, event) => {
12
+ if (condition.eventName !== event.name) return false;
13
+ if (condition.eventVersion !== void 0 && event.version !== void 0) {
14
+ if (condition.eventVersion !== event.version) return false;
15
+ }
16
+ if (condition.sourceModule && event.sourceModule && condition.sourceModule !== event.sourceModule) return false;
17
+ return matchesFilter(condition.payloadFilter, event.payload);
18
+ };
19
+ const matchesCondition = (condition, event, step, trackStartedAt) => {
20
+ if (condition.kind === "count") {
21
+ if (!matchesBaseEvent(condition, event)) return { matched: false };
22
+ const occurrences = (step.occurrences ?? 0) + 1;
23
+ return {
24
+ matched: (condition.withinHours === void 0 || Boolean(trackStartedAt && event.occurredAt && (event.occurredAt.getTime() - trackStartedAt.getTime()) / (1e3 * 60 * 60) <= condition.withinHours)) && occurrences >= condition.atLeast,
25
+ occurrences
26
+ };
27
+ }
28
+ if (condition.kind === "time_window") {
29
+ if (!matchesBaseEvent(condition, event)) return { matched: false };
30
+ if (condition.withinHoursOfStart !== void 0 && trackStartedAt && event.occurredAt) {
31
+ if ((event.occurredAt.getTime() - trackStartedAt.getTime()) / (1e3 * 60 * 60) > condition.withinHoursOfStart) return { matched: false };
32
+ }
33
+ return { matched: true };
34
+ }
35
+ if (condition.kind === "srs_mastery") {
36
+ if (event.name !== condition.eventName) return { matched: false };
37
+ const payload = event.payload;
38
+ if (!matchesFilter(condition.payloadFilter, payload)) return { matched: false };
39
+ const skillKey = condition.skillIdField ?? "skillId";
40
+ const masteryKey = condition.masteryField ?? "mastery";
41
+ const skillId = payload?.[skillKey];
42
+ const masteryValue = payload?.[masteryKey];
43
+ if (skillId === void 0 || masteryValue === void 0) return { matched: false };
44
+ if (typeof masteryValue !== "number") return { matched: false };
45
+ if (masteryValue < condition.minimumMastery) return { matched: false };
46
+ const masteryCount = (step.masteryCount ?? 0) + 1;
47
+ return {
48
+ matched: masteryCount >= (condition.requiredCount ?? 1),
49
+ masteryCount
50
+ };
51
+ }
52
+ return { matched: matchesBaseEvent(condition, event) };
53
+ };
54
+ const getAvailability = (availability, startedAt) => {
55
+ if (!availability || !startedAt) return {};
56
+ const baseTime = startedAt.getTime();
57
+ let unlockTime = baseTime;
58
+ if (availability.unlockOnDay !== void 0) unlockTime = baseTime + (availability.unlockOnDay - 1) * 24 * 60 * 60 * 1e3;
59
+ if (availability.unlockAfterHours !== void 0) unlockTime = baseTime + availability.unlockAfterHours * 60 * 60 * 1e3;
60
+ const availableAt = new Date(unlockTime);
61
+ return {
62
+ availableAt,
63
+ dueAt: availability.dueWithinHours !== void 0 ? new Date(availableAt.getTime() + availability.dueWithinHours * 60 * 60 * 1e3) : void 0
64
+ };
65
+ };
66
+ const computeProgressPercent = (steps) => {
67
+ const total = steps.length || 1;
68
+ const done = steps.filter((s) => s.status === "COMPLETED").length;
69
+ return Math.round(done / total * 100);
70
+ };
71
+ const applyTrackCompletionBonuses = (track, progress) => {
72
+ if (progress.isCompleted) return progress;
73
+ const completedAt = /* @__PURE__ */ new Date();
74
+ const startedAt = progress.startedAt ?? completedAt;
75
+ const hoursElapsed = (completedAt.getTime() - startedAt.getTime()) / (1e3 * 60 * 60);
76
+ let xpEarned = progress.xpEarned;
77
+ const { completionRewards, streakRule } = track;
78
+ if (completionRewards?.xpBonus) xpEarned += completionRewards.xpBonus;
79
+ if (streakRule?.hoursWindow !== void 0 && hoursElapsed <= streakRule.hoursWindow && streakRule.bonusXp) xpEarned += streakRule.bonusXp;
80
+ return {
81
+ ...progress,
82
+ xpEarned,
83
+ isCompleted: true,
84
+ completedAt,
85
+ lastActivityAt: completedAt
86
+ };
87
+ };
88
+ const listTracks = (learnerId) => {
89
+ const progressMap = learnerId ? getLearnerTracks(learnerId) : void 0;
90
+ return {
91
+ tracks: learningJourneyTracks,
92
+ progress: learnerId && progressMap ? Array.from(progressMap.values()) : []
93
+ };
94
+ };
95
+ const getProgress = (trackId, learnerId) => {
96
+ const track = getTrack(trackId);
97
+ if (!track) return void 0;
98
+ const map = getLearnerTracks(learnerId);
99
+ const existing = map.get(trackId) ?? initProgress(learnerId, track);
100
+ map.set(trackId, existing);
101
+ return existing;
102
+ };
103
+ const recordEvent = (event) => {
104
+ const targets = event.trackId !== void 0 ? learningJourneyTracks.filter((t) => t.id === event.trackId) : learningJourneyTracks;
105
+ const updated = [];
106
+ const eventTime = event.occurredAt ?? /* @__PURE__ */ new Date();
107
+ for (const track of targets) {
108
+ const map = getLearnerTracks(event.learnerId);
109
+ const current = map.get(track.id) ?? initProgress(event.learnerId, track);
110
+ const startedAt = current.startedAt ?? eventTime;
111
+ let changed = current.startedAt === void 0;
112
+ const steps = current.steps.map((step) => {
113
+ if (step.status === "COMPLETED") return step;
114
+ const spec = track.steps.find((s) => s.id === step.id);
115
+ if (!spec) return step;
116
+ const { availableAt, dueAt } = getAvailability(spec.availability, startedAt);
117
+ if (availableAt && eventTime < availableAt) return {
118
+ ...step,
119
+ availableAt,
120
+ dueAt
121
+ };
122
+ if (dueAt && eventTime > dueAt) return {
123
+ ...step,
124
+ availableAt,
125
+ dueAt
126
+ };
127
+ const result = matchesCondition(spec.completion, event, step, startedAt);
128
+ if (result.matched) {
129
+ changed = true;
130
+ return {
131
+ ...step,
132
+ status: "COMPLETED",
133
+ xpEarned: spec.xpReward ?? 0,
134
+ completedAt: eventTime,
135
+ triggeringEvent: event.name,
136
+ eventPayload: event.payload,
137
+ occurrences: result.occurrences ?? step.occurrences,
138
+ masteryCount: result.masteryCount ?? step.masteryCount,
139
+ availableAt,
140
+ dueAt
141
+ };
142
+ }
143
+ if (result.occurrences !== void 0 || result.masteryCount !== void 0) changed = true;
144
+ return {
145
+ ...step,
146
+ occurrences: result.occurrences ?? step.occurrences,
147
+ masteryCount: result.masteryCount ?? step.masteryCount,
148
+ availableAt,
149
+ dueAt
150
+ };
151
+ });
152
+ if (!changed) continue;
153
+ const xpEarned = steps.reduce((sum, s) => sum + s.xpEarned, 0) + (track.totalXp ?? 0);
154
+ let progress = {
155
+ ...current,
156
+ steps,
157
+ xpEarned,
158
+ startedAt,
159
+ lastActivityAt: eventTime,
160
+ progress: computeProgressPercent(steps)
161
+ };
162
+ if (steps.every((s) => s.status === "COMPLETED")) progress = applyTrackCompletionBonuses(track, progress);
163
+ map.set(track.id, progress);
164
+ updated.push(progress);
165
+ }
166
+ return updated;
167
+ };
168
+
169
+ //#endregion
170
+ export { getProgress, listTracks, recordEvent };
171
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","names":[],"sources":["../src/api.ts"],"sourcesContent":["import { learningJourneyTracks } from './tracks';\nimport type {\n LearningJourneyTrackSpec,\n StepAvailabilitySpec,\n StepCompletionConditionSpec,\n} from '@contractspec/module.learning-journey/track-spec';\nimport type { LearningEvent, StepProgress, TrackProgress } from './api-types';\nimport {\n getLearnerTracks,\n getTrackResolver,\n initProgress,\n} from './progress-store';\n\nconst getTrack = getTrackResolver(learningJourneyTracks);\n\nconst matchesFilter = (\n filter: Record<string, unknown> | undefined,\n payload: Record<string, unknown> | undefined\n): boolean => {\n if (!filter) return true;\n if (!payload) return false;\n return Object.entries(filter).every(([key, value]) => payload[key] === value);\n};\n\nconst matchesBaseEvent = (\n condition: {\n eventName: string;\n eventVersion?: number;\n sourceModule?: string;\n payloadFilter?: Record<string, unknown>;\n },\n event: LearningEvent\n): boolean => {\n if (condition.eventName !== event.name) return false;\n if (condition.eventVersion !== undefined && event.version !== undefined) {\n if (condition.eventVersion !== event.version) return false;\n }\n if (\n condition.sourceModule &&\n event.sourceModule &&\n condition.sourceModule !== event.sourceModule\n ) {\n return false;\n }\n return matchesFilter(\n condition.payloadFilter,\n event.payload as Record<string, unknown> | undefined\n );\n};\n\nconst matchesCondition = (\n condition: StepCompletionConditionSpec,\n event: LearningEvent,\n step: StepProgress,\n trackStartedAt: Date | undefined\n): {\n matched: boolean;\n occurrences?: number;\n masteryCount?: number;\n} => {\n if (condition.kind === 'count') {\n if (!matchesBaseEvent(condition, event)) return { matched: false };\n const occurrences = (step.occurrences ?? 0) + 1;\n const within =\n condition.withinHours === undefined ||\n Boolean(\n trackStartedAt &&\n event.occurredAt &&\n (event.occurredAt.getTime() - trackStartedAt.getTime()) /\n (1000 * 60 * 60) <=\n condition.withinHours\n );\n return { matched: within && occurrences >= condition.atLeast, occurrences };\n }\n\n if (condition.kind === 'time_window') {\n if (!matchesBaseEvent(condition, event)) return { matched: false };\n if (\n condition.withinHoursOfStart !== undefined &&\n trackStartedAt &&\n event.occurredAt\n ) {\n const hoursSinceStart =\n (event.occurredAt.getTime() - trackStartedAt.getTime()) /\n (1000 * 60 * 60);\n if (hoursSinceStart > condition.withinHoursOfStart) {\n return { matched: false };\n }\n }\n return { matched: true };\n }\n\n if (condition.kind === 'srs_mastery') {\n if (event.name !== condition.eventName) return { matched: false };\n const payload = event.payload as Record<string, unknown> | undefined;\n if (!matchesFilter(condition.payloadFilter, payload)) {\n return { matched: false };\n }\n const skillKey = condition.skillIdField ?? 'skillId';\n const masteryKey = condition.masteryField ?? 'mastery';\n const skillId = payload?.[skillKey];\n const masteryValue = payload?.[masteryKey];\n if (skillId === undefined || masteryValue === undefined) {\n return { matched: false };\n }\n if (typeof masteryValue !== 'number') return { matched: false };\n if (masteryValue < condition.minimumMastery) return { matched: false };\n const masteryCount = (step.masteryCount ?? 0) + 1;\n const required = condition.requiredCount ?? 1;\n return { matched: masteryCount >= required, masteryCount };\n }\n\n return { matched: matchesBaseEvent(condition, event) };\n};\n\nconst getAvailability = (\n availability: StepAvailabilitySpec | undefined,\n startedAt: Date | undefined\n): { availableAt?: Date; dueAt?: Date } => {\n if (!availability || !startedAt) return {};\n\n const baseTime = startedAt.getTime();\n let unlockTime = baseTime;\n\n if (availability.unlockOnDay !== undefined) {\n unlockTime =\n baseTime + (availability.unlockOnDay - 1) * 24 * 60 * 60 * 1000;\n }\n\n if (availability.unlockAfterHours !== undefined) {\n unlockTime = baseTime + availability.unlockAfterHours * 60 * 60 * 1000;\n }\n\n const availableAt = new Date(unlockTime);\n const dueAt =\n availability.dueWithinHours !== undefined\n ? new Date(\n availableAt.getTime() + availability.dueWithinHours * 60 * 60 * 1000\n )\n : undefined;\n\n return { availableAt, dueAt };\n};\n\nconst computeProgressPercent = (steps: StepProgress[]): number => {\n const total = steps.length || 1;\n const done = steps.filter((s) => s.status === 'COMPLETED').length;\n return Math.round((done / total) * 100);\n};\n\nconst applyTrackCompletionBonuses = (\n track: LearningJourneyTrackSpec,\n progress: TrackProgress\n) => {\n if (progress.isCompleted) return progress;\n\n const completedAt = new Date();\n const startedAt = progress.startedAt ?? completedAt;\n const hoursElapsed =\n (completedAt.getTime() - startedAt.getTime()) / (1000 * 60 * 60);\n\n let xpEarned = progress.xpEarned;\n const { completionRewards, streakRule } = track;\n\n if (completionRewards?.xpBonus) {\n xpEarned += completionRewards.xpBonus;\n }\n\n if (\n streakRule?.hoursWindow !== undefined &&\n hoursElapsed <= streakRule.hoursWindow &&\n streakRule.bonusXp\n ) {\n xpEarned += streakRule.bonusXp;\n }\n\n return {\n ...progress,\n xpEarned,\n isCompleted: true,\n completedAt,\n lastActivityAt: completedAt,\n };\n};\n\nexport const listTracks = (learnerId?: string) => {\n const progressMap = learnerId ? getLearnerTracks(learnerId) : undefined;\n const progress =\n learnerId && progressMap\n ? Array.from(progressMap.values())\n : ([] as TrackProgress[]);\n\n return {\n tracks: learningJourneyTracks,\n progress,\n };\n};\n\nexport const getProgress = (trackId: string, learnerId: string) => {\n const track = getTrack(trackId);\n if (!track) return undefined;\n\n const map = getLearnerTracks(learnerId);\n const existing = map.get(trackId) ?? initProgress(learnerId, track);\n map.set(trackId, existing);\n return existing;\n};\n\nexport const recordEvent = (event: LearningEvent) => {\n const targets =\n event.trackId !== undefined\n ? learningJourneyTracks.filter((t) => t.id === event.trackId)\n : learningJourneyTracks;\n\n const updated: TrackProgress[] = [];\n const eventTime = event.occurredAt ?? new Date();\n\n for (const track of targets) {\n const map = getLearnerTracks(event.learnerId);\n const current = map.get(track.id) ?? initProgress(event.learnerId, track);\n const startedAt = current.startedAt ?? eventTime;\n\n let changed = current.startedAt === undefined;\n const steps: StepProgress[] = current.steps.map((step) => {\n if (step.status === 'COMPLETED') return step;\n\n const spec = track.steps.find((s) => s.id === step.id);\n if (!spec) return step;\n\n const { availableAt, dueAt } = getAvailability(\n spec.availability,\n startedAt\n );\n if (availableAt && eventTime < availableAt) {\n return { ...step, availableAt, dueAt };\n }\n if (dueAt && eventTime > dueAt) {\n // keep pending but note deadlines\n return { ...step, availableAt, dueAt };\n }\n\n const result = matchesCondition(spec.completion, event, step, startedAt);\n\n if (result.matched) {\n changed = true;\n return {\n ...step,\n status: 'COMPLETED',\n xpEarned: spec.xpReward ?? 0,\n completedAt: eventTime,\n triggeringEvent: event.name,\n eventPayload: event.payload,\n occurrences: result.occurrences ?? step.occurrences,\n masteryCount: result.masteryCount ?? step.masteryCount,\n availableAt,\n dueAt,\n };\n }\n\n if (\n result.occurrences !== undefined ||\n result.masteryCount !== undefined\n ) {\n changed = true;\n }\n\n return {\n ...step,\n occurrences: result.occurrences ?? step.occurrences,\n masteryCount: result.masteryCount ?? step.masteryCount,\n availableAt,\n dueAt,\n };\n });\n\n if (!changed) {\n continue;\n }\n\n const xpEarned =\n steps.reduce((sum, s) => sum + s.xpEarned, 0) + (track.totalXp ?? 0);\n let progress: TrackProgress = {\n ...current,\n steps,\n xpEarned,\n startedAt,\n lastActivityAt: eventTime,\n progress: computeProgressPercent(steps),\n };\n\n const allDone = steps.every((s) => s.status === 'COMPLETED');\n if (allDone) {\n progress = applyTrackCompletionBonuses(track, progress);\n }\n\n map.set(track.id, progress);\n updated.push(progress);\n }\n\n return updated;\n};\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1 @@
1
+ import "./learning-journey-registry.docblock.js";
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,38 @@
1
+ import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
2
+
3
+ //#region src/docs/learning-journey-registry.docblock.ts
4
+ registerDocBlocks([{
5
+ id: "docs.learning-journey.registry",
6
+ title: "Learning Journey — Example Track Registry",
7
+ summary: "Aggregates learning journey example tracks (Studio onboarding, Platform tour, CRM first win, Drills, Ambient Coach, Quest challenges).",
8
+ kind: "usage",
9
+ visibility: "public",
10
+ route: "/docs/learning-journey/registry",
11
+ tags: [
12
+ "learning",
13
+ "registry",
14
+ "onboarding"
15
+ ],
16
+ body: `## Tracks
17
+ - \`studio_getting_started\` (Studio onboarding)
18
+ - \`platform_primitives_tour\` (Platform primitives)
19
+ - \`crm_first_win\` (CRM pipeline onboarding)
20
+ - \`drills_language_basics\` (Drills & SRS)
21
+ - \`money_ambient_coach\`, \`coliving_ambient_coach\` (Ambient tips)
22
+ - \`money_reset_7day\` (Quest/challenge)
23
+
24
+ ## Exports
25
+ - \`learningJourneyTracks\` — raw specs
26
+ - \`onboardingTrackCatalog\` — DTOs aligned with onboarding API
27
+ - \`mapTrackSpecToDto\` — helper to map individual tracks
28
+
29
+ ## Wiring
30
+ - Use with onboarding API contracts:
31
+ - \`learning.onboarding.listTracks\`
32
+ - \`learning.onboarding.getProgress\`
33
+ - \`learning.onboarding.recordEvent\`
34
+ - Intended for registry/adapters in Studio UI or services that surface tracks.`
35
+ }]);
36
+
37
+ //#endregion
38
+ //# sourceMappingURL=learning-journey-registry.docblock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-journey-registry.docblock.js","names":[],"sources":["../../src/docs/learning-journey-registry.docblock.ts"],"sourcesContent":["import type { DocBlock } from '@contractspec/lib.contracts/docs';\nimport { registerDocBlocks } from '@contractspec/lib.contracts/docs';\n\nconst registryDocBlocks: DocBlock[] = [\n {\n id: 'docs.learning-journey.registry',\n title: 'Learning Journey — Example Track Registry',\n summary:\n 'Aggregates learning journey example tracks (Studio onboarding, Platform tour, CRM first win, Drills, Ambient Coach, Quest challenges).',\n kind: 'usage',\n visibility: 'public',\n route: '/docs/learning-journey/registry',\n tags: ['learning', 'registry', 'onboarding'],\n body: `## Tracks\n- \\`studio_getting_started\\` (Studio onboarding)\n- \\`platform_primitives_tour\\` (Platform primitives)\n- \\`crm_first_win\\` (CRM pipeline onboarding)\n- \\`drills_language_basics\\` (Drills & SRS)\n- \\`money_ambient_coach\\`, \\`coliving_ambient_coach\\` (Ambient tips)\n- \\`money_reset_7day\\` (Quest/challenge)\n\n## Exports\n- \\`learningJourneyTracks\\` — raw specs\n- \\`onboardingTrackCatalog\\` — DTOs aligned with onboarding API\n- \\`mapTrackSpecToDto\\` — helper to map individual tracks\n\n## Wiring\n- Use with onboarding API contracts:\n - \\`learning.onboarding.listTracks\\`\n - \\`learning.onboarding.getProgress\\`\n - \\`learning.onboarding.recordEvent\\`\n- Intended for registry/adapters in Studio UI or services that surface tracks.`,\n },\n];\n\nregisterDocBlocks(registryDocBlocks);\n"],"mappings":";;;AAmCA,kBAhCsC,CACpC;CACE,IAAI;CACJ,OAAO;CACP,SACE;CACF,MAAM;CACN,YAAY;CACZ,OAAO;CACP,MAAM;EAAC;EAAY;EAAY;EAAa;CAC5C,MAAM;;;;;;;;;;;;;;;;;;;CAmBP,CACF,CAEmC"}
@@ -0,0 +1,7 @@
1
+ import * as _contractspec_lib_contracts4 from "@contractspec/lib.contracts";
2
+
3
+ //#region src/example.d.ts
4
+ declare const example: _contractspec_lib_contracts4.ExampleSpec;
5
+ //#endregion
6
+ export { example as default };
7
+ //# sourceMappingURL=example.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example.d.ts","names":[],"sources":["../src/example.ts"],"sourcesContent":[],"mappings":";;;cAEM,SA0BJ,4BAAA,CA1BW"}
@@ -0,0 +1,42 @@
1
+ import { defineExample } from "@contractspec/lib.contracts";
2
+
3
+ //#region src/example.ts
4
+ const example = defineExample({
5
+ meta: {
6
+ key: "learning-journey-registry",
7
+ version: "1.0.0",
8
+ title: "Learning Journey Registry",
9
+ description: "Registry of learning journey tracks + presentations + UI mini-app bindings.",
10
+ kind: "library",
11
+ visibility: "public",
12
+ stability: "experimental",
13
+ owners: ["@platform.core"],
14
+ tags: [
15
+ "learning",
16
+ "journey",
17
+ "registry"
18
+ ]
19
+ },
20
+ docs: { rootDocId: "docs.examples.learning-journey-registry" },
21
+ entrypoints: {
22
+ packageName: "@contractspec/example.learning-journey-registry",
23
+ docs: "./docs"
24
+ },
25
+ surfaces: {
26
+ templates: true,
27
+ sandbox: {
28
+ enabled: true,
29
+ modes: ["markdown", "specs"]
30
+ },
31
+ studio: {
32
+ enabled: true,
33
+ installable: true
34
+ },
35
+ mcp: { enabled: true }
36
+ }
37
+ });
38
+ var example_default = example;
39
+
40
+ //#endregion
41
+ export { example_default as default };
42
+ //# sourceMappingURL=example.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example.js","names":[],"sources":["../src/example.ts"],"sourcesContent":["import { defineExample } from '@contractspec/lib.contracts';\n\nconst example = defineExample({\n meta: {\n key: 'learning-journey-registry',\n version: '1.0.0',\n title: 'Learning Journey Registry',\n description:\n 'Registry of learning journey tracks + presentations + UI mini-app bindings.',\n kind: 'library',\n visibility: 'public',\n stability: 'experimental',\n owners: ['@platform.core'],\n tags: ['learning', 'journey', 'registry'],\n },\n docs: {\n rootDocId: 'docs.examples.learning-journey-registry',\n },\n entrypoints: {\n packageName: '@contractspec/example.learning-journey-registry',\n docs: './docs',\n },\n surfaces: {\n templates: true,\n sandbox: { enabled: true, modes: ['markdown', 'specs'] },\n studio: { enabled: true, installable: true },\n mcp: { enabled: true },\n },\n});\n\nexport default example;\n"],"mappings":";;;AAEA,MAAM,UAAU,cAAc;CAC5B,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aACE;EACF,MAAM;EACN,YAAY;EACZ,WAAW;EACX,QAAQ,CAAC,iBAAiB;EAC1B,MAAM;GAAC;GAAY;GAAW;GAAW;EAC1C;CACD,MAAM,EACJ,WAAW,2CACZ;CACD,aAAa;EACX,aAAa;EACb,MAAM;EACP;CACD,UAAU;EACR,WAAW;EACX,SAAS;GAAE,SAAS;GAAM,OAAO,CAAC,YAAY,QAAQ;GAAE;EACxD,QAAQ;GAAE,SAAS;GAAM,aAAa;GAAM;EAC5C,KAAK,EAAE,SAAS,MAAM;EACvB;CACF,CAAC;AAEF,sBAAe"}
@@ -0,0 +1,8 @@
1
+ import { getProgress, listTracks, recordEvent } from "./api.js";
2
+ import example from "./example.js";
3
+ import { OnboardingStepDto, OnboardingTrackDto, crmLearningTracks, learningJourneyTracks, mapStep, mapTrackSpecToDto, onboardingTrackCatalog, platformLearningTracks, studioLearningTracks } from "./tracks.js";
4
+ import { LearningTrackDetailPresentation, LearningTrackListPresentation, LearningTrackProgressWidgetPresentation, learningJourneyPresentations } from "./presentations/index.js";
5
+ import { LearningJourneyRegistryFeature } from "./learning-journey-registry.feature.js";
6
+ import { LearningMiniApp, getLearningTemplateIds, isLearningTemplate } from "./ui/LearningMiniApp.js";
7
+ import "./ui/index.js";
8
+ export { LearningJourneyRegistryFeature, LearningMiniApp, LearningTrackDetailPresentation, LearningTrackListPresentation, LearningTrackProgressWidgetPresentation, OnboardingStepDto, OnboardingTrackDto, crmLearningTracks, example, getLearningTemplateIds, getProgress, isLearningTemplate, learningJourneyPresentations, learningJourneyTracks, listTracks, mapStep, mapTrackSpecToDto, onboardingTrackCatalog, platformLearningTracks, recordEvent, studioLearningTracks };
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { crmLearningTracks, learningJourneyTracks, mapStep, mapTrackSpecToDto, onboardingTrackCatalog, platformLearningTracks, studioLearningTracks } from "./tracks.js";
2
+ import { getProgress, listTracks, recordEvent } from "./api.js";
3
+ import example_default from "./example.js";
4
+ import "./docs/index.js";
5
+ import { LearningTrackDetailPresentation, LearningTrackListPresentation, LearningTrackProgressWidgetPresentation, learningJourneyPresentations } from "./presentations/index.js";
6
+ import { LearningJourneyRegistryFeature } from "./learning-journey-registry.feature.js";
7
+ import { LearningMiniApp, getLearningTemplateIds, isLearningTemplate } from "./ui/LearningMiniApp.js";
8
+ import "./ui/index.js";
9
+
10
+ export { LearningJourneyRegistryFeature, LearningMiniApp, LearningTrackDetailPresentation, LearningTrackListPresentation, LearningTrackProgressWidgetPresentation, crmLearningTracks, example_default as example, getLearningTemplateIds, getProgress, isLearningTemplate, learningJourneyPresentations, learningJourneyTracks, listTracks, mapStep, mapTrackSpecToDto, onboardingTrackCatalog, platformLearningTracks, recordEvent, studioLearningTracks };
@@ -0,0 +1,12 @@
1
+ import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
2
+
3
+ //#region src/learning-journey-registry.feature.d.ts
4
+
5
+ /**
6
+ * Learning Journey Registry feature module that bundles
7
+ * the shared presentations for learning journey tracks.
8
+ */
9
+ declare const LearningJourneyRegistryFeature: _contractspec_lib_contracts0.FeatureModuleSpec;
10
+ //#endregion
11
+ export { LearningJourneyRegistryFeature };
12
+ //# sourceMappingURL=learning-journey-registry.feature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-journey-registry.feature.d.ts","names":[],"sources":["../src/learning-journey-registry.feature.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;cAAa,gCAoDX,4BAAA,CApDyC"}
@@ -0,0 +1,75 @@
1
+ import { defineFeature } from "@contractspec/lib.contracts";
2
+
3
+ //#region src/learning-journey-registry.feature.ts
4
+ /**
5
+ * Learning Journey Registry Feature Module Specification
6
+ *
7
+ * Defines the feature module for the learning journey registry.
8
+ */
9
+ /**
10
+ * Learning Journey Registry feature module that bundles
11
+ * the shared presentations for learning journey tracks.
12
+ */
13
+ const LearningJourneyRegistryFeature = defineFeature({
14
+ meta: {
15
+ key: "learning-journey-registry",
16
+ version: "1.0.0",
17
+ title: "Learning Journey Registry",
18
+ description: "Shared registry and presentations for learning journey tracks",
19
+ domain: "learning-journey",
20
+ owners: ["@learning-team"],
21
+ tags: [
22
+ "learning",
23
+ "journey",
24
+ "onboarding",
25
+ "registry"
26
+ ],
27
+ stability: "experimental"
28
+ },
29
+ operations: [],
30
+ events: [],
31
+ presentations: [
32
+ {
33
+ key: "learning.journey.track_list",
34
+ version: "1.0.0"
35
+ },
36
+ {
37
+ key: "learning.journey.track_detail",
38
+ version: "1.0.0"
39
+ },
40
+ {
41
+ key: "learning.journey.progress_widget",
42
+ version: "1.0.0"
43
+ }
44
+ ],
45
+ opToPresentation: [],
46
+ presentationsTargets: [
47
+ {
48
+ key: "learning.journey.track_list",
49
+ version: "1.0.0",
50
+ targets: ["react", "markdown"]
51
+ },
52
+ {
53
+ key: "learning.journey.track_detail",
54
+ version: "1.0.0",
55
+ targets: [
56
+ "react",
57
+ "markdown",
58
+ "application/json"
59
+ ]
60
+ },
61
+ {
62
+ key: "learning.journey.progress_widget",
63
+ version: "1.0.0",
64
+ targets: ["react"]
65
+ }
66
+ ],
67
+ capabilities: { requires: [{
68
+ key: "identity",
69
+ version: "1.0.0"
70
+ }] }
71
+ });
72
+
73
+ //#endregion
74
+ export { LearningJourneyRegistryFeature };
75
+ //# sourceMappingURL=learning-journey-registry.feature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learning-journey-registry.feature.js","names":[],"sources":["../src/learning-journey-registry.feature.ts"],"sourcesContent":["/**\n * Learning Journey Registry Feature Module Specification\n *\n * Defines the feature module for the learning journey registry.\n */\nimport { defineFeature } from '@contractspec/lib.contracts';\n\n/**\n * Learning Journey Registry feature module that bundles\n * the shared presentations for learning journey tracks.\n */\nexport const LearningJourneyRegistryFeature = defineFeature({\n meta: {\n key: 'learning-journey-registry',\n version: '1.0.0',\n title: 'Learning Journey Registry',\n description:\n 'Shared registry and presentations for learning journey tracks',\n domain: 'learning-journey',\n owners: ['@learning-team'],\n tags: ['learning', 'journey', 'onboarding', 'registry'],\n stability: 'experimental',\n },\n\n // No operations in the registry - it's presentation-only\n operations: [],\n\n // Events emitted by this feature\n events: [],\n\n // Presentations associated with this feature\n presentations: [\n { key: 'learning.journey.track_list', version: '1.0.0' },\n { key: 'learning.journey.track_detail', version: '1.0.0' },\n { key: 'learning.journey.progress_widget', version: '1.0.0' },\n ],\n\n // No op to presentation links for registry\n opToPresentation: [],\n\n // Target requirements for multi-surface rendering\n presentationsTargets: [\n {\n key: 'learning.journey.track_list',\n version: '1.0.0',\n targets: ['react', 'markdown'],\n },\n {\n key: 'learning.journey.track_detail',\n version: '1.0.0',\n targets: ['react', 'markdown', 'application/json'],\n },\n {\n key: 'learning.journey.progress_widget',\n version: '1.0.0',\n targets: ['react'],\n },\n ],\n\n // Capability requirements\n capabilities: {\n requires: [{ key: 'identity', version: '1.0.0' }],\n },\n});\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,iCAAiC,cAAc;CAC1D,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aACE;EACF,QAAQ;EACR,QAAQ,CAAC,iBAAiB;EAC1B,MAAM;GAAC;GAAY;GAAW;GAAc;GAAW;EACvD,WAAW;EACZ;CAGD,YAAY,EAAE;CAGd,QAAQ,EAAE;CAGV,eAAe;EACb;GAAE,KAAK;GAA+B,SAAS;GAAS;EACxD;GAAE,KAAK;GAAiC,SAAS;GAAS;EAC1D;GAAE,KAAK;GAAoC,SAAS;GAAS;EAC9D;CAGD,kBAAkB,EAAE;CAGpB,sBAAsB;EACpB;GACE,KAAK;GACL,SAAS;GACT,SAAS,CAAC,SAAS,WAAW;GAC/B;EACD;GACE,KAAK;GACL,SAAS;GACT,SAAS;IAAC;IAAS;IAAY;IAAmB;GACnD;EACD;GACE,KAAK;GACL,SAAS;GACT,SAAS,CAAC,QAAQ;GACnB;EACF;CAGD,cAAc,EACZ,UAAU,CAAC;EAAE,KAAK;EAAY,SAAS;EAAS,CAAC,EAClD;CACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
2
+
3
+ //#region src/presentations/index.d.ts
4
+ declare const LearningTrackListPresentation: _contractspec_lib_contracts0.PresentationSpec;
5
+ declare const LearningTrackDetailPresentation: _contractspec_lib_contracts0.PresentationSpec;
6
+ declare const LearningTrackProgressWidgetPresentation: _contractspec_lib_contracts0.PresentationSpec;
7
+ declare const learningJourneyPresentations: _contractspec_lib_contracts0.PresentationSpec[];
8
+ //#endregion
9
+ export { LearningTrackDetailPresentation, LearningTrackListPresentation, LearningTrackProgressWidgetPresentation, learningJourneyPresentations };
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/presentations/index.ts"],"sourcesContent":[],"mappings":";;;cAea,+BAaX,4BAAA,CAbwC;cAe7B,iCAaX,4BAAA,CAb0C;cAe/B,yCAaX,4BAAA,CAbkD;AA9BvC,cA6CA,4BAhCX,EAoCD,4BAAA,CAJwC,gBAAA,EAhCvC"}
@@ -0,0 +1,71 @@
1
+ import { StabilityEnum, definePresentation } from "@contractspec/lib.contracts";
2
+
3
+ //#region src/presentations/index.ts
4
+ const baseMeta = {
5
+ domain: "learning-journey",
6
+ title: "Learning Journey",
7
+ owners: ["@learning-team"],
8
+ tags: [
9
+ "learning",
10
+ "journey",
11
+ "onboarding"
12
+ ],
13
+ stability: StabilityEnum.Experimental,
14
+ goal: "Progress through learning tracks",
15
+ context: "Learning journey section"
16
+ };
17
+ const LearningTrackListPresentation = definePresentation({
18
+ meta: {
19
+ key: "learning.journey.track_list",
20
+ version: "1.0.0",
21
+ description: "List of learning journeys available to the learner.",
22
+ ...baseMeta
23
+ },
24
+ source: {
25
+ type: "component",
26
+ framework: "react",
27
+ componentKey: "LearningTrackList"
28
+ },
29
+ targets: ["react", "markdown"]
30
+ });
31
+ const LearningTrackDetailPresentation = definePresentation({
32
+ meta: {
33
+ key: "learning.journey.track_detail",
34
+ version: "1.0.0",
35
+ description: "Track detail with steps and progress state.",
36
+ ...baseMeta
37
+ },
38
+ source: {
39
+ type: "component",
40
+ framework: "react",
41
+ componentKey: "LearningTrackDetail"
42
+ },
43
+ targets: [
44
+ "react",
45
+ "markdown",
46
+ "application/json"
47
+ ]
48
+ });
49
+ const LearningTrackProgressWidgetPresentation = definePresentation({
50
+ meta: {
51
+ key: "learning.journey.progress_widget",
52
+ version: "1.0.0",
53
+ description: "Compact widget showing progress for active track.",
54
+ ...baseMeta
55
+ },
56
+ source: {
57
+ type: "component",
58
+ framework: "react",
59
+ componentKey: "LearningTrackProgressWidget"
60
+ },
61
+ targets: ["react"]
62
+ });
63
+ const learningJourneyPresentations = [
64
+ LearningTrackListPresentation,
65
+ LearningTrackDetailPresentation,
66
+ LearningTrackProgressWidgetPresentation
67
+ ];
68
+
69
+ //#endregion
70
+ export { LearningTrackDetailPresentation, LearningTrackListPresentation, LearningTrackProgressWidgetPresentation, learningJourneyPresentations };
71
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/presentations/index.ts"],"sourcesContent":["import { definePresentation, StabilityEnum, type PresentationSpecMeta } from '@contractspec/lib.contracts';\n\nconst baseMeta: Pick<\n PresentationSpecMeta,\n 'domain' | 'owners' | 'tags' | 'title' | 'stability' | 'goal' | 'context'\n> = {\n domain: 'learning-journey',\n title: 'Learning Journey',\n owners: ['@learning-team'] as string[],\n tags: ['learning', 'journey', 'onboarding'] as string[],\n stability: StabilityEnum.Experimental,\n goal: 'Progress through learning tracks',\n context: 'Learning journey section',\n};\n\nexport const LearningTrackListPresentation = definePresentation({\n meta: {\n key: 'learning.journey.track_list',\n version: '1.0.0',\n description: 'List of learning journeys available to the learner.',\n ...baseMeta,\n },\n source: {\n type: 'component',\n framework: 'react',\n componentKey: 'LearningTrackList',\n },\n targets: ['react', 'markdown'],\n});\n\nexport const LearningTrackDetailPresentation = definePresentation({\n meta: {\n key: 'learning.journey.track_detail',\n version: '1.0.0',\n description: 'Track detail with steps and progress state.',\n ...baseMeta,\n },\n source: {\n type: 'component',\n framework: 'react',\n componentKey: 'LearningTrackDetail',\n },\n targets: ['react', 'markdown', 'application/json'],\n});\n\nexport const LearningTrackProgressWidgetPresentation = definePresentation({\n meta: {\n key: 'learning.journey.progress_widget',\n version: '1.0.0',\n description: 'Compact widget showing progress for active track.',\n ...baseMeta,\n },\n source: {\n type: 'component',\n framework: 'react',\n componentKey: 'LearningTrackProgressWidget',\n },\n targets: ['react'],\n});\n\nexport const learningJourneyPresentations = [\n LearningTrackListPresentation,\n LearningTrackDetailPresentation,\n LearningTrackProgressWidgetPresentation,\n];\n"],"mappings":";;;AAEA,MAAM,WAGF;CACF,QAAQ;CACR,OAAO;CACP,QAAQ,CAAC,iBAAiB;CAC1B,MAAM;EAAC;EAAY;EAAW;EAAa;CAC3C,WAAW,cAAc;CACzB,MAAM;CACN,SAAS;CACV;AAED,MAAa,gCAAgC,mBAAmB;CAC9D,MAAM;EACJ,KAAK;EACL,SAAS;EACT,aAAa;EACb,GAAG;EACJ;CACD,QAAQ;EACN,MAAM;EACN,WAAW;EACX,cAAc;EACf;CACD,SAAS,CAAC,SAAS,WAAW;CAC/B,CAAC;AAEF,MAAa,kCAAkC,mBAAmB;CAChE,MAAM;EACJ,KAAK;EACL,SAAS;EACT,aAAa;EACb,GAAG;EACJ;CACD,QAAQ;EACN,MAAM;EACN,WAAW;EACX,cAAc;EACf;CACD,SAAS;EAAC;EAAS;EAAY;EAAmB;CACnD,CAAC;AAEF,MAAa,0CAA0C,mBAAmB;CACxE,MAAM;EACJ,KAAK;EACL,SAAS;EACT,aAAa;EACb,GAAG;EACJ;CACD,QAAQ;EACN,MAAM;EACN,WAAW;EACX,cAAc;EACf;CACD,SAAS,CAAC,QAAQ;CACnB,CAAC;AAEF,MAAa,+BAA+B;CAC1C;CACA;CACA;CACD"}
@@ -0,0 +1,11 @@
1
+ import { TrackProgress } from "./api-types.js";
2
+ import { LearningJourneyTrackSpec } from "@contractspec/module.learning-journey/track-spec";
3
+
4
+ //#region src/progress-store.d.ts
5
+ declare const progressStore: Map<string, Map<string, TrackProgress>>;
6
+ declare const getTrackResolver: (tracks: LearningJourneyTrackSpec[]) => (trackId: string) => LearningJourneyTrackSpec | undefined;
7
+ declare const getLearnerTracks: (learnerId: string) => Map<string, TrackProgress>;
8
+ declare const initProgress: (learnerId: string, track: LearningJourneyTrackSpec) => TrackProgress;
9
+ //#endregion
10
+ export { getLearnerTracks, getTrackResolver, initProgress, progressStore };
11
+ //# sourceMappingURL=progress-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-store.d.ts","names":[],"sources":["../src/progress-store.ts"],"sourcesContent":[],"mappings":";;;;cAIa,eAAa,YAAA,YAAA;cAEb,2BACF,oDACU;AAJR,cAOA,gBAP6D,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,GAOxB,GAPwB,CAAA,MAAA,EAOxB,aAPwB,CAAA;AAAhD,cAeb,YAfa,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,KAAA,EAiBjB,wBAjBiB,EAAA,GAkBvB,aAlBuB"}
@@ -0,0 +1,31 @@
1
+ //#region src/progress-store.ts
2
+ const progressStore = /* @__PURE__ */ new Map();
3
+ const getTrackResolver = (tracks) => (trackId) => tracks.find((t) => t.id === trackId);
4
+ const getLearnerTracks = (learnerId) => {
5
+ const existing = progressStore.get(learnerId);
6
+ if (existing) return existing;
7
+ const map = /* @__PURE__ */ new Map();
8
+ progressStore.set(learnerId, map);
9
+ return map;
10
+ };
11
+ const initProgress = (learnerId, track) => ({
12
+ learnerId,
13
+ trackId: track.id,
14
+ progress: 0,
15
+ isCompleted: false,
16
+ xpEarned: 0,
17
+ steps: track.steps.map((step) => ({
18
+ id: step.id,
19
+ status: "PENDING",
20
+ xpEarned: 0,
21
+ occurrences: 0,
22
+ masteryCount: 0
23
+ })),
24
+ startedAt: void 0,
25
+ completedAt: void 0,
26
+ lastActivityAt: void 0
27
+ });
28
+
29
+ //#endregion
30
+ export { getLearnerTracks, getTrackResolver, initProgress, progressStore };
31
+ //# sourceMappingURL=progress-store.js.map