@lssm/module.learning-journey 0.0.0-canary-20251217083314 → 1.41.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.
Files changed (167) hide show
  1. package/dist/contracts/index.js +1 -6
  2. package/dist/contracts/models.js +1 -389
  3. package/dist/contracts/onboarding.js +1 -404
  4. package/dist/contracts/operations.js +1 -151
  5. package/dist/contracts/shared.js +1 -5
  6. package/dist/docs/index.js +1 -1
  7. package/dist/docs/learning-journey.docblock.js +5 -61
  8. package/dist/engines/index.js +1 -5
  9. package/dist/engines/srs.js +1 -219
  10. package/dist/engines/streak.js +1 -193
  11. package/dist/engines/xp.js +1 -212
  12. package/dist/entities/ai.js +1 -376
  13. package/dist/entities/course.js +1 -316
  14. package/dist/entities/flashcard.js +1 -249
  15. package/dist/entities/gamification.js +1 -392
  16. package/dist/entities/index.js +1 -44
  17. package/dist/entities/learner.js +1 -365
  18. package/dist/entities/onboarding.js +1 -307
  19. package/dist/entities/quiz.js +1 -370
  20. package/dist/events.js +1 -583
  21. package/dist/index.js +1 -22
  22. package/dist/learning-journey.feature.js +1 -148
  23. package/package.json +28 -29
  24. package/dist/contracts/index.d.ts +0 -5
  25. package/dist/contracts/models.d.ts +0 -450
  26. package/dist/contracts/onboarding.d.ts +0 -665
  27. package/dist/contracts/operations.d.ts +0 -279
  28. package/dist/contracts/shared.d.ts +0 -4
  29. package/dist/docs/index.d.ts +0 -1
  30. package/dist/docs/learning-journey.docblock.d.ts +0 -1
  31. package/dist/engines/index.d.ts +0 -4
  32. package/dist/engines/srs.d.ts +0 -110
  33. package/dist/engines/streak.d.ts +0 -99
  34. package/dist/engines/xp.d.ts +0 -96
  35. package/dist/entities/ai.d.ts +0 -231
  36. package/dist/entities/course.d.ts +0 -183
  37. package/dist/entities/flashcard.d.ts +0 -169
  38. package/dist/entities/gamification.d.ts +0 -237
  39. package/dist/entities/index.d.ts +0 -628
  40. package/dist/entities/learner.d.ts +0 -223
  41. package/dist/entities/onboarding.d.ts +0 -189
  42. package/dist/entities/quiz.d.ts +0 -219
  43. package/dist/events.d.ts +0 -795
  44. package/dist/index.d.ts +0 -19
  45. package/dist/learning-journey.feature.d.ts +0 -11
  46. package/dist/libs/contracts/dist/capabilities/openbanking.js +0 -88
  47. package/dist/libs/contracts/dist/client/index.js +0 -5
  48. package/dist/libs/contracts/dist/client/react/feature-render.js +0 -2
  49. package/dist/libs/contracts/dist/client/react/form-render.js +0 -4
  50. package/dist/libs/contracts/dist/client/react/index.js +0 -4
  51. package/dist/libs/contracts/dist/contract-registry/index.js +0 -1
  52. package/dist/libs/contracts/dist/contract-registry/schemas.js +0 -60
  53. package/dist/libs/contracts/dist/docs/PUBLISHING.docblock.js +0 -16
  54. package/dist/libs/contracts/dist/docs/accessibility_wcag_compliance_specs.docblock.js +0 -16
  55. package/dist/libs/contracts/dist/docs/index.js +0 -29
  56. package/dist/libs/contracts/dist/docs/presentations.js +0 -71
  57. package/dist/libs/contracts/dist/docs/registry.js +0 -44
  58. package/dist/libs/contracts/dist/docs/tech/PHASE_1_QUICKSTART.docblock.js +0 -16
  59. package/dist/libs/contracts/dist/docs/tech/PHASE_2_AI_NATIVE_OPERATIONS.docblock.js +0 -16
  60. package/dist/libs/contracts/dist/docs/tech/PHASE_3_AUTO_EVOLUTION.docblock.js +0 -16
  61. package/dist/libs/contracts/dist/docs/tech/PHASE_4_PERSONALIZATION_ENGINE.docblock.js +0 -16
  62. package/dist/libs/contracts/dist/docs/tech/PHASE_5_ZERO_TOUCH_OPERATIONS.docblock.js +0 -16
  63. package/dist/libs/contracts/dist/docs/tech/auth/better-auth-nextjs.docblock.js +0 -80
  64. package/dist/libs/contracts/dist/docs/tech/contracts/openapi-export.docblock.js +0 -57
  65. package/dist/libs/contracts/dist/docs/tech/lifecycle-stage-system.docblock.js +0 -16
  66. package/dist/libs/contracts/dist/docs/tech/llm/llm-integration.docblock.js +0 -357
  67. package/dist/libs/contracts/dist/docs/tech/mcp-endpoints.docblock.js +0 -37
  68. package/dist/libs/contracts/dist/docs/tech/presentation-runtime.docblock.js +0 -16
  69. package/dist/libs/contracts/dist/docs/tech/schema/README.docblock.js +0 -20
  70. package/dist/libs/contracts/dist/docs/tech/studio/learning-events.docblock.js +0 -48
  71. package/dist/libs/contracts/dist/docs/tech/studio/learning-journeys.docblock.js +0 -79
  72. package/dist/libs/contracts/dist/docs/tech/studio/platform-admin-panel.docblock.js +0 -84
  73. package/dist/libs/contracts/dist/docs/tech/studio/project-access-teams.docblock.js +0 -45
  74. package/dist/libs/contracts/dist/docs/tech/studio/project-routing.docblock.js +0 -67
  75. package/dist/libs/contracts/dist/docs/tech/studio/sandbox-unlogged.docblock.js +0 -40
  76. package/dist/libs/contracts/dist/docs/tech/studio/team-invitations.docblock.js +0 -69
  77. package/dist/libs/contracts/dist/docs/tech/studio/workspace-ops.docblock.js +0 -47
  78. package/dist/libs/contracts/dist/docs/tech/studio/workspaces.docblock.js +0 -62
  79. package/dist/libs/contracts/dist/docs/tech/telemetry-ingest.docblock.js +0 -155
  80. package/dist/libs/contracts/dist/docs/tech/templates/runtime.docblock.js +0 -20
  81. package/dist/libs/contracts/dist/docs/tech/vscode-extension.docblock.js +0 -101
  82. package/dist/libs/contracts/dist/docs/tech/workflows/overview.docblock.js +0 -20
  83. package/dist/libs/contracts/dist/events.js +0 -10
  84. package/dist/libs/contracts/dist/experiments/evaluator.js +0 -1
  85. package/dist/libs/contracts/dist/index.js +0 -71
  86. package/dist/libs/contracts/dist/install.js +0 -2
  87. package/dist/libs/contracts/dist/integrations/contracts.js +0 -377
  88. package/dist/libs/contracts/dist/integrations/index.js +0 -18
  89. package/dist/libs/contracts/dist/integrations/openbanking/contracts/accounts.js +0 -228
  90. package/dist/libs/contracts/dist/integrations/openbanking/contracts/balances.js +0 -159
  91. package/dist/libs/contracts/dist/integrations/openbanking/contracts/index.js +0 -3
  92. package/dist/libs/contracts/dist/integrations/openbanking/contracts/transactions.js +0 -210
  93. package/dist/libs/contracts/dist/integrations/openbanking/models.js +0 -242
  94. package/dist/libs/contracts/dist/integrations/openbanking/telemetry.js +0 -13
  95. package/dist/libs/contracts/dist/integrations/providers/elevenlabs.js +0 -52
  96. package/dist/libs/contracts/dist/integrations/providers/gcs-storage.js +0 -75
  97. package/dist/libs/contracts/dist/integrations/providers/gmail.js +0 -87
  98. package/dist/libs/contracts/dist/integrations/providers/google-calendar.js +0 -66
  99. package/dist/libs/contracts/dist/integrations/providers/index.js +0 -11
  100. package/dist/libs/contracts/dist/integrations/providers/mistral.js +0 -68
  101. package/dist/libs/contracts/dist/integrations/providers/postmark.js +0 -68
  102. package/dist/libs/contracts/dist/integrations/providers/powens.js +0 -116
  103. package/dist/libs/contracts/dist/integrations/providers/qdrant.js +0 -73
  104. package/dist/libs/contracts/dist/integrations/providers/registry.js +0 -10
  105. package/dist/libs/contracts/dist/integrations/providers/stripe.js +0 -83
  106. package/dist/libs/contracts/dist/integrations/providers/twilio-sms.js +0 -61
  107. package/dist/libs/contracts/dist/jsonschema.js +0 -1
  108. package/dist/libs/contracts/dist/knowledge/contracts.js +0 -306
  109. package/dist/libs/contracts/dist/knowledge/index.js +0 -7
  110. package/dist/libs/contracts/dist/knowledge/spaces/email-threads.js +0 -34
  111. package/dist/libs/contracts/dist/knowledge/spaces/financial-docs.js +0 -34
  112. package/dist/libs/contracts/dist/knowledge/spaces/financial-overview.js +0 -38
  113. package/dist/libs/contracts/dist/knowledge/spaces/index.js +0 -6
  114. package/dist/libs/contracts/dist/knowledge/spaces/product-canon.js +0 -34
  115. package/dist/libs/contracts/dist/knowledge/spaces/support-faq.js +0 -37
  116. package/dist/libs/contracts/dist/knowledge/spaces/uploaded-docs.js +0 -34
  117. package/dist/libs/contracts/dist/llm/exporters.js +0 -19
  118. package/dist/libs/contracts/dist/llm/index.js +0 -2
  119. package/dist/libs/contracts/dist/llm/prompts.js +0 -1
  120. package/dist/libs/contracts/dist/onboarding-base.js +0 -196
  121. package/dist/libs/contracts/dist/openapi.js +0 -1
  122. package/dist/libs/contracts/dist/ownership.js +0 -21
  123. package/dist/libs/contracts/dist/presentations.js +0 -1
  124. package/dist/libs/contracts/dist/presentations.v2.js +0 -11
  125. package/dist/libs/contracts/dist/prompt.js +0 -1
  126. package/dist/libs/contracts/dist/promptRegistry.js +0 -1
  127. package/dist/libs/contracts/dist/regenerator/index.js +0 -1
  128. package/dist/libs/contracts/dist/regenerator/service.js +0 -6
  129. package/dist/libs/contracts/dist/registry.js +0 -2
  130. package/dist/libs/contracts/dist/resources.js +0 -1
  131. package/dist/libs/contracts/dist/schema/dist/EnumType.js +0 -2
  132. package/dist/libs/contracts/dist/schema/dist/FieldType.js +0 -49
  133. package/dist/libs/contracts/dist/schema/dist/ScalarTypeEnum.js +0 -236
  134. package/dist/libs/contracts/dist/schema/dist/SchemaModel.js +0 -34
  135. package/dist/libs/contracts/dist/schema/dist/entity/defineEntity.js +0 -1
  136. package/dist/libs/contracts/dist/schema/dist/entity/index.js +0 -2
  137. package/dist/libs/contracts/dist/schema/dist/entity/types.js +0 -1
  138. package/dist/libs/contracts/dist/schema/dist/index.js +0 -6
  139. package/dist/libs/contracts/dist/server/graphql-pothos.js +0 -6
  140. package/dist/libs/contracts/dist/server/index.js +0 -8
  141. package/dist/libs/contracts/dist/server/mcp/createMcpServer.js +0 -4
  142. package/dist/libs/contracts/dist/server/mcp/registerPresentations.js +0 -2
  143. package/dist/libs/contracts/dist/server/mcp/registerPrompts.js +0 -1
  144. package/dist/libs/contracts/dist/server/mcp/registerResources.js +0 -2
  145. package/dist/libs/contracts/dist/server/mcp/registerTools.js +0 -1
  146. package/dist/libs/contracts/dist/server/provider-mcp.js +0 -1
  147. package/dist/libs/contracts/dist/server/rest-elysia.js +0 -1
  148. package/dist/libs/contracts/dist/server/rest-express.js +0 -1
  149. package/dist/libs/contracts/dist/server/rest-generic.js +0 -1
  150. package/dist/libs/contracts/dist/server/rest-next-app.js +0 -1
  151. package/dist/libs/contracts/dist/server/rest-next-pages.js +0 -1
  152. package/dist/libs/contracts/dist/spec.js +0 -34
  153. package/dist/libs/contracts/dist/telemetry/index.js +0 -1
  154. package/dist/libs/contracts/dist/telemetry/tracker.js +0 -1
  155. package/dist/libs/contracts/dist/tests/index.js +0 -1
  156. package/dist/libs/contracts/dist/tests/runner.js +0 -2
  157. package/dist/libs/contracts/dist/workflow/index.js +0 -1
  158. package/dist/libs/contracts/dist/workflow/runner.js +0 -1
  159. package/dist/libs/schema/dist/EnumType.js +0 -2
  160. package/dist/libs/schema/dist/FieldType.js +0 -49
  161. package/dist/libs/schema/dist/ScalarTypeEnum.js +0 -236
  162. package/dist/libs/schema/dist/SchemaModel.js +0 -39
  163. package/dist/libs/schema/dist/entity/defineEntity.js +0 -236
  164. package/dist/libs/schema/dist/entity/index.js +0 -2
  165. package/dist/libs/schema/dist/entity/types.js +0 -1
  166. package/dist/libs/schema/dist/index.js +0 -6
  167. package/dist/track-spec.d.ts +0 -128
