@dgpholdings/greatoak-shared 1.2.85 → 1.2.87

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 (79) hide show
  1. package/README.md +148 -148
  2. package/dist/__mocks__/exercises.mock.js +1 -0
  3. package/dist/constants/index.d.ts +1 -0
  4. package/dist/constants/index.js +1 -0
  5. package/dist/constants/quickStartIntents.d.ts +19 -0
  6. package/dist/constants/quickStartIntents.js +39 -0
  7. package/dist/types/TApiAiExerciseAnalysis.d.ts +2 -1
  8. package/dist/types/TApiClientConstellation.d.ts +33 -0
  9. package/dist/types/TApiClientConstellation.js +13 -0
  10. package/dist/types/TApiExercise.d.ts +5 -3
  11. package/dist/types/index.d.ts +1 -0
  12. package/dist/utils/constellation/computeNormalisedLoad.d.ts +48 -0
  13. package/dist/utils/constellation/computeNormalisedLoad.js +150 -0
  14. package/dist/utils/constellation/evaluateConstellation.d.ts +27 -0
  15. package/dist/utils/constellation/evaluateConstellation.js +135 -0
  16. package/dist/utils/constellation/index.d.ts +17 -0
  17. package/dist/utils/constellation/index.js +26 -0
  18. package/dist/utils/constellation/levelThresholds.d.ts +99 -0
  19. package/dist/utils/constellation/levelThresholds.js +123 -0
  20. package/dist/utils/constellation/starFoundation.d.ts +25 -0
  21. package/dist/utils/constellation/starFoundation.js +54 -0
  22. package/dist/utils/constellation/stars/consistency.d.ts +29 -0
  23. package/dist/utils/constellation/stars/consistency.js +142 -0
  24. package/dist/utils/constellation/stars/lowerBody.d.ts +17 -0
  25. package/dist/utils/constellation/stars/lowerBody.js +30 -0
  26. package/dist/utils/constellation/stars/pull.d.ts +11 -0
  27. package/dist/utils/constellation/stars/pull.js +24 -0
  28. package/dist/utils/constellation/stars/push.d.ts +11 -0
  29. package/dist/utils/constellation/stars/push.js +24 -0
  30. package/dist/utils/constellation/stars/quality.d.ts +19 -0
  31. package/dist/utils/constellation/stars/quality.js +98 -0
  32. package/dist/utils/constellation/stars/recovery.d.ts +29 -0
  33. package/dist/utils/constellation/stars/recovery.js +169 -0
  34. package/dist/utils/constellation/strengthStarHelpers.d.ts +41 -0
  35. package/dist/utils/constellation/strengthStarHelpers.js +104 -0
  36. package/dist/utils/constellation/types.d.ts +124 -0
  37. package/dist/utils/constellation/types.js +18 -0
  38. package/dist/utils/index.d.ts +5 -3
  39. package/dist/utils/index.js +1 -0
  40. package/dist/utils/scoringWorkout/calculateQualityScore.d.ts +59 -36
  41. package/dist/utils/scoringWorkout/calculateQualityScore.js +234 -233
  42. package/dist/utils/scoringWorkout/computeMuscleFatigueMap.d.ts +8 -5
  43. package/dist/utils/scoringWorkout/computeMuscleFatigueMap.js +72 -88
  44. package/dist/utils/scoringWorkout/constants.d.ts +20 -6
  45. package/dist/utils/scoringWorkout/constants.js +23 -9
  46. package/dist/utils/scoringWorkout/helpers.d.ts +7 -0
  47. package/dist/utils/scoringWorkout/helpers.js +24 -18
  48. package/dist/utils/scoringWorkout/index.d.ts +12 -8
  49. package/dist/utils/scoringWorkout/index.js +23 -15
  50. package/dist/utils/scoringWorkout/parseRecords.js +4 -3
  51. package/dist/utils/scoringWorkout/scoringWorkout.integration.test.js +210 -172
  52. package/dist/utils/scoringWorkout/types.d.ts +34 -14
  53. package/package.json +31 -31
  54. package/dist/utils/exerciseRecord/__mocks__/exercises.mock.d.ts +0 -30
  55. package/dist/utils/exerciseRecord/__mocks__/exercises.mock.js +0 -138
  56. package/dist/utils/scaleProPlan.util.d.ts +0 -9
  57. package/dist/utils/scaleProPlan.util.js +0 -139
  58. package/dist/utils/scoring/calculateCalories.d.ts +0 -67
  59. package/dist/utils/scoring/calculateCalories.js +0 -345
  60. package/dist/utils/scoring/calculateMuscleFatiue.d.ts +0 -67
  61. package/dist/utils/scoring/calculateMuscleFatiue.js +0 -310
  62. package/dist/utils/scoring/calculateQualityScore.d.ts +0 -71
  63. package/dist/utils/scoring/calculateQualityScore.js +0 -334
  64. package/dist/utils/scoring/calculateTotalVolume.d.ts +0 -15
  65. package/dist/utils/scoring/calculateTotalVolume.js +0 -73
  66. package/dist/utils/scoring/constants.d.ts +0 -211
  67. package/dist/utils/scoring/constants.js +0 -247
  68. package/dist/utils/scoring/helpers.d.ts +0 -119
  69. package/dist/utils/scoring/helpers.js +0 -229
  70. package/dist/utils/scoring/index.d.ts +0 -28
  71. package/dist/utils/scoring/index.js +0 -47
  72. package/dist/utils/scoring/parseRecords.d.ts +0 -98
  73. package/dist/utils/scoring/parseRecords.js +0 -284
  74. package/dist/utils/scoring/types.d.ts +0 -86
  75. package/dist/utils/scoring/types.js +0 -11
  76. package/dist/utils/scoring.utils.d.ts +0 -14
  77. package/dist/utils/scoring.utils.js +0 -243
  78. /package/dist/utils/scoringWorkout/{calculateMuscleFatiue.d.ts → calculateMuscleFatigue.d.ts} +0 -0
  79. /package/dist/utils/scoringWorkout/{calculateMuscleFatiue.js → calculateMuscleFatigue.js} +0 -0
