@dlwiest/ts-tonal-client 0.0.1 → 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.
Files changed (48) hide show
  1. package/README.md +404 -38
  2. package/dist/examples/create-workout.d.ts +1 -0
  3. package/dist/examples/debug-daily-lifts.d.ts +1 -0
  4. package/dist/examples/delete-workout.d.ts +1 -0
  5. package/dist/examples/edit-workout.d.ts +1 -0
  6. package/dist/examples/estimate-workout.d.ts +1 -0
  7. package/dist/examples/get-achievement-stats.d.ts +2 -0
  8. package/dist/examples/get-achievements.d.ts +2 -0
  9. package/dist/examples/get-activity-summaries.d.ts +2 -0
  10. package/dist/examples/get-current-streak.d.ts +1 -0
  11. package/dist/examples/get-daily-lifts.d.ts +1 -0
  12. package/dist/examples/get-daily-metrics.d.ts +1 -0
  13. package/dist/examples/get-goal-metrics.d.ts +1 -0
  14. package/dist/examples/get-goals.d.ts +1 -0
  15. package/dist/examples/get-home-calendar.d.ts +2 -0
  16. package/dist/examples/get-metric-scores.d.ts +1 -0
  17. package/dist/examples/get-movements.d.ts +1 -0
  18. package/dist/examples/get-muscle-readiness.d.ts +1 -0
  19. package/dist/examples/get-program-by-id.d.ts +1 -0
  20. package/dist/examples/get-target-scores.d.ts +1 -0
  21. package/dist/examples/get-training-effect-goals.d.ts +1 -0
  22. package/dist/examples/get-training-types.d.ts +1 -0
  23. package/dist/examples/get-user-info.d.ts +1 -0
  24. package/dist/examples/get-user-settings.d.ts +1 -0
  25. package/dist/examples/get-user-statistics.d.ts +2 -0
  26. package/dist/examples/get-user-workouts.d.ts +1 -0
  27. package/dist/examples/get-workout-by-id.d.ts +1 -0
  28. package/dist/examples/get-workout-by-share-url.d.ts +1 -0
  29. package/dist/examples/raw-daily-lifts-test.d.ts +1 -0
  30. package/dist/index.d.ts +573 -29
  31. package/dist/index.esm.js +447 -119
  32. package/dist/index.js +451 -119
  33. package/dist/src/auth/auth-manager.d.ts +12 -0
  34. package/dist/src/client.d.ts +39 -0
  35. package/dist/src/http/http-client.d.ts +12 -0
  36. package/dist/src/index.d.ts +4 -0
  37. package/dist/src/services/movement-service.d.ts +7 -0
  38. package/dist/src/services/user-service.d.ts +51 -0
  39. package/dist/src/services/workout-service.d.ts +14 -0
  40. package/dist/src/types/auth.d.ts +18 -0
  41. package/dist/src/types/common.d.ts +1 -0
  42. package/dist/src/types/index.d.ts +6 -0
  43. package/dist/src/types/movements.d.ts +30 -0
  44. package/dist/src/types/programs.d.ts +46 -0
  45. package/dist/src/types/users.d.ts +418 -0
  46. package/dist/src/types/workouts.d.ts +120 -0
  47. package/dist/src/types.d.ts +125 -0
  48. package/package.json +43 -4
package/README.md CHANGED
@@ -1,17 +1,23 @@
1
- # Tonal Client
2
-
3
- This repository contains a TypeScript client for accessing Tonal data. It is designed to interact with Tonal's systems to retrieve various types of workout-related data.
1
+ # TypeScript Tonal Client
4
2
 
3
+ A comprehensive TypeScript client for accessing Tonal's API. This library provides a robust interface to retrieve workout data, user information, movements, and more from your Tonal account.
5
4
 
6
5
  ## Features
7
6
 
