hevy-shared 1.0.1038 → 1.0.1039

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.
@@ -1,6 +1,6 @@
1
- import { WeeklyTrainingFrequency, TrainingGoal, TrainingLevel, SimplifiedMuscleGroup, MuscleGroup, LibraryExercise, ExerciseCategory, GranularEquipment, HevyTrainerProgramEquipment, RestTimerLength, CardioPreference } from '.';
1
+ import { WeeklyTrainingFrequency, TrainingGoal, TrainingLevel, SimplifiedMuscleGroup, MuscleGroup, LibraryExercise, ExerciseCategory, GranularEquipment, HevyTrainerProgramEquipment, RestTimerLength, CardioPreference, StrictRepRange, ExerciseType } from '.';
2
2
  export type HevyTrainerExerciseCategory = (typeof hevyTrainerExerciseCategories)[number];
3
- export type HevyTrainerRoutineName = (typeof routineNames)[number];
3
+ export type TrainerWorkoutTemplateName = (typeof workoutTemplateNames)[number];
4
4
  export declare const workoutDurationOptions: readonly [40, 60, 80];
5
5
  export type WorkoutDurationMinutes = (typeof workoutDurationOptions)[number];
6
6
  export declare const trainerGymTypes: readonly ["home_gym", "garage_gym", "commercial_gym", "full_gym"];
