whoop-cli 1.2.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 (52) hide show
  1. package/.env.example +4 -0
  2. package/LICENSE +21 -0
  3. package/README.md +182 -0
  4. package/dist/api/client.d.ts +19 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +99 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/api/endpoints.d.ts +10 -0
  9. package/dist/api/endpoints.d.ts.map +1 -0
  10. package/dist/api/endpoints.js +10 -0
  11. package/dist/api/endpoints.js.map +1 -0
  12. package/dist/auth/oauth.d.ts +9 -0
  13. package/dist/auth/oauth.d.ts.map +1 -0
  14. package/dist/auth/oauth.js +122 -0
  15. package/dist/auth/oauth.js.map +1 -0
  16. package/dist/auth/server.d.ts +7 -0
  17. package/dist/auth/server.d.ts.map +1 -0
  18. package/dist/auth/server.js +53 -0
  19. package/dist/auth/server.js.map +1 -0
  20. package/dist/auth/tokens.d.ts +12 -0
  21. package/dist/auth/tokens.d.ts.map +1 -0
  22. package/dist/auth/tokens.js +102 -0
  23. package/dist/auth/tokens.js.map +1 -0
  24. package/dist/cli.d.ts +3 -0
  25. package/dist/cli.d.ts.map +1 -0
  26. package/dist/cli.js +251 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +6 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/types/whoop.d.ts +159 -0
  33. package/dist/types/whoop.d.ts.map +1 -0
  34. package/dist/types/whoop.js +2 -0
  35. package/dist/types/whoop.js.map +1 -0
  36. package/dist/utils/analysis.d.ts +30 -0
  37. package/dist/utils/analysis.d.ts.map +1 -0
  38. package/dist/utils/analysis.js +231 -0
  39. package/dist/utils/analysis.js.map +1 -0
  40. package/dist/utils/date.d.ts +10 -0
  41. package/dist/utils/date.d.ts.map +1 -0
  42. package/dist/utils/date.js +38 -0
  43. package/dist/utils/date.js.map +1 -0
  44. package/dist/utils/errors.d.ts +14 -0
  45. package/dist/utils/errors.d.ts.map +1 -0
  46. package/dist/utils/errors.js +36 -0
  47. package/dist/utils/errors.js.map +1 -0
  48. package/dist/utils/format.d.ts +14 -0
  49. package/dist/utils/format.d.ts.map +1 -0
  50. package/dist/utils/format.js +241 -0
  51. package/dist/utils/format.js.map +1 -0
  52. package/package.json +58 -0