@@ -1,219 +1 @@
1
- //#region src/engines/srs.ts
2
- const DEFAULT_SRS_CONFIG = {
3
- learningSteps: [1, 10],
4
- graduatingInterval: 1,
5
- easyInterval: 4,
6
- relearningSteps: [10],
7
- minEaseFactor: 1.3,
8
- maxInterval: 365,
9
- intervalModifier: 1,
10
- newIntervalModifier: .5,
11
- hardIntervalModifier: 1.2,
12
- easyBonus: 1.3
13
- };
14
- var SRSEngine = class {
15
- config;
16
- constructor(config = {}) {
17
- this.config = {
18
- ...DEFAULT_SRS_CONFIG,
19
- ...config
20
- };
21
- }
22
- /**
23
- * Calculate the next review state based on rating.
24
- */
25
- calculateNextReview(state, rating, now = /* @__PURE__ */ new Date()) {
26
- if (!state.isGraduated && !state.isRelearning) return this.handleLearningCard(state, rating, now);
27
- if (state.isRelearning) return this.handleRelearningCard(state, rating, now);
28
- return this.handleReviewCard(state, rating, now);
29
- }
30
- /**
31
- * Handle learning phase (new cards).
32
- */
33
- handleLearningCard(state, rating, now) {
34
- const steps = this.config.learningSteps;
35
- let newStep = state.learningStep;
36
- let isGraduated = false;
37
- let interval = 0;
38
- let nextReviewAt;
39
- switch (rating) {
40
- case "AGAIN":
41
- newStep = 0;
42
- interval = steps[0] ?? 1;
43
- nextReviewAt = this.addMinutes(now, interval);
44
- break;
45
- case "HARD":
46
- interval = steps[newStep] ?? steps[0] ?? 1;
47
- nextReviewAt = this.addMinutes(now, interval);
48
- break;
49
- case "GOOD":
50
- newStep++;
51
- if (newStep >= steps.length) {
52
- isGraduated = true;
53
- interval = this.config.graduatingInterval;
54
- nextReviewAt = this.addDays(now, interval);
55
- } else {
56
- interval = steps[newStep] ?? 10;
57
- nextReviewAt = this.addMinutes(now, interval);
58
- }
59
- break;
60
- case "EASY":
61
- isGraduated = true;
62
- interval = this.config.easyInterval;
63
- nextReviewAt = this.addDays(now, interval);
64
- break;
65
- }
66
- return {
67
- interval: isGraduated ? interval : 0,
68
- easeFactor: state.easeFactor,
69
- repetitions: isGraduated ? 1 : 0,
70
- nextReviewAt,
71
- learningStep: newStep,
72
- isGraduated,
73
- isRelearning: false,
74
- lapses: state.lapses
75
- };
76
- }
77
- /**
78
- * Handle relearning phase (lapsed cards).
79
- */
80
- handleRelearningCard(state, rating, now) {
81
- const steps = this.config.relearningSteps;
82
- let newStep = state.learningStep;
83
- let isRelearning = true;
84
- let interval = 0;
85
- let nextReviewAt;
86
- switch (rating) {
87
- case "AGAIN":
88
- newStep = 0;
89
- interval = steps[0] ?? 10;
90
- nextReviewAt = this.addMinutes(now, interval);
91
- break;
92
- case "HARD":
93
- interval = steps[newStep] ?? steps[0] ?? 10;
94
- nextReviewAt = this.addMinutes(now, interval);
95
- break;
96
- case "GOOD":
97
- newStep++;
98
- if (newStep >= steps.length) {
99
- isRelearning = false;
100
- interval = Math.max(1, Math.floor(state.interval * this.config.newIntervalModifier));
101
- nextReviewAt = this.addDays(now, interval);
102
- } else {
103
- interval = steps[newStep] ?? 10;
104
- nextReviewAt = this.addMinutes(now, interval);
105
- }
106
- break;
107
- case "EASY":
108
- isRelearning = false;
109
- interval = Math.max(1, Math.floor(state.interval * this.config.newIntervalModifier * 1.5));
110
- nextReviewAt = this.addDays(now, interval);
111
- break;
112
- }
113
- return {
114
- interval: isRelearning ? state.interval : interval,
115
- easeFactor: state.easeFactor,
116
- repetitions: isRelearning ? state.repetitions : state.repetitions + 1,
117
- nextReviewAt,
118
- learningStep: newStep,
119
- isGraduated: true,
120
- isRelearning,
121
- lapses: state.lapses
122
- };
123
- }
124
- /**
125
- * Handle review phase (graduated cards).
126
- */
127
- handleReviewCard(state, rating, now) {
128
- let newInterval;
129
- let newEaseFactor = state.easeFactor;
130
- let repetitions = state.repetitions;
131
- let isRelearning = false;
132
- let learningStep = 0;
133
- let lapses = state.lapses;
134
- switch (rating) {
135
- case "AGAIN":
136
- lapses++;
137
- isRelearning = true;
138
- learningStep = 0;
139
- newEaseFactor = Math.max(this.config.minEaseFactor, newEaseFactor - .2);
140
- newInterval = state.interval;
141
- const relearnStep = this.config.relearningSteps[0] ?? 10;
142
- return {
143
- interval: newInterval,
144
- easeFactor: newEaseFactor,
145
- repetitions,
146
- nextReviewAt: this.addMinutes(now, relearnStep),
147
- learningStep,
148
- isGraduated: true,
149
- isRelearning: true,
150
- lapses
151
- };
152
- case "HARD":
153
- newEaseFactor = Math.max(this.config.minEaseFactor, newEaseFactor - .15);
154
- newInterval = Math.max(state.interval + 1, state.interval * this.config.hardIntervalModifier);
155
- break;
156
- case "GOOD":
157
- newInterval = state.interval * newEaseFactor * this.config.intervalModifier;
158
- repetitions++;
159
- break;
160
- case "EASY":
161
- newEaseFactor = newEaseFactor + .15;
162
- newInterval = state.interval * newEaseFactor * this.config.easyBonus * this.config.intervalModifier;
163
- repetitions++;
164
- break;
165
- }
166
- newInterval = Math.min(Math.round(newInterval), this.config.maxInterval);
167
- newInterval = Math.max(1, newInterval);
168
- return {
169
- interval: newInterval,
170
- easeFactor: newEaseFactor,
171
- repetitions,
172
- nextReviewAt: this.addDays(now, newInterval),
173
- learningStep,
174
- isGraduated: true,
175
- isRelearning,
176
- lapses
177
- };
178
- }
179
- /**
180
- * Get initial SRS state for a new card.
181
- */
182
- getInitialState() {
183
- return {
184
- interval: 0,
185
- easeFactor: 2.5,
186
- repetitions: 0,
187
- learningStep: 0,
188
- isGraduated: false,
189
- isRelearning: false,
190
- lapses: 0
191
- };
192
- }
193
- /**
194
- * Check if a card is due for review.
195
- */
196
- isDue(nextReviewAt, now = /* @__PURE__ */ new Date()) {
197
- return nextReviewAt <= now;
198
- }
199
- /**
200
- * Calculate overdue days (negative if not yet due).
201
- */
202
- getOverdueDays(nextReviewAt, now = /* @__PURE__ */ new Date()) {
203
- const diff = now.getTime() - nextReviewAt.getTime();
204
- return Math.floor(diff / (1e3 * 60 * 60 * 24));
205
- }
206
- addMinutes(date, minutes) {
207
- return new Date(date.getTime() + minutes * 60 * 1e3);
208
- }
209
- addDays(date, days) {
210
- return new Date(date.getTime() + days * 24 * 60 * 60 * 1e3);
211
- }
212
- };
213
- /**
214
- * Default SRS engine instance.
215
- */
216
- const srsEngine = new SRSEngine();
217
-
218
- //#endregion
219
- export { DEFAULT_SRS_CONFIG, SRSEngine, srsEngine };
1
+ const e={learningSteps:[1,10],graduatingInterval:1,easyInterval:4,relearningSteps:[10],minEaseFactor:1.3,maxInterval:365,intervalModifier:1,newIntervalModifier:.5,hardIntervalModifier:1.2,easyBonus:1.3};var t=class{config;constructor(t={}){this.config={...e,...t}}calculateNextReview(e,t,n=new Date){return!e.isGraduated&&!e.isRelearning?this.handleLearningCard(e,t,n):e.isRelearning?this.handleRelearningCard(e,t,n):this.handleReviewCard(e,t,n)}handleLearningCard(e,t,n){let r=this.config.learningSteps,i=e.learningStep,a=!1,o=0,s;switch(t){case`AGAIN`:i=0,o=r[0]??1,s=this.addMinutes(n,o);break;case`HARD`:o=r[i]??r[0]??1,s=this.addMinutes(n,o);break;case`GOOD`:i++,i>=r.length?(a=!0,o=this.config.graduatingInterval,s=this.addDays(n,o)):(o=r[i]??10,s=this.addMinutes(n,o));break;case`EASY`:a=!0,o=this.config.easyInterval,s=this.addDays(n,o);break}return{interval:a?o:0,easeFactor:e.easeFactor,repetitions:a?1:0,nextReviewAt:s,learningStep:i,isGraduated:a,isRelearning:!1,lapses:e.lapses}}handleRelearningCard(e,t,n){let r=this.config.relearningSteps,i=e.learningStep,a=!0,o=0,s;switch(t){case`AGAIN`:i=0,o=r[0]??10,s=this.addMinutes(n,o);break;case`HARD`:o=r[i]??r[0]??10,s=this.addMinutes(n,o);break;case`GOOD`:i++,i>=r.length?(a=!1,o=Math.max(1,Math.floor(e.interval*this.config.newIntervalModifier)),s=this.addDays(n,o)):(o=r[i]??10,s=this.addMinutes(n,o));break;case`EASY`:a=!1,o=Math.max(1,Math.floor(e.interval*this.config.newIntervalModifier*1.5)),s=this.addDays(n,o);break}return{interval:a?e.interval:o,easeFactor:e.easeFactor,repetitions:a?e.repetitions:e.repetitions+1,nextReviewAt:s,learningStep:i,isGraduated:!0,isRelearning:a,lapses:e.lapses}}handleReviewCard(e,t,n){let r,i=e.easeFactor,a=e.repetitions,o=!1,s=0,c=e.lapses;switch(t){case`AGAIN`:c++,o=!0,s=0,i=Math.max(this.config.minEaseFactor,i-.2),r=e.interval;let t=this.config.relearningSteps[0]??10;return{interval:r,easeFactor:i,repetitions:a,nextReviewAt:this.addMinutes(n,t),learningStep:s,isGraduated:!0,isRelearning:!0,lapses:c};case`HARD`:i=Math.max(this.config.minEaseFactor,i-.15),r=Math.max(e.interval+1,e.interval*this.config.hardIntervalModifier);break;case`GOOD`:r=e.interval*i*this.config.intervalModifier,a++;break;case`EASY`:i+=.15,r=e.interval*i*this.config.easyBonus*this.config.intervalModifier,a++;break}return r=Math.min(Math.round(r),this.config.maxInterval),r=Math.max(1,r),{interval:r,easeFactor:i,repetitions:a,nextReviewAt:this.addDays(n,r),learningStep:s,isGraduated:!0,isRelearning:o,lapses:c}}getInitialState(){return{interval:0,easeFactor:2.5,repetitions:0,learningStep:0,isGraduated:!1,isRelearning:!1,lapses:0}}isDue(e,t=new Date){return e<=t}getOverdueDays(e,t=new Date){let n=t.getTime()-e.getTime();return Math.floor(n/(1e3*60*60*24))}addMinutes(e,t){return new Date(e.getTime()+t*60*1e3)}addDays(e,t){return new Date(e.getTime()+t*24*60*60*1e3)}};const n=new t;export{e as DEFAULT_SRS_CONFIG,t as SRSEngine,n as srsEngine};
@@ -1,193 +1 @@
1
- //#region src/engines/streak.ts
2
- const DEFAULT_STREAK_CONFIG = {
3
- timezone: "UTC",
4
- freezesPerMonth: 2,
5
- maxFreezes: 5,
6
- gracePeriodHours: 4
7
- };
8
- var StreakEngine = class {
9
- config;
10
- constructor(config = {}) {
11
- this.config = {
12
- ...DEFAULT_STREAK_CONFIG,
13
- ...config
14
- };
15
- }
16
- /**
17
- * Update streak based on new activity.
18
- */
19
- update(state, now = /* @__PURE__ */ new Date()) {
20
- const todayDate = this.getDateString(now);
21
- const result = {
22
- state: { ...state },
23
- streakMaintained: false,
24
- streakLost: false,
25
- freezeUsed: false,
26
- newStreak: false,
27
- daysMissed: 0
28
- };
29
- if (!state.lastActivityDate) {
30
- result.state.currentStreak = 1;
31
- result.state.longestStreak = Math.max(1, state.longestStreak);
32
- result.state.lastActivityAt = now;
33
- result.state.lastActivityDate = todayDate;
34
- result.newStreak = true;
35
- result.streakMaintained = true;
36
- return result;
37
- }
38
- if (state.lastActivityDate === todayDate) {
39
- result.state.lastActivityAt = now;
40
- result.streakMaintained = true;
41
- return result;
42
- }
43
- const daysSinceActivity = this.getDaysBetween(state.lastActivityDate, todayDate);
44
- if (daysSinceActivity === 1) {
45
- result.state.currentStreak = state.currentStreak + 1;
46
- result.state.longestStreak = Math.max(result.state.currentStreak, state.longestStreak);
47
- result.state.lastActivityAt = now;
48
- result.state.lastActivityDate = todayDate;
49
- result.streakMaintained = true;
50
- return result;
51
- }
52
- result.daysMissed = daysSinceActivity - 1;
53
- const freezesNeeded = result.daysMissed;
54
- if (freezesNeeded <= state.freezesRemaining) {
55
- result.state.freezesRemaining = state.freezesRemaining - freezesNeeded;
56
- result.state.freezeUsedAt = now;
57
- result.state.currentStreak = state.currentStreak + 1;
58
- result.state.longestStreak = Math.max(result.state.currentStreak, state.longestStreak);
59
- result.state.lastActivityAt = now;
60
- result.state.lastActivityDate = todayDate;
61
- result.freezeUsed = true;
62
- result.streakMaintained = true;
63
- return result;
64
- }
65
- result.streakLost = true;
66
- result.state.currentStreak = 1;
67
- result.state.lastActivityAt = now;
68
- result.state.lastActivityDate = todayDate;
69
- result.newStreak = true;
70
- return result;
71
- }
72
- /**
73
- * Check streak status without recording activity.
74
- */
75
- checkStatus(state, now = /* @__PURE__ */ new Date()) {
76
- if (!state.lastActivityDate) return {
77
- isActive: false,
78
- willExpireAt: null,
79
- canUseFreeze: false,
80
- daysUntilExpiry: 0
81
- };
82
- const todayDate = this.getDateString(now);
83
- const daysSinceActivity = this.getDaysBetween(state.lastActivityDate, todayDate);
84
- if (daysSinceActivity === 0) {
85
- const tomorrow = this.addDays(now, 1);
86
- tomorrow.setHours(23, 59, 59, 999);
87
- return {
88
- isActive: true,
89
- willExpireAt: tomorrow,
90
- canUseFreeze: state.freezesRemaining > 0,
91
- daysUntilExpiry: 1
92
- };
93
- }
94
- if (daysSinceActivity === 1) {
95
- const endOfDay = new Date(now);
96
- endOfDay.setHours(23 + this.config.gracePeriodHours, 59, 59, 999);
97
- return {
98
- isActive: true,
99
- willExpireAt: endOfDay,
100
- canUseFreeze: state.freezesRemaining > 0,
101
- daysUntilExpiry: 0
102
- };
103
- }
104
- const missedDays = daysSinceActivity - 1;
105
- return {
106
- isActive: missedDays <= state.freezesRemaining,
107
- willExpireAt: null,
108
- canUseFreeze: missedDays <= state.freezesRemaining,
109
- daysUntilExpiry: -missedDays
110
- };
111
- }
112
- /**
113
- * Manually use a freeze to protect streak.
114
- */
115
- useFreeze(state, now = /* @__PURE__ */ new Date()) {
116
- if (state.freezesRemaining <= 0) return null;
117
- return {
118
- ...state,
119
- freezesRemaining: state.freezesRemaining - 1,
120
- freezeUsedAt: now
121
- };
122
- }
123
- /**
124
- * Award monthly freezes.
125
- */
126
- awardMonthlyFreezes(state) {
127
- return {
128
- ...state,
129
- freezesRemaining: Math.min(state.freezesRemaining + this.config.freezesPerMonth, this.config.maxFreezes)
130
- };
131
- }
132
- /**
133
- * Get initial streak state.
134
- */
135
- getInitialState() {
136
- return {
137
- currentStreak: 0,
138
- longestStreak: 0,
139
- lastActivityAt: null,
140
- lastActivityDate: null,
141
- freezesRemaining: this.config.freezesPerMonth,
142
- freezeUsedAt: null
143
- };
144
- }
145
- /**
146
- * Calculate streak milestones.
147
- */
148
- getMilestones(currentStreak) {
149
- const milestones = [
150
- 3,
151
- 7,
152
- 14,
153
- 30,
154
- 60,
155
- 90,
156
- 180,
157
- 365,
158
- 500,
159
- 1e3
160
- ];
161
- return {
162
- achieved: milestones.filter((m) => currentStreak >= m),
163
- next: milestones.find((m) => currentStreak < m) ?? null
164
- };
165
- }
166
- /**
167
- * Get date string in YYYY-MM-DD format.
168
- */
169
- getDateString(date) {
170
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
171
- }
172
- /**
173
- * Get number of days between two date strings.
174
- */
175
- getDaysBetween(dateStr1, dateStr2) {
176
- const date1 = new Date(dateStr1);
177
- const diffTime = new Date(dateStr2).getTime() - date1.getTime();
178
- return Math.floor(diffTime / (1e3 * 60 * 60 * 24));
179
- }
180
- /**
181
- * Add days to a date.
182
- */
183
- addDays(date, days) {
184
- return new Date(date.getTime() + days * 24 * 60 * 60 * 1e3);
185
- }
186
- };
187
- /**
188
- * Default streak engine instance.
189
- */
190
- const streakEngine = new StreakEngine();
191
-
192
- //#endregion
193
- export { DEFAULT_STREAK_CONFIG, StreakEngine, streakEngine };
1
+ const e={timezone:`UTC`,freezesPerMonth:2,maxFreezes:5,gracePeriodHours:4};var t=class{config;constructor(t={}){this.config={...e,...t}}update(e,t=new Date){let n=this.getDateString(t),r={state:{...e},streakMaintained:!1,streakLost:!1,freezeUsed:!1,newStreak:!1,daysMissed:0};if(!e.lastActivityDate)return r.state.currentStreak=1,r.state.longestStreak=Math.max(1,e.longestStreak),r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.newStreak=!0,r.streakMaintained=!0,r;if(e.lastActivityDate===n)return r.state.lastActivityAt=t,r.streakMaintained=!0,r;let i=this.getDaysBetween(e.lastActivityDate,n);if(i===1)return r.state.currentStreak=e.currentStreak+1,r.state.longestStreak=Math.max(r.state.currentStreak,e.longestStreak),r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.streakMaintained=!0,r;r.daysMissed=i-1;let a=r.daysMissed;return a<=e.freezesRemaining?(r.state.freezesRemaining=e.freezesRemaining-a,r.state.freezeUsedAt=t,r.state.currentStreak=e.currentStreak+1,r.state.longestStreak=Math.max(r.state.currentStreak,e.longestStreak),r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.freezeUsed=!0,r.streakMaintained=!0,r):(r.streakLost=!0,r.state.currentStreak=1,r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.newStreak=!0,r)}checkStatus(e,t=new Date){if(!e.lastActivityDate)return{isActive:!1,willExpireAt:null,canUseFreeze:!1,daysUntilExpiry:0};let n=this.getDateString(t),r=this.getDaysBetween(e.lastActivityDate,n);if(r===0){let n=this.addDays(t,1);return n.setHours(23,59,59,999),{isActive:!0,willExpireAt:n,canUseFreeze:e.freezesRemaining>0,daysUntilExpiry:1}}if(r===1){let n=new Date(t);return n.setHours(23+this.config.gracePeriodHours,59,59,999),{isActive:!0,willExpireAt:n,canUseFreeze:e.freezesRemaining>0,daysUntilExpiry:0}}let i=r-1;return{isActive:i<=e.freezesRemaining,willExpireAt:null,canUseFreeze:i<=e.freezesRemaining,daysUntilExpiry:-i}}useFreeze(e,t=new Date){return e.freezesRemaining<=0?null:{...e,freezesRemaining:e.freezesRemaining-1,freezeUsedAt:t}}awardMonthlyFreezes(e){return{...e,freezesRemaining:Math.min(e.freezesRemaining+this.config.freezesPerMonth,this.config.maxFreezes)}}getInitialState(){return{currentStreak:0,longestStreak:0,lastActivityAt:null,lastActivityDate:null,freezesRemaining:this.config.freezesPerMonth,freezeUsedAt:null}}getMilestones(e){let t=[3,7,14,30,60,90,180,365,500,1e3];return{achieved:t.filter(t=>e>=t),next:t.find(t=>e<t)??null}}getDateString(e){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}getDaysBetween(e,t){let n=new Date(e),r=new Date(t).getTime()-n.getTime();return Math.floor(r/(1e3*60*60*24))}addDays(e,t){return new Date(e.getTime()+t*24*60*60*1e3)}};const n=new t;export{e as DEFAULT_STREAK_CONFIG,t as StreakEngine,n as streakEngine};
@@ -1,212 +1 @@
1
- //#region src/engines/xp.ts
2
- const DEFAULT_XP_CONFIG = {
3
- baseValues: {
4
- lesson_complete: 10,
5
- quiz_pass: 20,
6
- quiz_perfect: 50,
7
- flashcard_review: 1,
8
- course_complete: 200,
9
- module_complete: 50,
10
- streak_bonus: 5,
11
- achievement_unlock: 0,
12
- daily_goal_complete: 15,
13
- first_lesson: 25,
14
- onboarding_step: 5,
15
- onboarding_complete: 50
16
- },
17
- scoreThresholds: [
18
- {
19
- min: 90,
20
- multiplier: 1.5
21
- },
22
- {
23
- min: 80,
24
- multiplier: 1.25
25
- },
26
- {
27
- min: 70,
28
- multiplier: 1
29
- },
30
- {
31
- min: 60,
32
- multiplier: .75
33
- },
34
- {
35
- min: 0,
36
- multiplier: .5
37
- }
38
- ],
39
- streakTiers: [
40
- {
41
- days: 365,
42
- bonus: 50
43
- },
44
- {
45
- days: 180,
46
- bonus: 30
47
- },
48
- {
49
- days: 90,
50
- bonus: 20
51
- },
52
- {
53
- days: 30,
54
- bonus: 15
55
- },
56
- {
57
- days: 14,
58
- bonus: 10
59
- },
60
- {
61
- days: 7,
62
- bonus: 5
63
- },
64
- {
65
- days: 3,
66
- bonus: 2
67
- },
68
- {
69
- days: 1,
70
- bonus: 0
71
- }
72
- ],
73
- perfectScoreMultiplier: 1.5,
74
- firstAttemptBonus: 10,
75
- retryPenalty: .5,
76
- speedBonusMultiplier: 1.2,
77
- speedBonusThreshold: .8
78
- };
79
- var XPEngine = class {
80
- config;
81
- constructor(config = {}) {
82
- this.config = {
83
- ...DEFAULT_XP_CONFIG,
84
- ...config,
85
- baseValues: {
86
- ...DEFAULT_XP_CONFIG.baseValues,
87
- ...config.baseValues
88
- },
89
- scoreThresholds: config.scoreThresholds || DEFAULT_XP_CONFIG.scoreThresholds,
90
- streakTiers: config.streakTiers || DEFAULT_XP_CONFIG.streakTiers
91
- };
92
- }
93
- /**
94
- * Calculate XP for an activity.
95
- */
96
- calculate(input) {
97
- const breakdown = [];
98
- const baseXp = input.baseXp ?? this.config.baseValues[input.activity];
99
- let totalXp = baseXp;
100
- breakdown.push({
101
- source: "base",
102
- amount: baseXp
103
- });
104
- if (input.score !== void 0) {
105
- const scoreMultiplier = this.getScoreMultiplier(input.score);
106
- if (scoreMultiplier !== 1) {
107
- const scoreBonus = Math.round(baseXp * (scoreMultiplier - 1));
108
- totalXp += scoreBonus;
109
- breakdown.push({
110
- source: "score_bonus",
111
- amount: scoreBonus,
112
- multiplier: scoreMultiplier
113
- });
114
- }
115
- if (input.score === 100) {
116
- const perfectBonus = Math.round(baseXp * (this.config.perfectScoreMultiplier - 1));
117
- totalXp += perfectBonus;
118
- breakdown.push({
119
- source: "perfect_score",
120
- amount: perfectBonus,
121
- multiplier: this.config.perfectScoreMultiplier
122
- });
123
- }
124
- }
125
- if (input.attemptNumber === 1 && !input.isRetry) {
126
- totalXp += this.config.firstAttemptBonus;
127
- breakdown.push({
128
- source: "first_attempt",
129
- amount: this.config.firstAttemptBonus
130
- });
131
- }
132
- if (input.isRetry) {
133
- const penalty = Math.round(totalXp * (1 - this.config.retryPenalty));
134
- totalXp -= penalty;
135
- breakdown.push({
136
- source: "retry_penalty",
137
- amount: -penalty,
138
- multiplier: this.config.retryPenalty
139
- });
140
- }
141
- if (input.currentStreak && input.currentStreak > 0) {
142
- const streakBonus = this.getStreakBonus(input.currentStreak);
143
- if (streakBonus > 0) {
144
- totalXp += streakBonus;
145
- breakdown.push({
146
- source: "streak_bonus",
147
- amount: streakBonus
148
- });
149
- }
150
- }
151
- if (baseXp > 0) totalXp = Math.max(1, totalXp);
152
- return {
153
- totalXp: Math.round(totalXp),
154
- baseXp,
155
- breakdown
156
- };
157
- }
158
- /**
159
- * Calculate streak bonus XP.
160
- */
161
- calculateStreakBonus(currentStreak) {
162
- const bonus = this.getStreakBonus(currentStreak);
163
- return {
164
- totalXp: bonus,
165
- baseXp: bonus,
166
- breakdown: [{
167
- source: "streak_bonus",
168
- amount: bonus
169
- }]
170
- };
171
- }
172
- /**
173
- * Calculate XP needed for a level.
174
- */
175
- getXpForLevel(level) {
176
- if (level <= 1) return 0;
177
- return Math.round(100 * Math.pow(level - 1, 1.5));
178
- }
179
- /**
180
- * Get level from total XP.
181
- */
182
- getLevelFromXp(totalXp) {
183
- let level = 1;
184
- let xpRequired = this.getXpForLevel(level + 1);
185
- while (totalXp >= xpRequired && level < 1e3) {
186
- level++;
187
- xpRequired = this.getXpForLevel(level + 1);
188
- }
189
- const xpForCurrentLevel = this.getXpForLevel(level);
190
- const xpForNextLevel = this.getXpForLevel(level + 1);
191
- return {
192
- level,
193
- xpInLevel: totalXp - xpForCurrentLevel,
194
- xpForNextLevel: xpForNextLevel - xpForCurrentLevel
195
- };
196
- }
197
- getScoreMultiplier(score) {
198
- for (const threshold of this.config.scoreThresholds) if (score >= threshold.min) return threshold.multiplier;
199
- return 1;
200
- }
201
- getStreakBonus(streak) {
202
- for (const tier of this.config.streakTiers) if (streak >= tier.days) return tier.bonus;
203
- return 0;
204
- }
205
- };
206
- /**
207
- * Default XP engine instance.
208
- */
209
- const xpEngine = new XPEngine();
210
-
211
- //#endregion
212
- export { DEFAULT_XP_CONFIG, XPEngine, xpEngine };
1
+ const e={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:.75},{min:0,multiplier:.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:.5,speedBonusMultiplier:1.2,speedBonusThreshold:.8};var t=class{config;constructor(t={}){this.config={...e,...t,baseValues:{...e.baseValues,...t.baseValues},scoreThresholds:t.scoreThresholds||e.scoreThresholds,streakTiers:t.streakTiers||e.streakTiers}}calculate(e){let t=[],n=e.baseXp??this.config.baseValues[e.activity],r=n;if(t.push({source:`base`,amount:n}),e.score!==void 0){let i=this.getScoreMultiplier(e.score);if(i!==1){let e=Math.round(n*(i-1));r+=e,t.push({source:`score_bonus`,amount:e,multiplier:i})}if(e.score===100){let e=Math.round(n*(this.config.perfectScoreMultiplier-1));r+=e,t.push({source:`perfect_score`,amount:e,multiplier:this.config.perfectScoreMultiplier})}}if(e.attemptNumber===1&&!e.isRetry&&(r+=this.config.firstAttemptBonus,t.push({source:`first_attempt`,amount:this.config.firstAttemptBonus})),e.isRetry){let e=Math.round(r*(1-this.config.retryPenalty));r-=e,t.push({source:`retry_penalty`,amount:-e,multiplier:this.config.retryPenalty})}if(e.currentStreak&&e.currentStreak>0){let n=this.getStreakBonus(e.currentStreak);n>0&&(r+=n,t.push({source:`streak_bonus`,amount:n}))}return n>0&&(r=Math.max(1,r)),{totalXp:Math.round(r),baseXp:n,breakdown:t}}calculateStreakBonus(e){let t=this.getStreakBonus(e);return{totalXp:t,baseXp:t,breakdown:[{source:`streak_bonus`,amount:t}]}}getXpForLevel(e){return e<=1?0:Math.round(100*(e-1)**1.5)}getLevelFromXp(e){let t=1,n=this.getXpForLevel(t+1);for(;e>=n&&t<1e3;)t++,n=this.getXpForLevel(t+1);let r=this.getXpForLevel(t),i=this.getXpForLevel(t+1);return{level:t,xpInLevel:e-r,xpForNextLevel:i-r}}getScoreMultiplier(e){for(let t of this.config.scoreThresholds)if(e>=t.min)return t.multiplier;return 1}getStreakBonus(e){for(let t of this.config.streakTiers)if(e>=t.days)return t.bonus;return 0}};const n=new t;export{e as DEFAULT_XP_CONFIG,t as XPEngine,n as xpEngine};