@dgpholdings/greatoak-shared 1.2.87 → 1.2.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/__mocks__/catalog.fixture.d.ts +2 -0
  2. package/dist/__mocks__/catalog.fixture.js +208 -0
  3. package/dist/__mocks__/exercises.mock.d.ts +4 -11
  4. package/dist/__mocks__/exercises.mock.js +82 -42
  5. package/dist/__mocks__/sessions.mock.d.ts +28 -0
  6. package/dist/__mocks__/sessions.mock.js +394 -0
  7. package/dist/__mocks__/testIds.d.ts +9 -0
  8. package/dist/__mocks__/testIds.js +13 -0
  9. package/dist/__mocks__/user.mock.js +3 -1
  10. package/dist/constants/goalJourney.d.ts +108 -0
  11. package/dist/constants/goalJourney.js +443 -0
  12. package/dist/constants/index.d.ts +1 -0
  13. package/dist/constants/index.js +1 -0
  14. package/dist/types/TApiUser.d.ts +4 -2
  15. package/dist/utils/adoptionEngine/scaleProPlan.util.js +9 -4
  16. package/dist/utils/constellation/computeNormalisedLoad.test.d.ts +1 -0
  17. package/dist/utils/constellation/computeNormalisedLoad.test.js +218 -0
  18. package/dist/utils/constellation/evaluateConstellation.js +1 -1
  19. package/dist/utils/constellation/evaluateConstellation.test.d.ts +1 -0
  20. package/dist/utils/constellation/evaluateConstellation.test.js +93 -0
  21. package/dist/utils/constellation/index.d.ts +1 -0
  22. package/dist/utils/constellation/index.js +4 -1
  23. package/dist/utils/constellation/starFoundation.test.d.ts +1 -0
  24. package/dist/utils/constellation/starFoundation.test.js +75 -0
  25. package/dist/utils/constellation/stars/consistency.test.d.ts +1 -0
  26. package/dist/utils/constellation/stars/consistency.test.js +94 -0
  27. package/dist/utils/constellation/stars/quality.test.d.ts +1 -0
  28. package/dist/utils/constellation/stars/quality.test.js +113 -0
  29. package/dist/utils/constellation/stars/recovery.test.d.ts +1 -0
  30. package/dist/utils/constellation/stars/recovery.test.js +131 -0
  31. package/dist/utils/constellation/strengthStar.test.d.ts +1 -0
  32. package/dist/utils/constellation/strengthStar.test.js +190 -0
  33. package/dist/utils/exerciseRecord/recordValidator.integration.test.js +1 -1
  34. package/dist/utils/exerciseRecord/recordValidator.js +1 -1
  35. package/dist/utils/exerciseRecord/recordValidator.test.js +8 -8
  36. package/dist/utils/scoringWorkout/scoringWorkout.integration.test.js +19 -19
  37. package/package.json +1 -1