@@ -0,0 +1,102 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { WhoopError, ExitCode } from '../utils/errors.js';
5
+ const CONFIG_DIR = join(homedir(), '.whoop-cli');
6
+ const TOKEN_FILE = join(CONFIG_DIR, 'tokens.json');
7
+ // Refresh tokens 15 minutes before expiry to avoid race conditions
8
+ const REFRESH_BUFFER_SECONDS = 900;
9
+ function ensureConfigDir() {
10
+ if (!existsSync(CONFIG_DIR)) {
11
+ mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
12
+ }
13
+ }
14
+ export function saveTokens(response) {
15
+ ensureConfigDir();
16
+ const data = {
17
+ access_token: response.access_token,
18
+ refresh_token: response.refresh_token,
19
+ expires_at: Math.floor(Date.now() / 1000) + response.expires_in,
20
+ token_type: response.token_type,
21
+ scope: response.scope,
22
+ };
23
+ writeFileSync(TOKEN_FILE, JSON.stringify(data, null, 2));
24
+ chmodSync(TOKEN_FILE, 0o600);
25
+ }
26
+ export function loadTokens() {
27
+ if (!existsSync(TOKEN_FILE)) {
28
+ return null;
29
+ }
30
+ try {
31
+ const content = readFileSync(TOKEN_FILE, 'utf-8');
32
+ return JSON.parse(content);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ export function clearTokens() {
39
+ if (existsSync(TOKEN_FILE)) {
40
+ writeFileSync(TOKEN_FILE, '');
41
+ }
42
+ }
43
+ export function isTokenExpired(tokens) {
44
+ const now = Math.floor(Date.now() / 1000);
45
+ return now >= tokens.expires_at - REFRESH_BUFFER_SECONDS;
46
+ }
47
+ export async function refreshAccessToken(tokens) {
48
+ const clientId = process.env.WHOOP_CLIENT_ID;
49
+ const clientSecret = process.env.WHOOP_CLIENT_SECRET;
50
+ if (!clientId || !clientSecret) {
51
+ throw new WhoopError('Missing WHOOP_CLIENT_ID or WHOOP_CLIENT_SECRET', ExitCode.AUTH_ERROR);
52
+ }
53
+ const response = await fetch('https://api.prod.whoop.com/oauth/oauth2/token', {
54
+ method: 'POST',
55
+ headers: {
56
+ 'Content-Type': 'application/x-www-form-urlencoded',
57
+ },
58
+ body: new URLSearchParams({
59
+ grant_type: 'refresh_token',
60
+ refresh_token: tokens.refresh_token,
61
+ client_id: clientId,
62
+ client_secret: clientSecret,
63
+ scope: 'offline',
64
+ }),
65
+ });
66
+ if (!response.ok) {
67
+ const errorBody = await response.text();
68
+ let errorMsg = `Token refresh failed (${response.status})`;
69
+ try {
70
+ const errorJson = JSON.parse(errorBody);
71
+ errorMsg = errorJson.error_description || errorJson.error || errorMsg;
72
+ }
73
+ catch {
74
+ // Use default error message
75
+ }
76
+ throw new WhoopError(errorMsg, ExitCode.AUTH_ERROR, response.status);
77
+ }
78
+ const data = (await response.json());
79
+ saveTokens(data);
80
+ return loadTokens();
81
+ }
82
+ export async function getValidTokens() {
83
+ let tokens = loadTokens();
84
+ if (!tokens) {
85
+ throw new WhoopError('Not authenticated. Run: whoop-cli auth login', ExitCode.AUTH_ERROR);
86
+ }
87
+ if (isTokenExpired(tokens)) {
88
+ tokens = await refreshAccessToken(tokens);
89
+ }
90
+ return tokens;
91
+ }
92
+ export function getTokenStatus() {
93
+ const tokens = loadTokens();
94
+ if (!tokens) {
95
+ return { authenticated: false };
96
+ }
97
+ return {
98
+ authenticated: true,
99
+ expires_at: tokens.expires_at,
100
+ };
101
+ }
102
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const program: Command;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,eAAO,MAAM,OAAO,SAAgB,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,251 @@
1
+ import { Command } from 'commander';
2
+ import { login, logout, status as authStatus, refresh as authRefresh } from './auth/oauth.js';
3
+ import { fetchData } from './api/client.js';
4
+ import { getWhoopDay, validateISODate, getDaysAgo } from './utils/date.js';
5
+ import { handleError, WhoopError, ExitCode } from './utils/errors.js';
6
+ import { formatPretty, formatSummary, formatSummaryColor, formatDashboard } from './utils/format.js';
7
+ import { analyzeTrends, generateInsights, formatTrends, formatInsights } from './utils/analysis.js';
8
+ export const program = new Command();
9
+ function output(data, pretty) {
10
+ console.log(pretty ? formatPretty(data) : JSON.stringify(data, null, 2));
11
+ }
12
+ program
13
+ .name('whoop-cli')
14
+ .description('CLI for fetching WHOOP health data')
15
+ .version('1.1.0');
16
+ program
17
+ .command('auth')
18
+ .description('Manage authentication')
19
+ .argument('<action>', 'login, logout, status, or refresh')
20
+ .action(async (action) => {
21
+ try {
22
+ switch (action) {
23
+ case 'login':
24
+ await login();
25
+ break;
26
+ case 'logout':
27
+ logout();
28
+ break;
29
+ case 'status':
30
+ authStatus();
31
+ break;
32
+ case 'refresh':
33
+ await authRefresh();
34
+ break;
35
+ default:
36
+ throw new WhoopError(`Unknown auth action: ${action}. Use: login, logout, status, or refresh`, ExitCode.GENERAL_ERROR);
37
+ }
38
+ }
39
+ catch (error) {
40
+ handleError(error);
41
+ }
42
+ });
43
+ function addDataCommand(name, description, dataType) {
44
+ program
45
+ .command(name)
46
+ .description(description)
47
+ .option('-d, --date <date>', 'Date in ISO format (YYYY-MM-DD)')
48
+ .option('-s, --start <date>', 'Start date for range query')
49
+ .option('-e, --end <date>', 'End date for range query')
50
+ .option('-l, --limit <number>', 'Max results per page', '25')
51
+ .option('-a, --all', 'Fetch all pages')
52
+ .option('-p, --pretty', 'Human-readable output')
53
+ .action(async (options) => {
54
+ try {
55
+ let dateOrRange;
56
+ if (options.start || options.end) {
57
+ if (options.start && !validateISODate(options.start)) {
58
+ throw new WhoopError('Invalid start date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
59
+ }
60
+ if (options.end && !validateISODate(options.end)) {
61
+ throw new WhoopError('Invalid end date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
62
+ }
63
+ const start = options.start || getWhoopDay();
64
+ const end = options.end || getWhoopDay();
65
+ dateOrRange = { start: start + 'T04:00:00.000Z', end: end + 'T04:00:00.000Z' };
66
+ }
67
+ else {
68
+ const date = options.date || getWhoopDay();
69
+ if (options.date && !validateISODate(options.date)) {
70
+ throw new WhoopError('Invalid date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
71
+ }
72
+ dateOrRange = date;
73
+ }
74
+ const result = await fetchData([dataType], dateOrRange, {
75
+ limit: parseInt(options.limit, 10),
76
+ all: options.all,
77
+ });
78
+ output(result, options.pretty);
79
+ }
80
+ catch (error) {
81
+ handleError(error);
82
+ }
83
+ });
84
+ }
85
+ addDataCommand('sleep', 'Get sleep data', 'sleep');
86
+ addDataCommand('recovery', 'Get recovery data', 'recovery');
87
+ addDataCommand('workout', 'Get workout data', 'workout');
88
+ addDataCommand('cycle', 'Get cycle data', 'cycle');
89
+ addDataCommand('profile', 'Get profile data', 'profile');
90
+ addDataCommand('body', 'Get body measurements', 'body');
91
+ program
92
+ .command('summary')
93
+ .description('One-liner health snapshot')
94
+ .option('-d, --date <date>', 'Date in ISO format (YYYY-MM-DD)')
95
+ .option('-c, --color', 'Color-coded output with status indicators')
96
+ .action(async (options) => {
97
+ try {
98
+ const date = options.date || getWhoopDay();
99
+ if (options.date && !validateISODate(options.date)) {
100
+ throw new WhoopError('Invalid date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
101
+ }
102
+ const result = await fetchData(['recovery', 'sleep', 'cycle', 'workout'], date, { limit: 25 });
103
+ console.log(options.color ? formatSummaryColor(result) : formatSummary(result));
104
+ }
105
+ catch (error) {
106
+ handleError(error);
107
+ }
108
+ });
109
+ program
110
+ .command('dashboard')
111
+ .description('Full health dashboard with trends')
112
+ .option('-d, --date <date>', 'Date in ISO format (YYYY-MM-DD)')
113
+ .option('--json', 'Output raw JSON instead of formatted text')
114
+ .action(async (options) => {
115
+ try {
116
+ const date = options.date || getWhoopDay();
117
+ if (options.date && !validateISODate(options.date)) {
118
+ throw new WhoopError('Invalid date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
119
+ }
120
+ const startDate = getDaysAgo(7);
121
+ const historyParams = { start: startDate + 'T00:00:00.000Z', end: date + 'T23:59:59.999Z', limit: 12 };
122
+ const [todayData, recoveryHistory, sleepHistory, cycleHistory] = await Promise.all([
123
+ fetchData(['profile', 'recovery', 'sleep', 'cycle', 'workout'], date, { limit: 25 }),
124
+ import('./api/client.js').then(m => m.getRecovery(historyParams, true)),
125
+ import('./api/client.js').then(m => m.getSleep(historyParams, true)),
126
+ import('./api/client.js').then(m => m.getCycle(historyParams, true)),
127
+ ]);
128
+ if (options.json) {
129
+ console.log(JSON.stringify({ today: todayData, recoveryHistory, sleepHistory, cycleHistory }, null, 2));
130
+ return;
131
+ }
132
+ const trends = analyzeTrends(recoveryHistory, sleepHistory, cycleHistory, 7);
133
+ console.log(formatDashboard({ today: todayData, recoveryHistory, sleepHistory, cycleHistory, trends }));
134
+ }
135
+ catch (error) {
136
+ handleError(error);
137
+ }
138
+ });
139
+ program
140
+ .command('trends')
141
+ .description('Show trends over time (7/14/30 days)')
142
+ .option('-n, --days <number>', 'Number of days to analyze', '7')
143
+ .option('--json', 'Output raw JSON instead of formatted text')
144
+ .action(async (options) => {
145
+ try {
146
+ const days = parseInt(options.days, 10);
147
+ if (![7, 14, 30].includes(days)) {
148
+ throw new WhoopError('Days must be 7, 14, or 30', ExitCode.GENERAL_ERROR);
149
+ }
150
+ const endDate = getWhoopDay();
151
+ const startDate = getDaysAgo(days);
152
+ const params = { start: startDate + 'T00:00:00.000Z', end: endDate + 'T23:59:59.999Z', limit: 25 };
153
+ const [recovery, sleep, cycle] = await Promise.all([
154
+ import('./api/client.js').then(m => m.getRecovery(params, true)),
155
+ import('./api/client.js').then(m => m.getSleep(params, true)),
156
+ import('./api/client.js').then(m => m.getCycle(params, true)),
157
+ ]);
158
+ const trends = analyzeTrends(recovery, sleep, cycle, days);
159
+ console.log(formatTrends(trends, !options.json));
160
+ }
161
+ catch (error) {
162
+ handleError(error);
163
+ }
164
+ });
165
+ program
166
+ .command('insights')
167
+ .description('AI-style health insights and recommendations')
168
+ .option('-d, --date <date>', 'Date in ISO format (YYYY-MM-DD)')
169
+ .option('--json', 'Output raw JSON instead of formatted text')
170
+ .action(async (options) => {
171
+ try {
172
+ const date = options.date || getWhoopDay();
173
+ if (options.date && !validateISODate(options.date)) {
174
+ throw new WhoopError('Invalid date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
175
+ }
176
+ const startDate = getDaysAgo(7);
177
+ const params = { start: startDate + 'T00:00:00.000Z', end: date + 'T23:59:59.999Z' };
178
+ const [recovery, sleep, cycle, workout] = await Promise.all([
179
+ import('./api/client.js').then(m => m.getRecovery(params, true)),
180
+ import('./api/client.js').then(m => m.getSleep(params, true)),
181
+ import('./api/client.js').then(m => m.getCycle(params, true)),
182
+ import('./api/client.js').then(m => m.getWorkout({ start: date + 'T00:00:00.000Z', end: date + 'T23:59:59.999Z' }, true)),
183
+ ]);
184
+ const insights = generateInsights(recovery, sleep, cycle, workout);
185
+ console.log(formatInsights(insights, !options.json));
186
+ }
187
+ catch (error) {
188
+ handleError(error);
189
+ }
190
+ });
191
+ program
192
+ .option('-d, --date <date>', 'Date in ISO format (YYYY-MM-DD)')
193
+ .option('-s, --start <date>', 'Start date for range query')
194
+ .option('-e, --end <date>', 'End date for range query')
195
+ .option('-l, --limit <number>', 'Max results per page', '25')
196
+ .option('-a, --all', 'Fetch all pages')
197
+ .option('-p, --pretty', 'Human-readable output')
198
+ .option('--sleep', 'Include sleep data')
199
+ .option('--recovery', 'Include recovery data')
200
+ .option('--workout', 'Include workout data')
201
+ .option('--cycle', 'Include cycle data')
202
+ .option('--profile', 'Include profile data')
203
+ .option('--body', 'Include body measurements')
204
+ .action(async (options) => {
205
+ try {
206
+ const types = [];
207
+ if (options.sleep)
208
+ types.push('sleep');
209
+ if (options.recovery)
210
+ types.push('recovery');
211
+ if (options.workout)
212
+ types.push('workout');
213
+ if (options.cycle)
214
+ types.push('cycle');
215
+ if (options.profile)
216
+ types.push('profile');
217
+ if (options.body)
218
+ types.push('body');
219
+ if (types.length === 0) {
220
+ types.push('profile', 'body', 'sleep', 'recovery', 'workout', 'cycle');
221
+ }
222
+ let dateOrRange;
223
+ if (options.start || options.end) {
224
+ if (options.start && !validateISODate(options.start)) {
225
+ throw new WhoopError('Invalid start date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
226
+ }
227
+ if (options.end && !validateISODate(options.end)) {
228
+ throw new WhoopError('Invalid end date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
229
+ }
230
+ const start = options.start || getWhoopDay();
231
+ const end = options.end || getWhoopDay();
232
+ dateOrRange = { start: start + 'T04:00:00.000Z', end: end + 'T04:00:00.000Z' };
233
+ }
234
+ else {
235
+ const date = options.date || getWhoopDay();
236
+ if (options.date && !validateISODate(options.date)) {
237
+ throw new WhoopError('Invalid date format. Use YYYY-MM-DD', ExitCode.GENERAL_ERROR);
238
+ }
239
+ dateOrRange = date;
240
+ }
241
+ const result = await fetchData(types, dateOrRange, {
242
+ limit: parseInt(options.limit, 10),
243
+ all: options.all,
244
+ });
245
+ output(result, options.pretty);
246
+ }
247
+ catch (error) {
248
+ handleError(error);
249
+ }
250
+ });
251
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { config } from 'dotenv';
3
+ import { program } from './cli.js';
4
+ config();
5
+ program.parse();
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,MAAM,EAAE,CAAC;AAET,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,159 @@
1
+ export interface WhoopProfile {
2
+ user_id: number;
3
+ email: string;
4
+ first_name: string;
5
+ last_name: string;
6
+ }
7
+ export interface WhoopBody {
8
+ height_meter: number;
9
+ weight_kilogram: number;
10
+ max_heart_rate: number;
11
+ }
12
+ export interface SleepStageSummary {
13
+ total_in_bed_time_milli: number;
14
+ total_awake_time_milli: number;
15
+ total_no_data_time_milli: number;
16
+ total_light_sleep_time_milli: number;
17
+ total_slow_wave_sleep_time_milli: number;
18
+ total_rem_sleep_time_milli: number;
19
+ sleep_cycle_count: number;
20
+ disturbance_count: number;
21
+ }
22
+ export interface SleepNeeded {
23
+ baseline_milli: number;
24
+ need_from_sleep_debt_milli: number;
25
+ need_from_recent_strain_milli: number;
26
+ need_from_recent_nap_milli: number;
27
+ }
28
+ export interface SleepScore {
29
+ stage_summary: SleepStageSummary;
30
+ sleep_needed: SleepNeeded;
31
+ respiratory_rate: number;
32
+ sleep_performance_percentage: number;
33
+ sleep_consistency_percentage: number;
34
+ sleep_efficiency_percentage: number;
35
+ }
36
+ export interface WhoopSleep {
37
+ id: number;
38
+ user_id: number;
39
+ created_at: string;
40
+ updated_at: string;
41
+ start: string;
42
+ end: string;
43
+ timezone_offset: string;
44
+ nap: boolean;
45
+ score: SleepScore;
46
+ }
47
+ export interface RecoveryScore {
48
+ user_calibrating: boolean;
49
+ recovery_score: number;
50
+ resting_heart_rate: number;
51
+ hrv_rmssd_milli: number;
52
+ spo2_percentage?: number;
53
+ skin_temp_celsius?: number;
54
+ }
55
+ export interface WhoopRecovery {
56
+ cycle_id: number;
57
+ sleep_id: string;
58
+ user_id: number;
59
+ created_at: string;
60
+ updated_at: string;
61
+ score_state: string;
62
+ score: RecoveryScore;
63
+ }
64
+ export interface WorkoutScore {
65
+ strain: number;
66
+ average_heart_rate: number;
67
+ max_heart_rate: number;
68
+ kilojoule: number;
69
+ percent_recorded?: number;
70
+ distance_meter?: number;
71
+ altitude_gain_meter?: number;
72
+ zone_durations?: {
73
+ zone_zero_milli: number;
74
+ zone_one_milli: number;
75
+ zone_two_milli: number;
76
+ zone_three_milli: number;
77
+ zone_four_milli: number;
78
+ zone_five_milli: number;
79
+ };
80
+ }
81
+ export interface WhoopWorkout {
82
+ id: string;
83
+ user_id: number;
84
+ created_at: string;
85
+ updated_at: string;
86
+ start: string;
87
+ end: string;
88
+ timezone_offset: string;
89
+ sport_id: number;
90
+ sport_name: string;
91
+ score_state: string;
92
+ score: WorkoutScore;
93
+ }
94
+ export interface CycleScore {
95
+ strain: number;
96
+ kilojoule: number;
97
+ average_heart_rate: number;
98
+ max_heart_rate: number;
99
+ }
100
+ export interface CycleRecovery {
101
+ id: number;
102
+ score: number;
103
+ user_calibrating: boolean;
104
+ recovery_score: number;
105
+ resting_heart_rate: number;
106
+ hrv_rmssd_milli: number;
107
+ spo2_percentage: number;
108
+ skin_temp_celsius: number;
109
+ }
110
+ export interface WhoopCycle {
111
+ id: number;
112
+ user_id: number;
113
+ created_at: string;
114
+ updated_at: string;
115
+ start: string;
116
+ end: string;
117
+ timezone_offset: string;
118
+ score: CycleScore;
119
+ recovery: CycleRecovery;
120
+ }
121
+ export interface ApiResponse<T> {
122
+ records: T[];
123
+ next_token?: string;
124
+ }
125
+ export interface TokenData {
126
+ access_token: string;
127
+ refresh_token: string;
128
+ expires_at: number;
129
+ token_type: string;
130
+ scope: string;
131
+ }
132
+ export interface OAuthTokenResponse {
133
+ access_token: string;
134
+ refresh_token: string;
135
+ expires_in: number;
136
+ token_type: string;
137
+ scope: string;
138
+ }
139
+ export type DataType = 'profile' | 'body' | 'sleep' | 'recovery' | 'workout' | 'cycle';
140
+ export interface DateRange {
141
+ start?: string;
142
+ end?: string;
143
+ }
144
+ export interface QueryParams extends DateRange {
145
+ limit?: number;
146
+ nextToken?: string;
147
+ }
148
+ export interface CombinedOutput {
149
+ profile?: WhoopProfile;
150
+ body?: WhoopBody;
151
+ sleep?: WhoopSleep[];
152
+ recovery?: WhoopRecovery[];
153
+ workout?: WhoopWorkout[];
154
+ cycle?: WhoopCycle[];
155
+ date: string;
156
+ fetched_at: string;
157
+ }
158
+ export type WhoopData = CombinedOutput;
159
+ //# sourceMappingURL=whoop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoop.d.ts","sourceRoot":"","sources":["../../src/types/whoop.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,wBAAwB,EAAE,MAAM,CAAC;IACjC,4BAA4B,EAAE,MAAM,CAAC;IACrC,gCAAgC,EAAE,MAAM,CAAC;IACzC,0BAA0B,EAAE,MAAM,CAAC;IACnC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,0BAA0B,EAAE,MAAM,CAAC;IACnC,6BAA6B,EAAE,MAAM,CAAC;IACtC,0BAA0B,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,iBAAiB,CAAC;IACjC,YAAY,EAAE,WAAW,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,4BAA4B,EAAE,MAAM,CAAC;IACrC,4BAA4B,EAAE,MAAM,CAAC;IACrC,2BAA2B,EAAE,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,aAAa,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE;QACf,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,YAAY,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;AAEvF,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,SAAS,GAAG,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=whoop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoop.js","sourceRoot":"","sources":["../../src/types/whoop.ts"],"names":[],"mappings":""}
@@ -0,0 +1,30 @@
1
+ import type { WhoopRecovery, WhoopSleep, WhoopCycle, WhoopWorkout } from '../types/whoop.js';
2
+ export interface TrendStats {
3
+ avg: number;
4
+ min: number;
5
+ max: number;
6
+ current: number;
7
+ trend: 'up' | 'down' | 'stable';
8
+ values: number[];
9
+ }
10
+ export interface TrendData {
11
+ period: number;
12
+ recovery: TrendStats | null;
13
+ hrv: TrendStats | null;
14
+ rhr: TrendStats | null;
15
+ sleepPerformance: TrendStats | null;
16
+ sleepHours: TrendStats | null;
17
+ strain: TrendStats | null;
18
+ }
19
+ export interface Insight {
20
+ category: 'recovery' | 'sleep' | 'strain' | 'hrv';
21
+ level: 'good' | 'warning' | 'critical';
22
+ title: string;
23
+ message: string;
24
+ action?: string;
25
+ }
26
+ export declare function analyzeTrends(recovery: WhoopRecovery[], sleep: WhoopSleep[], cycle: WhoopCycle[], period: number): TrendData;
27
+ export declare function generateInsights(recovery: WhoopRecovery[], sleep: WhoopSleep[], cycle: WhoopCycle[], workout: WhoopWorkout[]): Insight[];
28
+ export declare function formatTrends(data: TrendData, pretty: boolean): string;
29
+ export declare function formatInsights(insights: Insight[], pretty: boolean): string;
30
+ //# sourceMappingURL=analysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis.d.ts","sourceRoot":"","sources":["../../src/utils/analysis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7F,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACvB,GAAG,EAAE,UAAU,GAAG,IAAI,CAAC;IACvB,gBAAgB,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAClD,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAwBD,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,aAAa,EAAE,EACzB,KAAK,EAAE,UAAU,EAAE,EACnB,KAAK,EAAE,UAAU,EAAE,EACnB,MAAM,EAAE,MAAM,GACb,SAAS,CA4CX;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,aAAa,EAAE,EACzB,KAAK,EAAE,UAAU,EAAE,EACnB,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,EAAE,YAAY,EAAE,GACtB,OAAO,EAAE,CAqJX;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CA0BrE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAkB3E"}