@@ -1,243 +0,0 @@
1
- "use strict";
2
- /*
3
- * Exercise Scoring System Documentation
4
- *
5
- * OVERVIEW:
6
- * Evaluates workout performance (0-100) with overall score and muscle fatigue ratings.
7
- * Designed to motivate users by quantifying effort and tracking muscle engagement.
8
- *
9
- * SCORE COMPOSITION:
10
- * - Volume (35%): Total work (weight×reps, duration×difficulty, distance×speed)
11
- * - Intensity (35%): Effort level (relative weight, rep ranges, speed, RPE when provided)
12
- * - Quality (30%): Set consistency and performance maintenance
13
- *
14
- * SCORE INTERPRETATION:
15
- * 90-100: Exceptional - peak performance with high volume/intensity/consistency
16
- * 75-89: Excellent - strong effort with good form and progression
17
- * 60-74: Good - solid baseline performance, room for improvement
18
- * 45-59: Moderate - acceptable but consider increasing intensity/volume
19
- * 0-44: Light - warm-up sets or recovery day
20
- *
21
- * MUSCLE FATIGUE (0-100):
22
- * Primary muscles get 70% fatigue impact, secondary muscles get 30%
23
- * 80-100: Fully fatigued - heavily worked, needs recovery
24
- * 60-79: High fatigue - significant work, approaching limit
25
- * 40-59: Moderate fatigue - good activation, can handle more
26
- * 20-39: Light fatigue - warmed up, plenty capacity remaining
27
- * 0-19: Minimal fatigue - barely engaged
28
- *
29
- * QUALITY SCORE EXPLAINED:
30
- * Measures how well performance is maintained across sets (starts at 85 points)
31
- * - Performance drop <10% between sets: +5 points
32
- * - Performance drop 10-20%: +2 points
33
- * - Performance drop >30%: -10 points
34
- * - Consistent RIR/RPE between sets: +3 points
35
- * - Completing 3+ sets: +5 points, 4+ sets: +8 total points
36
- *
37
- * KEY FACTORS:
38
- * - User fitness level (higher level = higher expectations)
39
- * - Exercise difficulty (harder exercises boost score)
40
- * - RPE (1-10): When provided, adjusts intensity (higher RPE = higher intensity)
41
- * - RIR (0+): When provided, checks consistency between sets
42
- * - Fatigue multiplier (later sets get 8% bonus per set for accumulated fatigue)
43
- */
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.calculateExerciseScore = void 0;
46
- const time_util_1 = require("./time.util");
47
- const scoring_1 = require("./scoring");
48
- const calculateExerciseScore = (param) => {
49
- const { exercise, record, user } = param;
50
- // Filter only completed sets
51
- const completedSets = record.filter((r) => r.isDone);
52
- if (completedSets.length === 0) {
53
- return { score: 0, muscleScores: {} };
54
- }
55
- // Calculate base performance metrics
56
- const totalVolume = (0, scoring_1.calculateTotalVolume)(completedSets, user);
57
- const avgIntensity = calculateAverageIntensity(completedSets, exercise, user);
58
- const setQuality = calculateSetQuality(completedSets);
59
- // Calculate muscle fatigue scores
60
- const muscleScores = calculateMuscleScores(exercise, completedSets, totalVolume, user);
61
- // Final score composition
62
- const volumeComponent = normalizeVolume(totalVolume, exercise, user) * 0.35;
63
- const intensityComponent = avgIntensity * 0.35;
64
- const qualityComponent = setQuality * 0.3;
65
- const score = Math.round(volumeComponent + intensityComponent + qualityComponent);
66
- return {
67
- score: Math.min(100, Math.max(0, score)),
68
- muscleScores,
69
- };
70
- };
71
- exports.calculateExerciseScore = calculateExerciseScore;
72
- const calculateAverageIntensity = (record, exercise, user) => {
73
- const intensities = record.map((set, index) => {
74
- let baseIntensity = 0;
75
- if (set.type === "weight-reps") {
76
- const weight = parseFloat(set.kg) || 0;
77
- const reps = parseFloat(set.reps) || 0;
78
- const userWeight = user.weightKg || 70;
79
- const relativeLoad = weight / userWeight;
80
- const repIntensity = getRepIntensity(reps);
81
- baseIntensity = (relativeLoad * 40 + repIntensity * 60) / 100;
82
- // RPE adjustment (only if provided and valid)
83
- if (set.rpe && set.rpe !== "0") {
84
- const rpe = parseFloat(set.rpe);
85
- if (rpe > 0 && rpe <= 10) {
86
- baseIntensity *= 0.5 + rpe / 20; // Scale from 0.55x to 1.0x
87
- }
88
- }
89
- }
90
- else if (set.type === "reps-only") {
91
- const reps = parseFloat(set.reps) || 0;
92
- baseIntensity = getRepIntensity(reps) / 100;
93
- if (set.workDurationSecs) {
94
- const tempo = (reps * 3) / set.workDurationSecs;
95
- baseIntensity *= Math.min(1.2, Math.max(0.8, tempo));
96
- }
97
- // RPE adjustment for bodyweight exercises
98
- if (set.rpe && set.rpe !== "0") {
99
- const rpe = parseFloat(set.rpe);
100
- if (rpe > 0 && rpe <= 10) {
101
- baseIntensity *= 0.5 + rpe / 20;
102
- }
103
- }
104
- }
105
- else if (set.type === "duration") {
106
- const duration = (0, time_util_1.mmssToSecs)(set.durationMmSs);
107
- const weight = parseFloat(set.auxWeightKg) || 0;
108
- baseIntensity = Math.min(100, duration * 1.5) / 100;
109
- if (weight > 0) {
110
- baseIntensity *= 1 + weight / 100;
111
- }
112
- }
113
- else if (set.type === "cardio-machine" || set.type === "cardio-free") {
114
- const duration = (0, time_util_1.mmssToSecs)(set.durationMmSs);
115
- if (set.type === "cardio-machine") {
116
- const avgSpeed = (parseFloat(set.speedMin) + parseFloat(set.speedMax)) / 2 || 0;
117
- baseIntensity = Math.min(100, avgSpeed * 5.5) / 100;
118
- }
119
- else {
120
- const distance = parseFloat(set.distance) || 0;
121
- const speedKmh = duration > 0 ? distance / (duration / 3600) : 0;
122
- baseIntensity = Math.min(100, speedKmh * 5.5) / 100;
123
- }
124
- }
125
- // Apply fatigue factor for later sets (8% bonus per set)
126
- const fatigueMultiplier = 1 + index * 0.08;
127
- return Math.min(100, baseIntensity * fatigueMultiplier * 100);
128
- });
129
- const avgIntensity = intensities.reduce((a, b) => a + b, 0) / intensities.length;
130
- const difficultyBonus = exercise.difficultyLevel * 5;
131
- return Math.min(100, avgIntensity + difficultyBonus);
132
- };
133
- const calculateSetQuality = (record) => {
134
- if (record.length === 0)
135
- return 0;
136
- if (record.length === 1)
137
- return 75;
138
- let qualityScore = 85; // Base score
139
- // Check performance drop-off between sets
140
- for (let i = 1; i < record.length; i++) {
141
- const curr = record[i];
142
- const prev = record[i - 1];
143
- if (curr.type === "weight-reps" && prev.type === "weight-reps") {
144
- const currWork = parseFloat(curr.reps) * parseFloat(curr.kg);
145
- const prevWork = parseFloat(prev.reps) * parseFloat(prev.kg);
146
- const dropOff = prevWork > 0 ? 1 - currWork / prevWork : 0;
147
- if (dropOff < 0.1)
148
- qualityScore += 5; // Excellent maintenance
149
- else if (dropOff < 0.2)
150
- qualityScore += 2; // Good maintenance
151
- else if (dropOff > 0.3)
152
- qualityScore -= 10; // Poor pacing
153
- }
154
- else if (curr.type === "reps-only" && prev.type === "reps-only") {
155
- const currReps = parseFloat(curr.reps);
156
- const prevReps = parseFloat(prev.reps);
157
- const dropOff = prevReps > 0 ? 1 - currReps / prevReps : 0;
158
- if (dropOff < 0.15)
159
- qualityScore += 5;
160
- else if (dropOff > 0.3)
161
- qualityScore -= 8;
162
- }
163
- // Check effort consistency using either RIR or RPE (whichever is provided)
164
- // RIR consistency check
165
- if ("rir" in curr &&
166
- "rir" in prev &&
167
- curr.rir &&
168
- prev.rir &&
169
- curr.rir !== "0" &&
170
- prev.rir !== "0") {
171
- const currRir = parseFloat(curr.rir);
172
- const prevRir = parseFloat(prev.rir);
173
- if (!isNaN(currRir) && !isNaN(prevRir)) {
174
- const rirDiff = Math.abs(currRir - prevRir);
175
- if (rirDiff <= 1)
176
- qualityScore += 3; // Consistent effort
177
- }
178
- }
179
- // RPE consistency check (alternative to RIR)
180
- else if (curr.rpe && prev.rpe && curr.rpe !== "0" && prev.rpe !== "0") {
181
- const currRpe = parseFloat(curr.rpe);
182
- const prevRpe = parseFloat(prev.rpe);
183
- if (!isNaN(currRpe) && !isNaN(prevRpe)) {
184
- const rpeDiff = Math.abs(currRpe - prevRpe);
185
- if (rpeDiff <= 1)
186
- qualityScore += 3; // Consistent effort
187
- }
188
- }
189
- }
190
- // Bonus for multiple quality sets
191
- if (record.length >= 3)
192
- qualityScore += 5;
193
- if (record.length >= 4)
194
- qualityScore += 3;
195
- return Math.min(100, Math.max(0, qualityScore));
196
- };
197
- const calculateMuscleScores = (exercise, record, totalVolume, user) => {
198
- const muscleScores = {};
199
- const volumePerSet = totalVolume / record.length;
200
- // Normalize volume by bodyweight if available
201
- const normalizedVolumePerSet = user.weightKg
202
- ? volumePerSet / (user.weightKg * 10)
203
- : volumePerSet / 500; // Fallback to absolute scale
204
- // Primary muscles take 70% of the fatigue
205
- exercise.primaryMuscles.forEach((muscle) => {
206
- const baseFatigue = Math.min(100, normalizedVolumePerSet * 70);
207
- const setMultiplier = Math.min(1.5, 1 + (record.length - 1) * 0.15);
208
- muscleScores[muscle] = Math.min(100, baseFatigue * setMultiplier);
209
- });
210
- // Secondary muscles take 30% of the fatigue
211
- exercise.secondaryMuscles.forEach((muscle) => {
212
- const baseFatigue = Math.min(100, normalizedVolumePerSet * 30);
213
- const setMultiplier = Math.min(1.3, 1 + (record.length - 1) * 0.1);
214
- muscleScores[muscle] = Math.min(100, baseFatigue * setMultiplier);
215
- });
216
- return muscleScores;
217
- };
218
- const normalizeVolume = (totalVolume, exercise, user) => {
219
- const userWeight = user.weightKg || 70;
220
- const fitnessLevel = user.fitnessLevel || 2;
221
- // Expected volume baseline
222
- const baseExpected = userWeight * 15 * fitnessLevel;
223
- const difficultyAdjustment = 1 + exercise.difficultyLevel / 8;
224
- const expectedVolume = baseExpected * difficultyAdjustment;
225
- // Sigmoid normalization for smooth scoring
226
- const ratio = totalVolume / expectedVolume;
227
- return 100 / (1 + Math.exp(-3 * (ratio - 0.8)));
228
- };
229
- const getRepIntensity = (reps) => {
230
- if (reps <= 3)
231
- return 95;
232
- if (reps <= 5)
233
- return 87;
234
- if (reps <= 8)
235
- return 80;
236
- if (reps <= 12)
237
- return 70;
238
- if (reps <= 15)
239
- return 65;
240
- if (reps <= 20)
241
- return 60;
242
- return 50;
243
- };