8
- - Retrieve detailed workout data by ID.
9
- - Access shared workouts through share URLs.
10
- - Fetch movements and other related workout data.
7
+ - 🏋️ **Complete Workout Management** - Get, create, estimate, and share workouts including daily lifts
8
+ - 👤 **User Management** - Access user info, goals, and preferences
9
+ - 💪 **Movement Database** - Browse all available Tonal movements
10
+ - 🎯 **Muscle Readiness Tracking** - Monitor recovery status for all muscle groups
11
+ - 📋 **Program Details** - Get comprehensive information about training programs
12
+ - 🎯 **Target Score Tracking** - Get weekly fitness targets and progress ranges for all metrics
13
+ - 📈 **Metric Score Analysis** - Track actual performance vs targets with comprehensive analytics
14
+ - 🛡️ **Enterprise-Grade Reliability** - Built-in error handling, retries, and timeouts
15
+ - 📝 **Full TypeScript Support** - Comprehensive types for all API responses
16
+ - 🔄 **Smart Token Management** - Automatic authentication and token refresh
11
17
 
12
18
  ## Installation
13
19
 
14
- To use this client, clone the repository and install the necessary dependencies:
20
+ Clone the repository and install dependencies:
15
21
 
16
22
  ```bash
17
23
  git clone https://github.com/dlwiest/ts-tonal-client.git
@@ -19,58 +25,418 @@ cd ts-tonal-client
19
25
  npm install
20
26
  ```
21
27
 
22
- In order to test with the example scripts in `/src/examples` you will need to create a `.env` file based on the formatting described in `.env.sample`.
23
- Note that your Tonal username is most likely an email address.
28
+ ## Quick Start
24
29
 
25
- ## Usage
30
+ Basic usage:
26
31
 
27
- The client can be used in scripts or applications that require data from Tonal. Here are some examples of how to use the client:
32
+ ```typescript
33
+ import TonalClient from './src/index'
28
34
 
29
- ### Get Movements
35
+ const client = await TonalClient.create({
36
+ username: 'your_email@example.com',
37
+ password: 'your_password',
38
+ })
30
39
 
31
- ```typescript
32
- // Example: Fetching movements
33
- import { TonalClient } from './src/client';
40
+ // Get your workouts
41
+ const workouts = await client.getUserWorkouts()
42
+ console.log(`You have ${workouts.length} workouts`)
43
+ ```
34
44
 
35
- async function fetchMovements() {
36
- const client = await TonalClient.create({ username: 'your_username', password: 'your_password' });
37
- const movements = await client.getMovements();
38
- console.log(movements);
39
- }
45
+ ## Examples
46
+
47
+ To run the example scripts, first create a `.env` file:
48
+
49
+ ```bash
50
+ cp .env.sample .env
51
+ # Edit .env with your Tonal username (email) and password
52
+ ```
53
+
54
+ Then try the examples:
55
+
56
+ ```bash
57
+ # See all your workouts
58
+ npm run example:user-workouts
59
+
60
+ # Get your user info
61
+ npm run example:user
62
+
63
+ # Browse available movements
64
+ npm run example:movements
65
+
66
+ # See fitness goals
67
+ npm run example:goals
68
+
69
+ # Estimate workout duration
70
+ npm run example:estimate
71
+
72
+ # Create a new workout
73
+ npm run example:create-workout
74
+
75
+ # Edit an existing workout
76
+ npm run example:edit-workout
77
+
78
+ # Delete a workout
79
+ npm run example:delete-workout
40
80
 
