@contractspec/example.learning-journey-registry 1.56.1 → 1.58.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/.turbo/turbo-build.log +53 -51
- package/.turbo/turbo-prebuild.log +1 -0
- package/CHANGELOG.md +50 -0
- package/dist/api-types.d.ts +33 -37
- package/dist/api-types.d.ts.map +1 -1
- package/dist/api-types.js +1 -0
- package/dist/api.d.ts +7 -11
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +261 -161
- package/dist/api.test.d.ts +2 -0
- package/dist/api.test.d.ts.map +1 -0
- package/dist/browser/api-types.js +0 -0
- package/dist/browser/api.js +270 -0
- package/dist/browser/docs/index.js +33 -0
- package/dist/browser/docs/learning-journey-registry.docblock.js +33 -0
- package/dist/browser/example.js +32 -0
- package/dist/browser/index.js +540 -0
- package/dist/browser/learning-journey-registry.feature.js +45 -0
- package/dist/browser/presentations/index.js +67 -0
- package/dist/browser/progress-store.js +34 -0
- package/dist/browser/tracks.js +52 -0
- package/dist/browser/ui/LearningMiniApp.js +133 -0
- package/dist/browser/ui/index.js +133 -0
- package/dist/docs/index.d.ts +2 -1
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +34 -1
- package/dist/docs/learning-journey-registry.docblock.d.ts +2 -1
- package/dist/docs/learning-journey-registry.docblock.d.ts.map +1 -0
- package/dist/docs/learning-journey-registry.docblock.js +18 -22
- package/dist/example.d.ts +2 -6
- package/dist/example.d.ts.map +1 -1
- package/dist/example.js +30 -39
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +541 -10
- package/dist/learning-journey-registry.feature.d.ts +1 -7
- package/dist/learning-journey-registry.feature.d.ts.map +1 -1
- package/dist/learning-journey-registry.feature.js +44 -73
- package/dist/node/api-types.js +0 -0
- package/dist/node/api.js +270 -0
- package/dist/node/docs/index.js +33 -0
- package/dist/node/docs/learning-journey-registry.docblock.js +33 -0
- package/dist/node/example.js +32 -0
- package/dist/node/index.js +540 -0
- package/dist/node/learning-journey-registry.feature.js +45 -0
- package/dist/node/presentations/index.js +67 -0
- package/dist/node/progress-store.js +34 -0
- package/dist/node/tracks.js +52 -0
- package/dist/node/ui/LearningMiniApp.js +133 -0
- package/dist/node/ui/index.js +133 -0
- package/dist/presentations/index.d.ts +4 -9
- package/dist/presentations/index.d.ts.map +1 -1
- package/dist/presentations/index.js +63 -66
- package/dist/progress-store.d.ts +6 -10
- package/dist/progress-store.d.ts.map +1 -1
- package/dist/progress-store.js +33 -29
- package/dist/tracks.d.ts +33 -36
- package/dist/tracks.d.ts.map +1 -1
- package/dist/tracks.js +44 -39
- package/dist/ui/LearningMiniApp.d.ts +8 -16
- package/dist/ui/LearningMiniApp.d.ts.map +1 -1
- package/dist/ui/LearningMiniApp.js +123 -69
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +134 -3
- package/package.json +144 -49
- package/tsdown.config.js +1 -2
- package/.turbo/turbo-build$colon$bundle.log +0 -50
- package/dist/api.js.map +0 -1
- package/dist/docs/learning-journey-registry.docblock.js.map +0 -1
- package/dist/example.js.map +0 -1
- package/dist/learning-journey-registry.feature.js.map +0 -1
- package/dist/presentations/index.js.map +0 -1
- package/dist/progress-store.js.map +0 -1
- package/dist/tracks.js.map +0 -1
- package/dist/ui/LearningMiniApp.js.map +0 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// src/tracks.ts
|
|
2
|
+
import { crmLearningTracks } from "@contractspec/example.learning-journey-crm-onboarding/track";
|
|
3
|
+
import { drillTracks } from "@contractspec/example.learning-journey-duo-drills/track";
|
|
4
|
+
import { ambientCoachTracks } from "@contractspec/example.learning-journey-ambient-coach/track";
|
|
5
|
+
import { questTracks } from "@contractspec/example.learning-journey-quest-challenges/track";
|
|
6
|
+
import { platformLearningTracks } from "@contractspec/example.learning-journey-platform-tour/track";
|
|
7
|
+
import { studioLearningTracks } from "@contractspec/example.learning-journey-studio-onboarding/track";
|
|
8
|
+
var mapStep = (step) => ({
|
|
9
|
+
id: step.id,
|
|
10
|
+
title: step.title,
|
|
11
|
+
description: step.description,
|
|
12
|
+
completionEvent: step.completion.eventName,
|
|
13
|
+
completionCondition: step.completion,
|
|
14
|
+
xpReward: step.xpReward,
|
|
15
|
+
isRequired: step.isRequired,
|
|
16
|
+
canSkip: step.canSkip,
|
|
17
|
+
actionUrl: step.actionUrl,
|
|
18
|
+
actionLabel: step.actionLabel,
|
|
19
|
+
availability: step.availability,
|
|
20
|
+
metadata: step.metadata
|
|
21
|
+
});
|
|
22
|
+
var mapTrackSpecToDto = (track) => ({
|
|
23
|
+
id: track.id,
|
|
24
|
+
name: track.name,
|
|
25
|
+
description: track.description,
|
|
26
|
+
productId: track.productId,
|
|
27
|
+
targetUserSegment: track.targetUserSegment,
|
|
28
|
+
targetRole: track.targetRole,
|
|
29
|
+
totalXp: track.totalXp,
|
|
30
|
+
streakRule: track.streakRule,
|
|
31
|
+
completionRewards: track.completionRewards,
|
|
32
|
+
steps: track.steps.map(mapStep),
|
|
33
|
+
metadata: track.metadata
|
|
34
|
+
});
|
|
35
|
+
var learningJourneyTracks = [
|
|
36
|
+
...studioLearningTracks,
|
|
37
|
+
...platformLearningTracks,
|
|
38
|
+
...crmLearningTracks,
|
|
39
|
+
...drillTracks,
|
|
40
|
+
...ambientCoachTracks,
|
|
41
|
+
...questTracks
|
|
42
|
+
];
|
|
43
|
+
var onboardingTrackCatalog = learningJourneyTracks.map(mapTrackSpecToDto);
|
|
44
|
+
// src/progress-store.ts
|
|
45
|
+
var progressStore = new Map;
|
|
46
|
+
var getTrackResolver = (tracks) => (trackId) => tracks.find((t) => t.id === trackId);
|
|
47
|
+
var getLearnerTracks = (learnerId) => {
|
|
48
|
+
const existing = progressStore.get(learnerId);
|
|
49
|
+
if (existing)
|
|
50
|
+
return existing;
|
|
51
|
+
const map = new Map;
|
|
52
|
+
progressStore.set(learnerId, map);
|
|
53
|
+
return map;
|
|
54
|
+
};
|
|
55
|
+
var initProgress = (learnerId, track) => ({
|
|
56
|
+
learnerId,
|
|
57
|
+
trackId: track.id,
|
|
58
|
+
progress: 0,
|
|
59
|
+
isCompleted: false,
|
|
60
|
+
xpEarned: 0,
|
|
61
|
+
steps: track.steps.map((step) => ({
|
|
62
|
+
id: step.id,
|
|
63
|
+
status: "PENDING",
|
|
64
|
+
xpEarned: 0,
|
|
65
|
+
occurrences: 0,
|
|
66
|
+
masteryCount: 0
|
|
67
|
+
})),
|
|
68
|
+
startedAt: undefined,
|
|
69
|
+
completedAt: undefined,
|
|
70
|
+
lastActivityAt: undefined
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// src/api.ts
|
|
74
|
+
var getTrack = getTrackResolver(learningJourneyTracks);
|
|
75
|
+
var matchesFilter = (filter, payload) => {
|
|
76
|
+
if (!filter)
|
|
77
|
+
return true;
|
|
78
|
+
if (!payload)
|
|
79
|
+
return false;
|
|
80
|
+
return Object.entries(filter).every(([key, value]) => payload[key] === value);
|
|
81
|
+
};
|
|
82
|
+
var matchesBaseEvent = (condition, event) => {
|
|
83
|
+
if (condition.eventName !== event.name)
|
|
84
|
+
return false;
|
|
85
|
+
if (condition.eventVersion !== undefined && event.version !== undefined) {
|
|
86
|
+
if (condition.eventVersion !== event.version)
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
if (condition.sourceModule && event.sourceModule && condition.sourceModule !== event.sourceModule) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
return matchesFilter(condition.payloadFilter, event.payload);
|
|
93
|
+
};
|
|
94
|
+
var matchesCondition = (condition, event, step, trackStartedAt) => {
|
|
95
|
+
if (condition.kind === "count") {
|
|
96
|
+
if (!matchesBaseEvent(condition, event))
|
|
97
|
+
return { matched: false };
|
|
98
|
+
const occurrences = (step.occurrences ?? 0) + 1;
|
|
99
|
+
const within = condition.withinHours === undefined || Boolean(trackStartedAt && event.occurredAt && (event.occurredAt.getTime() - trackStartedAt.getTime()) / (1000 * 60 * 60) <= condition.withinHours);
|
|
100
|
+
return { matched: within && occurrences >= condition.atLeast, occurrences };
|
|
101
|
+
}
|
|
102
|
+
if (condition.kind === "time_window") {
|
|
103
|
+
if (!matchesBaseEvent(condition, event))
|
|
104
|
+
return { matched: false };
|
|
105
|
+
if (condition.withinHoursOfStart !== undefined && trackStartedAt && event.occurredAt) {
|
|
106
|
+
const hoursSinceStart = (event.occurredAt.getTime() - trackStartedAt.getTime()) / (1000 * 60 * 60);
|
|
107
|
+
if (hoursSinceStart > condition.withinHoursOfStart) {
|
|
108
|
+
return { matched: false };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { matched: true };
|
|
112
|
+
}
|
|
113
|
+
if (condition.kind === "srs_mastery") {
|
|
114
|
+
if (event.name !== condition.eventName)
|
|
115
|
+
return { matched: false };
|
|
116
|
+
const payload = event.payload;
|
|
117
|
+
if (!matchesFilter(condition.payloadFilter, payload)) {
|
|
118
|
+
return { matched: false };
|
|
119
|
+
}
|
|
120
|
+
const skillKey = condition.skillIdField ?? "skillId";
|
|
121
|
+
const masteryKey = condition.masteryField ?? "mastery";
|
|
122
|
+
const skillId = payload?.[skillKey];
|
|
123
|
+
const masteryValue = payload?.[masteryKey];
|
|
124
|
+
if (skillId === undefined || masteryValue === undefined) {
|
|
125
|
+
return { matched: false };
|
|
126
|
+
}
|
|
127
|
+
if (typeof masteryValue !== "number")
|
|
128
|
+
return { matched: false };
|
|
129
|
+
if (masteryValue < condition.minimumMastery)
|
|
130
|
+
return { matched: false };
|
|
131
|
+
const masteryCount = (step.masteryCount ?? 0) + 1;
|
|
132
|
+
const required = condition.requiredCount ?? 1;
|
|
133
|
+
return { matched: masteryCount >= required, masteryCount };
|
|
134
|
+
}
|
|
135
|
+
return { matched: matchesBaseEvent(condition, event) };
|
|
136
|
+
};
|
|
137
|
+
var getAvailability = (availability, startedAt) => {
|
|
138
|
+
if (!availability || !startedAt)
|
|
139
|
+
return {};
|
|
140
|
+
const baseTime = startedAt.getTime();
|
|
141
|
+
let unlockTime = baseTime;
|
|
142
|
+
if (availability.unlockOnDay !== undefined) {
|
|
143
|
+
unlockTime = baseTime + (availability.unlockOnDay - 1) * 24 * 60 * 60 * 1000;
|
|
144
|
+
}
|
|
145
|
+
if (availability.unlockAfterHours !== undefined) {
|
|
146
|
+
unlockTime = baseTime + availability.unlockAfterHours * 60 * 60 * 1000;
|
|
147
|
+
}
|
|
148
|
+
const availableAt = new Date(unlockTime);
|
|
149
|
+
const dueAt = availability.dueWithinHours !== undefined ? new Date(availableAt.getTime() + availability.dueWithinHours * 60 * 60 * 1000) : undefined;
|
|
150
|
+
return { availableAt, dueAt };
|
|
151
|
+
};
|
|
152
|
+
var computeProgressPercent = (steps) => {
|
|
153
|
+
const total = steps.length || 1;
|
|
154
|
+
const done = steps.filter((s) => s.status === "COMPLETED").length;
|
|
155
|
+
return Math.round(done / total * 100);
|
|
156
|
+
};
|
|
157
|
+
var applyTrackCompletionBonuses = (track, progress) => {
|
|
158
|
+
if (progress.isCompleted)
|
|
159
|
+
return progress;
|
|
160
|
+
const completedAt = new Date;
|
|
161
|
+
const startedAt = progress.startedAt ?? completedAt;
|
|
162
|
+
const hoursElapsed = (completedAt.getTime() - startedAt.getTime()) / (1000 * 60 * 60);
|
|
163
|
+
let xpEarned = progress.xpEarned;
|
|
164
|
+
const { completionRewards, streakRule } = track;
|
|
165
|
+
if (completionRewards?.xpBonus) {
|
|
166
|
+
xpEarned += completionRewards.xpBonus;
|
|
167
|
+
}
|
|
168
|
+
if (streakRule?.hoursWindow !== undefined && hoursElapsed <= streakRule.hoursWindow && streakRule.bonusXp) {
|
|
169
|
+
xpEarned += streakRule.bonusXp;
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
...progress,
|
|
173
|
+
xpEarned,
|
|
174
|
+
isCompleted: true,
|
|
175
|
+
completedAt,
|
|
176
|
+
lastActivityAt: completedAt
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
var listTracks = (learnerId) => {
|
|
180
|
+
const progressMap = learnerId ? getLearnerTracks(learnerId) : undefined;
|
|
181
|
+
const progress = learnerId && progressMap ? Array.from(progressMap.values()) : [];
|
|
182
|
+
return {
|
|
183
|
+
tracks: learningJourneyTracks,
|
|
184
|
+
progress
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
var getProgress = (trackId, learnerId) => {
|
|
188
|
+
const track = getTrack(trackId);
|
|
189
|
+
if (!track)
|
|
190
|
+
return;
|
|
191
|
+
const map = getLearnerTracks(learnerId);
|
|
192
|
+
const existing = map.get(trackId) ?? initProgress(learnerId, track);
|
|
193
|
+
map.set(trackId, existing);
|
|
194
|
+
return existing;
|
|
195
|
+
};
|
|
196
|
+
var recordEvent = (event) => {
|
|
197
|
+
const targets = event.trackId !== undefined ? learningJourneyTracks.filter((t) => t.id === event.trackId) : learningJourneyTracks;
|
|
198
|
+
const updated = [];
|
|
199
|
+
const eventTime = event.occurredAt ?? new Date;
|
|
200
|
+
for (const track of targets) {
|
|
201
|
+
const map = getLearnerTracks(event.learnerId);
|
|
202
|
+
const current = map.get(track.id) ?? initProgress(event.learnerId, track);
|
|
203
|
+
const startedAt = current.startedAt ?? eventTime;
|
|
204
|
+
let changed = current.startedAt === undefined;
|
|
205
|
+
const steps = current.steps.map((step) => {
|
|
206
|
+
if (step.status === "COMPLETED")
|
|
207
|
+
return step;
|
|
208
|
+
const spec = track.steps.find((s) => s.id === step.id);
|
|
209
|
+
if (!spec)
|
|
210
|
+
return step;
|
|
211
|
+
const { availableAt, dueAt } = getAvailability(spec.availability, startedAt);
|
|
212
|
+
if (availableAt && eventTime < availableAt) {
|
|
213
|
+
return { ...step, availableAt, dueAt };
|
|
214
|
+
}
|
|
215
|
+
if (dueAt && eventTime > dueAt) {
|
|
216
|
+
return { ...step, availableAt, dueAt };
|
|
217
|
+
}
|
|
218
|
+
const result = matchesCondition(spec.completion, event, step, startedAt);
|
|
219
|
+
if (result.matched) {
|
|
220
|
+
changed = true;
|
|
221
|
+
return {
|
|
222
|
+
...step,
|
|
223
|
+
status: "COMPLETED",
|
|
224
|
+
xpEarned: spec.xpReward ?? 0,
|
|
225
|
+
completedAt: eventTime,
|
|
226
|
+
triggeringEvent: event.name,
|
|
227
|
+
eventPayload: event.payload,
|
|
228
|
+
occurrences: result.occurrences ?? step.occurrences,
|
|
229
|
+
masteryCount: result.masteryCount ?? step.masteryCount,
|
|
230
|
+
availableAt,
|
|
231
|
+
dueAt
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (result.occurrences !== undefined || result.masteryCount !== undefined) {
|
|
235
|
+
changed = true;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
...step,
|
|
239
|
+
occurrences: result.occurrences ?? step.occurrences,
|
|
240
|
+
masteryCount: result.masteryCount ?? step.masteryCount,
|
|
241
|
+
availableAt,
|
|
242
|
+
dueAt
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
if (!changed) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const xpEarned = steps.reduce((sum, s) => sum + s.xpEarned, 0) + (track.totalXp ?? 0);
|
|
249
|
+
let progress = {
|
|
250
|
+
...current,
|
|
251
|
+
steps,
|
|
252
|
+
xpEarned,
|
|
253
|
+
startedAt,
|
|
254
|
+
lastActivityAt: eventTime,
|
|
255
|
+
progress: computeProgressPercent(steps)
|
|
256
|
+
};
|
|
257
|
+
const allDone = steps.every((s) => s.status === "COMPLETED");
|
|
258
|
+
if (allDone) {
|
|
259
|
+
progress = applyTrackCompletionBonuses(track, progress);
|
|
260
|
+
}
|
|
261
|
+
map.set(track.id, progress);
|
|
262
|
+
updated.push(progress);
|
|
263
|
+
}
|
|
264
|
+
return updated;
|
|
265
|
+
};
|
|
266
|
+
export {
|
|
267
|
+
recordEvent,
|
|
268
|
+
listTracks,
|
|
269
|
+
getProgress
|
|
270
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/docs/learning-journey-registry.docblock.ts
|
|
2
|
+
import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
|
|
3
|
+
var registryDocBlocks = [
|
|
4
|
+
{
|
|
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: ["learning", "registry", "onboarding"],
|
|
12
|
+
body: `## Tracks
|
|
13
|
+
- \`studio_getting_started\` (Studio onboarding)
|
|
14
|
+
- \`platform_primitives_tour\` (Platform primitives)
|
|
15
|
+
- \`crm_first_win\` (CRM pipeline onboarding)
|
|
16
|
+
- \`drills_language_basics\` (Drills & SRS)
|
|
17
|
+
- \`money_ambient_coach\`, \`coliving_ambient_coach\` (Ambient tips)
|
|
18
|
+
- \`money_reset_7day\` (Quest/challenge)
|
|
19
|
+
|
|
20
|
+
## Exports
|
|
21
|
+
- \`learningJourneyTracks\` — raw specs
|
|
22
|
+
- \`onboardingTrackCatalog\` — DTOs aligned with onboarding API
|
|
23
|
+
- \`mapTrackSpecToDto\` — helper to map individual tracks
|
|
24
|
+
|
|
25
|
+
## Wiring
|
|
26
|
+
- Use with onboarding API contracts:
|
|
27
|
+
- \`learning.onboarding.listTracks\`
|
|
28
|
+
- \`learning.onboarding.getProgress\`
|
|
29
|
+
- \`learning.onboarding.recordEvent\`
|
|
30
|
+
- Intended for registry/adapters in Studio UI or services that surface tracks.`
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
registerDocBlocks(registryDocBlocks);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/docs/learning-journey-registry.docblock.ts
|
|
2
|
+
import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
|
|
3
|
+
var registryDocBlocks = [
|
|
4
|
+
{
|
|
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: ["learning", "registry", "onboarding"],
|
|
12
|
+
body: `## Tracks
|
|
13
|
+
- \`studio_getting_started\` (Studio onboarding)
|
|
14
|
+
- \`platform_primitives_tour\` (Platform primitives)
|
|
15
|
+
- \`crm_first_win\` (CRM pipeline onboarding)
|
|
16
|
+
- \`drills_language_basics\` (Drills & SRS)
|
|
17
|
+
- \`money_ambient_coach\`, \`coliving_ambient_coach\` (Ambient tips)
|
|
18
|
+
- \`money_reset_7day\` (Quest/challenge)
|
|
19
|
+
|
|
20
|
+
## Exports
|
|
21
|
+
- \`learningJourneyTracks\` — raw specs
|
|
22
|
+
- \`onboardingTrackCatalog\` — DTOs aligned with onboarding API
|
|
23
|
+
- \`mapTrackSpecToDto\` — helper to map individual tracks
|
|
24
|
+
|
|
25
|
+
## Wiring
|
|
26
|
+
- Use with onboarding API contracts:
|
|
27
|
+
- \`learning.onboarding.listTracks\`
|
|
28
|
+
- \`learning.onboarding.getProgress\`
|
|
29
|
+
- \`learning.onboarding.recordEvent\`
|
|
30
|
+
- Intended for registry/adapters in Studio UI or services that surface tracks.`
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
registerDocBlocks(registryDocBlocks);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/example.ts
|
|
2
|
+
import { defineExample } from "@contractspec/lib.contracts";
|
|
3
|
+
var example = defineExample({
|
|
4
|
+
meta: {
|
|
5
|
+
key: "learning-journey-registry",
|
|
6
|
+
version: "1.0.0",
|
|
7
|
+
title: "Learning Journey Registry",
|
|
8
|
+
description: "Registry of learning journey tracks + presentations + UI mini-app bindings.",
|
|
9
|
+
kind: "library",
|
|
10
|
+
visibility: "public",
|
|
11
|
+
stability: "experimental",
|
|
12
|
+
owners: ["@platform.core"],
|
|
13
|
+
tags: ["learning", "journey", "registry"]
|
|
14
|
+
},
|
|
15
|
+
docs: {
|
|
16
|
+
rootDocId: "docs.examples.learning-journey-registry"
|
|
17
|
+
},
|
|
18
|
+
entrypoints: {
|
|
19
|
+
packageName: "@contractspec/example.learning-journey-registry",
|
|
20
|
+
docs: "./docs"
|
|
21
|
+
},
|
|
22
|
+
surfaces: {
|
|
23
|
+
templates: true,
|
|
24
|
+
sandbox: { enabled: true, modes: ["markdown", "specs"] },
|
|
25
|
+
studio: { enabled: true, installable: true },
|
|
26
|
+
mcp: { enabled: true }
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
var example_default = example;
|
|
30
|
+
export {
|
|
31
|
+
example_default as default
|
|
32
|
+
};
|