@contractspec/module.learning-journey 3.7.18 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/browser/contracts/index.js +1 -1
- package/dist/browser/contracts/journey.js +1 -0
- package/dist/browser/contracts/operations.js +1 -1
- package/dist/browser/docs/index.js +13 -12
- package/dist/browser/docs/learning-journey.docblock.js +13 -12
- package/dist/browser/engines/index.js +1 -1
- package/dist/browser/engines/xp.js +1 -1
- package/dist/browser/entities/index.js +1 -1
- package/dist/browser/entities/journey.js +1 -0
- package/dist/browser/index.js +14 -13
- package/dist/browser/learning-journey.feature.js +1 -1
- package/dist/browser/runtime/index.js +1 -0
- package/dist/browser/runtime/matchers.js +1 -0
- package/dist/browser/runtime/progress-state.js +1 -0
- package/dist/browser/runtime/snapshot.js +1 -0
- package/dist/contracts/index.d.ts +1 -1
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/{onboarding.d.ts → journey.d.ts} +477 -180
- package/dist/contracts/journey.js +2 -0
- package/dist/contracts/operations.js +1 -1
- package/dist/docs/index.js +13 -12
- package/dist/docs/learning-journey.docblock.js +13 -12
- package/dist/engines/index.js +1 -1
- package/dist/engines/xp.d.ts +1 -1
- package/dist/engines/xp.js +1 -1
- package/dist/entities/index.d.ts +28 -27
- package/dist/entities/index.js +1 -1
- package/dist/entities/{onboarding.d.ts → journey.d.ts} +61 -74
- package/dist/entities/journey.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +14 -13
- package/dist/learning-journey.feature.js +1 -1
- package/dist/node/contracts/index.js +1 -1
- package/dist/node/contracts/journey.js +1 -0
- package/dist/node/contracts/operations.js +1 -1
- package/dist/node/docs/index.js +13 -12
- package/dist/node/docs/learning-journey.docblock.js +13 -12
- package/dist/node/engines/index.js +1 -1
- package/dist/node/engines/xp.js +1 -1
- package/dist/node/entities/index.js +1 -1
- package/dist/node/entities/journey.js +1 -0
- package/dist/node/index.js +14 -13
- package/dist/node/learning-journey.feature.js +1 -1
- package/dist/node/runtime/index.js +1 -0
- package/dist/node/runtime/matchers.js +1 -0
- package/dist/node/runtime/progress-state.js +1 -0
- package/dist/node/runtime/snapshot.js +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/journey-runtime.test.d.ts +1 -0
- package/dist/runtime/matchers.d.ts +20 -0
- package/dist/runtime/matchers.js +2 -0
- package/dist/runtime/progress-state.d.ts +19 -0
- package/dist/runtime/progress-state.js +2 -0
- package/dist/runtime/snapshot.d.ts +8 -0
- package/dist/runtime/snapshot.js +2 -0
- package/dist/track-spec.d.ts +118 -87
- package/package.json +86 -30
- package/dist/browser/contracts/onboarding.js +0 -1
- package/dist/browser/entities/onboarding.js +0 -1
- package/dist/contracts/onboarding.js +0 -2
- package/dist/entities/onboarding.js +0 -2
- package/dist/node/contracts/onboarding.js +0 -1
- package/dist/node/entities/onboarding.js +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var q=["modules.learning-journey"];import{defineCommand as F,defineQuery as B}from"@contractspec/lib.contracts-spec";import{defineSchemaModel as x,ScalarTypeEnum as j}from"@contractspec/lib.schema";var H=x({name:"JourneyCondition",description:"Adaptive completion condition for a journey step.",fields:{kind:{type:j.String_unsecure(),isOptional:!0},eventName:{type:j.String_unsecure(),isOptional:!1},eventVersion:{type:j.Int_unsecure(),isOptional:!0},sourceModule:{type:j.String_unsecure(),isOptional:!0},payloadFilter:{type:j.JSON(),isOptional:!0},atLeast:{type:j.Int_unsecure(),isOptional:!0},withinHours:{type:j.Int_unsecure(),isOptional:!0},withinHoursOfStart:{type:j.Int_unsecure(),isOptional:!0},availableAfterHours:{type:j.Int_unsecure(),isOptional:!0},skillIdField:{type:j.String_unsecure(),isOptional:!0},masteryField:{type:j.String_unsecure(),isOptional:!0},minimumMastery:{type:j.Float_unsecure(),isOptional:!0},requiredCount:{type:j.Int_unsecure(),isOptional:!0}}}),D=x({name:"JourneyReward",description:"XP and badge rewards for journey outcomes.",fields:{badgeKey:{type:j.String_unsecure(),isOptional:!0},xp:{type:j.Int_unsecure(),isOptional:!0}}}),K=x({name:"JourneyStep",description:"Adaptive learning journey step definition.",fields:{id:{type:j.String_unsecure(),isOptional:!1},title:{type:j.String_unsecure(),isOptional:!1},description:{type:j.String_unsecure(),isOptional:!0},instructions:{type:j.String_unsecure(),isOptional:!0},helpUrl:{type:j.String_unsecure(),isOptional:!0},order:{type:j.Int_unsecure(),isOptional:!0},completion:{type:H,isOptional:!1},availability:{type:j.JSON(),isOptional:!0},prerequisites:{type:j.JSON(),isOptional:!0},prerequisiteMode:{type:j.String_unsecure(),isOptional:!0},branches:{type:j.JSON(),isOptional:!0},reward:{type:D,isOptional:!0},xpReward:{type:j.Int_unsecure(),isOptional:!0},isRequired:{type:j.Boolean(),isOptional:!0},canSkip:{type:j.Boolean(),isOptional:!0},actionUrl:{type:j.String_unsecure(),isOptional:!0},actionLabel:{type:j.String_unsecure(),isOptional:!0},metadata:{type:j.JSON(),isOptional:!0}}}),V=x({name:"JourneyTrack",description:"Headless adaptive journey track definition.",fields:{id:{type:j.String_unsecure(),isOptional:!1},productId:{type:j.String_unsecure(),isOptional:!0},name:{type:j.String_unsecure(),isOptional:!1},description:{type:j.String_unsecure(),isOptional:!0},targetUserSegment:{type:j.String_unsecure(),isOptional:!0},targetRole:{type:j.String_unsecure(),isOptional:!0},totalXp:{type:j.Int_unsecure(),isOptional:!0},isActive:{type:j.Boolean(),isOptional:!0},isRequired:{type:j.Boolean(),isOptional:!0},canSkip:{type:j.Boolean(),isOptional:!0},streakRule:{type:j.JSON(),isOptional:!0},completionRewards:{type:D,isOptional:!0},metadata:{type:j.JSON(),isOptional:!0},steps:{type:K,isArray:!0,isOptional:!1}}}),X=x({name:"JourneyStepProgress",description:"Persisted and projected state for a journey step.",fields:{stepId:{type:j.String_unsecure(),isOptional:!1},status:{type:j.String_unsecure(),isOptional:!1},xpEarned:{type:j.Int_unsecure(),isOptional:!1},selectedBranchKey:{type:j.String_unsecure(),isOptional:!0},availableAt:{type:j.DateTime(),isOptional:!0},dueAt:{type:j.DateTime(),isOptional:!0},completedAt:{type:j.DateTime(),isOptional:!0},skippedAt:{type:j.DateTime(),isOptional:!0},blockedAt:{type:j.DateTime(),isOptional:!0},missedAt:{type:j.DateTime(),isOptional:!0},triggeringEvent:{type:j.String_unsecure(),isOptional:!0},eventPayload:{type:j.JSON(),isOptional:!0},occurrences:{type:j.Int_unsecure(),isOptional:!0},masteryCount:{type:j.Int_unsecure(),isOptional:!0}}}),z=x({name:"JourneyProgress",description:"Projected adaptive journey progress snapshot.",fields:{learnerId:{type:j.String_unsecure(),isOptional:!0},trackId:{type:j.String_unsecure(),isOptional:!1},progressPercent:{type:j.Int_unsecure(),isOptional:!1},isCompleted:{type:j.Boolean(),isOptional:!1},xpEarned:{type:j.Int_unsecure(),isOptional:!1},streakDays:{type:j.Int_unsecure(),isOptional:!1},badges:{type:j.String_unsecure(),isArray:!0,isOptional:!1},activeStepCount:{type:j.Int_unsecure(),isOptional:!1},completedStepCount:{type:j.Int_unsecure(),isOptional:!1},nextStepId:{type:j.String_unsecure(),isOptional:!0},currentStepId:{type:j.String_unsecure(),isOptional:!0},startedAt:{type:j.DateTime(),isOptional:!0},completedAt:{type:j.DateTime(),isOptional:!0},lastActivityAt:{type:j.DateTime(),isOptional:!0},steps:{type:X,isArray:!0,isOptional:!1}}}),Z=x({name:"JourneyTrackListInput",description:"Filters for listing adaptive journey tracks.",fields:{learnerId:{type:j.String_unsecure(),isOptional:!0},productId:{type:j.String_unsecure(),isOptional:!0},trackIds:{type:j.String_unsecure(),isArray:!0,isOptional:!0},includeProgress:{type:j.Boolean(),isOptional:!0}}}),$=x({name:"JourneyTrackListOutput",description:"Adaptive journey catalog with optional progress snapshots.",fields:{tracks:{type:V,isArray:!0,isOptional:!1},progress:{type:z,isArray:!0,isOptional:!0}}}),v=x({name:"JourneyProgressInput",description:"Input for fetching projected progress for one track.",fields:{learnerId:{type:j.String_unsecure(),isOptional:!0},trackId:{type:j.String_unsecure(),isOptional:!1}}}),b=x({name:"JourneyRecordEventInput",description:"Domain event used to advance an adaptive journey.",fields:{learnerId:{type:j.String_unsecure(),isOptional:!1},trackId:{type:j.String_unsecure(),isOptional:!0},eventName:{type:j.String_unsecure(),isOptional:!1},eventVersion:{type:j.Int_unsecure(),isOptional:!0},sourceModule:{type:j.String_unsecure(),isOptional:!0},eventPayload:{type:j.JSON(),isOptional:!0},occurredAt:{type:j.DateTime(),isOptional:!0}}}),Q=B({meta:{key:"learning.journey.listTracks",version:"1.0.0",stability:"stable",owners:[...q],tags:["adaptive-learning","journey","learning"],description:"List adaptive learning journeys for a learner or product.",goal:"Expose the adaptive journey catalog to UI and API surfaces.",context:"Called when rendering journey lists, launchers, or registries."},io:{input:Z,output:$},policy:{auth:"user"}}),U=B({meta:{key:"learning.journey.getProgress",version:"1.0.0",stability:"stable",owners:[...q],tags:["adaptive-learning","journey","progress"],description:"Project the latest adaptive journey progress for one track.",goal:"Render next-step, branch, and reward state consistently.",context:"Called by widgets, journey detail pages, and adaptive shells."},io:{input:v,output:z},policy:{auth:"user"}}),W=F({meta:{key:"learning.journey.recordEvent",version:"1.0.0",stability:"stable",owners:[...q],tags:["adaptive-learning","journey","events"],description:"Record a domain event and re-evaluate an adaptive journey.",goal:"Advance branch-aware journey progress from product activity.",context:"Called by event handlers when product activity may unlock or complete steps."},io:{input:b,output:z},policy:{auth:"user"}});export{W as RecordJourneyEventContract,Q as ListJourneyTracksContract,V as JourneyTrackModel,z as JourneyProgressModel,U as GetJourneyProgressContract};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{defineSchemaModel as t,ScalarTypeEnum as e}from"@contractspec/lib.schema";var
|
|
2
|
+
var s=["modules.learning-journey"];import{defineSchemaModel as t,ScalarTypeEnum as e}from"@contractspec/lib.schema";var S=t({name:"Course",description:"A learning course",fields:{id:{type:e.String_unsecure(),isOptional:!1},title:{type:e.String_unsecure(),isOptional:!1},slug:{type:e.String_unsecure(),isOptional:!1},description:{type:e.String_unsecure(),isOptional:!0},difficulty:{type:e.String_unsecure(),isOptional:!1},status:{type:e.String_unsecure(),isOptional:!1},estimatedDuration:{type:e.Int_unsecure(),isOptional:!0},thumbnailUrl:{type:e.String_unsecure(),isOptional:!0},createdAt:{type:e.DateTime(),isOptional:!1}}}),f=t({name:"Learner",description:"A learner profile",fields:{id:{type:e.String_unsecure(),isOptional:!1},userId:{type:e.String_unsecure(),isOptional:!1},displayName:{type:e.String_unsecure(),isOptional:!0},level:{type:e.Int_unsecure(),isOptional:!1},totalXp:{type:e.Int_unsecure(),isOptional:!1},currentStreak:{type:e.Int_unsecure(),isOptional:!1},longestStreak:{type:e.Int_unsecure(),isOptional:!1},createdAt:{type:e.DateTime(),isOptional:!1}}}),n=t({name:"Enrollment",description:"A course enrollment",fields:{id:{type:e.String_unsecure(),isOptional:!1},learnerId:{type:e.String_unsecure(),isOptional:!1},courseId:{type:e.String_unsecure(),isOptional:!1},status:{type:e.String_unsecure(),isOptional:!1},progress:{type:e.Int_unsecure(),isOptional:!1},startedAt:{type:e.DateTime(),isOptional:!0},completedAt:{type:e.DateTime(),isOptional:!0}}}),I=t({name:"LessonProgress",description:"Lesson progress",fields:{id:{type:e.String_unsecure(),isOptional:!1},learnerId:{type:e.String_unsecure(),isOptional:!1},lessonId:{type:e.String_unsecure(),isOptional:!1},status:{type:e.String_unsecure(),isOptional:!1},progress:{type:e.Int_unsecure(),isOptional:!1},score:{type:e.Int_unsecure(),isOptional:!0},timeSpent:{type:e.Int_unsecure(),isOptional:!1},completedAt:{type:e.DateTime(),isOptional:!0}}}),x=t({name:"Deck",description:"A flashcard deck",fields:{id:{type:e.String_unsecure(),isOptional:!1},title:{type:e.String_unsecure(),isOptional:!1},description:{type:e.String_unsecure(),isOptional:!0},cardCount:{type:e.Int_unsecure(),isOptional:!1},isPublic:{type:e.Boolean(),isOptional:!1},createdAt:{type:e.DateTime(),isOptional:!1}}}),O=t({name:"Card",description:"A flashcard",fields:{id:{type:e.String_unsecure(),isOptional:!1},deckId:{type:e.String_unsecure(),isOptional:!1},front:{type:e.String_unsecure(),isOptional:!1},back:{type:e.String_unsecure(),isOptional:!1},hints:{type:e.JSON(),isOptional:!0},isDue:{type:e.Boolean(),isOptional:!1},nextReviewAt:{type:e.DateTime(),isOptional:!0}}}),g=t({name:"Achievement",description:"An achievement",fields:{id:{type:e.String_unsecure(),isOptional:!1},key:{type:e.String_unsecure(),isOptional:!1},name:{type:e.String_unsecure(),isOptional:!1},description:{type:e.String_unsecure(),isOptional:!1},icon:{type:e.String_unsecure(),isOptional:!0},xpReward:{type:e.Int_unsecure(),isOptional:!1},unlockedAt:{type:e.DateTime(),isOptional:!0}}}),a=t({name:"EnrollInCourseInput",description:"Input for enrolling in a course",fields:{courseId:{type:e.String_unsecure(),isOptional:!1}}}),p=t({name:"CompleteLessonInput",description:"Input for completing a lesson",fields:{lessonId:{type:e.String_unsecure(),isOptional:!1},score:{type:e.Int_unsecure(),isOptional:!0},timeSpent:{type:e.Int_unsecure(),isOptional:!1}}}),l=t({name:"SubmitCardReviewInput",description:"Input for submitting a card review",fields:{cardId:{type:e.String_unsecure(),isOptional:!1},rating:{type:e.String_unsecure(),isOptional:!1},responseTimeMs:{type:e.Int_unsecure(),isOptional:!0}}}),o=t({name:"GetDueCardsInput",description:"Input for getting due cards",fields:{deckId:{type:e.String_unsecure(),isOptional:!0},limit:{type:e.Int_unsecure(),isOptional:!0}}}),u=t({name:"GetDueCardsOutput",description:"Output for getting due cards",fields:{cards:{type:O,isArray:!0,isOptional:!1},total:{type:e.Int_unsecure(),isOptional:!1}}}),c=t({name:"GetLearnerDashboardInput",description:"Input for getting learner dashboard",fields:{learnerId:{type:e.String_unsecure(),isOptional:!0}}}),d=t({name:"LearnerDashboard",description:"Learner dashboard data",fields:{learner:{type:f,isOptional:!1},currentStreak:{type:e.Int_unsecure(),isOptional:!1},dailyXpGoal:{type:e.Int_unsecure(),isOptional:!1},dailyXpProgress:{type:e.Int_unsecure(),isOptional:!1},activeEnrollments:{type:n,isArray:!0,isOptional:!1},recentAchievements:{type:g,isArray:!0,isOptional:!1},dueCardCount:{type:e.Int_unsecure(),isOptional:!1}}}),i=t({name:"SuccessOutput",description:"Generic success output",fields:{success:{type:e.Boolean(),isOptional:!1},xpEarned:{type:e.Int_unsecure(),isOptional:!0}}});import{defineCommand as r,defineQuery as y}from"@contractspec/lib.contracts-spec";var T=r({meta:{key:"learning.enroll",version:"1.0.0",stability:"stable",owners:[...s],tags:["learning","enrollment"],description:"Enroll in a course.",goal:"Start learning a new course.",context:"Called when a learner wants to start a course."},io:{input:a,output:n,errors:{COURSE_NOT_FOUND:{description:"Course does not exist",http:404,gqlCode:"COURSE_NOT_FOUND",when:"Course ID is invalid"},ALREADY_ENROLLED:{description:"Already enrolled in course",http:409,gqlCode:"ALREADY_ENROLLED",when:"Learner is already enrolled"}}},policy:{auth:"user"}}),v=r({meta:{key:"learning.completeLesson",version:"1.0.0",stability:"stable",owners:[...s],tags:["learning","progress"],description:"Mark a lesson as completed.",goal:"Record lesson completion and earn XP.",context:"Called when a learner finishes a lesson."},io:{input:p,output:i,errors:{LESSON_NOT_FOUND:{description:"Lesson does not exist",http:404,gqlCode:"LESSON_NOT_FOUND",when:"Lesson ID is invalid"},NOT_ENROLLED:{description:"Not enrolled in course",http:403,gqlCode:"NOT_ENROLLED",when:"Learner is not enrolled in the course"}}},policy:{auth:"user"}}),C=r({meta:{key:"learning.submitCardReview",version:"1.0.0",stability:"stable",owners:[...s],tags:["learning","flashcards"],description:"Submit a flashcard review.",goal:"Record review and update SRS schedule.",context:"Called when reviewing flashcards."},io:{input:l,output:i,errors:{CARD_NOT_FOUND:{description:"Card does not exist",http:404,gqlCode:"CARD_NOT_FOUND",when:"Card ID is invalid"},INVALID_RATING:{description:"Invalid rating",http:400,gqlCode:"INVALID_RATING",when:"Rating must be AGAIN, HARD, GOOD, or EASY"}}},policy:{auth:"user"}}),b=y({meta:{key:"learning.getDueCards",version:"1.0.0",stability:"stable",owners:[...s],tags:["learning","flashcards"],description:"Get flashcards due for review.",goal:"Get the next batch of cards to review.",context:"Called when starting a review session."},io:{input:o,output:u},policy:{auth:"user"}}),M=y({meta:{key:"learning.getDashboard",version:"1.0.0",stability:"stable",owners:[...s],tags:["learning","dashboard"],description:"Get learner dashboard data.",goal:"Display learner progress and stats.",context:"Called when viewing the learning dashboard."},io:{input:c,output:d},policy:{auth:"user"}});export{C as SubmitCardReviewContract,M as GetLearnerDashboardContract,b as GetDueCardsContract,T as EnrollInCourseContract,v as CompleteLessonContract};
|
package/dist/docs/index.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{registerDocBlocks as m}from"@contractspec/lib.contracts-spec/docs";var f=[{id:"docs.learning-journey.engine",title:"Learning Journey Engine",summary:"
|
|
2
|
+
import{registerDocBlocks as m}from"@contractspec/lib.contracts-spec/docs";var f=[{id:"docs.learning-journey.engine",title:"Learning Journey Engine",summary:"Headless adaptive journey runtime for tracks, branching steps, progress, quizzes, streaks, XP, and AI coaching hooks.",kind:"reference",visibility:"public",route:"/docs/learning-journey/engine",tags:["adaptive-learning","journey","education"],body:`## Capabilities
|
|
3
3
|
|
|
4
4
|
- **Entities**: Learner, Track, Module, Step, Progress, Quiz, Flashcard, AI Coach, Gamification (XP, streaks, badges).
|
|
5
|
-
- **Contracts**: enroll/resume/advance steps, complete quizzes, record streaks, assign XP, fetch progress dashboards,
|
|
5
|
+
- **Contracts**: enroll/resume/advance steps, complete quizzes, record streaks, assign XP, fetch progress dashboards, journey list/progress/recordEvent.
|
|
6
|
+
- **Runtime**: canonical branch/prerequisite evaluator + projected next-step snapshots.
|
|
6
7
|
- **Engines**: spaced-repetition (SRS), streak calculator, XP progression.
|
|
7
|
-
- **Events**: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded,
|
|
8
|
+
- **Events**: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded, journey.started/completed/step_completed.
|
|
8
9
|
|
|
9
10
|
## Completion conditions
|
|
10
11
|
- Event-based: name/version/source + payload filter
|
|
11
12
|
- Count-based: require N events (optional time window)
|
|
12
13
|
- Time-bounded: must complete within a window; steps can unlock by day/hour
|
|
13
|
-
-
|
|
14
|
+
- Mastery: complete when cards/skills hit mastery thresholds (with required counts)
|
|
14
15
|
|
|
15
16
|
## Usage
|
|
16
17
|
|
|
@@ -21,7 +22,7 @@ import{registerDocBlocks as m}from"@contractspec/lib.contracts-spec/docs";var f=
|
|
|
21
22
|
- Import from \`@contractspec/module.learning-journey\` into your spec registry.
|
|
22
23
|
|
|
23
24
|
3) Bind to product actions
|
|
24
|
-
- Tie \`
|
|
25
|
+
- Tie \`JourneyStep\` completion conditions and branch rules to domain events (e.g., deal.created, agent.run.completed, drill.session.completed).
|
|
25
26
|
- Trigger notifications via Notification Center and audits on completion.
|
|
26
27
|
|
|
27
28
|
4) Gamification
|
|
@@ -42,10 +43,10 @@ const updated = streak.compute({ lastActiveAt: new Date(), today: new Date() });
|
|
|
42
43
|
- Keep steps bound to real product events, not just button clicks.
|
|
43
44
|
- Avoid storing PII in content; keep org/user scoping for multi-tenant isolation.
|
|
44
45
|
- Emit analytics and audit logs for completions; respect \`prefers-reduced-motion\` in UIs consuming these specs.
|
|
45
|
-
- Track completion bonuses: \`
|
|
46
|
+
- Track completion bonuses: \`completionRewards\`, optional \`streakRule\`, and branch-level rewards.
|
|
46
47
|
`},{id:"docs.learning-journey.goal",title:"Learning Journey \u2014 Goal",summary:"Why the learning journey engine exists and the outcomes it targets.",kind:"goal",visibility:"public",route:"/docs/learning-journey/goal",tags:["learning","goal"],body:`## Why it matters
|
|
47
|
-
- Provides a regenerable
|
|
48
|
-
- Keeps tracks, steps, quizzes, and gamification consistent across surfaces.
|
|
48
|
+
- Provides a regenerable adaptive-journey engine tied to product signals.
|
|
49
|
+
- Keeps tracks, steps, branches, quizzes, and gamification consistent across surfaces.
|
|
49
50
|
|
|
50
51
|
## Business/Product goal
|
|
51
52
|
- Drive activation and retention with measurable progress, SRS, and streaks.
|
|
@@ -56,18 +57,18 @@ const updated = streak.compute({ lastActiveAt: new Date(), today: new Date() });
|
|
|
56
57
|
- Analytics/audit hooks exist for completions and streaks.`},{id:"docs.learning-journey.usage",title:"Learning Journey \u2014 Usage",summary:"How to compose, bind, and regenerate journeys safely.",kind:"usage",visibility:"public",route:"/docs/learning-journey/usage",tags:["learning","usage"],body:`## Setup
|
|
57
58
|
1) Include \`learningJourneyEntities\` in schema composition.
|
|
58
59
|
2) Register contracts/events from \`@contractspec/module.learning-journey\`.
|
|
59
|
-
3) Bind steps to real product events (e.g., deal.created, run.completed).
|
|
60
|
+
3) Bind steps and branch outcomes to real product events (e.g., deal.created, run.completed).
|
|
60
61
|
|
|
61
62
|
## Extend & regenerate
|
|
62
|
-
1) Update track/module/step definitions or quiz schemas in spec.
|
|
63
|
+
1) Update track/module/step definitions, branch rules, or quiz schemas in spec.
|
|
63
64
|
2) Regenerate to sync UI/API/events; mark PII paths where needed.
|
|
64
65
|
3) Use Feature Flags to trial new tracks or streak rules.
|
|
65
66
|
|
|
66
67
|
## Guardrails
|
|
67
|
-
- Avoid hardcoded progression; keep
|
|
68
|
+
- Avoid hardcoded progression; keep runtime rules declarative.
|
|
68
69
|
- Emit analytics/audit for completions; respect user locale/accessibility in presentations.
|
|
69
70
|
- Keep content free of PII; scope learners by org/tenant.`},{id:"docs.learning-journey.constraints",title:"Learning Journey \u2014 Constraints & Safety",summary:"Internal guardrails for progression, telemetry, and regeneration semantics.",kind:"reference",visibility:"internal",route:"/docs/learning-journey/constraints",tags:["learning","constraints","internal"],body:`## Constraints
|
|
70
|
-
- Progression (tracks/modules/steps) and engines (SRS, streaks, XP) must stay declarative in spec.
|
|
71
|
+
- Progression (tracks/modules/steps/branches) and engines (SRS, streaks, XP) must stay declarative in spec.
|
|
71
72
|
- Events to emit: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded.
|
|
72
73
|
- Regeneration should not change scoring/streak rules without explicit spec change.
|
|
73
74
|
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{registerDocBlocks as f}from"@contractspec/lib.contracts-spec/docs";var h=[{id:"docs.learning-journey.engine",title:"Learning Journey Engine",summary:"
|
|
2
|
+
import{registerDocBlocks as f}from"@contractspec/lib.contracts-spec/docs";var h=[{id:"docs.learning-journey.engine",title:"Learning Journey Engine",summary:"Headless adaptive journey runtime for tracks, branching steps, progress, quizzes, streaks, XP, and AI coaching hooks.",kind:"reference",visibility:"public",route:"/docs/learning-journey/engine",tags:["adaptive-learning","journey","education"],body:`## Capabilities
|
|
3
3
|
|
|
4
4
|
- **Entities**: Learner, Track, Module, Step, Progress, Quiz, Flashcard, AI Coach, Gamification (XP, streaks, badges).
|
|
5
|
-
- **Contracts**: enroll/resume/advance steps, complete quizzes, record streaks, assign XP, fetch progress dashboards,
|
|
5
|
+
- **Contracts**: enroll/resume/advance steps, complete quizzes, record streaks, assign XP, fetch progress dashboards, journey list/progress/recordEvent.
|
|
6
|
+
- **Runtime**: canonical branch/prerequisite evaluator + projected next-step snapshots.
|
|
6
7
|
- **Engines**: spaced-repetition (SRS), streak calculator, XP progression.
|
|
7
|
-
- **Events**: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded,
|
|
8
|
+
- **Events**: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded, journey.started/completed/step_completed.
|
|
8
9
|
|
|
9
10
|
## Completion conditions
|
|
10
11
|
- Event-based: name/version/source + payload filter
|
|
11
12
|
- Count-based: require N events (optional time window)
|
|
12
13
|
- Time-bounded: must complete within a window; steps can unlock by day/hour
|
|
13
|
-
-
|
|
14
|
+
- Mastery: complete when cards/skills hit mastery thresholds (with required counts)
|
|
14
15
|
|
|
15
16
|
## Usage
|
|
16
17
|
|
|
@@ -21,7 +22,7 @@ import{registerDocBlocks as f}from"@contractspec/lib.contracts-spec/docs";var h=
|
|
|
21
22
|
- Import from \`@contractspec/module.learning-journey\` into your spec registry.
|
|
22
23
|
|
|
23
24
|
3) Bind to product actions
|
|
24
|
-
- Tie \`
|
|
25
|
+
- Tie \`JourneyStep\` completion conditions and branch rules to domain events (e.g., deal.created, agent.run.completed, drill.session.completed).
|
|
25
26
|
- Trigger notifications via Notification Center and audits on completion.
|
|
26
27
|
|
|
27
28
|
4) Gamification
|
|
@@ -42,10 +43,10 @@ const updated = streak.compute({ lastActiveAt: new Date(), today: new Date() });
|
|
|
42
43
|
- Keep steps bound to real product events, not just button clicks.
|
|
43
44
|
- Avoid storing PII in content; keep org/user scoping for multi-tenant isolation.
|
|
44
45
|
- Emit analytics and audit logs for completions; respect \`prefers-reduced-motion\` in UIs consuming these specs.
|
|
45
|
-
- Track completion bonuses: \`
|
|
46
|
+
- Track completion bonuses: \`completionRewards\`, optional \`streakRule\`, and branch-level rewards.
|
|
46
47
|
`},{id:"docs.learning-journey.goal",title:"Learning Journey \u2014 Goal",summary:"Why the learning journey engine exists and the outcomes it targets.",kind:"goal",visibility:"public",route:"/docs/learning-journey/goal",tags:["learning","goal"],body:`## Why it matters
|
|
47
|
-
- Provides a regenerable
|
|
48
|
-
- Keeps tracks, steps, quizzes, and gamification consistent across surfaces.
|
|
48
|
+
- Provides a regenerable adaptive-journey engine tied to product signals.
|
|
49
|
+
- Keeps tracks, steps, branches, quizzes, and gamification consistent across surfaces.
|
|
49
50
|
|
|
50
51
|
## Business/Product goal
|
|
51
52
|
- Drive activation and retention with measurable progress, SRS, and streaks.
|
|
@@ -56,18 +57,18 @@ const updated = streak.compute({ lastActiveAt: new Date(), today: new Date() });
|
|
|
56
57
|
- Analytics/audit hooks exist for completions and streaks.`},{id:"docs.learning-journey.usage",title:"Learning Journey \u2014 Usage",summary:"How to compose, bind, and regenerate journeys safely.",kind:"usage",visibility:"public",route:"/docs/learning-journey/usage",tags:["learning","usage"],body:`## Setup
|
|
57
58
|
1) Include \`learningJourneyEntities\` in schema composition.
|
|
58
59
|
2) Register contracts/events from \`@contractspec/module.learning-journey\`.
|
|
59
|
-
3) Bind steps to real product events (e.g., deal.created, run.completed).
|
|
60
|
+
3) Bind steps and branch outcomes to real product events (e.g., deal.created, run.completed).
|
|
60
61
|
|
|
61
62
|
## Extend & regenerate
|
|
62
|
-
1) Update track/module/step definitions or quiz schemas in spec.
|
|
63
|
+
1) Update track/module/step definitions, branch rules, or quiz schemas in spec.
|
|
63
64
|
2) Regenerate to sync UI/API/events; mark PII paths where needed.
|
|
64
65
|
3) Use Feature Flags to trial new tracks or streak rules.
|
|
65
66
|
|
|
66
67
|
## Guardrails
|
|
67
|
-
- Avoid hardcoded progression; keep
|
|
68
|
+
- Avoid hardcoded progression; keep runtime rules declarative.
|
|
68
69
|
- Emit analytics/audit for completions; respect user locale/accessibility in presentations.
|
|
69
70
|
- Keep content free of PII; scope learners by org/tenant.`},{id:"docs.learning-journey.constraints",title:"Learning Journey \u2014 Constraints & Safety",summary:"Internal guardrails for progression, telemetry, and regeneration semantics.",kind:"reference",visibility:"internal",route:"/docs/learning-journey/constraints",tags:["learning","constraints","internal"],body:`## Constraints
|
|
70
|
-
- Progression (tracks/modules/steps) and engines (SRS, streaks, XP) must stay declarative in spec.
|
|
71
|
+
- Progression (tracks/modules/steps/branches) and engines (SRS, streaks, XP) must stay declarative in spec.
|
|
71
72
|
- Events to emit: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded.
|
|
72
73
|
- Regeneration should not change scoring/streak rules without explicit spec change.
|
|
73
74
|
|
package/dist/engines/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var N={learningSteps:[1,10],graduatingInterval:1,easyInterval:4,relearningSteps:[10],minEaseFactor:1.3,maxInterval:365,intervalModifier:1,newIntervalModifier:0.5,hardIntervalModifier:1.2,easyBonus:1.3};class K{config;constructor(j={}){this.config={...N,...j}}calculateNextReview(j,Q,W=new Date){if(!j.isGraduated&&!j.isRelearning)return this.handleLearningCard(j,Q,W);if(j.isRelearning)return this.handleRelearningCard(j,Q,W);return this.handleReviewCard(j,Q,W)}getInitialState(){return{interval:0,easeFactor:2.5,repetitions:0,learningStep:0,isGraduated:!1,isRelearning:!1,lapses:0}}isDue(j,Q=new Date){return j<=Q}getOverdueDays(j,Q=new Date){let W=Q.getTime()-j.getTime();return Math.floor(W/86400000)}handleLearningCard(j,Q,W){let H=this.config.learningSteps,V=j.learningStep,Z=!1,$=0,J;switch(Q){case"AGAIN":V=0,$=H[0]??1,J=this.addMinutes(W,$);break;case"HARD":$=H[V]??H[0]??1,J=this.addMinutes(W,$);break;case"GOOD":if(V++,V>=H.length)Z=!0,$=this.config.graduatingInterval,J=this.addDays(W,$);else $=H[V]??10,J=this.addMinutes(W,$);break;case"EASY":Z=!0,$=this.config.easyInterval,J=this.addDays(W,$);break}return{interval:Z?$:0,easeFactor:j.easeFactor,repetitions:Z?1:0,nextReviewAt:J,learningStep:V,isGraduated:Z,isRelearning:!1,lapses:j.lapses}}handleRelearningCard(j,Q,W){let H=this.config.relearningSteps,V=j.learningStep,Z=!0,$=0,J;switch(Q){case"AGAIN":V=0,$=H[0]??10,J=this.addMinutes(W,$);break;case"HARD":$=H[V]??H[0]??10,J=this.addMinutes(W,$);break;case"GOOD":if(V++,V>=H.length)Z=!1,$=Math.max(1,Math.floor(j.interval*this.config.newIntervalModifier)),J=this.addDays(W,$);else $=H[V]??10,J=this.addMinutes(W,$);break;case"EASY":Z=!1,$=Math.max(1,Math.floor(j.interval*this.config.newIntervalModifier*1.5)),J=this.addDays(W,$);break}return{interval:Z?j.interval:$,easeFactor:j.easeFactor,repetitions:Z?j.repetitions:j.repetitions+1,nextReviewAt:J,learningStep:V,isGraduated:!0,isRelearning:Z,lapses:j.lapses}}handleReviewCard(j,Q,W){let H,V=j.easeFactor,Z=j.repetitions,$=!1,J=0,q=j.lapses;switch(Q){case"AGAIN":return q++,$=!0,J=0,V=Math.max(this.config.minEaseFactor,V-0.2),H=j.interval,{interval:H,easeFactor:V,repetitions:Z,nextReviewAt:this.addMinutes(W,this.config.relearningSteps[0]??10),learningStep:J,isGraduated:!0,isRelearning:!0,lapses:q};case"HARD":V=Math.max(this.config.minEaseFactor,V-0.15),H=Math.max(j.interval+1,j.interval*this.config.hardIntervalModifier);break;case"GOOD":H=j.interval*V*this.config.intervalModifier,Z++;break;case"EASY":V=V+0.15,H=j.interval*V*this.config.easyBonus*this.config.intervalModifier,Z++;break}return H=Math.min(Math.round(H),this.config.maxInterval),H=Math.max(1,H),{interval:H,easeFactor:V,repetitions:Z,nextReviewAt:this.addDays(W,H),learningStep:J,isGraduated:!0,isRelearning:$,lapses:q}}addMinutes(j,Q){return new Date(j.getTime()+Q*60*1000)}addDays(j,Q){return new Date(j.getTime()+Q*24*60*60*1000)}}var I=new K;var O={timezone:"UTC",freezesPerMonth:2,maxFreezes:5,gracePeriodHours:4};class h{config;constructor(j={}){this.config={...O,...j}}update(j,Q=new Date){let W=this.getDateString(Q),H={state:{...j},streakMaintained:!1,streakLost:!1,freezeUsed:!1,newStreak:!1,daysMissed:0};if(!j.lastActivityDate)return H.state.currentStreak=1,H.state.longestStreak=Math.max(1,j.longestStreak),H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.newStreak=!0,H.streakMaintained=!0,H;if(j.lastActivityDate===W)return H.state.lastActivityAt=Q,H.streakMaintained=!0,H;let V=this.getDaysBetween(j.lastActivityDate,W);if(V===1)return H.state.currentStreak=j.currentStreak+1,H.state.longestStreak=Math.max(H.state.currentStreak,j.longestStreak),H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.streakMaintained=!0,H;H.daysMissed=V-1;let Z=H.daysMissed;if(Z<=j.freezesRemaining)return H.state.freezesRemaining=j.freezesRemaining-Z,H.state.freezeUsedAt=Q,H.state.currentStreak=j.currentStreak+1,H.state.longestStreak=Math.max(H.state.currentStreak,j.longestStreak),H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.freezeUsed=!0,H.streakMaintained=!0,H;return H.streakLost=!0,H.state.currentStreak=1,H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.newStreak=!0,H}checkStatus(j,Q=new Date){if(!j.lastActivityDate)return{isActive:!1,willExpireAt:null,canUseFreeze:!1,daysUntilExpiry:0};let W=this.getDateString(Q),H=this.getDaysBetween(j.lastActivityDate,W);if(H===0){let Z=this.addDays(Q,1);return Z.setHours(23,59,59,999),{isActive:!0,willExpireAt:Z,canUseFreeze:j.freezesRemaining>0,daysUntilExpiry:1}}if(H===1){let Z=new Date(Q);return Z.setHours(23+this.config.gracePeriodHours,59,59,999),{isActive:!0,willExpireAt:Z,canUseFreeze:j.freezesRemaining>0,daysUntilExpiry:0}}let V=H-1;return{isActive:V<=j.freezesRemaining,willExpireAt:null,canUseFreeze:V<=j.freezesRemaining,daysUntilExpiry:-V}}useFreeze(j,Q=new Date){if(j.freezesRemaining<=0)return null;return{...j,freezesRemaining:j.freezesRemaining-1,freezeUsedAt:Q}}awardMonthlyFreezes(j){return{...j,freezesRemaining:Math.min(j.freezesRemaining+this.config.freezesPerMonth,this.config.maxFreezes)}}getInitialState(){return{currentStreak:0,longestStreak:0,lastActivityAt:null,lastActivityDate:null,freezesRemaining:this.config.freezesPerMonth,freezeUsedAt:null}}getMilestones(j){let Q=[3,7,14,30,60,90,180,365,500,1000],W=Q.filter((V)=>j>=V),H=Q.find((V)=>j<V)??null;return{achieved:W,next:H}}getDateString(j){let Q=j.getFullYear(),W=String(j.getMonth()+1).padStart(2,"0"),H=String(j.getDate()).padStart(2,"0");return`${Q}-${W}-${H}`}getDaysBetween(j,Q){let W=new Date(j),V=new Date(Q).getTime()-W.getTime();return Math.floor(V/86400000)}addDays(j,Q){return new Date(j.getTime()+Q*24*60*60*1000)}}var x=new h;import{defineTranslation as L}from"@contractspec/lib.contracts-spec/translations";var B=L({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels for the learning-journey module",owners:["platform"],stability:"experimental"},locale:"en",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Score Bonus",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Perfect Score",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"First Attempt",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Retry Penalty",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Streak Bonus",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as G}from"@contractspec/lib.contracts-spec/translations";var M=G({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (Spanish)",owners:["platform"],stability:"experimental"},locale:"es",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonificaci\xF3n por puntuaci\xF3n",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Puntuaci\xF3n perfecta",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Primer intento",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Penalizaci\xF3n por reintento",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonificaci\xF3n por racha",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as T}from"@contractspec/lib.contracts-spec/translations";var U=T({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (French)",owners:["platform"],stability:"experimental"},locale:"fr",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonus de score",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Score parfait",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Premier essai",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"P\xE9nalit\xE9 de r\xE9essai",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonus de s\xE9rie",description:"XP breakdown label for streak bonus"}}});import{createI18nFactory as m}from"@contractspec/lib.contracts-spec/translations";var z=m({specKey:"learning-journey.messages",catalogs:[B,U,M]}),P=z.create,v=z.getDefault,d=z.resetRegistry;var Y={baseValues:{lesson_complete:10,quiz_pass:20,quiz_perfect:50,flashcard_review:1,course_complete:200,module_complete:50,streak_bonus:5,achievement_unlock:0,daily_goal_complete:15,first_lesson:25,onboarding_step:5,onboarding_complete:50},scoreThresholds:[{min:90,multiplier:1.5},{min:80,multiplier:1.25},{min:70,multiplier:1},{min:60,multiplier:0.75},{min:0,multiplier:0.5}],streakTiers:[{days:365,bonus:50},{days:180,bonus:30},{days:90,bonus:20},{days:30,bonus:15},{days:14,bonus:10},{days:7,bonus:5},{days:3,bonus:2},{days:1,bonus:0}],perfectScoreMultiplier:1.5,firstAttemptBonus:10,retryPenalty:0.5,speedBonusMultiplier:1.2,speedBonusThreshold:0.8};class C{config;constructor(j={}){this.config={...Y,...j,baseValues:{...Y.baseValues,...j.baseValues},scoreThresholds:j.scoreThresholds||Y.scoreThresholds,streakTiers:j.streakTiers||Y.streakTiers}}calculate(j){let Q=[],W=j.baseXp??this.config.baseValues[j.activity],H=W;if(Q.push({source:"base",amount:W}),j.score!==void 0){let V=this.getScoreMultiplier(j.score);if(V!==1){let Z=Math.round(W*(V-1));H+=Z,Q.push({source:"score_bonus",amount:Z,multiplier:V})}if(j.score===100){let Z=Math.round(W*(this.config.perfectScoreMultiplier-1));H+=Z,Q.push({source:"perfect_score",amount:Z,multiplier:this.config.perfectScoreMultiplier})}}if(j.attemptNumber===1&&!j.isRetry)H+=this.config.firstAttemptBonus,Q.push({source:"first_attempt",amount:this.config.firstAttemptBonus});if(j.isRetry){let V=Math.round(H*(1-this.config.retryPenalty));H-=V,Q.push({source:"retry_penalty",amount:-V,multiplier:this.config.retryPenalty})}if(j.currentStreak&&j.currentStreak>0){let V=this.getStreakBonus(j.currentStreak);if(V>0)H+=V,Q.push({source:"streak_bonus",amount:V})}if(W>0)H=Math.max(1,H);return{totalXp:Math.round(H),baseXp:W,breakdown:Q}}calculateStreakBonus(j){let Q=this.getStreakBonus(j);return{totalXp:Q,baseXp:Q,breakdown:[{source:"streak_bonus",amount:Q}]}}getXpForLevel(j){if(j<=1)return 0;return Math.round(100*Math.pow(j-1,1.5))}getLevelFromXp(j){let Q=1,W=this.getXpForLevel(Q+1);while(j>=W&&Q<1000)Q++,W=this.getXpForLevel(Q+1);let H=this.getXpForLevel(Q),V=this.getXpForLevel(Q+1);return{level:Q,xpInLevel:j-H,xpForNextLevel:V-H}}getScoreMultiplier(j){for(let Q of this.config.scoreThresholds)if(j>=Q.min)return Q.multiplier;return 1}getStreakBonus(j){for(let Q of this.config.streakTiers)if(j>=Q.days)return Q.bonus;return 0}}var _={base:"xp.source.base",score_bonus:"xp.source.scoreBonus",perfect_score:"xp.source.perfectScore",first_attempt:"xp.source.firstAttempt",retry_penalty:"xp.source.retryPenalty",streak_bonus:"xp.source.streakBonus"};function u(j,Q){let W=P(Q),H=_[j];return H?W.t(H):j}var w=new C;export{w as xpEngine,x as streakEngine,I as srsEngine,u as getXpSourceLabel,C as XPEngine,h as StreakEngine,K as SRSEngine,Y as DEFAULT_XP_CONFIG,O as DEFAULT_STREAK_CONFIG,N as DEFAULT_SRS_CONFIG};
|
|
2
|
+
var N={learningSteps:[1,10],graduatingInterval:1,easyInterval:4,relearningSteps:[10],minEaseFactor:1.3,maxInterval:365,intervalModifier:1,newIntervalModifier:0.5,hardIntervalModifier:1.2,easyBonus:1.3};class K{config;constructor(j={}){this.config={...N,...j}}calculateNextReview(j,Q,W=new Date){if(!j.isGraduated&&!j.isRelearning)return this.handleLearningCard(j,Q,W);if(j.isRelearning)return this.handleRelearningCard(j,Q,W);return this.handleReviewCard(j,Q,W)}getInitialState(){return{interval:0,easeFactor:2.5,repetitions:0,learningStep:0,isGraduated:!1,isRelearning:!1,lapses:0}}isDue(j,Q=new Date){return j<=Q}getOverdueDays(j,Q=new Date){let W=Q.getTime()-j.getTime();return Math.floor(W/86400000)}handleLearningCard(j,Q,W){let H=this.config.learningSteps,V=j.learningStep,Z=!1,$=0,J;switch(Q){case"AGAIN":V=0,$=H[0]??1,J=this.addMinutes(W,$);break;case"HARD":$=H[V]??H[0]??1,J=this.addMinutes(W,$);break;case"GOOD":if(V++,V>=H.length)Z=!0,$=this.config.graduatingInterval,J=this.addDays(W,$);else $=H[V]??10,J=this.addMinutes(W,$);break;case"EASY":Z=!0,$=this.config.easyInterval,J=this.addDays(W,$);break}return{interval:Z?$:0,easeFactor:j.easeFactor,repetitions:Z?1:0,nextReviewAt:J,learningStep:V,isGraduated:Z,isRelearning:!1,lapses:j.lapses}}handleRelearningCard(j,Q,W){let H=this.config.relearningSteps,V=j.learningStep,Z=!0,$=0,J;switch(Q){case"AGAIN":V=0,$=H[0]??10,J=this.addMinutes(W,$);break;case"HARD":$=H[V]??H[0]??10,J=this.addMinutes(W,$);break;case"GOOD":if(V++,V>=H.length)Z=!1,$=Math.max(1,Math.floor(j.interval*this.config.newIntervalModifier)),J=this.addDays(W,$);else $=H[V]??10,J=this.addMinutes(W,$);break;case"EASY":Z=!1,$=Math.max(1,Math.floor(j.interval*this.config.newIntervalModifier*1.5)),J=this.addDays(W,$);break}return{interval:Z?j.interval:$,easeFactor:j.easeFactor,repetitions:Z?j.repetitions:j.repetitions+1,nextReviewAt:J,learningStep:V,isGraduated:!0,isRelearning:Z,lapses:j.lapses}}handleReviewCard(j,Q,W){let H,V=j.easeFactor,Z=j.repetitions,$=!1,J=0,q=j.lapses;switch(Q){case"AGAIN":return q++,$=!0,J=0,V=Math.max(this.config.minEaseFactor,V-0.2),H=j.interval,{interval:H,easeFactor:V,repetitions:Z,nextReviewAt:this.addMinutes(W,this.config.relearningSteps[0]??10),learningStep:J,isGraduated:!0,isRelearning:!0,lapses:q};case"HARD":V=Math.max(this.config.minEaseFactor,V-0.15),H=Math.max(j.interval+1,j.interval*this.config.hardIntervalModifier);break;case"GOOD":H=j.interval*V*this.config.intervalModifier,Z++;break;case"EASY":V=V+0.15,H=j.interval*V*this.config.easyBonus*this.config.intervalModifier,Z++;break}return H=Math.min(Math.round(H),this.config.maxInterval),H=Math.max(1,H),{interval:H,easeFactor:V,repetitions:Z,nextReviewAt:this.addDays(W,H),learningStep:J,isGraduated:!0,isRelearning:$,lapses:q}}addMinutes(j,Q){return new Date(j.getTime()+Q*60*1000)}addDays(j,Q){return new Date(j.getTime()+Q*24*60*60*1000)}}var I=new K;var O={timezone:"UTC",freezesPerMonth:2,maxFreezes:5,gracePeriodHours:4};class h{config;constructor(j={}){this.config={...O,...j}}update(j,Q=new Date){let W=this.getDateString(Q),H={state:{...j},streakMaintained:!1,streakLost:!1,freezeUsed:!1,newStreak:!1,daysMissed:0};if(!j.lastActivityDate)return H.state.currentStreak=1,H.state.longestStreak=Math.max(1,j.longestStreak),H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.newStreak=!0,H.streakMaintained=!0,H;if(j.lastActivityDate===W)return H.state.lastActivityAt=Q,H.streakMaintained=!0,H;let V=this.getDaysBetween(j.lastActivityDate,W);if(V===1)return H.state.currentStreak=j.currentStreak+1,H.state.longestStreak=Math.max(H.state.currentStreak,j.longestStreak),H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.streakMaintained=!0,H;H.daysMissed=V-1;let Z=H.daysMissed;if(Z<=j.freezesRemaining)return H.state.freezesRemaining=j.freezesRemaining-Z,H.state.freezeUsedAt=Q,H.state.currentStreak=j.currentStreak+1,H.state.longestStreak=Math.max(H.state.currentStreak,j.longestStreak),H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.freezeUsed=!0,H.streakMaintained=!0,H;return H.streakLost=!0,H.state.currentStreak=1,H.state.lastActivityAt=Q,H.state.lastActivityDate=W,H.newStreak=!0,H}checkStatus(j,Q=new Date){if(!j.lastActivityDate)return{isActive:!1,willExpireAt:null,canUseFreeze:!1,daysUntilExpiry:0};let W=this.getDateString(Q),H=this.getDaysBetween(j.lastActivityDate,W);if(H===0){let Z=this.addDays(Q,1);return Z.setHours(23,59,59,999),{isActive:!0,willExpireAt:Z,canUseFreeze:j.freezesRemaining>0,daysUntilExpiry:1}}if(H===1){let Z=new Date(Q);return Z.setHours(23+this.config.gracePeriodHours,59,59,999),{isActive:!0,willExpireAt:Z,canUseFreeze:j.freezesRemaining>0,daysUntilExpiry:0}}let V=H-1;return{isActive:V<=j.freezesRemaining,willExpireAt:null,canUseFreeze:V<=j.freezesRemaining,daysUntilExpiry:-V}}useFreeze(j,Q=new Date){if(j.freezesRemaining<=0)return null;return{...j,freezesRemaining:j.freezesRemaining-1,freezeUsedAt:Q}}awardMonthlyFreezes(j){return{...j,freezesRemaining:Math.min(j.freezesRemaining+this.config.freezesPerMonth,this.config.maxFreezes)}}getInitialState(){return{currentStreak:0,longestStreak:0,lastActivityAt:null,lastActivityDate:null,freezesRemaining:this.config.freezesPerMonth,freezeUsedAt:null}}getMilestones(j){let Q=[3,7,14,30,60,90,180,365,500,1000],W=Q.filter((V)=>j>=V),H=Q.find((V)=>j<V)??null;return{achieved:W,next:H}}getDateString(j){let Q=j.getFullYear(),W=String(j.getMonth()+1).padStart(2,"0"),H=String(j.getDate()).padStart(2,"0");return`${Q}-${W}-${H}`}getDaysBetween(j,Q){let W=new Date(j),V=new Date(Q).getTime()-W.getTime();return Math.floor(V/86400000)}addDays(j,Q){return new Date(j.getTime()+Q*24*60*60*1000)}}var x=new h;import{defineTranslation as L}from"@contractspec/lib.contracts-spec/translations";var B=L({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels for the learning-journey module",owners:["platform"],stability:"experimental"},locale:"en",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Score Bonus",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Perfect Score",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"First Attempt",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Retry Penalty",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Streak Bonus",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as G}from"@contractspec/lib.contracts-spec/translations";var M=G({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (Spanish)",owners:["platform"],stability:"experimental"},locale:"es",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonificaci\xF3n por puntuaci\xF3n",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Puntuaci\xF3n perfecta",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Primer intento",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Penalizaci\xF3n por reintento",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonificaci\xF3n por racha",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as T}from"@contractspec/lib.contracts-spec/translations";var U=T({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (French)",owners:["platform"],stability:"experimental"},locale:"fr",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonus de score",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Score parfait",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Premier essai",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"P\xE9nalit\xE9 de r\xE9essai",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonus de s\xE9rie",description:"XP breakdown label for streak bonus"}}});import{createI18nFactory as m}from"@contractspec/lib.contracts-spec/translations";var z=m({specKey:"learning-journey.messages",catalogs:[B,U,M]}),P=z.create,v=z.getDefault,d=z.resetRegistry;var Y={baseValues:{lesson_complete:10,quiz_pass:20,quiz_perfect:50,flashcard_review:1,course_complete:200,module_complete:50,streak_bonus:5,achievement_unlock:0,daily_goal_complete:15,first_lesson:25,journey_step:5,journey_complete:50},scoreThresholds:[{min:90,multiplier:1.5},{min:80,multiplier:1.25},{min:70,multiplier:1},{min:60,multiplier:0.75},{min:0,multiplier:0.5}],streakTiers:[{days:365,bonus:50},{days:180,bonus:30},{days:90,bonus:20},{days:30,bonus:15},{days:14,bonus:10},{days:7,bonus:5},{days:3,bonus:2},{days:1,bonus:0}],perfectScoreMultiplier:1.5,firstAttemptBonus:10,retryPenalty:0.5,speedBonusMultiplier:1.2,speedBonusThreshold:0.8};class C{config;constructor(j={}){this.config={...Y,...j,baseValues:{...Y.baseValues,...j.baseValues},scoreThresholds:j.scoreThresholds||Y.scoreThresholds,streakTiers:j.streakTiers||Y.streakTiers}}calculate(j){let Q=[],W=j.baseXp??this.config.baseValues[j.activity],H=W;if(Q.push({source:"base",amount:W}),j.score!==void 0){let V=this.getScoreMultiplier(j.score);if(V!==1){let Z=Math.round(W*(V-1));H+=Z,Q.push({source:"score_bonus",amount:Z,multiplier:V})}if(j.score===100){let Z=Math.round(W*(this.config.perfectScoreMultiplier-1));H+=Z,Q.push({source:"perfect_score",amount:Z,multiplier:this.config.perfectScoreMultiplier})}}if(j.attemptNumber===1&&!j.isRetry)H+=this.config.firstAttemptBonus,Q.push({source:"first_attempt",amount:this.config.firstAttemptBonus});if(j.isRetry){let V=Math.round(H*(1-this.config.retryPenalty));H-=V,Q.push({source:"retry_penalty",amount:-V,multiplier:this.config.retryPenalty})}if(j.currentStreak&&j.currentStreak>0){let V=this.getStreakBonus(j.currentStreak);if(V>0)H+=V,Q.push({source:"streak_bonus",amount:V})}if(W>0)H=Math.max(1,H);return{totalXp:Math.round(H),baseXp:W,breakdown:Q}}calculateStreakBonus(j){let Q=this.getStreakBonus(j);return{totalXp:Q,baseXp:Q,breakdown:[{source:"streak_bonus",amount:Q}]}}getXpForLevel(j){if(j<=1)return 0;return Math.round(100*Math.pow(j-1,1.5))}getLevelFromXp(j){let Q=1,W=this.getXpForLevel(Q+1);while(j>=W&&Q<1000)Q++,W=this.getXpForLevel(Q+1);let H=this.getXpForLevel(Q),V=this.getXpForLevel(Q+1);return{level:Q,xpInLevel:j-H,xpForNextLevel:V-H}}getScoreMultiplier(j){for(let Q of this.config.scoreThresholds)if(j>=Q.min)return Q.multiplier;return 1}getStreakBonus(j){for(let Q of this.config.streakTiers)if(j>=Q.days)return Q.bonus;return 0}}var _={base:"xp.source.base",score_bonus:"xp.source.scoreBonus",perfect_score:"xp.source.perfectScore",first_attempt:"xp.source.firstAttempt",retry_penalty:"xp.source.retryPenalty",streak_bonus:"xp.source.streakBonus"};function u(j,Q){let W=P(Q),H=_[j];return H?W.t(H):j}var w=new C;export{w as xpEngine,x as streakEngine,I as srsEngine,u as getXpSourceLabel,C as XPEngine,h as StreakEngine,K as SRSEngine,Y as DEFAULT_XP_CONFIG,O as DEFAULT_STREAK_CONFIG,N as DEFAULT_SRS_CONFIG};
|
package/dist/engines/xp.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Calculates XP rewards for various learning activities.
|
|
5
5
|
*/
|
|
6
|
-
export type XPActivityType = 'lesson_complete' | 'quiz_pass' | 'quiz_perfect' | 'flashcard_review' | 'course_complete' | 'module_complete' | 'streak_bonus' | 'achievement_unlock' | 'daily_goal_complete' | 'first_lesson' | '
|
|
6
|
+
export type XPActivityType = 'lesson_complete' | 'quiz_pass' | 'quiz_perfect' | 'flashcard_review' | 'course_complete' | 'module_complete' | 'streak_bonus' | 'achievement_unlock' | 'daily_goal_complete' | 'first_lesson' | 'journey_step' | 'journey_complete';
|
|
7
7
|
export interface XPCalculationInput {
|
|
8
8
|
/** Type of activity */
|
|
9
9
|
activity: XPActivityType;
|
package/dist/engines/xp.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{defineTranslation as R}from"@contractspec/lib.contracts-spec/translations";var m=R({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels for the learning-journey module",owners:["platform"],stability:"experimental"},locale:"en",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Score Bonus",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Perfect Score",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"First Attempt",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Retry Penalty",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Streak Bonus",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as S}from"@contractspec/lib.contracts-spec/translations";var J=S({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (Spanish)",owners:["platform"],stability:"experimental"},locale:"es",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonificaci\xF3n por puntuaci\xF3n",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Puntuaci\xF3n perfecta",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Primer intento",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Penalizaci\xF3n por reintento",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonificaci\xF3n por racha",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as h}from"@contractspec/lib.contracts-spec/translations";var Y=h({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (French)",owners:["platform"],stability:"experimental"},locale:"fr",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonus de score",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Score parfait",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Premier essai",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"P\xE9nalit\xE9 de r\xE9essai",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonus de s\xE9rie",description:"XP breakdown label for streak bonus"}}});import{createI18nFactory as G}from"@contractspec/lib.contracts-spec/translations";var $=G({specKey:"learning-journey.messages",catalogs:[m,Y,J]}),q=$.create,T=$.getDefault,E=$.resetRegistry;var Z={baseValues:{lesson_complete:10,quiz_pass:20,quiz_perfect:50,flashcard_review:1,course_complete:200,module_complete:50,streak_bonus:5,achievement_unlock:0,daily_goal_complete:15,first_lesson:25,
|
|
2
|
+
import{defineTranslation as R}from"@contractspec/lib.contracts-spec/translations";var m=R({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels for the learning-journey module",owners:["platform"],stability:"experimental"},locale:"en",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Score Bonus",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Perfect Score",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"First Attempt",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Retry Penalty",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Streak Bonus",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as S}from"@contractspec/lib.contracts-spec/translations";var J=S({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (Spanish)",owners:["platform"],stability:"experimental"},locale:"es",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonificaci\xF3n por puntuaci\xF3n",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Puntuaci\xF3n perfecta",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Primer intento",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"Penalizaci\xF3n por reintento",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonificaci\xF3n por racha",description:"XP breakdown label for streak bonus"}}});import{defineTranslation as h}from"@contractspec/lib.contracts-spec/translations";var Y=h({meta:{key:"learning-journey.messages",version:"1.0.0",domain:"learning-journey",description:"XP source labels (French)",owners:["platform"],stability:"experimental"},locale:"fr",fallback:"en",messages:{"xp.source.base":{value:"Base",description:"XP breakdown label for base XP"},"xp.source.scoreBonus":{value:"Bonus de score",description:"XP breakdown label for score-based bonus"},"xp.source.perfectScore":{value:"Score parfait",description:"XP breakdown label for perfect score bonus"},"xp.source.firstAttempt":{value:"Premier essai",description:"XP breakdown label for first attempt bonus"},"xp.source.retryPenalty":{value:"P\xE9nalit\xE9 de r\xE9essai",description:"XP breakdown label for retry penalty"},"xp.source.streakBonus":{value:"Bonus de s\xE9rie",description:"XP breakdown label for streak bonus"}}});import{createI18nFactory as G}from"@contractspec/lib.contracts-spec/translations";var $=G({specKey:"learning-journey.messages",catalogs:[m,Y,J]}),q=$.create,T=$.getDefault,E=$.resetRegistry;var Z={baseValues:{lesson_complete:10,quiz_pass:20,quiz_perfect:50,flashcard_review:1,course_complete:200,module_complete:50,streak_bonus:5,achievement_unlock:0,daily_goal_complete:15,first_lesson:25,journey_step:5,journey_complete:50},scoreThresholds:[{min:90,multiplier:1.5},{min:80,multiplier:1.25},{min:70,multiplier:1},{min:60,multiplier:0.75},{min:0,multiplier:0.5}],streakTiers:[{days:365,bonus:50},{days:180,bonus:30},{days:90,bonus:20},{days:30,bonus:15},{days:14,bonus:10},{days:7,bonus:5},{days:3,bonus:2},{days:1,bonus:0}],perfectScoreMultiplier:1.5,firstAttemptBonus:10,retryPenalty:0.5,speedBonusMultiplier:1.2,speedBonusThreshold:0.8};class K{config;constructor(j={}){this.config={...Z,...j,baseValues:{...Z.baseValues,...j.baseValues},scoreThresholds:j.scoreThresholds||Z.scoreThresholds,streakTiers:j.streakTiers||Z.streakTiers}}calculate(j){let z=[],V=j.baseXp??this.config.baseValues[j.activity],H=V;if(z.push({source:"base",amount:V}),j.score!==void 0){let Q=this.getScoreMultiplier(j.score);if(Q!==1){let W=Math.round(V*(Q-1));H+=W,z.push({source:"score_bonus",amount:W,multiplier:Q})}if(j.score===100){let W=Math.round(V*(this.config.perfectScoreMultiplier-1));H+=W,z.push({source:"perfect_score",amount:W,multiplier:this.config.perfectScoreMultiplier})}}if(j.attemptNumber===1&&!j.isRetry)H+=this.config.firstAttemptBonus,z.push({source:"first_attempt",amount:this.config.firstAttemptBonus});if(j.isRetry){let Q=Math.round(H*(1-this.config.retryPenalty));H-=Q,z.push({source:"retry_penalty",amount:-Q,multiplier:this.config.retryPenalty})}if(j.currentStreak&&j.currentStreak>0){let Q=this.getStreakBonus(j.currentStreak);if(Q>0)H+=Q,z.push({source:"streak_bonus",amount:Q})}if(V>0)H=Math.max(1,H);return{totalXp:Math.round(H),baseXp:V,breakdown:z}}calculateStreakBonus(j){let z=this.getStreakBonus(j);return{totalXp:z,baseXp:z,breakdown:[{source:"streak_bonus",amount:z}]}}getXpForLevel(j){if(j<=1)return 0;return Math.round(100*Math.pow(j-1,1.5))}getLevelFromXp(j){let z=1,V=this.getXpForLevel(z+1);while(j>=V&&z<1000)z++,V=this.getXpForLevel(z+1);let H=this.getXpForLevel(z),Q=this.getXpForLevel(z+1);return{level:z,xpInLevel:j-H,xpForNextLevel:Q-H}}getScoreMultiplier(j){for(let z of this.config.scoreThresholds)if(j>=z.min)return z.multiplier;return 1}getStreakBonus(j){for(let z of this.config.streakTiers)if(j>=z.days)return z.bonus;return 0}}var A={base:"xp.source.base",score_bonus:"xp.source.scoreBonus",perfect_score:"xp.source.perfectScore",first_attempt:"xp.source.firstAttempt",retry_penalty:"xp.source.retryPenalty",streak_bonus:"xp.source.streakBonus"};function y(j,z){let V=q(z),H=A[j];return H?V.t(H):j}var _=new K;export{_ as xpEngine,y as getXpSourceLabel,K as XPEngine,Z as DEFAULT_XP_CONFIG};
|
package/dist/entities/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ModuleSchemaContribution } from '@contractspec/lib.schema';
|
|
2
2
|
export * from './course';
|
|
3
3
|
export * from './learner';
|
|
4
|
-
export * from './
|
|
4
|
+
export * from './journey';
|
|
5
5
|
export * from './flashcard';
|
|
6
6
|
export * from './quiz';
|
|
7
7
|
export * from './gamification';
|
|
@@ -183,19 +183,12 @@ export declare const learningJourneyEntities: (import("@contractspec/lib.schema"
|
|
|
183
183
|
description: import("@contractspec/lib.schema").EntityScalarField;
|
|
184
184
|
targetUserSegment: import("@contractspec/lib.schema").EntityScalarField;
|
|
185
185
|
targetRole: import("@contractspec/lib.schema").EntityScalarField;
|
|
186
|
-
welcomeTitle: import("@contractspec/lib.schema").EntityScalarField;
|
|
187
|
-
welcomeMessage: import("@contractspec/lib.schema").EntityScalarField;
|
|
188
|
-
completionTitle: import("@contractspec/lib.schema").EntityScalarField;
|
|
189
|
-
completionMessage: import("@contractspec/lib.schema").EntityScalarField;
|
|
190
186
|
isActive: import("@contractspec/lib.schema").EntityScalarField;
|
|
191
187
|
isRequired: import("@contractspec/lib.schema").EntityScalarField;
|
|
192
188
|
canSkip: import("@contractspec/lib.schema").EntityScalarField;
|
|
193
189
|
totalXp: import("@contractspec/lib.schema").EntityScalarField;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
streakHoursWindow: import("@contractspec/lib.schema").EntityScalarField;
|
|
197
|
-
streakBonusXp: import("@contractspec/lib.schema").EntityScalarField;
|
|
198
|
-
orgId: import("@contractspec/lib.schema").EntityScalarField;
|
|
190
|
+
streakRule: import("@contractspec/lib.schema").EntityScalarField;
|
|
191
|
+
completionRewards: import("@contractspec/lib.schema").EntityScalarField;
|
|
199
192
|
metadata: import("@contractspec/lib.schema").EntityScalarField;
|
|
200
193
|
createdAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
201
194
|
updatedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
@@ -209,18 +202,17 @@ export declare const learningJourneyEntities: (import("@contractspec/lib.schema"
|
|
|
209
202
|
instructions: import("@contractspec/lib.schema").EntityScalarField;
|
|
210
203
|
helpUrl: import("@contractspec/lib.schema").EntityScalarField;
|
|
211
204
|
order: import("@contractspec/lib.schema").EntityScalarField;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
actionLabel: import("@contractspec/lib.schema").EntityScalarField;
|
|
219
|
-
highlightSelector: import("@contractspec/lib.schema").EntityScalarField;
|
|
220
|
-
tooltipPosition: import("@contractspec/lib.schema").EntityScalarField;
|
|
205
|
+
completion: import("@contractspec/lib.schema").EntityScalarField;
|
|
206
|
+
availability: import("@contractspec/lib.schema").EntityScalarField;
|
|
207
|
+
prerequisites: import("@contractspec/lib.schema").EntityScalarField;
|
|
208
|
+
prerequisiteMode: import("@contractspec/lib.schema").EntityScalarField;
|
|
209
|
+
branches: import("@contractspec/lib.schema").EntityScalarField;
|
|
210
|
+
reward: import("@contractspec/lib.schema").EntityScalarField;
|
|
221
211
|
xpReward: import("@contractspec/lib.schema").EntityScalarField;
|
|
222
212
|
isRequired: import("@contractspec/lib.schema").EntityScalarField;
|
|
223
213
|
canSkip: import("@contractspec/lib.schema").EntityScalarField;
|
|
214
|
+
actionUrl: import("@contractspec/lib.schema").EntityScalarField;
|
|
215
|
+
actionLabel: import("@contractspec/lib.schema").EntityScalarField;
|
|
224
216
|
metadata: import("@contractspec/lib.schema").EntityScalarField;
|
|
225
217
|
createdAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
226
218
|
updatedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
@@ -229,32 +221,41 @@ export declare const learningJourneyEntities: (import("@contractspec/lib.schema"
|
|
|
229
221
|
id: import("@contractspec/lib.schema").EntityScalarField;
|
|
230
222
|
learnerId: import("@contractspec/lib.schema").EntityScalarField;
|
|
231
223
|
trackId: import("@contractspec/lib.schema").EntityScalarField;
|
|
232
|
-
|
|
233
|
-
completedSteps: import("@contractspec/lib.schema").EntityScalarField;
|
|
234
|
-
skippedSteps: import("@contractspec/lib.schema").EntityScalarField;
|
|
235
|
-
progress: import("@contractspec/lib.schema").EntityScalarField;
|
|
224
|
+
progressPercent: import("@contractspec/lib.schema").EntityScalarField;
|
|
236
225
|
isCompleted: import("@contractspec/lib.schema").EntityScalarField;
|
|
226
|
+
nextStepId: import("@contractspec/lib.schema").EntityScalarField;
|
|
237
227
|
xpEarned: import("@contractspec/lib.schema").EntityScalarField;
|
|
228
|
+
badges: import("@contractspec/lib.schema").EntityScalarField;
|
|
229
|
+
streakState: import("@contractspec/lib.schema").EntityScalarField;
|
|
230
|
+
eventLog: import("@contractspec/lib.schema").EntityScalarField;
|
|
231
|
+
completionRewardApplied: import("@contractspec/lib.schema").EntityScalarField;
|
|
238
232
|
startedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
239
233
|
completedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
240
234
|
lastActivityAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
241
|
-
isDismissed: import("@contractspec/lib.schema").EntityScalarField;
|
|
242
|
-
dismissedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
243
|
-
metadata: import("@contractspec/lib.schema").EntityScalarField;
|
|
244
235
|
createdAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
245
236
|
updatedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
246
237
|
learner: import("@contractspec/lib.schema").EntityRelationField;
|
|
247
238
|
track: import("@contractspec/lib.schema").EntityRelationField;
|
|
239
|
+
stepProgress: import("@contractspec/lib.schema").EntityRelationField;
|
|
248
240
|
}> | import("@contractspec/lib.schema").EntitySpec<{
|
|
249
241
|
id: import("@contractspec/lib.schema").EntityScalarField;
|
|
250
242
|
progressId: import("@contractspec/lib.schema").EntityScalarField;
|
|
251
243
|
stepId: import("@contractspec/lib.schema").EntityScalarField;
|
|
252
244
|
status: import("@contractspec/lib.schema").EntityEnumField;
|
|
245
|
+
selectedBranchKey: import("@contractspec/lib.schema").EntityScalarField;
|
|
253
246
|
xpEarned: import("@contractspec/lib.schema").EntityScalarField;
|
|
247
|
+
occurrences: import("@contractspec/lib.schema").EntityScalarField;
|
|
248
|
+
masteryCount: import("@contractspec/lib.schema").EntityScalarField;
|
|
249
|
+
availableAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
250
|
+
dueAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
251
|
+
completedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
252
|
+
skippedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
253
|
+
blockedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
254
|
+
missedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
254
255
|
triggeringEvent: import("@contractspec/lib.schema").EntityScalarField;
|
|
255
256
|
eventPayload: import("@contractspec/lib.schema").EntityScalarField;
|
|
256
|
-
completedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
257
257
|
createdAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
258
|
+
updatedAt: import("@contractspec/lib.schema").EntityScalarField;
|
|
258
259
|
progress: import("@contractspec/lib.schema").EntityRelationField;
|
|
259
260
|
step: import("@contractspec/lib.schema").EntityRelationField;
|
|
260
261
|
}> | import("@contractspec/lib.schema").EntitySpec<{
|