@@ -0,0 +1,443 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DAYS_PER_WEEK_OPTIONS = exports.GOAL_CATEGORY_DISPLAY = exports.GOAL_DISPLAY = exports.INTENT_DISPLAY = exports.PHASE_DISPLAY = exports.TRAINING_PHASES = exports.GOAL_TO_AI_FITNESS_GOAL = exports.GOAL_SESSION_INTENTS = exports.USER_FITNESS_GOALS = void 0;
4
+ exports.derivePhase = derivePhase;
5
+ exports.USER_FITNESS_GOALS = [
6
+ // Appearance
7
+ "lose_weight",
8
+ "build_muscle",
9
+ "lean_and_toned",
10
+ "glutes_and_legs",
11
+ // Performance
12
+ "get_stronger",
13
+ "boost_endurance",
14
+ "athletic_performance",
15
+ // Health
16
+ "general_fitness",
17
+ "posture_and_back",
18
+ "stress_relief",
19
+ "rehabilitation",
20
+ // Focused
21
+ "core_strength",
22
+ "mobility_flexibility",
23
+ ];
24
+ // The canonical weekly template per goal (7 slots, Mon→Sun)
25
+ // Phase-aware structures live in the app layer, not shared
26
+ // This is the "default" / Phase 2-3 reference structure
27
+ exports.GOAL_SESSION_INTENTS = {
28
+ lose_weight: [
29
+ "cardio",
30
+ "full-body",
31
+ "rest",
32
+ "cardio",
33
+ "full-body",
34
+ "cardio",
35
+ "rest",
36
+ ],
37
+ build_muscle: ["push", "pull", "legs", "rest", "upper", "lower", "rest"],
38
+ lean_and_toned: [
39
+ "full-body",
40
+ "cardio",
41
+ "full-body",
42
+ "rest",
43
+ "full-body",
44
+ "cardio",
45
+ "rest",
46
+ ],
47
+ glutes_and_legs: ["legs", "upper", "legs", "rest", "legs", "cardio", "rest"],
48
+ get_stronger: ["push", "pull", "legs", "rest", "push", "pull", "rest"],
49
+ boost_endurance: [
50
+ "cardio",
51
+ "legs",
52
+ "cardio",
53
+ "upper",
54
+ "cardio",
55
+ "full-body",
56
+ "rest",
57
+ ],
58
+ athletic_performance: [
59
+ "legs",
60
+ "upper",
61
+ "cardio",
62
+ "core",
63
+ "full-body",
64
+ "rest",
65
+ "rest",
66
+ ],
67
+ general_fitness: [
68
+ "full-body",
69
+ "rest",
70
+ "full-body",
71
+ "cardio",
72
+ "full-body",
73
+ "rest",
74
+ "rest",
75
+ ],
76
+ posture_and_back: [
77
+ "pull",
78
+ "core",
79
+ "mobility",
80
+ "pull",
81
+ "core",
82
+ "mobility",
83
+ "rest",
84
+ ],
85
+ stress_relief: [
86
+ "cardio",
87
+ "mobility",
88
+ "full-body",
89
+ "rest",
90
+ "cardio",
91
+ "mobility",
92
+ "rest",
93
+ ],
94
+ rehabilitation: [
95
+ "mobility",
96
+ "core",
97
+ "mobility",
98
+ "rest",
99
+ "mobility",
100
+ "core",
101
+ "rest",
102
+ ],
103
+ core_strength: ["core", "pull", "legs", "core", "push", "rest", "rest"],
104
+ mobility_flexibility: [
105
+ "mobility",
106
+ "full-body",
107
+ "mobility",
108
+ "rest",
109
+ "mobility",
110
+ "full-body",
111
+ "rest",
112
+ ],
113
+ };
114
+ exports.GOAL_TO_AI_FITNESS_GOAL = {
115
+ lose_weight: "fat_loss",
116
+ build_muscle: "hypertrophy",
117
+ lean_and_toned: "fat_loss",
118
+ glutes_and_legs: "hypertrophy",
119
+ get_stronger: "strength",
120
+ boost_endurance: "endurance",
121
+ athletic_performance: "sport_performance",
122
+ general_fitness: "general_fitness",
123
+ posture_and_back: "strength",
124
+ stress_relief: "general_fitness",
125
+ rehabilitation: "rehabilitation",
126
+ core_strength: "core_strength",
127
+ mobility_flexibility: "mobility",
128
+ };
129
+ exports.TRAINING_PHASES = [1, 2, 3, 4];
130
+ exports.PHASE_DISPLAY = {
131
+ 1: {
132
+ nameKey: "goalPhase.foundation.name",
133
+ nameEn: "Foundation",
134
+ subtitleKey: "goalPhase.foundation.subtitle",
135
+ subtitleEn: "Build the base",
136
+ purposeKey: "goalPhase.foundation.purpose",
137
+ purposeEn: "Preparing your joints, learning movement patterns, and building the work capacity for what's ahead. Every great physique starts here — don't skip it.",
138
+ durationKey: "goalPhase.foundation.duration",
139
+ durationEn: "Weeks 1–2",
140
+ weekRange: [1, 2],
141
+ intensityPercent: 40,
142
+ },
143
+ 2: {
144
+ nameKey: "goalPhase.momentum.name",
145
+ nameEn: "Momentum",
146
+ subtitleKey: "goalPhase.momentum.subtitle",
147
+ subtitleEn: "Volume builds here",
148
+ purposeKey: "goalPhase.momentum.purpose",
149
+ purposeEn: "Your body has adapted. Now we increase the work. Splits begin, sessions get more specific. This is where the habit locks in.",
150
+ durationKey: "goalPhase.momentum.duration",
151
+ durationEn: "Weeks 3–5",
152
+ weekRange: [3, 5],
153
+ intensityPercent: 60,
154
+ },
155
+ 3: {
156
+ nameKey: "goalPhase.push.name",
157
+ nameEn: "Push",
158
+ subtitleKey: "goalPhase.push.subtitle",
159
+ subtitleEn: "This is where change happens",
160
+ purposeKey: "goalPhase.push.purpose",
161
+ purposeEn: "Goal-specific intensity. Your muscles are conditioned — now we challenge them. Expect to feel this one.",
162
+ durationKey: "goalPhase.push.duration",
163
+ durationEn: "Weeks 6–8",
164
+ weekRange: [6, 8],
165
+ intensityPercent: 80,
166
+ },
167
+ 4: {
168
+ nameKey: "goalPhase.peak.name",
169
+ nameEn: "Peak",
170
+ subtitleKey: "goalPhase.peak.subtitle",
171
+ subtitleEn: "Maximum output",
172
+ purposeKey: "goalPhase.peak.purpose",
173
+ purposeEn: "Highest specificity to your goal. You have earned this — now execute. A deload is built into the final week.",
174
+ durationKey: "goalPhase.peak.duration",
175
+ durationEn: "Weeks 9+",
176
+ weekRange: [9, 99],
177
+ intensityPercent: 95,
178
+ },
179
+ };
180
+ exports.INTENT_DISPLAY = {
181
+ push: {
182
+ labelKey: "sessionIntent.push.label",
183
+ labelEn: "Push Day",
184
+ shortLabelKey: "sessionIntent.push.shortLabel",
185
+ shortLabelEn: "Push",
186
+ emoji: "💪",
187
+ },
188
+ pull: {
189
+ labelKey: "sessionIntent.pull.label",
190
+ labelEn: "Pull Day",
191
+ shortLabelKey: "sessionIntent.pull.shortLabel",
192
+ shortLabelEn: "Pull",
193
+ emoji: "🔗",
194
+ },
195
+ legs: {
196
+ labelKey: "sessionIntent.legs.label",
197
+ labelEn: "Leg Day",
198
+ shortLabelKey: "sessionIntent.legs.shortLabel",
199
+ shortLabelEn: "Legs",
200
+ emoji: "🦵",
201
+ },
202
+ lower: {
203
+ labelKey: "sessionIntent.lower.label",
204
+ labelEn: "Lower Body",
205
+ shortLabelKey: "sessionIntent.lower.shortLabel",
206
+ shortLabelEn: "Lower",
207
+ emoji: "🦵",
208
+ },
209
+ upper: {
210
+ labelKey: "sessionIntent.upper.label",
211
+ labelEn: "Upper Body",
212
+ shortLabelKey: "sessionIntent.upper.shortLabel",
213
+ shortLabelEn: "Upper",
214
+ emoji: "💪",
215
+ },
216
+ core: {
217
+ labelKey: "sessionIntent.core.label",
218
+ labelEn: "Core & Abs",
219
+ shortLabelKey: "sessionIntent.core.shortLabel",
220
+ shortLabelEn: "Core",
221
+ emoji: "⚡",
222
+ },
223
+ cardio: {
224
+ labelKey: "sessionIntent.cardio.label",
225
+ labelEn: "Cardio",
226
+ shortLabelKey: "sessionIntent.cardio.shortLabel",
227
+ shortLabelEn: "Cardio",
228
+ emoji: "🏃",
229
+ },
230
+ strength: {
231
+ labelKey: "sessionIntent.strength.label",
232
+ labelEn: "Strength",
233
+ shortLabelKey: "sessionIntent.strength.shortLabel",
234
+ shortLabelEn: "Strength",
235
+ emoji: "🏋️",
236
+ },
237
+ fatburn: {
238
+ labelKey: "sessionIntent.fatburn.label",
239
+ labelEn: "Fat Burn",
240
+ shortLabelKey: "sessionIntent.fatburn.shortLabel",
241
+ shortLabelEn: "Burn",
242
+ emoji: "🔥",
243
+ },
244
+ mobility: {
245
+ labelKey: "sessionIntent.mobility.label",
246
+ labelEn: "Mobility",
247
+ shortLabelKey: "sessionIntent.mobility.shortLabel",
248
+ shortLabelEn: "Mobility",
249
+ emoji: "🧘",
250
+ },
251
+ "full-body": {
252
+ labelKey: "sessionIntent.fullBody.label",
253
+ labelEn: "Full Body",
254
+ shortLabelKey: "sessionIntent.fullBody.shortLabel",
255
+ shortLabelEn: "Full",
256
+ emoji: "⭐",
257
+ },
258
+ rest: {
259
+ labelKey: "sessionIntent.rest.label",
260
+ labelEn: "Rest Day",
261
+ shortLabelKey: "sessionIntent.rest.shortLabel",
262
+ shortLabelEn: "Rest",
263
+ emoji: "😴",
264
+ },
265
+ };
266
+ exports.GOAL_DISPLAY = {
267
+ // ── Appearance ────────────────────────────────────────────────────────────
268
+ lose_weight: {
269
+ nameKey: "userGoal.loseWeight.name",
270
+ nameEn: "Lose Weight",
271
+ descriptionKey: "userGoal.loseWeight.description",
272
+ descriptionEn: "Burn fat and drop weight through cardio and full-body training.",
273
+ taglineKey: "userGoal.loseWeight.tagline",
274
+ taglineEn: "Every session burns, every week counts.",
275
+ emoji: "🔥",
276
+ category: "appearance",
277
+ },
278
+ build_muscle: {
279
+ nameKey: "userGoal.buildMuscle.name",
280
+ nameEn: "Build Muscle",
281
+ descriptionKey: "userGoal.buildMuscle.description",
282
+ descriptionEn: "Add size and strength with structured push, pull, and leg splits.",
283
+ taglineKey: "userGoal.buildMuscle.tagline",
284
+ taglineEn: "Progressive overload. Every rep builds the next.",
285
+ emoji: "💪",
286
+ category: "appearance",
287
+ },
288
+ lean_and_toned: {
289
+ nameKey: "userGoal.leanAndToned.name",
290
+ nameEn: "Get Lean & Toned",
291
+ descriptionKey: "userGoal.leanAndToned.description",
292
+ descriptionEn: "Burn fat while preserving muscle for a lean, defined look.",
293
+ taglineKey: "userGoal.leanAndToned.tagline",
294
+ taglineEn: "Defined. Lean. Confident.",
295
+ emoji: "✨",
296
+ category: "appearance",
297
+ },
298
+ glutes_and_legs: {
299
+ nameKey: "userGoal.glutesAndLegs.name",
300
+ nameEn: "Grow Glutes & Legs",
301
+ descriptionKey: "userGoal.glutesAndLegs.description",
302
+ descriptionEn: "Build powerful glutes and legs with targeted lower-body training.",
303
+ taglineKey: "userGoal.glutesAndLegs.tagline",
304
+ taglineEn: "Strong legs carry everything.",
305
+ emoji: "🦵",
306
+ category: "appearance",
307
+ },
308
+ // ── Performance ───────────────────────────────────────────────────────────
309
+ get_stronger: {
310
+ nameKey: "userGoal.getStronger.name",
311
+ nameEn: "Get Stronger",
312
+ descriptionKey: "userGoal.getStronger.description",
313
+ descriptionEn: "Build real-world strength through compound lifts and progressive overload.",
314
+ taglineKey: "userGoal.getStronger.tagline",
315
+ taglineEn: "Lift more. Be more.",
316
+ emoji: "🏋️",
317
+ category: "performance",
318
+ },
319
+ boost_endurance: {
320
+ nameKey: "userGoal.boostEndurance.name",
321
+ nameEn: "Build Endurance",
322
+ descriptionKey: "userGoal.boostEndurance.description",
323
+ descriptionEn: "Increase stamina and cardiovascular capacity through progressive cardio and leg work.",
324
+ taglineKey: "userGoal.boostEndurance.tagline",
325
+ taglineEn: "Go further. Last longer.",
326
+ emoji: "🏃",
327
+ category: "performance",
328
+ },
329
+ athletic_performance: {
330
+ nameKey: "userGoal.athleticPerformance.name",
331
+ nameEn: "Athletic Performance",
332
+ descriptionKey: "userGoal.athleticPerformance.description",
333
+ descriptionEn: "Train like an athlete — explosive power, speed, agility, and conditioning.",
334
+ taglineKey: "userGoal.athleticPerformance.tagline",
335
+ taglineEn: "Train hard. Perform harder.",
336
+ emoji: "⚡",
337
+ category: "performance",
338
+ },
339
+ // ── Health ────────────────────────────────────────────────────────────────
340
+ general_fitness: {
341
+ nameKey: "userGoal.generalFitness.name",
342
+ nameEn: "Stay Active & Healthy",
343
+ descriptionKey: "userGoal.generalFitness.description",
344
+ descriptionEn: "A balanced mix of strength, cardio, and mobility for a healthy, active lifestyle.",
345
+ taglineKey: "userGoal.generalFitness.tagline",
346
+ taglineEn: "Move well. Feel well. Live well.",
347
+ emoji: "🌟",
348
+ category: "health",
349
+ },
350
+ posture_and_back: {
351
+ nameKey: "userGoal.postureAndBack.name",
352
+ nameEn: "Fix Posture & Back",
353
+ descriptionKey: "userGoal.postureAndBack.description",
354
+ descriptionEn: "Strengthen the posterior chain and core to fix posture and eliminate back pain.",
355
+ taglineKey: "userGoal.postureAndBack.tagline",
356
+ taglineEn: "Stand tall. Move pain-free.",
357
+ emoji: "🧍",
358
+ category: "health",
359
+ },
360
+ stress_relief: {
361
+ nameKey: "userGoal.stressRelief.name",
362
+ nameEn: "Reduce Stress",
363
+ descriptionKey: "userGoal.stressRelief.description",
364
+ descriptionEn: "Use movement to reset your mind — cardio endorphins and mobility to decompress.",
365
+ taglineKey: "userGoal.stressRelief.tagline",
366
+ taglineEn: "Move it out. Breathe it out.",
367
+ emoji: "🧘",
368
+ category: "health",
369
+ },
370
+ rehabilitation: {
371
+ nameKey: "userGoal.rehabilitation.name",
372
+ nameEn: "Recover from Injury",
373
+ descriptionKey: "userGoal.rehabilitation.description",
374
+ descriptionEn: "Gentle, progressive sessions to rebuild strength and movement after injury.",
375
+ taglineKey: "userGoal.rehabilitation.tagline",
376
+ taglineEn: "Slow and steady. Built to last.",
377
+ emoji: "🩹",
378
+ category: "health",
379
+ },
380
+ // ── Focused ───────────────────────────────────────────────────────────────
381
+ core_strength: {
382
+ nameKey: "userGoal.coreStrength.name",
383
+ nameEn: "Build a Strong Core",
384
+ descriptionKey: "userGoal.coreStrength.description",
385
+ descriptionEn: "Develop deep core stability and strength — the foundation of every movement.",
386
+ taglineKey: "userGoal.coreStrength.tagline",
387
+ taglineEn: "Strong core. Strong everything.",
388
+ emoji: "🎯",
389
+ category: "focused",
390
+ },
391
+ mobility_flexibility: {
392
+ nameKey: "userGoal.mobilityFlexibility.name",
393
+ nameEn: "Improve Flexibility",
394
+ descriptionKey: "userGoal.mobilityFlexibility.description",
395
+ descriptionEn: "Increase range of motion and joint health through consistent mobility work.",
396
+ taglineKey: "userGoal.mobilityFlexibility.tagline",
397
+ taglineEn: "Move freely. Age well.",
398
+ emoji: "🌀",
399
+ category: "focused",
400
+ },
401
+ };
402
+ exports.GOAL_CATEGORY_DISPLAY = {
403
+ appearance: {
404
+ labelKey: "goalCategory.appearance.label",
405
+ labelEn: "Appearance",
406
+ },
407
+ performance: {
408
+ labelKey: "goalCategory.performance.label",
409
+ labelEn: "Performance",
410
+ },
411
+ health: {
412
+ labelKey: "goalCategory.health.label",
413
+ labelEn: "Health & Wellbeing",
414
+ },
415
+ focused: {
416
+ labelKey: "goalCategory.focused.label",
417
+ labelEn: "Focused Training",
418
+ },
419
+ };
420
+ // ---------------------------------------------------------------------------
421
+ // derivePhase — pure helper
422
+ // Shared between Lambda and client — lives here so neither duplicates it
423
+ // ---------------------------------------------------------------------------
424
+ /**
425
+ * Derive the current training phase from the week number since goal start.
426
+ * Week is 1-indexed (week 1 = first week on the program).
427
+ *
428
+ * @example
429
+ * derivePhase(1) // → 1 (Foundation)
430
+ * derivePhase(3) // → 2 (Momentum)
431
+ * derivePhase(7) // → 3 (Push)
432
+ * derivePhase(10) // → 4 (Peak)
433
+ */
434
+ function derivePhase(weekNumber) {
435
+ if (weekNumber <= 2)
436
+ return 1;
437
+ if (weekNumber <= 5)
438
+ return 2;
439
+ if (weekNumber <= 8)
440
+ return 3;
441
+ return 4;
442
+ }
443
+ exports.DAYS_PER_WEEK_OPTIONS = [2, 3, 4, 5];
@@ -1,3 +1,4 @@
1
1
  export * from "./BodyCategories";