41
- fetchMovements();
81
+ # Get daily lifts
82
+ npm run example:daily-lifts
83
+
84
+ # Get training effect goals
85
+ npm run example:training-effect-goals
86
+
87
+ # Get training types
88
+ npm run example:training-types
89
+
90
+ # Get user settings
91
+ npm run example:user-settings
92
+
93
+ # Get daily metrics
94
+ npm run example:daily-metrics
95
+
96
+ # Get current workout streak
97
+ npm run example:current-streak
98
+
99
+ # Get workout activity history
100
+ npm run example:activity-summaries
101
+
102
+ # Get lifetime user statistics
103
+ npm run example:user-statistics
104
+
105
+ # Get achievement stats and milestones
106
+ npm run example:achievement-stats
107
+
108
+ # Get earned achievement history
109
+ npm run example:achievements
110
+
111
+ # Get home calendar and workout recommendations
112
+ npm run example:home-calendar
113
+
114
+ # Get muscle readiness and recovery status
115
+ npm run example:muscle-readiness
116
+
117
+ # Get detailed program information by ID
118
+ npm run example:program-by-id
119
+
120
+ # Get weekly fitness targets and progress tracking
121
+ npm run example:target-scores
122
+
123
+ # Get actual performance scores vs targets with comprehensive analytics
124
+ npm run example:metric-scores
42
125
  ```
43
126
 
44
- ### Get Workout by ID
127
+ ## API Reference
128
+
129
+ ### Workouts
45
130
 
46
131
  ```typescript
47
- // Example: Fetching a workout by ID
48
- import { TonalClient } from './src/client';
132
+ // Get your workouts (with pagination)
133
+ const workouts = await client.getUserWorkouts(0, 10)
134
+ console.log(`You have ${workouts.length} workouts`)
49
135
 
50
- async function fetchWorkoutById(workoutId: string) {
51
- const client = await TonalClient.create({ username: 'your_username', password: 'your_password' });
52
- const workout = await client.getWorkoutById(workoutId);
53
- console.log(workout);
54
- }
136
+ // Get daily lifts (auto-detects timezone)
137
+ const dailyLifts = await client.getDailyLifts()
138
+ console.log(`You have ${dailyLifts.length} daily lifts`)
139
+
140
+ // Get daily lifts with specific timezone
141
+ const dailyLiftsEST = await client.getDailyLifts('America/New_York')
142
+
143
+ // Get specific workout details
144
+ const workout = await client.getWorkoutById('workout-uuid')
145
+
146
+ // Get shared workout
147
+ const sharedWorkout = await client.getWorkoutByShareUrl('https://share.tonal.com/workout/...')
55
148
 
56
- fetchWorkoutById('workout_id_here');
149
+ // Estimate workout duration
150
+ const sets = [/* workout sets */]
151
+ const estimate = await client.estimateWorkoutDuration(sets)
152
+ console.log(`Estimated duration: ${estimate.duration} seconds`)
153
+
154
+ // Create a new workout
155
+ const newWorkout = await client.createWorkout({
156
+ title: 'My Custom Workout',
157
+ sets: sets,
158
+ createdSource: 'WorkoutBuilder',
159
+ description: 'A great workout!'
160
+ })
161
+
162
+ // Edit an existing workout
163
+ const updatedWorkout = await client.updateWorkout({
164
+ id: 'workout-uuid',
165
+ title: 'My Updated Workout Title',
166
+ description: 'Updated description with changes',
167
+ coachId: '00000000-0000-0000-0000-000000000000',
168
+ sets: modifiedSets,
169
+ assetId: 'asset-uuid',
170
+ createdSource: 'WorkoutBuilder'
171
+ })
172
+
173
+ // Delete a workout
174
+ await client.deleteWorkout('workout-uuid')
57
175
  ```
58
176
 
59
- ### Get Workout by Share URL
177
+ ### User Information
60
178
 
61
179
  ```typescript
