@dofek/training 0.1.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/LICENSE +21 -0
- package/README.md +123 -0
- package/dist/activity-icons.d.ts +10 -0
- package/dist/activity-icons.d.ts.map +1 -0
- package/dist/activity-icons.js +102 -0
- package/dist/activity-icons.js.map +1 -0
- package/dist/climbing-grades.d.ts +8 -0
- package/dist/climbing-grades.d.ts.map +1 -0
- package/dist/climbing-grades.js +80 -0
- package/dist/climbing-grades.js.map +1 -0
- package/dist/derived-cardio.d.ts +17 -0
- package/dist/derived-cardio.d.ts.map +1 -0
- package/dist/derived-cardio.js +84 -0
- package/dist/derived-cardio.js.map +1 -0
- package/dist/endurance-types.d.ts +21 -0
- package/dist/endurance-types.d.ts.map +1 -0
- package/dist/endurance-types.js +39 -0
- package/dist/endurance-types.js.map +1 -0
- package/dist/grade-adjusted-pace.d.ts +34 -0
- package/dist/grade-adjusted-pace.d.ts.map +1 -0
- package/dist/grade-adjusted-pace.js +41 -0
- package/dist/grade-adjusted-pace.js.map +1 -0
- package/dist/muscle-groups.d.ts +35 -0
- package/dist/muscle-groups.d.ts.map +1 -0
- package/dist/muscle-groups.js +135 -0
- package/dist/muscle-groups.js.map +1 -0
- package/dist/pmc.d.ts +77 -0
- package/dist/pmc.d.ts.map +1 -0
- package/dist/pmc.js +83 -0
- package/dist/pmc.js.map +1 -0
- package/dist/power-analysis.d.ts +82 -0
- package/dist/power-analysis.d.ts.map +1 -0
- package/dist/power-analysis.js +162 -0
- package/dist/power-analysis.js.map +1 -0
- package/dist/training-distribution.d.ts +43 -0
- package/dist/training-distribution.d.ts.map +1 -0
- package/dist/training-distribution.js +68 -0
- package/dist/training-distribution.js.map +1 -0
- package/dist/training-load.d.ts +66 -0
- package/dist/training-load.d.ts.map +1 -0
- package/dist/training-load.js +89 -0
- package/dist/training-load.js.map +1 -0
- package/dist/training.d.ts +61 -0
- package/dist/training.d.ts.map +1 -0
- package/dist/training.js +564 -0
- package/dist/training.js.map +1 -0
- package/dist/workout-recommendation.d.ts +86 -0
- package/dist/workout-recommendation.d.ts.map +1 -0
- package/dist/workout-recommendation.js +338 -0
- package/dist/workout-recommendation.js.map +1 -0
- package/package.json +52 -0
package/dist/training.js
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
export const OTHER_ACTIVITY_TYPE = "__other__";
|
|
2
|
+
// ============================================================
|
|
3
|
+
// Canonical activity types
|
|
4
|
+
// ============================================================
|
|
5
|
+
/**
|
|
6
|
+
* Superset of all valid internal activity types across all providers.
|
|
7
|
+
* Providers map their domain-specific types to one of these canonical values.
|
|
8
|
+
*/
|
|
9
|
+
export const CANONICAL_ACTIVITY_TYPES = [
|
|
10
|
+
"cycling",
|
|
11
|
+
"road_cycling",
|
|
12
|
+
"mountain_biking",
|
|
13
|
+
"gravel_cycling",
|
|
14
|
+
"indoor_cycling",
|
|
15
|
+
"virtual_cycling",
|
|
16
|
+
"e_bike_cycling",
|
|
17
|
+
"cyclocross",
|
|
18
|
+
"track_cycling",
|
|
19
|
+
"bmx",
|
|
20
|
+
"running",
|
|
21
|
+
"swimming",
|
|
22
|
+
"walking",
|
|
23
|
+
"hiking",
|
|
24
|
+
"strength",
|
|
25
|
+
"strength_training",
|
|
26
|
+
"functional_strength",
|
|
27
|
+
"yoga",
|
|
28
|
+
"pilates",
|
|
29
|
+
"elliptical",
|
|
30
|
+
"rowing",
|
|
31
|
+
"skiing",
|
|
32
|
+
"skating",
|
|
33
|
+
"climbing",
|
|
34
|
+
"cardio",
|
|
35
|
+
"hiit",
|
|
36
|
+
"cross_training",
|
|
37
|
+
"trail_running",
|
|
38
|
+
"stair_climbing",
|
|
39
|
+
"stairmaster",
|
|
40
|
+
"stretching",
|
|
41
|
+
"dance",
|
|
42
|
+
"martial_arts",
|
|
43
|
+
"tennis",
|
|
44
|
+
"basketball",
|
|
45
|
+
"soccer",
|
|
46
|
+
"golf",
|
|
47
|
+
"ice_hockey",
|
|
48
|
+
"snowboarding",
|
|
49
|
+
"rock_climbing",
|
|
50
|
+
"surfing",
|
|
51
|
+
"kayaking",
|
|
52
|
+
"functional_fitness",
|
|
53
|
+
"bootcamp",
|
|
54
|
+
"boxing",
|
|
55
|
+
"core",
|
|
56
|
+
"aqua_fitness",
|
|
57
|
+
"circuit_training",
|
|
58
|
+
"group_exercise",
|
|
59
|
+
"triathlon",
|
|
60
|
+
"dancing",
|
|
61
|
+
// Apple Health granular types
|
|
62
|
+
"american_football",
|
|
63
|
+
"archery",
|
|
64
|
+
"australian_football",
|
|
65
|
+
"badminton",
|
|
66
|
+
"baseball",
|
|
67
|
+
"bowling",
|
|
68
|
+
"cricket",
|
|
69
|
+
"curling",
|
|
70
|
+
"equestrian",
|
|
71
|
+
"fencing",
|
|
72
|
+
"fishing",
|
|
73
|
+
"gymnastics",
|
|
74
|
+
"handball",
|
|
75
|
+
"hockey",
|
|
76
|
+
"hunting",
|
|
77
|
+
"lacrosse",
|
|
78
|
+
"mind_and_body",
|
|
79
|
+
"mixed_cardio",
|
|
80
|
+
"paddle_sports",
|
|
81
|
+
"play",
|
|
82
|
+
"preparation_and_recovery",
|
|
83
|
+
"racquetball",
|
|
84
|
+
"rugby",
|
|
85
|
+
"sailing",
|
|
86
|
+
"snow_sports",
|
|
87
|
+
"softball",
|
|
88
|
+
"squash",
|
|
89
|
+
"table_tennis",
|
|
90
|
+
"track_and_field",
|
|
91
|
+
"volleyball",
|
|
92
|
+
"water_fitness",
|
|
93
|
+
"water_polo",
|
|
94
|
+
"water_sports",
|
|
95
|
+
"wrestling",
|
|
96
|
+
"barre",
|
|
97
|
+
"core_training",
|
|
98
|
+
"flexibility",
|
|
99
|
+
"jump_rope",
|
|
100
|
+
"kickboxing",
|
|
101
|
+
"stairs",
|
|
102
|
+
"step_training",
|
|
103
|
+
"wheelchair_walk",
|
|
104
|
+
"wheelchair_run",
|
|
105
|
+
"tai_chi",
|
|
106
|
+
"mixed_metabolic_cardio",
|
|
107
|
+
"hand_cycling",
|
|
108
|
+
"disc_sports",
|
|
109
|
+
"fitness_gaming",
|
|
110
|
+
"cardio_dance",
|
|
111
|
+
"social_dance",
|
|
112
|
+
"paddle_racquet",
|
|
113
|
+
"cooldown",
|
|
114
|
+
"transition",
|
|
115
|
+
"underwater_diving",
|
|
116
|
+
"cross_country_skiing",
|
|
117
|
+
"downhill_skiing",
|
|
118
|
+
// Provider-specific types (Garmin, Peloton, Komoot, Decathlon)
|
|
119
|
+
"breathwork",
|
|
120
|
+
"meditation",
|
|
121
|
+
"paddleboarding",
|
|
122
|
+
"snowshoeing",
|
|
123
|
+
"pickleball",
|
|
124
|
+
"padel",
|
|
125
|
+
"football",
|
|
126
|
+
"multisport",
|
|
127
|
+
"disc_golf",
|
|
128
|
+
"skydiving",
|
|
129
|
+
"paragliding",
|
|
130
|
+
"diving",
|
|
131
|
+
"snorkeling",
|
|
132
|
+
"navigation",
|
|
133
|
+
"geocaching",
|
|
134
|
+
"paddling",
|
|
135
|
+
"gym",
|
|
136
|
+
"open_water_swimming",
|
|
137
|
+
"other",
|
|
138
|
+
];
|
|
139
|
+
// ============================================================
|
|
140
|
+
// Cycling activity types
|
|
141
|
+
// ============================================================
|
|
142
|
+
/**
|
|
143
|
+
* All canonical activity types considered "cycling" for consolidated views.
|
|
144
|
+
* Individual activities show the specific subtype, but aggregated views
|
|
145
|
+
* (weekly volume, PMC, cycling page) treat them as one sport.
|
|
146
|
+
*/
|
|
147
|
+
export const CYCLING_ACTIVITY_TYPES = [
|
|
148
|
+
"cycling",
|
|
149
|
+
"road_cycling",
|
|
150
|
+
"mountain_biking",
|
|
151
|
+
"gravel_cycling",
|
|
152
|
+
"indoor_cycling",
|
|
153
|
+
"virtual_cycling",
|
|
154
|
+
"e_bike_cycling",
|
|
155
|
+
"cyclocross",
|
|
156
|
+
"track_cycling",
|
|
157
|
+
"bmx",
|
|
158
|
+
"hand_cycling",
|
|
159
|
+
];
|
|
160
|
+
/** Check whether an activity type is a cycling variant. */
|
|
161
|
+
export function isCyclingActivity(activityType) {
|
|
162
|
+
return CYCLING_ACTIVITY_TYPES.some((t) => t === activityType);
|
|
163
|
+
}
|
|
164
|
+
/** Cadence unit for display based on activity type. */
|
|
165
|
+
export function cadenceUnit(activityType) {
|
|
166
|
+
return isCyclingActivity(activityType) ? "rpm" : "steps/min";
|
|
167
|
+
}
|
|
168
|
+
/** Y-axis label for cadence charts. */
|
|
169
|
+
export function cadenceAxisLabel(activityType) {
|
|
170
|
+
return `Cadence (${cadenceUnit(activityType)})`;
|
|
171
|
+
}
|
|
172
|
+
// ============================================================
|
|
173
|
+
// Endurance activity types
|
|
174
|
+
// ============================================================
|
|
175
|
+
// ============================================================
|
|
176
|
+
// Activity type mapper factory
|
|
177
|
+
// ============================================================
|
|
178
|
+
/**
|
|
179
|
+
* Creates a mapping function from provider-specific types to canonical types.
|
|
180
|
+
* Unknown provider types default to "other".
|
|
181
|
+
*/
|
|
182
|
+
export function createActivityTypeMapper(providerMappings) {
|
|
183
|
+
return (providerType) => {
|
|
184
|
+
return providerMappings[providerType] ?? "other";
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// ============================================================
|
|
188
|
+
// Provider-specific mapping constants
|
|
189
|
+
// ============================================================
|
|
190
|
+
/** Strava sport_type → canonical activity type */
|
|
191
|
+
export const STRAVA_ACTIVITY_TYPE_MAP = {
|
|
192
|
+
Ride: "road_cycling",
|
|
193
|
+
VirtualRide: "virtual_cycling",
|
|
194
|
+
MountainBikeRide: "mountain_biking",
|
|
195
|
+
GravelRide: "gravel_cycling",
|
|
196
|
+
EBikeRide: "e_bike_cycling",
|
|
197
|
+
EMountainBikeRide: "e_bike_cycling",
|
|
198
|
+
Run: "running",
|
|
199
|
+
VirtualRun: "running",
|
|
200
|
+
TrailRun: "running",
|
|
201
|
+
Walk: "walking",
|
|
202
|
+
Hike: "hiking",
|
|
203
|
+
Swim: "swimming",
|
|
204
|
+
WeightTraining: "strength",
|
|
205
|
+
Yoga: "yoga",
|
|
206
|
+
Rowing: "rowing",
|
|
207
|
+
Canoeing: "rowing",
|
|
208
|
+
Kayaking: "rowing",
|
|
209
|
+
Elliptical: "elliptical",
|
|
210
|
+
NordicSki: "skiing",
|
|
211
|
+
AlpineSki: "skiing",
|
|
212
|
+
BackcountrySki: "skiing",
|
|
213
|
+
Snowboard: "skiing",
|
|
214
|
+
IceSkate: "skating",
|
|
215
|
+
RollerSki: "skiing",
|
|
216
|
+
Crossfit: "strength",
|
|
217
|
+
RockClimbing: "climbing",
|
|
218
|
+
};
|
|
219
|
+
/** Wahoo workout_type_id (numeric) → canonical activity type */
|
|
220
|
+
export const WAHOO_WORKOUT_TYPE_MAP = {
|
|
221
|
+
0: "cycling",
|
|
222
|
+
1: "running",
|
|
223
|
+
2: "running", // treadmill
|
|
224
|
+
3: "indoor_cycling",
|
|
225
|
+
4: "mountain_biking",
|
|
226
|
+
5: "gravel_cycling",
|
|
227
|
+
6: "swimming",
|
|
228
|
+
7: "yoga",
|
|
229
|
+
8: "walking",
|
|
230
|
+
9: "hiking",
|
|
231
|
+
10: "rowing",
|
|
232
|
+
11: "strength",
|
|
233
|
+
12: "elliptical",
|
|
234
|
+
13: "skiing",
|
|
235
|
+
};
|
|
236
|
+
/** Polar sport (lowercased) → canonical activity type */
|
|
237
|
+
export const POLAR_SPORT_MAP = {
|
|
238
|
+
running: "running",
|
|
239
|
+
cycling: "cycling",
|
|
240
|
+
swimming: "swimming",
|
|
241
|
+
walking: "walking",
|
|
242
|
+
hiking: "hiking",
|
|
243
|
+
strength_training: "strength",
|
|
244
|
+
yoga: "yoga",
|
|
245
|
+
pilates: "pilates",
|
|
246
|
+
cross_country_skiing: "cross_country_skiing",
|
|
247
|
+
rowing: "rowing",
|
|
248
|
+
elliptical: "elliptical",
|
|
249
|
+
mountain_biking: "mountain_biking",
|
|
250
|
+
trail_running: "trail_running",
|
|
251
|
+
cross_training: "cross_training",
|
|
252
|
+
group_exercise: "group_exercise",
|
|
253
|
+
stretching: "stretching",
|
|
254
|
+
dance: "dance",
|
|
255
|
+
martial_arts: "martial_arts",
|
|
256
|
+
tennis: "tennis",
|
|
257
|
+
basketball: "basketball",
|
|
258
|
+
soccer: "soccer",
|
|
259
|
+
golf: "golf",
|
|
260
|
+
ice_hockey: "ice_hockey",
|
|
261
|
+
skiing: "skiing",
|
|
262
|
+
snowboarding: "snowboarding",
|
|
263
|
+
skating: "skating",
|
|
264
|
+
rock_climbing: "rock_climbing",
|
|
265
|
+
surfing: "surfing",
|
|
266
|
+
kayaking: "kayaking",
|
|
267
|
+
functional_training: "functional_fitness",
|
|
268
|
+
bootcamp: "bootcamp",
|
|
269
|
+
boxing: "boxing",
|
|
270
|
+
core: "core",
|
|
271
|
+
aqua_fitness: "aqua_fitness",
|
|
272
|
+
circuit_training: "circuit_training",
|
|
273
|
+
triathlon: "triathlon",
|
|
274
|
+
indoor_cycling: "indoor_cycling",
|
|
275
|
+
indoor_rowing: "rowing",
|
|
276
|
+
indoor_running: "running",
|
|
277
|
+
indoor_walking: "walking",
|
|
278
|
+
treadmill_running: "running",
|
|
279
|
+
stair_climbing: "stairmaster",
|
|
280
|
+
};
|
|
281
|
+
/** Garmin activityType → canonical activity type */
|
|
282
|
+
export const GARMIN_ACTIVITY_TYPE_MAP = {
|
|
283
|
+
// Running
|
|
284
|
+
RUNNING: "running",
|
|
285
|
+
TRAIL_RUNNING: "running",
|
|
286
|
+
TREADMILL_RUNNING: "running",
|
|
287
|
+
TRACK_RUNNING: "running",
|
|
288
|
+
// Cycling
|
|
289
|
+
CYCLING: "cycling",
|
|
290
|
+
MOUNTAIN_BIKING: "mountain_biking",
|
|
291
|
+
ROAD_BIKING: "road_cycling",
|
|
292
|
+
INDOOR_CYCLING: "indoor_cycling",
|
|
293
|
+
GRAVEL_CYCLING: "gravel_cycling",
|
|
294
|
+
VIRTUAL_RIDE: "virtual_cycling",
|
|
295
|
+
// Swimming
|
|
296
|
+
SWIMMING: "swimming",
|
|
297
|
+
LAP_SWIMMING: "swimming",
|
|
298
|
+
OPEN_WATER_SWIMMING: "swimming",
|
|
299
|
+
// Walking / Hiking
|
|
300
|
+
WALKING: "walking",
|
|
301
|
+
HIKING: "hiking",
|
|
302
|
+
// Strength / Cardio
|
|
303
|
+
STRENGTH_TRAINING: "strength",
|
|
304
|
+
INDOOR_CARDIO: "cardio",
|
|
305
|
+
// Other fitness
|
|
306
|
+
YOGA: "yoga",
|
|
307
|
+
PILATES: "pilates",
|
|
308
|
+
ELLIPTICAL: "elliptical",
|
|
309
|
+
ROWING: "rowing",
|
|
310
|
+
};
|
|
311
|
+
/** Oura activity (lowercased) → canonical activity type */
|
|
312
|
+
export const OURA_ACTIVITY_TYPE_MAP = {
|
|
313
|
+
walking: "walking",
|
|
314
|
+
running: "running",
|
|
315
|
+
cycling: "cycling",
|
|
316
|
+
swimming: "swimming",
|
|
317
|
+
hiking: "hiking",
|
|
318
|
+
yoga: "yoga",
|
|
319
|
+
elliptical: "elliptical",
|
|
320
|
+
rowing: "rowing",
|
|
321
|
+
strength_training: "strength",
|
|
322
|
+
weight_training: "strength",
|
|
323
|
+
dancing: "dancing",
|
|
324
|
+
pilates: "pilates",
|
|
325
|
+
indoor_cycling: "indoor_cycling",
|
|
326
|
+
stairmaster: "stairmaster",
|
|
327
|
+
other: "other",
|
|
328
|
+
};
|
|
329
|
+
/** RideWithGPS activity_type → canonical activity type */
|
|
330
|
+
export const RIDE_WITH_GPS_ACTIVITY_TYPE_MAP = {
|
|
331
|
+
cycling: "cycling",
|
|
332
|
+
"cycling:generic": "cycling",
|
|
333
|
+
"cycling:road": "road_cycling",
|
|
334
|
+
"cycling:mountain": "mountain_biking",
|
|
335
|
+
"cycling:gravel": "gravel_cycling",
|
|
336
|
+
"cycling:cyclocross": "cyclocross",
|
|
337
|
+
"cycling:track": "track_cycling",
|
|
338
|
+
mountain_biking: "mountain_biking",
|
|
339
|
+
road_cycling: "road_cycling",
|
|
340
|
+
gravel_cycling: "gravel_cycling",
|
|
341
|
+
cyclocross: "cyclocross",
|
|
342
|
+
track_cycling: "track_cycling",
|
|
343
|
+
running: "running",
|
|
344
|
+
trail_running: "running",
|
|
345
|
+
walking: "walking",
|
|
346
|
+
hiking: "hiking",
|
|
347
|
+
swimming: "swimming",
|
|
348
|
+
};
|
|
349
|
+
/** Apple Health HKWorkoutActivityType → normalized lowercase name */
|
|
350
|
+
export const APPLE_HEALTH_WORKOUT_TYPE_MAP = {
|
|
351
|
+
HKWorkoutActivityTypeAmericanFootball: "american_football",
|
|
352
|
+
HKWorkoutActivityTypeArchery: "archery",
|
|
353
|
+
HKWorkoutActivityTypeAustralianFootball: "australian_football",
|
|
354
|
+
HKWorkoutActivityTypeBadminton: "badminton",
|
|
355
|
+
HKWorkoutActivityTypeBaseball: "baseball",
|
|
356
|
+
HKWorkoutActivityTypeBasketball: "basketball",
|
|
357
|
+
HKWorkoutActivityTypeBowling: "bowling",
|
|
358
|
+
HKWorkoutActivityTypeBoxing: "boxing",
|
|
359
|
+
HKWorkoutActivityTypeClimbing: "climbing",
|
|
360
|
+
HKWorkoutActivityTypeCricket: "cricket",
|
|
361
|
+
HKWorkoutActivityTypeCrossCountrySkiing: "cross_country_skiing",
|
|
362
|
+
HKWorkoutActivityTypeCrossTraining: "cross_training",
|
|
363
|
+
HKWorkoutActivityTypeCurling: "curling",
|
|
364
|
+
HKWorkoutActivityTypeCycling: "cycling",
|
|
365
|
+
HKWorkoutActivityTypeDance: "dance",
|
|
366
|
+
HKWorkoutActivityTypeDownhillSkiing: "downhill_skiing",
|
|
367
|
+
HKWorkoutActivityTypeElliptical: "elliptical",
|
|
368
|
+
HKWorkoutActivityTypeEquestrianSports: "equestrian",
|
|
369
|
+
HKWorkoutActivityTypeFencing: "fencing",
|
|
370
|
+
HKWorkoutActivityTypeFishing: "fishing",
|
|
371
|
+
HKWorkoutActivityTypeFunctionalStrengthTraining: "functional_strength",
|
|
372
|
+
HKWorkoutActivityTypeGolf: "golf",
|
|
373
|
+
HKWorkoutActivityTypeGymnastics: "gymnastics",
|
|
374
|
+
HKWorkoutActivityTypeHandball: "handball",
|
|
375
|
+
HKWorkoutActivityTypeHiking: "hiking",
|
|
376
|
+
HKWorkoutActivityTypeHockey: "hockey",
|
|
377
|
+
HKWorkoutActivityTypeHunting: "hunting",
|
|
378
|
+
HKWorkoutActivityTypeLacrosse: "lacrosse",
|
|
379
|
+
HKWorkoutActivityTypeMartialArts: "martial_arts",
|
|
380
|
+
HKWorkoutActivityTypeMindAndBody: "mind_and_body",
|
|
381
|
+
HKWorkoutActivityTypeMixedCardio: "mixed_cardio",
|
|
382
|
+
HKWorkoutActivityTypePaddleSports: "paddle_sports",
|
|
383
|
+
HKWorkoutActivityTypePlay: "play",
|
|
384
|
+
HKWorkoutActivityTypePreparationAndRecovery: "preparation_and_recovery",
|
|
385
|
+
HKWorkoutActivityTypeRacquetball: "racquetball",
|
|
386
|
+
HKWorkoutActivityTypeRowing: "rowing",
|
|
387
|
+
HKWorkoutActivityTypeRugby: "rugby",
|
|
388
|
+
HKWorkoutActivityTypeRunning: "running",
|
|
389
|
+
HKWorkoutActivityTypeSailing: "sailing",
|
|
390
|
+
HKWorkoutActivityTypeSkatingSports: "skating",
|
|
391
|
+
HKWorkoutActivityTypeSnowSports: "snow_sports",
|
|
392
|
+
HKWorkoutActivityTypeSoccer: "soccer",
|
|
393
|
+
HKWorkoutActivityTypeSoftball: "softball",
|
|
394
|
+
HKWorkoutActivityTypeSquash: "squash",
|
|
395
|
+
HKWorkoutActivityTypeStairClimbing: "stair_climbing",
|
|
396
|
+
HKWorkoutActivityTypeSurfingSports: "surfing",
|
|
397
|
+
HKWorkoutActivityTypeSwimming: "swimming",
|
|
398
|
+
HKWorkoutActivityTypeTableTennis: "table_tennis",
|
|
399
|
+
HKWorkoutActivityTypeTennis: "tennis",
|
|
400
|
+
HKWorkoutActivityTypeTrackAndField: "track_and_field",
|
|
401
|
+
HKWorkoutActivityTypeTraditionalStrengthTraining: "strength_training",
|
|
402
|
+
HKWorkoutActivityTypeVolleyball: "volleyball",
|
|
403
|
+
HKWorkoutActivityTypeWalking: "walking",
|
|
404
|
+
HKWorkoutActivityTypeWaterFitness: "water_fitness",
|
|
405
|
+
HKWorkoutActivityTypeWaterPolo: "water_polo",
|
|
406
|
+
HKWorkoutActivityTypeWaterSports: "water_sports",
|
|
407
|
+
HKWorkoutActivityTypeWrestling: "wrestling",
|
|
408
|
+
HKWorkoutActivityTypeYoga: "yoga",
|
|
409
|
+
HKWorkoutActivityTypeBarre: "barre",
|
|
410
|
+
HKWorkoutActivityTypeCoreTraining: "core_training",
|
|
411
|
+
HKWorkoutActivityTypeFlexibility: "flexibility",
|
|
412
|
+
HKWorkoutActivityTypeHighIntensityIntervalTraining: "hiit",
|
|
413
|
+
HKWorkoutActivityTypeJumpRope: "jump_rope",
|
|
414
|
+
HKWorkoutActivityTypeKickboxing: "kickboxing",
|
|
415
|
+
HKWorkoutActivityTypePilates: "pilates",
|
|
416
|
+
HKWorkoutActivityTypeSnowboarding: "snowboarding",
|
|
417
|
+
HKWorkoutActivityTypeStairs: "stairs",
|
|
418
|
+
HKWorkoutActivityTypeStepTraining: "step_training",
|
|
419
|
+
HKWorkoutActivityTypeWheelchairWalkPace: "wheelchair_walk",
|
|
420
|
+
HKWorkoutActivityTypeWheelchairRunPace: "wheelchair_run",
|
|
421
|
+
HKWorkoutActivityTypeTaiChi: "tai_chi",
|
|
422
|
+
HKWorkoutActivityTypeMixedMetabolicCardioTraining: "mixed_metabolic_cardio",
|
|
423
|
+
HKWorkoutActivityTypeHandCycling: "hand_cycling",
|
|
424
|
+
HKWorkoutActivityTypeDiscSports: "disc_sports",
|
|
425
|
+
HKWorkoutActivityTypeFitnessGaming: "fitness_gaming",
|
|
426
|
+
HKWorkoutActivityTypeCardioDance: "cardio_dance",
|
|
427
|
+
HKWorkoutActivityTypeSocialDance: "social_dance",
|
|
428
|
+
HKWorkoutActivityTypePickleball: "paddle_racquet",
|
|
429
|
+
HKWorkoutActivityTypeCooldown: "cooldown",
|
|
430
|
+
HKWorkoutActivityTypeSwimBikeRun: "triathlon",
|
|
431
|
+
HKWorkoutActivityTypeTransition: "transition",
|
|
432
|
+
HKWorkoutActivityTypeUnderwaterDiving: "underwater_diving",
|
|
433
|
+
HKWorkoutActivityTypeOther: "other",
|
|
434
|
+
};
|
|
435
|
+
const ACTIVITY_TYPE_LABELS = {
|
|
436
|
+
cycling: "Cycling",
|
|
437
|
+
road_cycling: "Road Cycling",
|
|
438
|
+
mountain_biking: "Mountain Biking",
|
|
439
|
+
gravel_cycling: "Gravel Cycling",
|
|
440
|
+
indoor_cycling: "Indoor Cycling",
|
|
441
|
+
virtual_cycling: "Virtual Cycling",
|
|
442
|
+
e_bike_cycling: "E-Bike Cycling",
|
|
443
|
+
cyclocross: "Cyclocross",
|
|
444
|
+
track_cycling: "Track Cycling",
|
|
445
|
+
bmx: "BMX",
|
|
446
|
+
running: "Running",
|
|
447
|
+
trail_running: "Trail Running",
|
|
448
|
+
walking: "Walking",
|
|
449
|
+
hiking: "Hiking",
|
|
450
|
+
swimming: "Swimming",
|
|
451
|
+
rowing: "Rowing",
|
|
452
|
+
yoga: "Yoga",
|
|
453
|
+
pilates: "Pilates",
|
|
454
|
+
elliptical: "Elliptical",
|
|
455
|
+
strength: "Strength",
|
|
456
|
+
strength_training: "Strength Training",
|
|
457
|
+
functional_strength: "Functional Strength",
|
|
458
|
+
stair_climbing: "Stair Climbing",
|
|
459
|
+
cross_training: "Cross Training",
|
|
460
|
+
hiit: "HIIT",
|
|
461
|
+
cardio: "Cardio",
|
|
462
|
+
other: "Other",
|
|
463
|
+
};
|
|
464
|
+
const VERTICAL_ASCENT_ACTIVITY_TYPE_GROUP_LABELS = {
|
|
465
|
+
road_cycling: "Road Cycling",
|
|
466
|
+
mountain_biking: "Mountain Biking",
|
|
467
|
+
gravel_cycling: "Gravel Cycling",
|
|
468
|
+
other_cycling: "Other Cycling",
|
|
469
|
+
};
|
|
470
|
+
function toTitleCase(value) {
|
|
471
|
+
return value
|
|
472
|
+
.split(/[_\-\s]+/)
|
|
473
|
+
.filter(Boolean)
|
|
474
|
+
.map((word) => {
|
|
475
|
+
const lower = word.toLowerCase();
|
|
476
|
+
if (lower === "hiit")
|
|
477
|
+
return "HIIT";
|
|
478
|
+
return `${lower.charAt(0).toUpperCase()}${lower.slice(1)}`;
|
|
479
|
+
})
|
|
480
|
+
.join(" ");
|
|
481
|
+
}
|
|
482
|
+
function normalizeActivityType(activityType) {
|
|
483
|
+
const normalized = activityType.trim().toLowerCase();
|
|
484
|
+
if (normalized === OTHER_ACTIVITY_TYPE || normalized === "other") {
|
|
485
|
+
return OTHER_ACTIVITY_TYPE;
|
|
486
|
+
}
|
|
487
|
+
return normalized;
|
|
488
|
+
}
|
|
489
|
+
export function formatActivityTypeLabel(activityType) {
|
|
490
|
+
const normalized = normalizeActivityType(activityType);
|
|
491
|
+
if (normalized === OTHER_ACTIVITY_TYPE) {
|
|
492
|
+
return "Other";
|
|
493
|
+
}
|
|
494
|
+
return ACTIVITY_TYPE_LABELS[normalized] ?? toTitleCase(normalized);
|
|
495
|
+
}
|
|
496
|
+
export function getVerticalAscentActivityTypeGroup(activityType) {
|
|
497
|
+
const normalized = normalizeActivityType(activityType);
|
|
498
|
+
if (normalized === "road_cycling")
|
|
499
|
+
return "road_cycling";
|
|
500
|
+
if (normalized === "mountain_biking")
|
|
501
|
+
return "mountain_biking";
|
|
502
|
+
if (normalized === "gravel_cycling")
|
|
503
|
+
return "gravel_cycling";
|
|
504
|
+
return "other_cycling";
|
|
505
|
+
}
|
|
506
|
+
export function formatVerticalAscentActivityTypeGroupLabel(activityTypeGroup) {
|
|
507
|
+
return VERTICAL_ASCENT_ACTIVITY_TYPE_GROUP_LABELS[activityTypeGroup];
|
|
508
|
+
}
|
|
509
|
+
export function collapseWeeklyVolumeActivityTypes(rows, maxLegendItems = 6) {
|
|
510
|
+
if (rows.length === 0)
|
|
511
|
+
return rows;
|
|
512
|
+
// Consolidate all cycling subtypes into generic "cycling" before grouping
|
|
513
|
+
const normalizedRows = rows.map((row) => {
|
|
514
|
+
const normalized = normalizeActivityType(row.activity_type);
|
|
515
|
+
return {
|
|
516
|
+
...row,
|
|
517
|
+
activity_type: isCyclingActivity(normalized) ? "cycling" : normalized,
|
|
518
|
+
};
|
|
519
|
+
});
|
|
520
|
+
const totalsByType = new Map();
|
|
521
|
+
for (const row of normalizedRows) {
|
|
522
|
+
totalsByType.set(row.activity_type, (totalsByType.get(row.activity_type) ?? 0) + row.hours);
|
|
523
|
+
}
|
|
524
|
+
const orderedTypes = [...totalsByType.entries()]
|
|
525
|
+
.sort((a, b) => b[1] - a[1])
|
|
526
|
+
.map(([type]) => type);
|
|
527
|
+
const shouldCollapse = orderedTypes.length > maxLegendItems;
|
|
528
|
+
const keepTypes = shouldCollapse
|
|
529
|
+
? new Set(orderedTypes.slice(0, Math.max(0, maxLegendItems - 1)))
|
|
530
|
+
: new Set(orderedTypes);
|
|
531
|
+
const aggregated = new Map();
|
|
532
|
+
for (const row of normalizedRows) {
|
|
533
|
+
const groupedType = keepTypes.has(row.activity_type) ? row.activity_type : OTHER_ACTIVITY_TYPE;
|
|
534
|
+
const key = `${row.week}::${groupedType}`;
|
|
535
|
+
const existing = aggregated.get(key);
|
|
536
|
+
if (existing) {
|
|
537
|
+
existing.count += row.count;
|
|
538
|
+
existing.hours += row.hours;
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
aggregated.set(key, {
|
|
542
|
+
week: row.week,
|
|
543
|
+
activity_type: groupedType,
|
|
544
|
+
count: row.count,
|
|
545
|
+
hours: row.hours,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
return [...aggregated.values()].sort((a, b) => {
|
|
549
|
+
if (a.week !== b.week)
|
|
550
|
+
return a.week.localeCompare(b.week);
|
|
551
|
+
return a.activity_type.localeCompare(b.activity_type);
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Pick the daily load row to display in "current strain" UI.
|
|
556
|
+
* Always returns the latest (most recent) row so the dashboard reflects the
|
|
557
|
+
* current day's rolling workload state.
|
|
558
|
+
*/
|
|
559
|
+
export function selectRecentDailyLoad(rows) {
|
|
560
|
+
if (rows.length === 0)
|
|
561
|
+
return null;
|
|
562
|
+
return rows[rows.length - 1] ?? null;
|
|
563
|
+
}
|
|
564
|
+
//# sourceMappingURL=training.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"training.js","sourceRoot":"","sources":["../src/training.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Next workout recommendation engine.
|
|
3
|
+
*
|
|
4
|
+
* Pure function: takes a snapshot of the user's training state and returns
|
|
5
|
+
* an evidence-based recommendation for what to do next.
|
|
6
|
+
*
|
|
7
|
+
* Based on:
|
|
8
|
+
* - Polarized training model (Seiler, Stoggl & Sperlich 2014): 80/20 zone split
|
|
9
|
+
* - Muscle group recovery (Schoenfeld 2016): 48h+ per group, 2x/week target
|
|
10
|
+
* - HRV-guided training (Plews 2013): modulate intensity by recovery
|
|
11
|
+
* - Hard/easy alternation (Seiler 2010): never stack high-intensity days
|
|
12
|
+
* - HIIT capping: max 2-3x/week with 48h spacing
|
|
13
|
+
*/
|
|
14
|
+
export type WorkoutType = "rest" | "active_recovery" | "cardio_easy" | "cardio_intervals" | "strength";
|
|
15
|
+
export interface IntervalProtocol {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
workSeconds: number;
|
|
19
|
+
restSeconds: number;
|
|
20
|
+
sets: number;
|
|
21
|
+
targetZone: number;
|
|
22
|
+
warmupMinutes: number;
|
|
23
|
+
cooldownMinutes: number;
|
|
24
|
+
totalMinutes: number;
|
|
25
|
+
}
|
|
26
|
+
export interface StrengthDetail {
|
|
27
|
+
muscleGroups: string[];
|
|
28
|
+
estimatedDurationMinutes: number;
|
|
29
|
+
}
|
|
30
|
+
export interface CardioEasyDetail {
|
|
31
|
+
targetZone: 1 | 2;
|
|
32
|
+
durationMinutes: number;
|
|
33
|
+
targetHrRange: {
|
|
34
|
+
min: number;
|
|
35
|
+
max: number;
|
|
36
|
+
} | null;
|
|
37
|
+
}
|
|
38
|
+
export interface CardioIntervalsDetail {
|
|
39
|
+
protocol: IntervalProtocol;
|
|
40
|
+
targetHrRange: {
|
|
41
|
+
min: number;
|
|
42
|
+
max: number;
|
|
43
|
+
} | null;
|
|
44
|
+
}
|
|
45
|
+
export interface WorkoutRecommendation {
|
|
46
|
+
type: WorkoutType;
|
|
47
|
+
summary: string;
|
|
48
|
+
reasoning: string[];
|
|
49
|
+
strengthDetail: StrengthDetail | null;
|
|
50
|
+
cardioEasyDetail: CardioEasyDetail | null;
|
|
51
|
+
cardioIntervalsDetail: CardioIntervalsDetail | null;
|
|
52
|
+
}
|
|
53
|
+
export interface RecentActivity {
|
|
54
|
+
type: "strength" | "cardio";
|
|
55
|
+
date: string;
|
|
56
|
+
wasHardDay: boolean;
|
|
57
|
+
muscleGroups: string[];
|
|
58
|
+
activityType: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ZoneDistribution {
|
|
61
|
+
zone1Samples: number;
|
|
62
|
+
zone2Samples: number;
|
|
63
|
+
zone3Samples: number;
|
|
64
|
+
zone4Samples: number;
|
|
65
|
+
zone5Samples: number;
|
|
66
|
+
}
|
|
67
|
+
export interface MuscleGroupFreshness {
|
|
68
|
+
muscleGroup: string;
|
|
69
|
+
lastWorkedDate: string;
|
|
70
|
+
setsThisWeek: number;
|
|
71
|
+
}
|
|
72
|
+
export interface RecommendationInput {
|
|
73
|
+
today: string;
|
|
74
|
+
readinessScore: number | null;
|
|
75
|
+
workloadRatio: number | null;
|
|
76
|
+
trainingStressBalance: number | null;
|
|
77
|
+
sleepDebtMinutes: number;
|
|
78
|
+
recentActivities: RecentActivity[];
|
|
79
|
+
zoneDistribution: ZoneDistribution | null;
|
|
80
|
+
muscleGroupFreshness: MuscleGroupFreshness[];
|
|
81
|
+
userMaxHr: number | null;
|
|
82
|
+
userRestingHr: number | null;
|
|
83
|
+
}
|
|
84
|
+
export declare function muscleGroupLabel(group: string): string;
|
|
85
|
+
export declare function recommendNextWorkout(input: RecommendationInput): WorkoutRecommendation;
|
|
86
|
+
//# sourceMappingURL=workout-recommendation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workout-recommendation.d.ts","sourceRoot":"","sources":["../src/workout-recommendation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,iBAAiB,GACjB,aAAa,GACb,kBAAkB,GAClB,UAAU,CAAC;AAEf,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACpD;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACpD;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,qBAAqB,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACrD;AAID,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,cAAc,EAAE,CAAC;IACnC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,oBAAoB,EAAE,oBAAoB,EAAE,CAAC;IAC7C,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAyCD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AA8BD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,qBAAqB,CA4EtF"}
|