2
2
  export * from "./AiExerciseVocabulary";
3
3
  export * from "./quickStartIntents";
4
+ export * from "./goalJourney";
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./BodyCategories"), exports);
18
18
  __exportStar(require("./AiExerciseVocabulary"), exports);
19
19
  __exportStar(require("./quickStartIntents"), exports);
20
+ __exportStar(require("./goalJourney"), exports);
@@ -1,4 +1,5 @@
1
1
  import type { TAiFitnessGoal, TAiUserInjury } from "../constants/AiExerciseVocabulary";
2
+ import { TConstellationUserLevel } from "../utils";
2
3
  import { TGdprData } from "./commonTypes";
3
4
  import { TUserPreferences } from "./TUserPreferences";
4
5
  export type TAuthType = "email" | "apple" | "anonymous" | "token";
@@ -37,11 +38,12 @@ export type TUserMetric = TUserPreferences & {
37
38
  subscriptionStore: TAppStore;
38
39
  subscriptionLastUpdatedAt: number;
39
40
  gdpr: TGdprData;
41
+ constellationLevel: TConstellationUserLevel;
40
42
  createdAt: Date;
41
43
  updatedAt?: Date;
42
44
  };
43
- export type TApiUserUpdateReq = Omit<TUserMetric, "userId" | "subscriptionStatus" | "subscriptionType" | "subscriptionTier" | "subscriptionExpiresAt" | "subscriptionStartedAt" | "subscriptionWillRenew" | "subscriptionStore" | "subscriptionLastUpdatedAt" | "createdAt" | "gdpr"> & {
44
- gdpr: Pick<TGdprData, "dataSharing">;
45
+ export type TApiUserUpdateReq = Partial<Omit<TUserMetric, "userId" | "subscriptionStatus" | "subscriptionType" | "subscriptionTier" | "subscriptionExpiresAt" | "subscriptionStartedAt" | "subscriptionWillRenew" | "subscriptionStore" | "subscriptionLastUpdatedAt" | "createdAt" | "gdpr">> & {
46
+ gdpr?: Pick<TGdprData, "dataSharing">;
45
47
  };
46
48
  export type TApiUserUpdateRes = {
47
49
  status: 400 | 500;
@@ -40,7 +40,7 @@ const getAdjustedBMIThreshold = (baseThreshold, activityLevel) => {
40
40
  * Reduces volume or duration by roughly 30%.
41
41
  */
42
42
  const applyFallbackScalingToRecord = (record) => {
43
- const scaledRecord = Object.assign({}, record);
43
+ const scaledRecord = { ...record };
44
44
  const SCALE_FACTOR = 0.7;
45
45
  // Scale reps
46
46
  if (scaledRecord.type === "reps-only" || scaledRecord.type === "weight-reps") {
@@ -119,7 +119,7 @@ const scaleProPlan = (masterPlan, userMetric, exercisesDictionary) => {
119
119
  newRecords = newRecords.map((record) => {
120
120
  if (record.type === "weight-reps") {
121
121
  isModified = true;
122
- return Object.assign(Object.assign({}, record), { kg: suggestedLoadKg.toString() });
122
+ return { ...record, kg: suggestedLoadKg.toString() };
123
123
  }
124
124
  // Guard against applying load to a falsy "0" aux weight
125
125
  if (record.type === "reps-only" ||
@@ -128,7 +128,7 @@ const scaleProPlan = (masterPlan, userMetric, exercisesDictionary) => {
128
128
  const currentAux = parseFloat(record.auxWeightKg || "0");
129
129
  if (!isNaN(currentAux) && currentAux > 0) {
130
130
  isModified = true;
131
- return Object.assign(Object.assign({}, record), { auxWeightKg: suggestedLoadKg.toString() });
131
+ return { ...record, auxWeightKg: suggestedLoadKg.toString() };
132
132
  }
133
133
  }
134
134
  return record;
@@ -136,7 +136,12 @@ const scaleProPlan = (masterPlan, userMetric, exercisesDictionary) => {
136
136
  }
137
137
  }
138
138
  // Return the tailored template exercise
139
- return Object.assign(Object.assign({}, templateExercise), { exerciseId: newExerciseId, initialRecords: newRecords, isAutoScaled: isModified || undefined });
139
+ return {
140
+ ...templateExercise,
141
+ exerciseId: newExerciseId,
142
+ initialRecords: newRecords,
143
+ isAutoScaled: isModified || undefined,
144
+ };
140
145
  });
141
146
  });
142
147
  });