62
- // Example: Fetching a workout by its share URL
63
- import { TonalClient } from './src/client';
180
+ // Get your profile information
181
+ const userInfo = await client.getUserInfo()
182
+ console.log(`Welcome ${userInfo.firstName}!`)
183
+ console.log(`Level: ${userInfo.level}`)
184
+ console.log(`Location: ${userInfo.location}`)
185
+
186
+ // Get available fitness goals
187
+ const goals = await client.getGoals()
188
+ goals.forEach(goal => {
189
+ console.log(`${goal.name}: ${goal.description}`)
190
+ })
191
+
192
+ // Get training effect goals with relationships
193
+ const trainingGoals = await client.getTrainingEffectGoals()
194
+ console.log(`${trainingGoals.goals.length} training goals available`)
195
+ trainingGoals.relations.forEach(relation => {
196
+ console.log(`Primary goal relationships found`)
197
+ })
198
+
199
+ // Get all training types
200
+ const trainingTypes = await client.getTrainingTypes()
201
+ console.log(`${trainingTypes.length} training types available`)
202
+ trainingTypes.forEach(type => {
203
+ console.log(`${type.name}: ${type.description}`)
204
+ })
205
+
206
+ // Get goal metrics
207
+ const goalMetrics = await client.getGoalMetrics()
208
+ console.log(`${goalMetrics.length} goal metrics available`)
209
+ goalMetrics.forEach(metric => {
210
+ console.log(`${metric.name}: ${metric.description}`)
211
+ })
212
+
213
+ // Get comprehensive user settings
214
+ const userSettings = await client.getUserSettings()
215
+ console.log(`Audio settings: ${userSettings.overallVolume * 100}% volume`)
216
+ console.log(`Preferred music service: ${userSettings.preferredMusicService}`)
217
+ console.log(`Time zone: ${userSettings.timeZone}`)
218
+ console.log(`Total settings tracked: ${Object.keys(userSettings).length}`)
219
+
220
+ // Get daily fitness metrics (analyzes 60 days, shows recent 10 workouts)
221
+ const dailyMetrics = await client.getDailyMetrics(60)
222
+ const activeDays = dailyMetrics.filter(day => day.totalWorkouts > 0)
223
+ console.log(`Workout frequency over 60 days: ${(activeDays.length / dailyMetrics.length * 100).toFixed(1)}%`)
224
+ console.log(`Total volume (all workouts): ${activeDays.reduce((sum, day) => sum + day.totalVolume, 0).toLocaleString()} lbs`)
225
+ console.log(`Average workout duration: ${Math.round(activeDays.reduce((sum, day) => sum + day.totalDuration, 0) / activeDays.length / 60)} minutes`)
226
+
227
+ // Get current workout streak
228
+ const streak = await client.getCurrentStreak()
229
+ console.log(`Current streak: ${streak.currentStreak} workouts`)
230
+ console.log(`Personal best: ${streak.maxStreak} workouts`)
231
+ console.log(`Progress to personal best: ${Math.round((streak.currentStreak / streak.maxStreak) * 100)}%`)
64
232
 
