hevy-shared 1.0.1018 → 1.0.1020

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, StrictRepRange } from '.';
1
+ import { WeeklyTrainingFrequency, TrainingGoal, TrainingLevel, SimplifiedMuscleGroup, MuscleGroup, LibraryExercise, ExerciseCategory, GranularEquipment, HevyTrainerProgramEquipment, RestTimerLength, CardioPreference } from '.';
2
2
  export type HevyTrainerExerciseCategory = typeof hevyTrainerExerciseCategories[number];
3
- export type TrainerWorkoutTemplateName = typeof workoutTemplateNames[number];
3
+ export type HevyTrainerRoutineName = typeof routineNames[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 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"];
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"];
20
20
  export type exerciseId = string;
21
21
  export interface ExerciseSelectionCriteria {
22
22
  exerciseCategory: HevyTrainerExerciseCategory | 'all';
23
23
  equipments: GranularEquipment[];
24
- workoutBarbellExerciseCount: number;
24
+ routineBarbellExerciseCount: 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
- workoutUsedExerciseIds?: Set<string>;
32
+ routineUsedExerciseIds?: 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
- workoutTemplate: TrainerWorkoutTemplateName;
72
+ routine: HevyTrainerRoutineName;
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
- workoutTemplate: TrainerWorkoutTemplateName;
82
+ routine: HevyTrainerRoutineName;
83
83
  prescriptionIndex: number;
84
84
  selectedExerciseId?: string;
85
85
  equipments: GranularEquipment[];
@@ -87,24 +87,24 @@ export interface CardioExerciseSelectionTraceRecord {
87
87
  trace: ExerciseSelectionTrace;
88
88
  }
89
89
  export type ProgramExerciseSelectionTraceRecord = TemplateExerciseSelectionTraceRecord | CardioExerciseSelectionTraceRecord;
90
- export type TrainerProgramAttemptWithTraces<T> = TrainerProgramAttempt<T> & {
90
+ export type TrainerProgramAttemptWithTraces = TrainerProgramAttempt & {
91
91
  exerciseSelectionTraces: ProgramExerciseSelectionTraceRecord[];
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, TrainerWorkoutTemplateName[]>;
95
+ export declare const programSplits: Record<WeeklyTrainingFrequency, HevyTrainerRoutineName[]>;
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 AlgorithmRepRange {
102
+ export interface RepRange {
103
103
  rep_range_start: number;
104
104
  rep_range_end: number;
105
105
  }
106
106
  export type RepRangesPerCategory = {
107
- [key in HevyTrainerExerciseCategory]: AlgorithmRepRange;
107
+ [key in HevyTrainerExerciseCategory]: RepRange;
108
108
  };
109
109
  export type RepRanges = {
110
110
  [key in TrainingGoal]: RepRangesPerCategory;
@@ -135,11 +135,10 @@ 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 */
139
138
  notes?: string;
140
139
  }
141
140
  export type Templates = {
142
- [key in TrainerWorkoutTemplateName]: WorkoutTemplate;
141
+ [key in HevyTrainerRoutineName]: WorkoutTemplate;
143
142
  };
144
143
  export interface BackofficeTrainerPreset {
145
144
  id?: number;
@@ -158,38 +157,39 @@ export interface TrainerAlgorithmSettings {
158
157
  exercise_notes: ExerciseNotes;
159
158
  exercise_replacements: ExerciseReplacements;
160
159
  }
161
- export interface TrainerProgramResistanceExercise<T> {
160
+ /** Resistance prescriptions from templates (sets, reps, rest, notes). */
161
+ export interface TrainerProgramResistanceExercise {
162
162
  kind: 'resistance';
163
- exercise_template: T;
164
- set_count: number;
165
- warmup_set_count: number;
166
- rep_range: StrictRepRange;
167
- rest_seconds: number;
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;
168
172
  }
169
- export interface TrainerProgramCardioExercise<T> {
173
+ /** Optional cardio attachment — no prescription semantics beyond exercise choice. */
174
+ export interface TrainerProgramCardioExercise {
170
175
  kind: 'cardio';
171
- exercise_template: T;
172
- set_count: 1;
173
- duration_seconds: number;
176
+ exerciseTemplate: HevyTrainerLibraryExercise;
177
+ durationSeconds: number;
174
178
  }
175
- export interface TrainerProgramOtherExercise<T> {
176
- kind: 'other';
177
- exercise_template: T;
178
- set_count: number;
179
- }
180
- export type TrainerProgramExercise<T> = TrainerProgramResistanceExercise<T> | TrainerProgramCardioExercise<T> | TrainerProgramOtherExercise<T>;
181
- export declare const isTrainerProgramResistanceExercise: <T>(exercise: TrainerProgramExercise<T>) => exercise is TrainerProgramResistanceExercise<T>;
182
- export declare const isTrainerProgramCardioExercise: <T>(exercise: TrainerProgramExercise<T>) => exercise is TrainerProgramCardioExercise<T>;
183
- export declare const isTrainerProgramOtherExercise: <T>(exercise: TrainerProgramExercise<T>) => exercise is TrainerProgramOtherExercise<T>;
184
- export interface TrainerProgramWorkoutTemplate<T> {
185
- name: TrainerWorkoutTemplateName;
186
- exercises: TrainerProgramExercise<T>[];
179
+ export type TrainerProgramExercise = TrainerProgramResistanceExercise | TrainerProgramCardioExercise;
180
+ export declare const isTrainerProgramResistanceExercise: (exercise: TrainerProgramExercise) => exercise is TrainerProgramResistanceExercise;
181
+ export declare const isTrainerProgramCardioExercise: (exercise: TrainerProgramExercise) => exercise is TrainerProgramCardioExercise;
182
+ export interface TrainerProgramRoutine {
183
+ name: HevyTrainerRoutineName;
184
+ exercises: TrainerProgramExercise[];
185
+ notes?: string;
187
186
  }
188
- export interface GeneratedTrainerProgram<T> {
189
- workoutTemplates: TrainerProgramWorkoutTemplate<T>[];
187
+ export interface TrainerProgram {
188
+ name: WeeklyTrainingFrequency;
189
+ routines: TrainerProgramRoutine[];
190
190
  }
191
191
  export declare const getTrainerSetCount: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, frequency: WeeklyTrainingFrequency) => number;
192
- export declare const getTrainerRepRange: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, exerciseCategory: HevyTrainerExerciseCategory) => AlgorithmRepRange;
192
+ export declare const getTrainerRepRange: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, exerciseCategory: HevyTrainerExerciseCategory) => RepRange;
193
193
  export declare const getTrainerRestTimerSeconds: (trainerAlgorithmSettings: TrainerAlgorithmSettings, goal: TrainingGoal, length: RestTimerLength, exerciseCategory: HevyTrainerExerciseCategory) => number;
194
194
  /**
195
195
  * Normalizes the exercise category to a HevyTrainerExerciseCategory
@@ -243,16 +243,25 @@ export interface ExercisePrescriptionError {
243
243
  focusMuscle?: SimplifiedMuscleGroup;
244
244
  };
245
245
  }
246
- export interface TrainerProgramResult<T> {
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
+ export interface TrainerProgramResult {
247
256
  success: true;
248
- program: GeneratedTrainerProgram<T>;
257
+ program: TrainerProgram;
249
258
  }
250
- export interface TrainerProgramError<T> {
259
+ export interface TrainerProgramError {
251
260
  success: false;
252
261
  errors: ExercisePrescriptionError[];
253
- partialProgram: GeneratedTrainerProgram<T>;
262
+ partialProgram: TrainerProgram;
254
263
  }
255
- export type TrainerProgramAttempt<T> = TrainerProgramResult<T> | TrainerProgramError<T>;
264
+ export type TrainerProgramAttempt = TrainerProgramResult | TrainerProgramError;
256
265
  /**
257
266
  * Generates a complete training program based on the provided parameters
258
267
  * - debugExerciseSelectionTrace: true -> includes exercise selection trace breadcrumbs in the result for debugging.
@@ -260,6 +269,6 @@ export type TrainerProgramAttempt<T> = TrainerProgramResult<T> | TrainerProgramE
260
269
  */
261
270
  export declare function generateProgram<T extends HevyTrainerLibraryExercise>(params: ProgramGenerationParams<T> & {
262
271
  debugExerciseSelectionTrace: true;
263
- }): TrainerProgramAttemptWithTraces<T>;
264
- export declare function generateProgram<T extends HevyTrainerLibraryExercise>(params: ProgramGenerationParams<T>): TrainerProgramAttempt<T>;
272
+ }): TrainerProgramAttemptWithTraces;
273
+ export declare function generateProgram<T extends HevyTrainerLibraryExercise>(params: ProgramGenerationParams<T>): TrainerProgramAttempt;
265
274
  export {};
@@ -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.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;
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;
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.workoutTemplateNames = [
155
+ exports.routineNames = [
156
156
  // Full body 1x
157
157
  'full_body_1',
158
158
  // Full body 2x
@@ -201,8 +201,6 @@ 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
204
  const getTrainerSetCount = (trainerAlgorithmSettings, goal, frequency) => {
207
205
  return trainerAlgorithmSettings.sets[exports.frequencyMap[frequency]][goal];
208
206
  };
@@ -293,12 +291,12 @@ const MAX_BARBELL_EXERCISES_FOR_ONCE_PER_WEEK = 3;
293
291
  * - Only enforce the cap when the user has at least one "barbell substitute" equipment available
294
292
  * (otherwise we allow barbell exercises to avoid running out of viable options)
295
293
  */
296
- const isBarbellExerciseAllowed = (exercise, workoutBarbellExerciseCount, userEquipments, frequency) => {
294
+ const isBarbellExerciseAllowed = (exercise, routineBarbellExerciseCount, userEquipments, frequency) => {
297
295
  const isCandidateBarbell = exercise.equipment_category === 'barbell';
298
296
  const isOncePerWeek = frequency === 1;
299
297
  if (!isCandidateBarbell || !isOncePerWeek)
300
298
  return true;
301
- const isAtOrOverLimit = workoutBarbellExerciseCount >= MAX_BARBELL_EXERCISES_FOR_ONCE_PER_WEEK;
299
+ const isAtOrOverLimit = routineBarbellExerciseCount >= MAX_BARBELL_EXERCISES_FOR_ONCE_PER_WEEK;
302
300
  if (!isAtOrOverLimit)
303
301
  return true;
304
302
  const barbellSubstitutes = [
@@ -316,7 +314,7 @@ const isBarbellExerciseAllowed = (exercise, workoutBarbellExerciseCount, userEqu
316
314
  const isExerciseUsed = (exercise, context) => {
317
315
  var _a, _b, _c;
318
316
  return (((_a = context.programUsedExerciseIds) === null || _a === void 0 ? void 0 : _a.has(exercise.id)) ||
319
- ((_b = context.workoutUsedExerciseIds) === null || _b === void 0 ? void 0 : _b.has(exercise.id)) ||
317
+ ((_b = context.routineUsedExerciseIds) === null || _b === void 0 ? void 0 : _b.has(exercise.id)) ||
320
318
  ((_c = context.excludedExerciseIds) === null || _c === void 0 ? void 0 : _c.has(exercise.id)) ||
321
319
  false);
322
320
  };
@@ -395,16 +393,16 @@ const getPrioritySortedExercises = (exercisePriorities, exerciseStore) => {
395
393
  return sortedExercises;
396
394
  };
397
395
  exports.getPrioritySortedExercises = getPrioritySortedExercises;
398
- const getMuscleGroup = ({ muscleGroupPrescription, programFocusMuscleExerciseCount, focusMuscle, workoutTemplateName, }) => {
396
+ const getMuscleGroup = ({ muscleGroupPrescription, programFocusMuscleExerciseCount, focusMuscle, routineName, }) => {
399
397
  if (muscleGroupPrescription === 'focus_muscle') {
400
- // If the user has selected a focus muscle and it is allowed for the workout template,
398
+ // If the user has selected a focus muscle and it is allowed for the routine,
401
399
  // we return the focus muscle extra exercise
402
400
  if (!!focusMuscle &&
403
- isFocusMuscleExtraExerciseAllowed(workoutTemplateName, focusMuscle)) {
401
+ isFocusMuscleExtraExerciseAllowed(routineName, focusMuscle)) {
404
402
  const n = _1.simplifiedMuscleGroupToMuscleGroups[focusMuscle].length;
405
403
  return _1.simplifiedMuscleGroupToMuscleGroups[focusMuscle][programFocusMuscleExerciseCount % n];
406
404
  }
407
- // If the user has not selected a focus muscle or it is not allowed for the workout template
405
+ // If the user has not selected a focus muscle or it is not allowed for the routine
408
406
  // we skip this extra exercise for the focus muscle in the program
409
407
  return undefined;
410
408
  }
@@ -422,7 +420,7 @@ const isExerciseMatch = (exercise, criteria) => {
422
420
  const levelMatch = (_b = (_a = exercise.level) === null || _a === void 0 ? void 0 : _a.includes(criteria.level)) !== null && _b !== void 0 ? _b : false;
423
421
  const goalMatch = (_d = (_c = exercise.goal) === null || _c === void 0 ? void 0 : _c.includes(criteria.goal)) !== null && _d !== void 0 ? _d : false;
424
422
  const equipmentMatch = (0, exports.isEquipmentCompatible)(exercise, criteria.equipments);
425
- const barbellLimitOk = isBarbellExerciseAllowed(exercise, criteria.workoutBarbellExerciseCount, criteria.equipments, criteria.frequency);
423
+ const barbellLimitOk = isBarbellExerciseAllowed(exercise, criteria.routineBarbellExerciseCount, criteria.equipments, criteria.frequency);
426
424
  return (categoryMatch && levelMatch && goalMatch && equipmentMatch && barbellLimitOk);
427
425
  };
428
426
  /**
@@ -467,8 +465,8 @@ const pickTrainerExerciseWithTrace = (params) => {
467
465
  programUsedExerciseIds: context.programUsedExerciseIds,
468
466
  excludedExerciseIds: context.excludedExerciseIds,
469
467
  };
470
- const workoutContext = {
471
- workoutUsedExerciseIds: context.workoutUsedExerciseIds,
468
+ const routineContext = {
469
+ routineUsedExerciseIds: context.routineUsedExerciseIds,
472
470
  excludedExerciseIds: context.excludedExerciseIds,
473
471
  };
474
472
  // Pass 1
@@ -482,10 +480,10 @@ const pickTrainerExerciseWithTrace = (params) => {
482
480
  if (exercise)
483
481
  return { exercise, trace: Object.assign(Object.assign({}, trace), { selectedPass: 1 }) };
484
482
  // Pass 2
485
- exercise = findMatchingExercise(exercises, criteria, workoutContext);
483
+ exercise = findMatchingExercise(exercises, criteria, routineContext);
486
484
  trace.entries.push({
487
485
  pass: 2,
488
- label: 'exact match; not used in the same workout (reuse allowed in program)',
486
+ label: 'exact match; not used in routine (reuse allowed in program)',
489
487
  candidatePoolSize: exercises.length,
490
488
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
491
489
  });
@@ -502,20 +500,20 @@ const pickTrainerExerciseWithTrace = (params) => {
502
500
  if (exercise)
503
501
  return { exercise, trace: Object.assign(Object.assign({}, trace), { selectedPass: 3 }) };
504
502
  // Pass 4
505
- exercise = findAlternativeIsolationExercise(exercises, criteria, workoutContext);
503
+ exercise = findAlternativeIsolationExercise(exercises, criteria, routineContext);
506
504
  trace.entries.push({
507
505
  pass: 4,
508
- label: 'handpicked alternative isolation; not used in the same workout (reuse allowed in program)',
506
+ label: 'handpicked alternative isolation; not used in routine (reuse allowed in program)',
509
507
  candidatePoolSize: exercises.length,
510
508
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
511
509
  });
512
510
  if (exercise)
513
511
  return { exercise, trace: Object.assign(Object.assign({}, trace), { selectedPass: 4 }) };
514
512
  // Pass 5
515
- exercise = findMatchingExercise(exercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), workoutContext);
513
+ exercise = findMatchingExercise(exercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), routineContext);
516
514
  trace.entries.push({
517
515
  pass: 5,
518
- label: 'match regardless of isolation or compound; not used in the same workout (reuse allowed in program)',
516
+ label: 'match regardless of isolation or compound; not used in routine (reuse allowed in program)',
519
517
  candidatePoolSize: exercises.length,
520
518
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
521
519
  });
@@ -525,10 +523,10 @@ const pickTrainerExerciseWithTrace = (params) => {
525
523
  const secondaryMuscleExercises = Object.values(sortedExercises)
526
524
  .flat()
527
525
  .filter((e) => e.other_muscles.includes(criteria.muscleGroup));
528
- exercise = findMatchingExercise(secondaryMuscleExercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), workoutContext);
526
+ exercise = findMatchingExercise(secondaryMuscleExercises, Object.assign(Object.assign({}, criteria), { exerciseCategory: 'all' }), routineContext);
529
527
  trace.entries.push({
530
528
  pass: 6,
531
- label: 'secondary muscle match; regardless of isolation or compound; not used in the same workout (reuse allowed in program)',
529
+ label: 'secondary muscle match; regardless of isolation or compound; not used in routine (reuse allowed in program)',
532
530
  candidatePoolSize: secondaryMuscleExercises.length,
533
531
  selectedExerciseId: exercise === null || exercise === void 0 ? void 0 : exercise.id,
534
532
  });
@@ -544,11 +542,11 @@ function pickTrainerExercise(params) {
544
542
  }
545
543
  const CARDIO_TRACE_INDEX_BEFORE_TEMPLATE = -1;
546
544
  exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS = 600;
547
- /** Inserts optional cardio before or after template exercises for one workout template. */
548
- const attachOptionalCardioToWorkoutTemplate = ({ cardioPreference, sortedExercises, criteria, debugExerciseSelectionTrace, exerciseSelectionTraces, workoutTemplate, templatePrescriptionCount, workoutExercises, }) => {
545
+ /** Inserts optional cardio before or after template exercises for one routine. */
546
+ const attachOptionalCardioToRoutine = ({ cardioPreference, sortedExercises, criteria, debugExerciseSelectionTrace, exerciseSelectionTraces, routine, templatePrescriptionCount, routineExercises, }) => {
549
547
  if (cardioPreference === 'no-cardio')
550
548
  return;
551
- // Cardio is reusable across workout templates, so program/workoutTemplate used-id contexts are
549
+ // Cardio is reusable across routines, so program/routine used-id contexts are
552
550
  // intentionally omitted — only the global excluded set applies.
553
551
  const selectionParams = {
554
552
  sortedExercises,
@@ -559,7 +557,7 @@ const attachOptionalCardioToWorkoutTemplate = ({ cardioPreference, sortedExercis
559
557
  equipments: criteria.equipments,
560
558
  muscleGroup: 'cardio',
561
559
  exerciseCategory: 'all',
562
- workoutBarbellExerciseCount: 0,
560
+ routineBarbellExerciseCount: 0,
563
561
  },
564
562
  context: { excludedExerciseIds: criteria.excludedExerciseIds },
565
563
  };
@@ -569,18 +567,17 @@ const attachOptionalCardioToWorkoutTemplate = ({ cardioPreference, sortedExercis
569
567
  return;
570
568
  const slot = {
571
569
  kind: 'cardio',
572
- exercise_template: cardioExercise,
573
- duration_seconds: exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS,
574
- set_count: 1,
570
+ exerciseTemplate: cardioExercise,
571
+ durationSeconds: exports.DEFAULT_TRAINER_CARDIO_ATTACHMENT_DURATION_SECONDS,
575
572
  };
576
573
  if (cardioPreference === 'workout-start')
577
- workoutExercises.unshift(slot);
574
+ routineExercises.unshift(slot);
578
575
  else
579
- workoutExercises.push(slot);
576
+ routineExercises.push(slot);
580
577
  if (debugExerciseSelectionTrace) {
581
578
  exerciseSelectionTraces.push({
582
579
  traceKind: 'cardio',
583
- workoutTemplate,
580
+ routine,
584
581
  prescriptionIndex: cardioPreference === 'workout-start'
585
582
  ? CARDIO_TRACE_INDEX_BEFORE_TEMPLATE
586
583
  : templatePrescriptionCount,
@@ -595,27 +592,28 @@ function generateProgram(params) {
595
592
  var _a, _b;
596
593
  const { trainerAlgorithmSettings, frequency, goal, level, equipments, workoutDurationMinutes, restTimerLength, exerciseStore, focusMuscle, excludedExerciseIds, debugExerciseSelectionTrace, cardioPreference, } = params;
597
594
  const exerciseSelectionTraces = [];
598
- const workoutTemplates = exports.programSplits[frequency];
595
+ const routines = exports.programSplits[frequency];
599
596
  const program = {
600
- workoutTemplates: [],
597
+ name: frequency,
598
+ routines: [],
601
599
  };
602
600
  // TODO: Rename sortedExercises to sortedExercisesByMuscleGroup or something similar
603
601
  const sortedExercises = (0, exports.getPrioritySortedExercises)(trainerAlgorithmSettings.exercise_priorities, exerciseStore);
604
602
  const programUsedExerciseIds = new Set();
605
603
  let programFocusMuscleExerciseCount = 0;
606
604
  const allErrors = [];
607
- for (const workout of workoutTemplates) {
608
- const workoutTemplate = trainerAlgorithmSettings.templates[workout];
609
- let workoutBarbellExerciseCount = 0;
610
- const workoutUsedExerciseIds = new Set();
611
- const workoutExercises = [];
612
- for (let prescriptionIndex = 0; prescriptionIndex < workoutTemplate.exercises.length; prescriptionIndex++) {
613
- const exercisePrescription = workoutTemplate.exercises[prescriptionIndex];
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];
614
612
  const muscleGroup = getMuscleGroup({
615
613
  muscleGroupPrescription: exercisePrescription.muscle_group,
616
614
  programFocusMuscleExerciseCount,
617
615
  focusMuscle,
618
- workoutTemplateName: workout,
616
+ routineName: routine,
619
617
  });
620
618
  // If the muscle group is not found, skip the exercise
621
619
  if (!muscleGroup) {
@@ -634,7 +632,7 @@ function generateProgram(params) {
634
632
  exerciseCategory: exercisePrescription.category,
635
633
  equipments,
636
634
  muscleGroup,
637
- workoutBarbellExerciseCount,
635
+ routineBarbellExerciseCount,
638
636
  level,
639
637
  goal,
640
638
  };
@@ -645,7 +643,7 @@ function generateProgram(params) {
645
643
  criteria,
646
644
  context: {
647
645
  programUsedExerciseIds,
648
- workoutUsedExerciseIds,
646
+ routineUsedExerciseIds,
649
647
  excludedExerciseIds,
650
648
  },
651
649
  withTrace: true,
@@ -653,7 +651,7 @@ function generateProgram(params) {
653
651
  exercise = selection.exercise;
654
652
  exerciseSelectionTraces.push({
655
653
  traceKind: 'template',
656
- workoutTemplate: workout,
654
+ routine,
657
655
  prescriptionIndex,
658
656
  prescription: exercisePrescription,
659
657
  resolvedMuscleGroup: muscleGroup,
@@ -668,29 +666,30 @@ function generateProgram(params) {
668
666
  criteria,
669
667
  context: {
670
668
  programUsedExerciseIds,
671
- workoutUsedExerciseIds,
669
+ routineUsedExerciseIds,
672
670
  excludedExerciseIds,
673
671
  },
674
672
  });
675
673
  }
676
674
  if (!!exercise) {
677
675
  programUsedExerciseIds.add(exercise.id);
678
- workoutUsedExerciseIds.add(exercise.id);
676
+ routineUsedExerciseIds.add(exercise.id);
679
677
  if (exercise.equipment_category === 'barbell')
680
- workoutBarbellExerciseCount++;
678
+ routineBarbellExerciseCount++;
681
679
  if (exercisePrescription.muscle_group === 'focus_muscle')
682
680
  programFocusMuscleExerciseCount++;
683
681
  const repRange = (0, exports.getTrainerRepRange)(trainerAlgorithmSettings, goal, exercisePrescription.category);
684
- workoutExercises.push({
682
+ routineExercises.push({
685
683
  kind: 'resistance',
686
- exercise_template: exercise,
687
- set_count: (0, exports.getTrainerSetCount)(trainerAlgorithmSettings, goal, frequency),
688
- warmup_set_count: (_b = exercisePrescription.warmup_set_count) !== null && _b !== void 0 ? _b : 0,
689
- rep_range: {
690
- start: repRange.rep_range_start,
691
- end: repRange.rep_range_end,
692
- },
693
- rest_seconds: (0, exports.getTrainerRestTimerSeconds)(trainerAlgorithmSettings, goal, restTimerLength, exercisePrescription.category),
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 : '',
694
693
  });
695
694
  }
696
695
  else {
@@ -708,21 +707,23 @@ function generateProgram(params) {
708
707
  });
709
708
  }
710
709
  }
711
- attachOptionalCardioToWorkoutTemplate({
710
+ attachOptionalCardioToRoutine({
712
711
  cardioPreference,
713
712
  sortedExercises,
714
713
  criteria: { equipments, level, goal, frequency, excludedExerciseIds },
715
714
  debugExerciseSelectionTrace,
716
715
  exerciseSelectionTraces,
717
- workoutTemplate: workout,
718
- templatePrescriptionCount: workoutTemplate.exercises.length,
719
- workoutExercises,
716
+ routine,
717
+ templatePrescriptionCount: routineTemplate.exercises.length,
718
+ routineExercises,
720
719
  });
721
- program.workoutTemplates.push({
722
- name: workout,
723
- exercises: workoutExercises,
720
+ program.routines.push({
721
+ name: routine,
722
+ notes: routineTemplate.notes,
723
+ exercises: routineExercises,
724
724
  });
725
725
  }
726
+ // Return result based on whether there were errors
726
727
  if (allErrors.length > 0) {
727
728
  const result = {
728
729
  success: false,