@@ -16,12 +16,12 @@ export declare const trainerEquipmentToGranularEquipments: (equipments: HevyTrai
16
16
  export declare const granularEquipmentsToTrainerEquipments: (granularEquipments: GranularEquipment[]) => HevyTrainerProgramEquipment[];
17
17
  export declare const hevyTrainerExerciseCategories: readonly ["compound", "isolation"];
18
18
  export declare const defaultDurationPerFrequency: Record<WeeklyTrainingFrequency, WorkoutDurationMinutes>;
19
- export declare const routineNames: readonly ["full_body_1", "full_body_2_a", "full_body_2_b", "full_body_3_a", "full_body_3_b", "full_body_3_c", "upper_1_a", "lower_1_a", "upper_1_b", "lower_1_b", "push_1", "pull_1", "legs_1", "upper_2", "lower_2", "push_2_a", "pull_2_a", "legs_2_a", "push_2_b", "pull_2_b", "legs_2_b"];
19
+ export declare const workoutTemplateNames: readonly ["full_body_1", "full_body_2_a", "full_body_2_b", "full_body_3_a", "full_body_3_b", "full_body_3_c", "upper_1_a", "lower_1_a", "upper_1_b", "lower_1_b", "push_1", "pull_1", "legs_1", "upper_2", "lower_2", "push_2_a", "pull_2_a", "legs_2_a", "push_2_b", "pull_2_b", "legs_2_b"];
20
20
  export type exerciseId = string;
21
21
  export interface ExerciseSelectionCriteria {
22
22
  exerciseCategory: HevyTrainerExerciseCategory | 'all';
23
23
  equipments: GranularEquipment[];
24
- routineBarbellExerciseCount: number;
24
+ workoutBarbellExerciseCount: number;
25
25
  level: TrainingLevel;
26
26
  goal: TrainingGoal;
27
27
  muscleGroup: MuscleGroup;
@@ -29,7 +29,7 @@ export interface ExerciseSelectionCriteria {
29
29
  }
30
30
  export interface ExerciseSelectionContext {
31
31
  programUsedExerciseIds?: Set<string>;
32
- routineUsedExerciseIds?: Set<string>;
32
+ workoutUsedExerciseIds?: Set<string>;
33
33
  excludedExerciseIds?: Set<string>;
34
34
  }
35
35
  export interface ExerciseSelectionParams<T extends HevyTrainerLibraryExercise> {
@@ -69,7 +69,7 @@ export interface ProgramGenerationParams<T extends HevyTrainerLibraryExercise> {
69
69
  }
70
70
  export interface TemplateExerciseSelectionTraceRecord {
71
71
  traceKind: 'template';
72
- routine: HevyTrainerRoutineName;
72
+ workoutTemplate: TrainerWorkoutTemplateName;
73
73
  prescriptionIndex: number;
74
74
  prescription: ExercisePrescription;
75
75
  resolvedMuscleGroup: MuscleGroup;
@@ -79,7 +79,7 @@ export interface TemplateExerciseSelectionTraceRecord {
79
79
  }
80
80
  export interface CardioExerciseSelectionTraceRecord {
81
81
  traceKind: 'cardio';
82
- routine: HevyTrainerRoutineName;
82
+ workoutTemplate: TrainerWorkoutTemplateName;
83
83
  prescriptionIndex: number;
84
84
  selectedExerciseId?: string;
85
85
  equipments: GranularEquipment[];
@@ -92,19 +92,19 @@ export type TrainerProgramAttemptWithTraces = TrainerProgramAttempt & {
92
92
  };
93
93
  export type FrequencyString = 'one_day' | 'two_days' | 'three_days' | 'four_days' | 'five_days' | 'six_days';
94
94
  export declare const frequencyMap: Record<WeeklyTrainingFrequency, FrequencyString>;
95
- export declare const programSplits: Record<WeeklyTrainingFrequency, HevyTrainerRoutineName[]>;
95
+ export declare const programSplits: Record<WeeklyTrainingFrequency, TrainerWorkoutTemplateName[]>;
96
96
  export type SetsPerGoal = {
97
97
  [key in TrainingGoal]: number;
98
98
  };
99
99
  export type SetsPerFrequency = {
100
100
  [key in FrequencyString]: SetsPerGoal;
101
101
  };
102
- export interface RepRange {
102
+ export interface AlgorithmRepRange {
103
103
  rep_range_start: number;
104
104
  rep_range_end: number;
105
105
  }
106
106
  export type RepRangesPerCategory = {
107
- [key in HevyTrainerExerciseCategory]: RepRange;
107
+ [key in HevyTrainerExerciseCategory]: AlgorithmRepRange;
108
108
  };
109
109
  export type RepRanges = {
110
110
  [key in TrainingGoal]: RepRangesPerCategory;
@@ -135,10 +135,11 @@ export type ExerciseReplacements = {
135
135
  };
136
136
  export interface WorkoutTemplate {
137
137
  exercises: ExercisePrescription[];
138
+ /** @deprecated Because this is english-only and not translatable so we are not using it currently */
138
139
  notes?: string;
139
140
  }
140
141
  export type Templates = {
141
- [key in HevyTrainerRoutineName]: WorkoutTemplate;
142
+ [key in TrainerWorkoutTemplateName]: WorkoutTemplate;
142
143
  };
143
144
  export interface BackofficeTrainerPreset {
144
145
  id?: number;
@@ -157,39 +158,40 @@ export interface TrainerAlgorithmSettings {
157
158
  exercise_notes: ExerciseNotes;
158
159
  exercise_replacements: ExerciseReplacements;
159
160
  }
160
- /** Resistance prescriptions from templates (sets, reps, rest, notes). */
161
161
  export interface TrainerProgramResistanceExercise {
162
162
  kind: 'resistance';
163
- exerciseTemplate: HevyTrainerLibraryExercise;
164
- muscleGroup: MuscleGroup | 'focus_muscle';
165
- category: HevyTrainerExerciseCategory;
166
- sets: number;
167
- warmupSetCount?: number;
168
- repRangeStart: number;
169
- repRangeEnd: number;
170
- restTimerSeconds: number;
171
- notes?: string;
163
+ exercise_template: HevyTrainerLibraryExercise;
164
+ set_count: number;
165
+ warmup_set_count: number;
166
+ rep_range: StrictRepRange;
167
+ rest_seconds: number;
172
168
  }
173
- /** Optional cardio attachment — no prescription semantics beyond exercise choice. */
174
169
  export interface TrainerProgramCardioExercise {
175
170
  kind: 'cardio';
176
- exerciseTemplate: HevyTrainerLibraryExercise;
177
- durationSeconds: number;
171
+ exercise_template: HevyTrainerLibraryExercise;
172
+ set_count: 1;
173
+ duration_seconds: number;
178
174
  }
179
- export type TrainerProgramExercise = TrainerProgramResistanceExercise | TrainerProgramCardioExercise;
175
+ export interface TrainerProgramOtherExercise {
176
+ kind: 'other';
177
+ exercise_template: HevyTrainerLibraryExercise;
178
+ set_count: number;
179
+ }
180
+ export type TrainerProgramExercise = TrainerProgramResistanceExercise | TrainerProgramCardioExercise | TrainerProgramOtherExercise;
180
181
  export declare const isTrainerProgramResistanceExercise: (exercise: TrainerProgramExercise) => exercise is TrainerProgramResistanceExercise;
181
182
  export declare const isTrainerProgramCardioExercise: (exercise: TrainerProgramExercise) => exercise is TrainerProgramCardioExercise;
182
- export interface TrainerProgramRoutine {
183
- name: HevyTrainerRoutineName;
183
+ export declare const isTrainerProgramOtherExercise: (exercise: TrainerProgramExercise) => exercise is TrainerProgramOtherExercise;
184
+ export declare const isTrainerResistanceExerciseType: (exerciseType: ExerciseType) => exerciseType is "weight_reps" | "reps_only" | "bodyweight_reps" | "bodyweight_assisted_reps";
185
+ export declare const isTrainerCardioExerciseType: (exerciseType: ExerciseType) => exerciseType is "duration" | "distance_duration" | "floors_duration" | "steps_duration";
186
+ export interface TrainerProgramWorkoutTemplate {
187
+ name: TrainerWorkoutTemplateName;
184
188
  exercises: TrainerProgramExercise[];
185
- notes?: string;
186
189
  }
187
- export interface TrainerProgram {
188
- name: WeeklyTrainingFrequency;
189
- routines: TrainerProgramRoutine[];
190
+ export interface GeneratedTrainerProgram {
191
+ workoutTemplates: TrainerProgramWorkoutTemplate[];
190
192
  }
191
193
  export declare const getTrainerSetCount: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, frequency: WeeklyTrainingFrequency) => number;
192
- export declare const getTrainerRepRange: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, exerciseCategory: HevyTrainerExerciseCategory) => RepRange;
194
+ export declare const getTrainerRepRange: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, exerciseCategory: HevyTrainerExerciseCategory) => AlgorithmRepRange;
193
195
  export declare const getTrainerRestTimerSeconds: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, length: RestTimerLength, exerciseCategory: HevyTrainerExerciseCategory) => number;
194
196
  /**
195
197
  * Normalizes the exercise category to a HevyTrainerExerciseCategory
@@ -243,23 +245,14 @@ export interface ExercisePrescriptionError {
243
245
  focusMuscle?: SimplifiedMuscleGroup;
244
246
  };
245
247
  }
246
- export interface TrainerProgramExerciseResult {
247
- success: true;
248
- exercise: TrainerProgramExercise;
249
- }
250
- export interface TrainerProgramExerciseError {
251
- success: false;
252
- error: ExercisePrescriptionError;
253
- }
254
- export type TrainerProgramExerciseAttempt = TrainerProgramExerciseResult | TrainerProgramExerciseError;
255
248
  export interface TrainerProgramResult {
256
249
  success: true;
257
- program: TrainerProgram;
250
+ program: GeneratedTrainerProgram;
258
251
  }
259
252
  export interface TrainerProgramError {
260
253
  success: false;
261
254
  errors: ExercisePrescriptionError[];
262
- partialProgram: TrainerProgram;
255
+ partialProgram: GeneratedTrainerProgram;
263
256
  }
264
257
  export type TrainerProgramAttempt = TrainerProgramResult | TrainerProgramError;
265
258
  /**
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS = exports.getPrioritySortedExercises = exports.isEquipmentCompatible = exports.normalizeExerciseCategory = exports.getTrainerRestTimerSeconds = exports.getTrainerRepRange = exports.getTrainerSetCount = exports.isTrainerProgramCardioExercise = exports.isTrainerProgramResistanceExercise = exports.programSplits = exports.frequencyMap = exports.routineNames = exports.defaultDurationPerFrequency = exports.hevyTrainerExerciseCategories = exports.granularEquipmentsToTrainerEquipments = exports.trainerEquipmentToGranularEquipments = exports.granularEquipmentDefaults = exports.trainerGymTypes = exports.workoutDurationOptions = void 0;
3
+ exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS = exports.getPrioritySortedExercises = exports.isEquipmentCompatible = exports.normalizeExerciseCategory = exports.getTrainerRestTimerSeconds = exports.getTrainerRepRange = exports.getTrainerSetCount = exports.isTrainerCardioExerciseType = exports.isTrainerResistanceExerciseType = exports.isTrainerProgramOtherExercise = exports.isTrainerProgramCardioExercise = exports.isTrainerProgramResistanceExercise = exports.programSplits = exports.frequencyMap = exports.workoutTemplateNames = exports.defaultDurationPerFrequency = exports.hevyTrainerExerciseCategories = exports.granularEquipmentsToTrainerEquipments = exports.trainerEquipmentToGranularEquipments = exports.granularEquipmentDefaults = exports.trainerGymTypes = exports.workoutDurationOptions = void 0;
4
4
  exports.pickTrainerExercise = pickTrainerExercise;
5
5
  exports.generateProgram = generateProgram;
6
6
  const _1 = require(".");
@@ -152,7 +152,7 @@ exports.defaultDurationPerFrequency = {
152
152
  5: 40,
153
153
  6: 40,
154
154
  };
155
- exports.routineNames = [
155
+ exports.workoutTemplateNames = [
156
156
  // Full body 1x
157
157
  'full_body_1',
158
158
  // Full body 2x
@@ -201,6 +201,18 @@ const isTrainerProgramResistanceExercise = (exercise) => exercise.kind === 'resi
201
201
  exports.isTrainerProgramResistanceExercise = isTrainerProgramResistanceExercise;
202
202
  const isTrainerProgramCardioExercise = (exercise) => exercise.kind === 'cardio';
203
203
  exports.isTrainerProgramCardioExercise = isTrainerProgramCardioExercise;
204
+ const isTrainerProgramOtherExercise = (exercise) => exercise.kind === 'other';
205
+ exports.isTrainerProgramOtherExercise = isTrainerProgramOtherExercise;
206
+ const isTrainerResistanceExerciseType = (exerciseType) => exerciseType === 'weight_reps' ||
207
+ exerciseType === 'bodyweight_reps' ||
208
+ exerciseType === 'bodyweight_assisted_reps' ||
209
+ exerciseType === 'reps_only';
210
+ exports.isTrainerResistanceExerciseType = isTrainerResistanceExerciseType;
211
+ const isTrainerCardioExerciseType = (exerciseType) => exerciseType === 'distance_duration' ||
212
+ exerciseType === 'duration' ||
213
+ exerciseType === 'floors_duration' ||
214
+ exerciseType === 'steps_duration';
215
+ exports.isTrainerCardioExerciseType = isTrainerCardioExerciseType;
204
216
  const getTrainerSetCount = (trainerAlgorithmSettings, goal, frequency) => {
205
217
  return trainerAlgorithmSettings.sets[exports.frequencyMap[frequency]][goal];
206
218
  };
@@ -291,12 +303,12 @@ const MAX_BARBELL_EXERCISES_FOR_ONCE_PER_WEEK = 3;
291
303
  * - Only enforce the cap when the user has at least one "barbell substitute" equipment available
292
304
  * (otherwise we allow barbell exercises to avoid running out of viable options)
293
305
  */
294
- const isBarbellExerciseAllowed = (exercise, routineBarbellExerciseCount, userEquipments, frequency) => {
306
+ const isBarbellExerciseAllowed = (exercise, workoutBarbellExerciseCount, userEquipments, frequency) => {
295
307
  const isCandidateBarbell = exercise.equipment_category === 'barbell';
296
308
  const isOncePerWeek = frequency === 1;
297
309
  if (!isCandidateBarbell || !isOncePerWeek)
298
310
  return true;
299
- const isAtOrOverLimit = routineBarbellExerciseCount >= MAX_BARBELL_EXERCISES_FOR_ONCE_PER_WEEK;
311
+ const isAtOrOverLimit = workoutBarbellExerciseCount >= MAX_BARBELL_EXERCISES_FOR_ONCE_PER_WEEK;
300
312
  if (!isAtOrOverLimit)
301
313
  return true;
302
314
  const barbellSubstitutes = [
@@ -314,7 +326,7 @@ const isBarbellExerciseAllowed = (exercise, routineBarbellExerciseCount, userEqu
314
326
  const isExerciseUsed = (exercise, context) => {
315
327
  var _a, _b, _c;
316
328
  return (((_a = context.programUsedExerciseIds) === null || _a === void 0 ? void 0 : _a.has(exercise.id)) ||
317
- ((_b = context.routineUsedExerciseIds) === null || _b === void 0 ? void 0 : _b.has(exercise.id)) ||
329
+ ((_b = context.workoutUsedExerciseIds) === null || _b === void 0 ? void 0 : _b.has(exercise.id)) ||
318
330
  ((_c = context.excludedExerciseIds) === null || _c === void 0 ? void 0 : _c.has(exercise.id)) ||
319
331
  false);
320
332
  };
@@ -393,16 +405,16 @@ const getPrioritySortedExercises = (exercisePriorities, exerciseStore) => {
393
405
  return sortedExercises;
394
406
  };
395
407
  exports.getPrioritySortedExercises = getPrioritySortedExercises;
396
- const getMuscleGroup = ({ muscleGroupPrescription, programFocusMuscleExerciseCount, focusMuscle, routineName, }) => {
408
+ const getMuscleGroup = ({ muscleGroupPrescription, programFocusMuscleExerciseCount, focusMuscle, workoutTemplateName, }) => {
397
409
  if (muscleGroupPrescription === 'focus_muscle') {
398
- // If the user has selected a focus muscle and it is allowed for the routine,
410
+ // If the user has selected a focus muscle and it is allowed for the workout template,
399
411
  // we return the focus muscle extra exercise
400
412
  if (!!focusMuscle &&
401
- isFocusMuscleExtraExerciseAllowed(routineName, focusMuscle)) {
413
+ isFocusMuscleExtraExerciseAllowed(workoutTemplateName, focusMuscle)) {
402
414
  const n = _1.simplifiedMuscleGroupToMuscleGroups[focusMuscle].length;
403
415
  return _1.simplifiedMuscleGroupToMuscleGroups[focusMuscle][programFocusMuscleExerciseCount % n];
404
416
  }
405
- // If the user has not selected a focus muscle or it is not allowed for the routine
417
+ // If the user has not selected a focus muscle or it is not allowed for the workout template
406
418
  // we skip this extra exercise for the focus muscle in the program
407
419
  return undefined;
408
420
  }
@@ -420,7 +432,7 @@ const isExerciseMatch = (exercise, criteria) => {
420
432
  const levelMatch = (_b = (_a = exercise.level) === null || _a === void 0 ? void 0 : _a.includes(criteria.level)) !== null && _b !== void 0 ? _b : false;
421
433
  const goalMatch = (_d = (_c = exercise.goal) === null || _c === void 0 ? void 0 : _c.includes(criteria.goal)) !== null && _d !== void 0 ? _d : false;
422
434
  const equipmentMatch = (0, exports.isEquipmentCompatible)(exercise, criteria.equipments);
423
- const barbellLimitOk = isBarbellExerciseAllowed(exercise, criteria.routineBarbellExerciseCount, criteria.equipments, criteria.frequency);
435
+ const barbellLimitOk = isBarbellExerciseAllowed(exercise, criteria.workoutBarbellExerciseCount, criteria.equipments, criteria.frequency);
424
436
  return (categoryMatch && levelMatch && goalMatch && equipmentMatch && barbellLimitOk);
425
437
  };
426
438
  /**
@@ -465,8 +477,8 @@ const pickTrainerExerciseWithTrace = (params) => {
465
477
  programUsedExerciseIds: context.programUsedExerciseIds,
466
478
  excludedExerciseIds: context.excludedExerciseIds,
467
479
  };
468
- const routineContext = {
469
- routineUsedExerciseIds: context.routineUsedExerciseIds,
480
+ const workoutContext = {
481
+ workoutUsedExerciseIds: context.workoutUsedExerciseIds,
470
482
  excludedExerciseIds: context.excludedExerciseIds,
471
483
  };
472
484
  // Pass 1
@@ -480,10 +492,10 @@ const pickTrainerExerciseWithTrace = (params) => {
480
492
  if (exercise)
481
493
  return { exercise, trace: Object.assign(Object.assign({}, trace), { selectedPass: 1 }) };
482
494
  // Pass 2
483
- exercise = findMatchingExercise(exercises, criteria, routineContext);
495
+ exercise = findMatchingExercise(exercises, criteria, workoutContext);
484
496
  trace.entries.push({
485
497
  pass: 2,
486
- label: 'exact match; not used in routine (reuse allowed in program)',
498
+ label: 'exact match; not used in the same workout (reuse allowed in program)',
487
499
  candidatePoolSize: exercises.length,
488
500
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
489
501
  });
@@ -500,20 +512,20 @@ const pickTrainerExerciseWithTrace = (params) => {
500
512
  if (exercise)
501
513
  return { exercise, trace: Object.assign(Object.assign({}, trace), { selectedPass: 3 }) };
502
514
  // Pass 4
503
- exercise = findAlternativeIsolationExercise(exercises, criteria, routineContext);
515
+ exercise = findAlternativeIsolationExercise(exercises, criteria, workoutContext);
504
516
  trace.entries.push({
505
517
  pass: 4,
506
- label: 'handpicked alternative isolation; not used in routine (reuse allowed in program)',
518
+ label: 'handpicked alternative isolation; not used in the same workout (reuse allowed in program)',
507
519
  candidatePoolSize: exercises.length,
508
520
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
509
521
  });
510
522
  if (exercise)
511
523
  return { exercise, trace: Object.assign(Object.assign({}, trace), { selectedPass: 4 }) };
512
524
  // Pass 5
513
- exercise = findMatchingExercise(exercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), routineContext);
525
+ exercise = findMatchingExercise(exercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), workoutContext);
514
526
  trace.entries.push({
515
527
  pass: 5,
516
- label: 'match regardless of isolation or compound; not used in routine (reuse allowed in program)',
528
+ label: 'match regardless of isolation or compound; not used in the same workout (reuse allowed in program)',
517
529
  candidatePoolSize: exercises.length,
518
530
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
519
531
  });
@@ -523,10 +535,10 @@ const pickTrainerExerciseWithTrace = (params) => {
523
535
  const secondaryMuscleExercises = Object.values(sortedExercises)
524
536
  .flat()
525
537
  .filter((e) => e.other_muscles.includes(criteria.muscleGroup));
526
- exercise = findMatchingExercise(secondaryMuscleExercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), routineContext);
538
+ exercise = findMatchingExercise(secondaryMuscleExercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), workoutContext);
527
539
  trace.entries.push({
528
540
  pass: 6,
529
- label: 'secondary muscle match; regardless of isolation or compound; not used in routine (reuse allowed in program)',
541
+ label: 'secondary muscle match; regardless of isolation or compound; not used in the same workout (reuse allowed in program)',
530
542
  candidatePoolSize: secondaryMuscleExercises.length,
531
543
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
532
544
  });
@@ -542,11 +554,11 @@ function pickTrainerExercise(params) {
542
554
  }
543
555
  const CARDIO_TRACE_INDEX_BEFORE_TEMPLATE = -1;
544
556
  exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS = 600;
545
- /** Inserts optional cardio before or after template exercises for one routine. */
546
- const attachOptionalCardioToRoutine = ({ cardioPreference, sortedExercises, criteria, debugExerciseSelectionTrace, exerciseSelectionTraces, routine, templatePrescriptionCount, routineExercises, }) => {
557
+ /** Inserts optional cardio before or after template exercises for one workout template. */
558
+ const attachOptionalCardioToWorkoutTemplate = ({ cardioPreference, sortedExercises, criteria, debugExerciseSelectionTrace, exerciseSelectionTraces, workoutTemplate, templatePrescriptionCount, workoutExercises, }) => {
547
559
  if (cardioPreference === 'no-cardio')
548
560
  return;
549
- // Cardio is reusable across routines, so program/routine used-id contexts are
561
+ // Cardio is reusable across workout templates, so program/workoutTemplate used-id contexts are
550
562
  // intentionally omitted — only the global excluded set applies.
551
563
  const selectionParams = {
552
564
  sortedExercises,
@@ -557,7 +569,7 @@ const attachOptionalCardioToRoutine = ({ cardioPreference, sortedExercises, crit
557
569
  equipments: criteria.equipments,
558
570
  muscleGroup: 'cardio',
559
571
  exerciseCategory: 'all',
560
- routineBarbellExerciseCount: 0,
572
+ workoutBarbellExerciseCount: 0,
561
573
  },
562
574
  context: { excludedExerciseIds: criteria.excludedExerciseIds },
563
575
  };
@@ -567,17 +579,18 @@ const attachOptionalCardioToRoutine = ({ cardioPreference, sortedExercises, crit
567
579
  return;
568
580
  const slot = {
569
581
  kind: 'cardio',
570
- exerciseTemplate: cardioExercise,
571
- durationSeconds: exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS,
582
+ exercise_template: cardioExercise,
583
+ duration_seconds: exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS,
584
+ set_count: 1,
572
585
  };
573
586
  if (cardioPreference === 'workout-start')
574
- routineExercises.unshift(slot);
587
+ workoutExercises.unshift(slot);
575
588
  else
576
- routineExercises.push(slot);
589
+ workoutExercises.push(slot);
577
590
  if (debugExerciseSelectionTrace) {
578
591
  exerciseSelectionTraces.push({
579
592
  traceKind: 'cardio',
580
- routine,
593
+ workoutTemplate,
581
594
  prescriptionIndex: cardioPreference === 'workout-start'
582
595
  ? CARDIO_TRACE_INDEX_BEFORE_TEMPLATE
583
596
  : templatePrescriptionCount,
@@ -592,28 +605,27 @@ function generateProgram(params) {
592
605
  var _a, _b;
593
606
  const { trainerAlgorithmSettings, frequency, goal, level, equipments, workoutDurationMinutes, restTimerLength, exerciseStore, focusMuscle, excludedExerciseIds, debugExerciseSelectionTrace, cardioPreference, } = params;
594
607
  const exerciseSelectionTraces = [];
595
- const routines = exports.programSplits[frequency];
608
+ const workoutTemplates = exports.programSplits[frequency];
596
609
  const program = {
597
- name: frequency,
598
- routines: [],
610
+ workoutTemplates: [],
599
611
  };
600
612
  // TODO: Rename sortedExercises to sortedExercisesByMuscleGroup or something similar
601
613
  const sortedExercises = (0, exports.getPrioritySortedExercises)(trainerAlgorithmSettings.exercise_priorities, exerciseStore);
602
614
  const programUsedExerciseIds = new Set();
603
615
  let programFocusMuscleExerciseCount = 0;
604
616
  const allErrors = [];
605
- for (const routine of routines) {
606
- const routineTemplate = trainerAlgorithmSettings.templates[routine];
607
- let routineBarbellExerciseCount = 0;
608
- const routineUsedExerciseIds = new Set();
609
- const routineExercises = [];
610
- for (let prescriptionIndex = 0; prescriptionIndex < routineTemplate.exercises.length; prescriptionIndex++) {
611
- const exercisePrescription = routineTemplate.exercises[prescriptionIndex];
617
+ for (const workout of workoutTemplates) {
618
+ const workoutTemplate = trainerAlgorithmSettings.templates[workout];
619
+ let workoutBarbellExerciseCount = 0;
620
+ const workoutUsedExerciseIds = new Set();
621
+ const workoutExercises = [];
622
+ for (let prescriptionIndex = 0; prescriptionIndex < workoutTemplate.exercises.length; prescriptionIndex++) {
623
+ const exercisePrescription = workoutTemplate.exercises[prescriptionIndex];
612
624
  const muscleGroup = getMuscleGroup({
613
625
  muscleGroupPrescription: exercisePrescription.muscle_group,
614
626
  programFocusMuscleExerciseCount,
615
627
  focusMuscle,
616
- routineName: routine,
628
+ workoutTemplateName: workout,
617
629
  });
618
630
  // If the muscle group is not found, skip the exercise
619
631
  if (!muscleGroup) {
@@ -632,7 +644,7 @@ function generateProgram(params) {
632
644
  exerciseCategory: exercisePrescription.category,
633
645
  equipments,
634
646
  muscleGroup,
635
- routineBarbellExerciseCount,
647
+ workoutBarbellExerciseCount,
636
648
  level,
637
649
  goal,
638
650
  };
@@ -643,7 +655,7 @@ function generateProgram(params) {
643
655
  criteria,
644
656
  context: {
645
657
  programUsedExerciseIds,
646
- routineUsedExerciseIds,
658
+ workoutUsedExerciseIds,
647
659
  excludedExerciseIds,
648
660
  },
649
661
  withTrace: true,
@@ -651,7 +663,7 @@ function generateProgram(params) {
651
663
  exercise = selection.exercise;
652
664
  exerciseSelectionTraces.push({
653
665
  traceKind: 'template',
654
- routine,
666
+ workoutTemplate: workout,
655
667
  prescriptionIndex,
656
668
  prescription: exercisePrescription,
657
669
  resolvedMuscleGroup: muscleGroup,
@@ -666,30 +678,29 @@ function generateProgram(params) {
666
678
  criteria,
667
679
  context: {
668
680
  programUsedExerciseIds,
669
- routineUsedExerciseIds,
681
+ workoutUsedExerciseIds,
670
682
  excludedExerciseIds,
671
683
  },
672
684
  });
673
685
  }
674
686
  if (!!exercise) {
675
687
  programUsedExerciseIds.add(exercise.id);
676
- routineUsedExerciseIds.add(exercise.id);
688
+ workoutUsedExerciseIds.add(exercise.id);
677
689
  if (exercise.equipment_category === 'barbell')
678
- routineBarbellExerciseCount++;
690
+ workoutBarbellExerciseCount++;
679
691
  if (exercisePrescription.muscle_group === 'focus_muscle')
680
692
  programFocusMuscleExerciseCount++;
681
693
  const repRange = (0, exports.getTrainerRepRange)(trainerAlgorithmSettings, goal, exercisePrescription.category);
682
- routineExercises.push({
694
+ workoutExercises.push({
683
695
  kind: 'resistance',
684
- exerciseTemplate: exercise,
685
- muscleGroup: exercisePrescription.muscle_group,
686
- category: exercisePrescription.category,
687
- sets: (0, exports.getTrainerSetCount)(trainerAlgorithmSettings, goal, frequency),
688
- repRangeStart: repRange.rep_range_start,
689
- repRangeEnd: repRange.rep_range_end,
690
- restTimerSeconds: (0, exports.getTrainerRestTimerSeconds)(trainerAlgorithmSettings, goal, restTimerLength, exercisePrescription.category),
691
- warmupSetCount: exercisePrescription.warmup_set_count,
692
- notes: (_b = trainerAlgorithmSettings.exercise_notes[exercise.id]) !== null && _b !== void 0 ? _b : '',
696
+ exercise_template: exercise,
697
+ set_count: (0, exports.getTrainerSetCount)(trainerAlgorithmSettings, goal, frequency),
698
+ warmup_set_count: (_b = exercisePrescription.warmup_set_count) !== null && _b !== void 0 ? _b : 0,
699
+ rep_range: {
700
+ start: repRange.rep_range_start,
701
+ end: repRange.rep_range_end,
702
+ },
703
+ rest_seconds: (0, exports.getTrainerRestTimerSeconds)(trainerAlgorithmSettings, goal, restTimerLength, exercisePrescription.category),
693
704
  });
694
705
  }
695
706
  else {
@@ -707,23 +718,21 @@ function generateProgram(params) {
707
718
  });
708
719
  }
709
720
  }
710
- attachOptionalCardioToRoutine({
721
+ attachOptionalCardioToWorkoutTemplate({
711
722
  cardioPreference,
712
723
  sortedExercises,
713
724
  criteria: { equipments, level, goal, frequency, excludedExerciseIds },
714
725
  debugExerciseSelectionTrace,
715
726
  exerciseSelectionTraces,
716
- routine,
717
- templatePrescriptionCount: routineTemplate.exercises.length,
718
- routineExercises,
727
+ workoutTemplate: workout,
728
+ templatePrescriptionCount: workoutTemplate.exercises.length,
729
+ workoutExercises,
719
730
  });
720
- program.routines.push({
721
- name: routine,
722
- notes: routineTemplate.notes,
723
- exercises: routineExercises,
731
+ program.workoutTemplates.push({
732
+ name: workout,
733
+ exercises: workoutExercises,
724
734
  });
725
735
  }
726
- // Return result based on whether there were errors
727
736
  if (allErrors.length > 0) {
728
737
  const result = {
729
738
  success: false,