65
- async function fetchWorkoutByShareUrl(shareUrl: string) {
66
- const client = await TonalClient.create({ username: 'your_username', password: 'your_password' });
67
- const workout = await client.getWorkoutByShareUrl(shareUrl);
68
- console.log(workout);
233
+ // Get comprehensive workout activity history
234
+ const activities = await client.getActivitySummaries()
235
+ console.log(`Total workouts completed: ${activities.length}`)
236
+ const totalVolume = activities.reduce((sum, activity) => sum + activity.totalVolume, 0)
237
+ console.log(`Total volume lifted: ${totalVolume.toLocaleString()} lbs`)
238
+ const guidedWorkouts = activities.filter(a => a.isGuidedWorkout).length
239
+ console.log(`Guided vs Free Lift: ${guidedWorkouts}/${activities.length - guidedWorkouts}`)
240
+
241
+ // Get lifetime statistics and achievements
242
+ const stats = await client.getUserStatistics()
243
+ console.log(`Total volume: ${stats.volume.total.toLocaleString()} lbs over ${stats.workouts.total} workouts`)
244
+ console.log(`Average per workout: ${stats.volume.avgVolumePerWorkout.toLocaleString()} lbs`)
245
+ console.log(`Total workout time: ${Math.round(stats.workouts.totalDuration / 3600)} hours`)
246
+ console.log(`Movement diversity: ${stats.movements.total} unique movements performed`)
247
+
248
+ // Get achievement progress and upcoming milestones
249
+ const achievementStats = await client.getAchievementStats()
250
+ console.log(`Achievements earned: ${achievementStats.totalAchievements}`)
251
+ console.log(`Upcoming milestones: ${achievementStats.nextMilestones.length}`)
252
+ achievementStats.nextMilestones.forEach(milestone => {
253
+ console.log(`Next goal: ${milestone.name} (${milestone.value.toLocaleString()})`)
254
+ })
255
+
256
+ // Get complete earned achievement history
257
+ const earnedAchievements = await client.getAchievements()
258
+ console.log(`Total achievements earned: ${earnedAchievements.length}`)
259
+ const recentAchievement = earnedAchievements[0]
260
+ console.log(`Most recent: ${recentAchievement.name} (${new Date(recentAchievement.createdAt).toLocaleDateString()})`)
261
+ const categories = [...new Set(earnedAchievements.map(a => a.achievement.achievementCategory.name))]
262
+ console.log(`Achievement categories: ${categories.join(', ')}`)
263
+
264
+ // Get home calendar with workout history and recommendations
265
+ const homeCalendar = await client.getHomeCalendar()
266
+ const completedWorkouts = homeCalendar.dailySchedules.filter(day =>
267
+ day.tiles.some(tile => tile.completed)
268
+ ).length
269
+ const recommendationCategories = [...new Set(
270
+ homeCalendar.dailySchedules.map(day => day.recommendationType).filter(Boolean)
271
+ )]
272
+ console.log(`Completed workout days: ${completedWorkouts}`)
273
+ console.log(`Recommendation categories: ${recommendationCategories.join(', ')}`)
274
+
275
+ // Get muscle readiness for all muscle groups
276
+ const readiness = await client.getMuscleReadiness()
277
+ console.log(`Muscle Readiness Status:`)
278
+ console.log(` Chest: ${readiness.Chest}%`)
279
+ console.log(` Shoulders: ${readiness.Shoulders}%`)
280
+ console.log(` Back: ${readiness.Back}%`)
281
+ console.log(` Triceps: ${readiness.Triceps}%`)
282
+ console.log(` Biceps: ${readiness.Biceps}%`)
283
+ console.log(` Abs: ${readiness.Abs}%`)
284
+ console.log(` Obliques: ${readiness.Obliques}%`)
285
+ console.log(` Quads: ${readiness.Quads}%`)
286
+ console.log(` Glutes: ${readiness.Glutes}%`)
287
+ console.log(` Hamstrings: ${readiness.Hamstrings}%`)
288
+ console.log(` Calves: ${readiness.Calves}%`)
289
+
290
+ // Calculate average readiness
291
+ const allMuscles = Object.values(readiness)
292
+ const averageReadiness = Math.round(allMuscles.reduce((sum, val) => sum + val, 0) / allMuscles.length)
293
+ console.log(`Average readiness: ${averageReadiness}%`)
294
+
295
+ // Find muscles that need recovery (< 60%)
296
+ const needsRecovery = Object.entries(readiness)
297
+ .filter(([_, percentage]) => percentage < 60)
298
+ .map(([muscle]) => muscle)
299
+ if (needsRecovery.length > 0) {
300
+ console.log(`Muscles needing recovery: ${needsRecovery.join(', ')}`)
69
301
  }
70
302
 
71
- fetchWorkoutByShareUrl('https://link.tonal.com/custom-workout/your_workout_id');
303
+ // Get detailed program information
304
+ const programId = 'f243be64-76f2-4073-8ce7-8adb37657e9f' // Example: House of Volume
305
+ const program = await client.getProgramById(programId)
306
+ console.log(`Program: ${program.name}`)
307
+ console.log(`Level: ${program.level}`)
308
+ console.log(`Duration: ${program.weeks} weeks`)
309
+ console.log(`Workouts per week: ${program.workoutsPerWeek}`)
310
+ console.log(`Total workouts: ${program.workouts.length}`)
311
+ console.log(`Description: ${program.description}`)
312
+
313
+ // Analyze program structure
314
+ const targetAreas = program.workouts.map(w => w.targetArea)
315
+ const targetAreaCounts = targetAreas.reduce((acc, area) => {
316
+ acc[area] = (acc[area] || 0) + 1
317
+ return acc
318
+ }, {} as Record<string, number>)
319
+ console.log(`Target area distribution:`, targetAreaCounts)
320
+
321
+ // Show weekly schedule
322
+ const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
323
+ const schedule = program.cadence.map((isWorkout, i) =>
324
+ isWorkout ? `${days[i]}: Workout` : `${days[i]}: Rest`
325
+ )
326
+ console.log(`Weekly schedule: ${schedule.join(', ')}`)
327
+
328
+ // Get weekly fitness targets for all metrics
329
+ const targetScores = await client.getTargetScores()
330
+ console.log('Weekly Fitness Targets:')
331
+
332
+ Object.entries(targetScores).forEach(([metricId, weeklyTargets]) => {
333
+ // Get the most recent week target
334
+ const currentTarget = weeklyTargets.sort((a, b) => b.weekNumber - a.weekNumber)[0]
335
+ const year = Math.floor(currentTarget.weekNumber / 100)
336
+ const week = currentTarget.weekNumber % 100
337
+
338
+ console.log(`Metric ${metricId}:`)
339
+ console.log(` Target: ${currentTarget.target}`)
340
+ console.log(` Range: ${currentTarget.lowRange} - ${currentTarget.highRange}`)
341
+ console.log(` Week: ${week}/${year}`)
342
+ })
343
+
344
+ // Analyze target trends
345
+ const volumeTargets = targetScores['2a2f499e-ae13-45d1-b501-aa1d25ff6a4a'] // Volume metric
346
+ if (volumeTargets && volumeTargets.length >= 2) {
347
+ const sorted = volumeTargets.sort((a, b) => a.weekNumber - b.weekNumber)
348
+ const firstTarget = sorted[0].target
349
+ const lastTarget = sorted[sorted.length - 1].target
350
+ const change = Math.round(((lastTarget - firstTarget) / firstTarget) * 100)
351
+ console.log(`Volume trend: ${change > 0 ? '+' : ''}${change}% over ${sorted.length} weeks`)
352
+ }
353
+
354
+ // Get actual performance scores vs targets with comprehensive analytics
355
+ const metricScores = await client.getMetricScores()
356
+ // Optional: get scores starting from a specific week
357
+ // const metricScores = await client.getMetricScores(202440) // Start from week 40 of 2024
358
+
359
+ console.log('Performance vs Targets Analysis:')
360
+
361
+ Object.entries(metricScores).forEach(([metricId, weeklyScores]) => {
362
+ // Get the most recent week score
363
+ const currentScore = weeklyScores.sort((a, b) => b.weekNumber - a.weekNumber)[0]
364
+ const year = Math.floor(currentScore.weekNumber / 100)
365
+ const week = currentScore.weekNumber % 100
366
+
367
+ console.log(`Metric ${metricId}:`)
368
+ console.log(` Actual Score: ${currentScore.score}`)
369
+ console.log(` Week: ${week}/${year}`)
370
+ })
371
+
372
+ // Compare against targets to see goal achievement
373
+ const volumeScores = metricScores['2a2f499e-ae13-45d1-b501-aa1d25ff6a4a'] // Volume metric
374
+ const volumeTargets = targetScores['2a2f499e-ae13-45d1-b501-aa1d25ff6a4a']
375
+ if (volumeScores && volumeTargets) {
376
+ const latestScore = volumeScores.sort((a, b) => b.weekNumber - a.weekNumber)[0]
377
+ const matchingTarget = volumeTargets.find(t => t.weekNumber === latestScore.weekNumber)
378
+
379
+ if (matchingTarget) {
380
+ const achievementPercent = Math.round((latestScore.score / matchingTarget.target) * 100)
381
+ const inRange = latestScore.score >= matchingTarget.lowRange && latestScore.score <= matchingTarget.highRange
382
+ console.log(`Volume Achievement: ${achievementPercent}% of target (${inRange ? 'In Range' : 'Out of Range'})`)
383
+ }
384
+ }
385
+
386
+ // Calculate performance trends
387
+ if (volumeScores && volumeScores.length >= 2) {
388
+ const sorted = volumeScores.sort((a, b) => a.weekNumber - b.weekNumber)
389
+ const firstScore = sorted[0].score
390
+ const lastScore = sorted[sorted.length - 1].score
391
+ const change = Math.round(((lastScore - firstScore) / firstScore) * 100)
392
+ console.log(`Volume performance trend: ${change > 0 ? '+' : ''}${change}% over ${sorted.length} weeks`)
393
+ }
72
394
  ```
73
395
 
396
+ ### Movements
397
+
398
+ ```typescript
399
+ // Get all available movements
400
+ const movements = await client.getMovements()
401
+ console.log(`${movements.length} movements available`)
402
+
403
+ // Filter by muscle group
404
+ const chestMovements = movements.filter(m =>
405
+ m.muscleGroups.includes('Chest')
406
+ )
407
+ ```
408
+
409
+ ## Available Scripts
410
+
411
+ - `npm run build` - Build the TypeScript client
412
+ - `npm run typecheck` - Run TypeScript type checking
413
+ - `npm run example:movements` - List all movements
414
+ - `npm run example:user` - Show user information
415
+ - `npm run example:goals` - Show available goals
416
+ - `npm run example:user-workouts` - List your workouts
417
+ - `npm run example:workout:id <id>` - Get specific workout
418
+ - `npm run example:workout:share <url>` - Get shared workout
419
+ - `npm run example:estimate` - Estimate workout duration
420
+ - `npm run example:create-workout` - Create a new workout
421
+ - `npm run example:edit-workout` - Create and edit a workout
422
+ - `npm run example:delete-workout` - Create and delete a workout
423
+ - `npm run example:daily-lifts` - Get daily lifts with auto-detected timezone
424
+ - `npm run example:training-effect-goals` - Get training effect goals and relationships
425
+ - `npm run example:training-types` - Get all available training types
426
+ - `npm run example:goal-metrics` - Get goal metrics and relationships
427
+ - `npm run example:user-settings` - Get comprehensive user settings and preferences
428
+ - `npm run example:daily-metrics` - Get daily fitness metrics with workout analytics
429
+ - `npm run example:current-streak` - Get current workout streak and personal best
430
+ - `npm run example:activity-summaries` - Get comprehensive workout activity history and analytics
431
+ - `npm run example:user-statistics` - Get lifetime user statistics and achievement milestones
432
+ - `npm run example:achievement-stats` - Get achievement progress and upcoming milestone targets
433
+ - `npm run example:achievements` - Get complete earned achievement history with timeline analytics
434
+ - `npm run example:home-calendar` - Get home calendar with workout history and personalized recommendations
435
+ - `npm run example:muscle-readiness` - Get muscle readiness percentages and recovery recommendations
436
+ - `npm run example:program-by-id` - Get comprehensive program details including all workouts and structure
437
+ - `npm run example:target-scores` - Get weekly fitness targets with ranges and trend analysis for all metrics
438
+ - `npm run example:metric-scores` - Get actual performance scores vs targets with comprehensive goal achievement analytics
439
+
74
440
  ## Contributing
75
441
 
76
442
  Contributions to this project are welcome, especially in the areas of error handling, expanding functionality, and improving the robustness of the client.
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env tsx
2
+ import 'dotenv/config';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env tsx
2
+ import 'dotenv/config';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env tsx
2
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env tsx
2
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env tsx
2
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';
@@ -0,0 +1 @@
1
+ import 'dotenv/config';