@openlifelog/sdk 1.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,2023 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ACTIVITY_METRICS: () => ACTIVITY_METRICS,
24
+ ALL_METRICS: () => ALL_METRICS,
25
+ AuthenticationError: () => AuthenticationError,
26
+ AuthorizationError: () => AuthorizationError,
27
+ BODY_METRICS: () => BODY_METRICS,
28
+ DistanceConverter: () => DistanceConverter,
29
+ HeightConverter: () => HeightConverter,
30
+ NetworkError: () => NetworkError,
31
+ NotFoundError: () => NotFoundError,
32
+ OpenLifeLog: () => OpenLifeLog,
33
+ OpenLifeLogError: () => OpenLifeLogError,
34
+ PaginatedIterator: () => PaginatedIterator,
35
+ RateLimitError: () => RateLimitError,
36
+ SLEEP_METRICS: () => SLEEP_METRICS,
37
+ ServerError: () => ServerError,
38
+ TimeoutError: () => TimeoutError,
39
+ UnitConversionError: () => UnitConversionError,
40
+ UnitConverter: () => UnitConverter,
41
+ VITAL_METRICS: () => VITAL_METRICS,
42
+ ValidationError: () => ValidationError,
43
+ WELLNESS_METRICS: () => WELLNESS_METRICS,
44
+ WeightConverter: () => WeightConverter,
45
+ createPaginatedIterator: () => createPaginatedIterator,
46
+ createUnitConverter: () => createUnitConverter,
47
+ default: () => OpenLifeLog,
48
+ fetchAllPages: () => fetchAllPages,
49
+ getMetricDefinition: () => getMetricDefinition,
50
+ getMetricsByCategory: () => getMetricsByCategory,
51
+ hasMorePages: () => hasMorePages
52
+ });
53
+ module.exports = __toCommonJS(index_exports);
54
+
55
+ // config.ts
56
+ var DEFAULT_CONFIG = {
57
+ baseUrl: "https://api.openlifelog.com",
58
+ measurementSystem: "metric",
59
+ autoConvertUnits: true,
60
+ timeout: 3e4,
61
+ maxRetries: 3,
62
+ enableRetries: true,
63
+ debug: false
64
+ };
65
+ function mergeConfig(userConfig) {
66
+ return {
67
+ ...DEFAULT_CONFIG,
68
+ ...userConfig,
69
+ apiKey: userConfig.apiKey,
70
+ headers: userConfig.headers || {},
71
+ // Bind fetch to globalThis to preserve context
72
+ fetch: userConfig.fetch || globalThis.fetch.bind(globalThis)
73
+ };
74
+ }
75
+
76
+ // utils/errors.ts
77
+ var OpenLifeLogError = class extends Error {
78
+ constructor(message, statusCode, code, rawError) {
79
+ super(message);
80
+ this.name = "OpenLifeLogError";
81
+ this.statusCode = statusCode;
82
+ this.code = code;
83
+ this.rawError = rawError;
84
+ if (Error.captureStackTrace) {
85
+ Error.captureStackTrace(this, this.constructor);
86
+ }
87
+ }
88
+ };
89
+ var AuthenticationError = class extends OpenLifeLogError {
90
+ constructor(message = "Authentication failed. Please check your credentials.", rawError) {
91
+ super(message, 401, "AUTHENTICATION_ERROR", rawError);
92
+ this.name = "AuthenticationError";
93
+ }
94
+ };
95
+ var AuthorizationError = class extends OpenLifeLogError {
96
+ constructor(message = "You do not have permission to access this resource.", rawError) {
97
+ super(message, 403, "AUTHORIZATION_ERROR", rawError);
98
+ this.name = "AuthorizationError";
99
+ }
100
+ };
101
+ var NotFoundError = class extends OpenLifeLogError {
102
+ constructor(message = "The requested resource was not found.", rawError) {
103
+ super(message, 404, "NOT_FOUND", rawError);
104
+ this.name = "NotFoundError";
105
+ }
106
+ };
107
+ var ValidationError = class extends OpenLifeLogError {
108
+ constructor(message = "Validation failed.", validationErrors, rawError) {
109
+ super(message, 400, "VALIDATION_ERROR", rawError);
110
+ this.name = "ValidationError";
111
+ this.validationErrors = validationErrors;
112
+ }
113
+ };
114
+ var RateLimitError = class extends OpenLifeLogError {
115
+ constructor(message = "Rate limit exceeded. Please try again later.", retryAfter, rawError) {
116
+ super(message, 429, "RATE_LIMIT_ERROR", rawError);
117
+ this.name = "RateLimitError";
118
+ this.retryAfter = retryAfter;
119
+ }
120
+ };
121
+ var ServerError = class extends OpenLifeLogError {
122
+ constructor(message = "An internal server error occurred.", rawError) {
123
+ super(message, 500, "SERVER_ERROR", rawError);
124
+ this.name = "ServerError";
125
+ }
126
+ };
127
+ var NetworkError = class extends OpenLifeLogError {
128
+ constructor(message = "A network error occurred. Please check your connection.", rawError) {
129
+ super(message, void 0, "NETWORK_ERROR", rawError);
130
+ this.name = "NetworkError";
131
+ }
132
+ };
133
+ var TimeoutError = class extends OpenLifeLogError {
134
+ constructor(message = "The request timed out.", rawError) {
135
+ super(message, 408, "TIMEOUT_ERROR", rawError);
136
+ this.name = "TimeoutError";
137
+ }
138
+ };
139
+ var UnitConversionError = class extends OpenLifeLogError {
140
+ constructor(message = "Failed to convert units.", rawError) {
141
+ super(message, void 0, "UNIT_CONVERSION_ERROR", rawError);
142
+ this.name = "UnitConversionError";
143
+ }
144
+ };
145
+ function parseErrorResponse(error, statusCode) {
146
+ const message = error?.message || error?.error || "An unknown error occurred";
147
+ const rawError = error;
148
+ if (statusCode === 401) {
149
+ return new AuthenticationError(message, rawError);
150
+ }
151
+ if (statusCode === 403) {
152
+ return new AuthorizationError(message, rawError);
153
+ }
154
+ if (statusCode === 404) {
155
+ return new NotFoundError(message, rawError);
156
+ }
157
+ if (statusCode === 400) {
158
+ return new ValidationError(message, error?.validationErrors, rawError);
159
+ }
160
+ if (statusCode === 429) {
161
+ return new RateLimitError(message, error?.retryAfter, rawError);
162
+ }
163
+ if (statusCode && statusCode >= 500) {
164
+ return new ServerError(message, rawError);
165
+ }
166
+ return new OpenLifeLogError(message, statusCode, error?.code, rawError);
167
+ }
168
+
169
+ // utils/http.ts
170
+ var HttpClient = class {
171
+ constructor(config) {
172
+ this.config = config;
173
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
174
+ }
175
+ /**
176
+ * Update the API key (token)
177
+ */
178
+ setApiKey(apiKey) {
179
+ this.config.apiKey = apiKey;
180
+ }
181
+ /**
182
+ * Get the current API key
183
+ */
184
+ getApiKey() {
185
+ return this.config.apiKey;
186
+ }
187
+ /**
188
+ * Convert camelCase to snake_case
189
+ */
190
+ toSnakeCase(str) {
191
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
192
+ }
193
+ /**
194
+ * Build full URL with query parameters
195
+ */
196
+ buildUrl(path, params) {
197
+ const url = new URL(path.startsWith("/") ? `${this.baseUrl}${path}` : `${this.baseUrl}/${path}`);
198
+ if (params) {
199
+ Object.entries(params).forEach(([key, value]) => {
200
+ if (value !== void 0 && value !== null) {
201
+ const snakeKey = this.toSnakeCase(key);
202
+ if (Array.isArray(value)) {
203
+ value.forEach((v) => url.searchParams.append(snakeKey, String(v)));
204
+ } else {
205
+ url.searchParams.append(snakeKey, String(value));
206
+ }
207
+ }
208
+ });
209
+ }
210
+ return url.toString();
211
+ }
212
+ /**
213
+ * Build request headers
214
+ */
215
+ buildHeaders(customHeaders) {
216
+ const headers = {
217
+ "Content-Type": "application/json",
218
+ ...this.config.headers,
219
+ ...customHeaders
220
+ };
221
+ if (this.config.apiKey) {
222
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
223
+ }
224
+ return headers;
225
+ }
226
+ /**
227
+ * Execute request with timeout support
228
+ */
229
+ async executeWithTimeout(url, init, timeout) {
230
+ const controller = new AbortController();
231
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
232
+ try {
233
+ const response = await this.config.fetch(url, {
234
+ ...init,
235
+ signal: controller.signal
236
+ });
237
+ clearTimeout(timeoutId);
238
+ return response;
239
+ } catch (error) {
240
+ clearTimeout(timeoutId);
241
+ if (error.name === "AbortError") {
242
+ throw new TimeoutError(`Request timed out after ${timeout}ms`);
243
+ }
244
+ throw error;
245
+ }
246
+ }
247
+ /**
248
+ * Sleep for exponential backoff
249
+ */
250
+ async sleep(ms) {
251
+ return new Promise((resolve) => setTimeout(resolve, ms));
252
+ }
253
+ /**
254
+ * Determine if error is retryable
255
+ */
256
+ isRetryableError(error, statusCode) {
257
+ if (error instanceof NetworkError || error instanceof TimeoutError) {
258
+ return true;
259
+ }
260
+ if (statusCode && statusCode >= 500 && statusCode < 600) {
261
+ return true;
262
+ }
263
+ if (statusCode === 429) {
264
+ return true;
265
+ }
266
+ return false;
267
+ }
268
+ /**
269
+ * Calculate exponential backoff delay
270
+ */
271
+ getRetryDelay(attempt) {
272
+ const baseDelay = Math.pow(2, attempt) * 1e3;
273
+ const jitter = Math.random() * 1e3;
274
+ return baseDelay + jitter;
275
+ }
276
+ /**
277
+ * Make HTTP request with automatic retries
278
+ */
279
+ async request(path, options = {}) {
280
+ const {
281
+ method = "GET",
282
+ headers: customHeaders,
283
+ body,
284
+ params,
285
+ timeout = this.config.timeout,
286
+ skipRetry = false
287
+ } = options;
288
+ const url = this.buildUrl(path, params);
289
+ const headers = this.buildHeaders(customHeaders);
290
+ const requestInit = {
291
+ method,
292
+ headers
293
+ };
294
+ if (body && (method === "POST" || method === "PUT" || method === "PATCH")) {
295
+ requestInit.body = JSON.stringify(body);
296
+ }
297
+ const maxAttempts = skipRetry || !this.config.enableRetries ? 1 : this.config.maxRetries + 1;
298
+ let lastError;
299
+ if (this.config.debug) {
300
+ console.log(`[OpenLifeLog SDK] ${method} ${url}`, body ? { body } : "");
301
+ }
302
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
303
+ try {
304
+ if (attempt > 0) {
305
+ const delay = this.getRetryDelay(attempt - 1);
306
+ if (this.config.debug) {
307
+ console.log(`[OpenLifeLog SDK] Retry attempt ${attempt}/${maxAttempts - 1}, waiting ${delay}ms`);
308
+ }
309
+ await this.sleep(delay);
310
+ }
311
+ const response = await this.executeWithTimeout(url, requestInit, timeout);
312
+ if (!response.ok) {
313
+ let errorData;
314
+ try {
315
+ errorData = await response.json();
316
+ } catch {
317
+ errorData = { error: response.statusText };
318
+ }
319
+ const error = parseErrorResponse(errorData, response.status);
320
+ if (this.isRetryableError(error, response.status) && attempt < maxAttempts - 1) {
321
+ lastError = error;
322
+ continue;
323
+ }
324
+ throw error;
325
+ }
326
+ let data;
327
+ const contentType = response.headers.get("content-type");
328
+ if (contentType?.includes("application/json")) {
329
+ data = await response.json();
330
+ } else {
331
+ data = await response.text();
332
+ }
333
+ if (this.config.debug) {
334
+ console.log(`[OpenLifeLog SDK] Response ${response.status}`, data);
335
+ }
336
+ return {
337
+ data,
338
+ status: response.status,
339
+ headers: response.headers
340
+ };
341
+ } catch (error) {
342
+ if (error.name === "TypeError" && error.message.includes("fetch")) {
343
+ lastError = new NetworkError(error.message, error);
344
+ } else if (error instanceof TimeoutError) {
345
+ lastError = error;
346
+ } else if (error.name === "AbortError") {
347
+ lastError = new TimeoutError("Request was aborted", error);
348
+ } else {
349
+ lastError = error;
350
+ }
351
+ if (this.isRetryableError(lastError) && attempt < maxAttempts - 1) {
352
+ continue;
353
+ }
354
+ throw lastError;
355
+ }
356
+ }
357
+ throw lastError;
358
+ }
359
+ /**
360
+ * GET request
361
+ */
362
+ async get(path, params, options) {
363
+ return this.request(path, { ...options, method: "GET", params });
364
+ }
365
+ /**
366
+ * POST request
367
+ */
368
+ async post(path, body, options) {
369
+ return this.request(path, { ...options, method: "POST", body });
370
+ }
371
+ /**
372
+ * PUT request
373
+ */
374
+ async put(path, body, options) {
375
+ return this.request(path, { ...options, method: "PUT", body });
376
+ }
377
+ /**
378
+ * PATCH request
379
+ */
380
+ async patch(path, body, options) {
381
+ return this.request(path, { ...options, method: "PATCH", body });
382
+ }
383
+ /**
384
+ * DELETE request
385
+ */
386
+ async delete(path, options) {
387
+ return this.request(path, { ...options, method: "DELETE" });
388
+ }
389
+ };
390
+
391
+ // utils/units.ts
392
+ var KG_TO_LBS = 2.20462;
393
+ var LBS_TO_KG = 1 / KG_TO_LBS;
394
+ var METERS_TO_MILES = 621371e-9;
395
+ var MILES_TO_METERS = 1 / METERS_TO_MILES;
396
+ var METERS_TO_FEET = 3.28084;
397
+ var FEET_TO_METERS = 1 / METERS_TO_FEET;
398
+ var CM_TO_INCHES = 0.393701;
399
+ var INCHES_TO_CM = 1 / CM_TO_INCHES;
400
+ var WeightConverter = class {
401
+ /**
402
+ * Convert kilograms to pounds
403
+ */
404
+ static kgToLbs(kg) {
405
+ return kg * KG_TO_LBS;
406
+ }
407
+ /**
408
+ * Convert pounds to kilograms
409
+ */
410
+ static lbsToKg(lbs) {
411
+ return lbs * LBS_TO_KG;
412
+ }
413
+ /**
414
+ * Convert weight from metric to the target measurement system
415
+ */
416
+ static fromMetric(kg, targetSystem) {
417
+ if (targetSystem === "imperial") {
418
+ return this.kgToLbs(kg);
419
+ }
420
+ return kg;
421
+ }
422
+ /**
423
+ * Convert weight to metric from the source measurement system
424
+ */
425
+ static toMetric(value, sourceSystem) {
426
+ if (sourceSystem === "imperial") {
427
+ return this.lbsToKg(value);
428
+ }
429
+ return value;
430
+ }
431
+ };
432
+ var DistanceConverter = class {
433
+ /**
434
+ * Convert meters to miles
435
+ */
436
+ static metersToMiles(meters) {
437
+ return meters * METERS_TO_MILES;
438
+ }
439
+ /**
440
+ * Convert miles to meters
441
+ */
442
+ static milesToMeters(miles) {
443
+ return miles * MILES_TO_METERS;
444
+ }
445
+ /**
446
+ * Convert meters to feet
447
+ */
448
+ static metersToFeet(meters) {
449
+ return meters * METERS_TO_FEET;
450
+ }
451
+ /**
452
+ * Convert feet to meters
453
+ */
454
+ static feetToMeters(feet) {
455
+ return feet * FEET_TO_METERS;
456
+ }
457
+ /**
458
+ * Convert distance from metric to the target measurement system
459
+ * For larger distances (> 1000m), converts to miles, otherwise to feet
460
+ */
461
+ static fromMetric(meters, targetSystem, preferMiles = false) {
462
+ if (targetSystem === "imperial") {
463
+ if (preferMiles || meters >= 1e3) {
464
+ return this.metersToMiles(meters);
465
+ }
466
+ return this.metersToFeet(meters);
467
+ }
468
+ return meters;
469
+ }
470
+ /**
471
+ * Convert distance to metric from the source measurement system
472
+ */
473
+ static toMetric(value, sourceSystem, isMiles = false) {
474
+ if (sourceSystem === "imperial") {
475
+ return isMiles ? this.milesToMeters(value) : this.feetToMeters(value);
476
+ }
477
+ return value;
478
+ }
479
+ };
480
+ var HeightConverter = class {
481
+ /**
482
+ * Convert centimeters to inches
483
+ */
484
+ static cmToInches(cm) {
485
+ return cm * CM_TO_INCHES;
486
+ }
487
+ /**
488
+ * Convert inches to centimeters
489
+ */
490
+ static inchesToCm(inches) {
491
+ return inches * INCHES_TO_CM;
492
+ }
493
+ /**
494
+ * Convert centimeters to feet and inches
495
+ */
496
+ static cmToFeetInches(cm) {
497
+ const totalInches = this.cmToInches(cm);
498
+ const feet = Math.floor(totalInches / 12);
499
+ const inches = Math.round(totalInches % 12);
500
+ return { feet, inches };
501
+ }
502
+ /**
503
+ * Convert feet and inches to centimeters
504
+ */
505
+ static feetInchesToCm(feet, inches) {
506
+ const totalInches = feet * 12 + inches;
507
+ return this.inchesToCm(totalInches);
508
+ }
509
+ /**
510
+ * Convert height from metric to the target measurement system
511
+ */
512
+ static fromMetric(cm, targetSystem) {
513
+ if (targetSystem === "imperial") {
514
+ return this.cmToInches(cm);
515
+ }
516
+ return cm;
517
+ }
518
+ /**
519
+ * Convert height to metric from the source measurement system
520
+ */
521
+ static toMetric(value, sourceSystem) {
522
+ if (sourceSystem === "imperial") {
523
+ return this.inchesToCm(value);
524
+ }
525
+ return value;
526
+ }
527
+ };
528
+ var UnitConverter = class {
529
+ constructor(measurementSystem = "metric") {
530
+ this.measurementSystem = measurementSystem;
531
+ }
532
+ /**
533
+ * Update the measurement system
534
+ */
535
+ setMeasurementSystem(system) {
536
+ this.measurementSystem = system;
537
+ }
538
+ /**
539
+ * Get the current measurement system
540
+ */
541
+ getMeasurementSystem() {
542
+ return this.measurementSystem;
543
+ }
544
+ /**
545
+ * Convert weight from metric (API storage format) to user preference
546
+ */
547
+ weightFromMetric(kg) {
548
+ if (kg === null || kg === void 0) return null;
549
+ return WeightConverter.fromMetric(kg, this.measurementSystem);
550
+ }
551
+ /**
552
+ * Convert weight to metric (API storage format) from user preference
553
+ */
554
+ weightToMetric(value) {
555
+ if (value === null || value === void 0) return null;
556
+ return WeightConverter.toMetric(value, this.measurementSystem);
557
+ }
558
+ /**
559
+ * Convert distance from metric to user preference
560
+ */
561
+ distanceFromMetric(meters, preferMiles = false) {
562
+ if (meters === null || meters === void 0) return null;
563
+ return DistanceConverter.fromMetric(meters, this.measurementSystem, preferMiles);
564
+ }
565
+ /**
566
+ * Convert distance to metric from user preference
567
+ */
568
+ distanceToMetric(value, isMiles = false) {
569
+ if (value === null || value === void 0) return null;
570
+ return DistanceConverter.toMetric(value, this.measurementSystem, isMiles);
571
+ }
572
+ /**
573
+ * Convert height from metric to user preference
574
+ */
575
+ heightFromMetric(cm) {
576
+ if (cm === null || cm === void 0) return null;
577
+ return HeightConverter.fromMetric(cm, this.measurementSystem);
578
+ }
579
+ /**
580
+ * Convert height to metric from user preference
581
+ */
582
+ heightToMetric(value) {
583
+ if (value === null || value === void 0) return null;
584
+ return HeightConverter.toMetric(value, this.measurementSystem);
585
+ }
586
+ /**
587
+ * Round number to specified decimal places
588
+ */
589
+ static round(value, decimals = 2) {
590
+ return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
591
+ }
592
+ /**
593
+ * Get the appropriate unit label for weight
594
+ */
595
+ getWeightUnit() {
596
+ return this.measurementSystem === "imperial" ? "lbs" : "kg";
597
+ }
598
+ /**
599
+ * Get the appropriate unit label for distance
600
+ */
601
+ getDistanceUnit(preferMiles = false) {
602
+ if (this.measurementSystem === "imperial") {
603
+ return preferMiles ? "mi" : "ft";
604
+ }
605
+ return "m";
606
+ }
607
+ /**
608
+ * Get the appropriate unit label for height
609
+ */
610
+ getHeightUnit() {
611
+ return this.measurementSystem === "imperial" ? "in" : "cm";
612
+ }
613
+ };
614
+ function createUnitConverter(measurementSystem = "metric") {
615
+ return new UnitConverter(measurementSystem);
616
+ }
617
+
618
+ // resources/auth.ts
619
+ var AuthResource = class {
620
+ constructor(http) {
621
+ this.http = http;
622
+ }
623
+ /**
624
+ * Sign up a new user
625
+ *
626
+ * @example
627
+ * ```typescript
628
+ * const { token, user } = await client.auth.signup({
629
+ * name: 'John Doe',
630
+ * email: 'john@example.com',
631
+ * password: 'securePassword123'
632
+ * });
633
+ * ```
634
+ */
635
+ async signup(request) {
636
+ const response = await this.http.post("/v1/auth/signup", request);
637
+ this.http.setApiKey(response.data.token);
638
+ return response.data;
639
+ }
640
+ /**
641
+ * Log in an existing user
642
+ *
643
+ * @example
644
+ * ```typescript
645
+ * const { token, user } = await client.auth.login({
646
+ * email: 'john@example.com',
647
+ * password: 'securePassword123'
648
+ * });
649
+ * ```
650
+ */
651
+ async login(request) {
652
+ const response = await this.http.post("/v1/auth/login", request);
653
+ this.http.setApiKey(response.data.token);
654
+ return response.data;
655
+ }
656
+ /**
657
+ * Request a password reset
658
+ *
659
+ * @example
660
+ * ```typescript
661
+ * await client.auth.requestPasswordReset({
662
+ * email: 'john@example.com'
663
+ * });
664
+ * ```
665
+ */
666
+ async requestPasswordReset(request) {
667
+ await this.http.post("/v1/auth/password-reset/request", request);
668
+ }
669
+ /**
670
+ * Confirm password reset with token
671
+ *
672
+ * @example
673
+ * ```typescript
674
+ * await client.auth.confirmPasswordReset({
675
+ * token: 'reset-token-from-email',
676
+ * newPassword: 'newSecurePassword123'
677
+ * });
678
+ * ```
679
+ */
680
+ async confirmPasswordReset(request) {
681
+ await this.http.post("/v1/auth/password-reset/confirm", request);
682
+ }
683
+ /**
684
+ * Log out the current user (clears the API key)
685
+ *
686
+ * @example
687
+ * ```typescript
688
+ * client.auth.logout();
689
+ * ```
690
+ */
691
+ logout() {
692
+ this.http.setApiKey("");
693
+ }
694
+ };
695
+
696
+ // utils/pagination.ts
697
+ var PaginatedIterator = class {
698
+ constructor(fetchPage) {
699
+ this.currentPage = [];
700
+ this.currentIndex = 0;
701
+ this.hasMore = true;
702
+ this.isFirstFetch = true;
703
+ this.fetchPage = fetchPage;
704
+ }
705
+ /**
706
+ * Async iterator implementation
707
+ */
708
+ async *[Symbol.asyncIterator]() {
709
+ while (this.hasMore || this.currentIndex < this.currentPage.length) {
710
+ if (this.currentIndex >= this.currentPage.length) {
711
+ if (!this.hasMore) {
712
+ break;
713
+ }
714
+ const response = await this.fetchPage(this.isFirstFetch ? void 0 : this.nextCursor);
715
+ this.isFirstFetch = false;
716
+ this.currentPage = response.data;
717
+ this.currentIndex = 0;
718
+ this.nextCursor = response.pageInfo.nextCursor;
719
+ this.hasMore = response.pageInfo.hasMore;
720
+ if (this.currentPage.length === 0) {
721
+ break;
722
+ }
723
+ }
724
+ yield this.currentPage[this.currentIndex++];
725
+ }
726
+ }
727
+ /**
728
+ * Get all items from all pages (be careful with large datasets!)
729
+ */
730
+ async toArray() {
731
+ const items = [];
732
+ for await (const item of this) {
733
+ items.push(item);
734
+ }
735
+ return items;
736
+ }
737
+ };
738
+ function createPaginatedIterator(fetchPage) {
739
+ return new PaginatedIterator(fetchPage);
740
+ }
741
+ async function fetchAllPages(fetchPage, maxPages) {
742
+ const allItems = [];
743
+ let cursor;
744
+ let hasMore = true;
745
+ let pageCount = 0;
746
+ while (hasMore && (!maxPages || pageCount < maxPages)) {
747
+ const response = await fetchPage(cursor);
748
+ allItems.push(...response.data);
749
+ cursor = response.pageInfo.nextCursor;
750
+ hasMore = response.pageInfo.hasMore;
751
+ pageCount++;
752
+ if (!hasMore || !cursor) {
753
+ break;
754
+ }
755
+ }
756
+ return allItems;
757
+ }
758
+ function hasMorePages(pageInfo) {
759
+ return pageInfo.hasMore && !!pageInfo.nextCursor;
760
+ }
761
+
762
+ // resources/users.ts
763
+ var UsersResource = class {
764
+ constructor(http) {
765
+ this.http = http;
766
+ }
767
+ /**
768
+ * Get current authenticated user
769
+ *
770
+ * @example
771
+ * ```typescript
772
+ * const user = await client.users.me();
773
+ * console.log(user.name, user.email);
774
+ * ```
775
+ */
776
+ async me() {
777
+ const response = await this.http.get("/v1/users/me");
778
+ return response.data;
779
+ }
780
+ /**
781
+ * Update current user profile
782
+ *
783
+ * @example
784
+ * ```typescript
785
+ * const user = await client.users.update({
786
+ * name: 'Updated Name',
787
+ * isOnboarded: true
788
+ * });
789
+ * ```
790
+ */
791
+ async update(request) {
792
+ const response = await this.http.patch("/v1/users/me", request);
793
+ return response.data;
794
+ }
795
+ /**
796
+ * Get user preferences
797
+ *
798
+ * @example
799
+ * ```typescript
800
+ * const prefs = await client.users.getPreferences();
801
+ * console.log(prefs.measurementSystem); // 'metric' or 'imperial'
802
+ * ```
803
+ */
804
+ async getPreferences() {
805
+ const response = await this.http.get("/v1/users/me/preferences");
806
+ return response.data;
807
+ }
808
+ /**
809
+ * Update user preferences
810
+ *
811
+ * @example
812
+ * ```typescript
813
+ * const prefs = await client.users.updatePreferences({
814
+ * measurementSystem: 'imperial'
815
+ * });
816
+ * ```
817
+ */
818
+ async updatePreferences(request) {
819
+ const response = await this.http.patch("/v1/users/me/preferences", request);
820
+ return response.data;
821
+ }
822
+ /**
823
+ * List all users (for admin/public lists)
824
+ *
825
+ * @example
826
+ * ```typescript
827
+ * const { data, pageInfo } = await client.users.list({ limit: 20 });
828
+ * ```
829
+ */
830
+ async list(params) {
831
+ const response = await this.http.get("/v1/users", params);
832
+ return response.data;
833
+ }
834
+ /**
835
+ * Search for users by name or email
836
+ *
837
+ * @example
838
+ * ```typescript
839
+ * const { data, pageInfo } = await client.users.search({ q: 'john' });
840
+ * ```
841
+ */
842
+ async search(params) {
843
+ const response = await this.http.get("/v1/users/search", params);
844
+ return response.data;
845
+ }
846
+ /**
847
+ * List all users with automatic pagination
848
+ *
849
+ * @example
850
+ * ```typescript
851
+ * for await (const user of client.users.listAutoPaginate({ limit: 100 })) {
852
+ * console.log(user.name);
853
+ * }
854
+ * ```
855
+ */
856
+ listAutoPaginate(params) {
857
+ return createPaginatedIterator(
858
+ (cursor) => this.list({ ...params, cursor })
859
+ );
860
+ }
861
+ /**
862
+ * Get specific user by ID
863
+ *
864
+ * @example
865
+ * ```typescript
866
+ * const user = await client.users.get('user-id');
867
+ * ```
868
+ */
869
+ async get(userId) {
870
+ const response = await this.http.get(`/v1/users/${userId}`);
871
+ return response.data;
872
+ }
873
+ };
874
+
875
+ // resources/foods.ts
876
+ var FoodsResource = class {
877
+ constructor(http) {
878
+ this.http = http;
879
+ }
880
+ /**
881
+ * List foods with pagination and search
882
+ *
883
+ * @example
884
+ * ```typescript
885
+ * const { data, pageInfo } = await client.foods.list({
886
+ * limit: 20,
887
+ * search: 'chicken'
888
+ * });
889
+ * ```
890
+ */
891
+ async list(params) {
892
+ const response = await this.http.get("/v1/foods", params);
893
+ return response.data;
894
+ }
895
+ /**
896
+ * List foods with automatic pagination
897
+ *
898
+ * @example
899
+ * ```typescript
900
+ * for await (const food of client.foods.listAutoPaginate({ limit: 100 })) {
901
+ * console.log(food.name);
902
+ * }
903
+ * ```
904
+ */
905
+ listAutoPaginate(params) {
906
+ return createPaginatedIterator(
907
+ (cursor) => this.list({ ...params, cursor })
908
+ );
909
+ }
910
+ /**
911
+ * Get total count of foods
912
+ *
913
+ * @example
914
+ * ```typescript
915
+ * const { count } = await client.foods.count();
916
+ * console.log(`Database has ${count} foods`);
917
+ * ```
918
+ */
919
+ async count() {
920
+ const response = await this.http.get("/v1/foods/count");
921
+ return response.data;
922
+ }
923
+ /**
924
+ * Search foods by name or brand
925
+ *
926
+ * @example
927
+ * ```typescript
928
+ * const { data } = await client.foods.search({
929
+ * q: 'chicken breast',
930
+ * limit: 10
931
+ * });
932
+ * ```
933
+ */
934
+ async search(params) {
935
+ const response = await this.http.get("/v1/foods/search", params);
936
+ return response.data;
937
+ }
938
+ /**
939
+ * Get specific food by ID
940
+ *
941
+ * @example
942
+ * ```typescript
943
+ * const food = await client.foods.get('food-id');
944
+ * console.log(food.nutrients);
945
+ * ```
946
+ */
947
+ async get(foodId) {
948
+ const response = await this.http.get(`/v1/foods/${foodId}`);
949
+ return response.data;
950
+ }
951
+ /**
952
+ * Create a new food item
953
+ *
954
+ * @example
955
+ * ```typescript
956
+ * const food = await client.foods.create({
957
+ * name: 'Custom Protein Shake',
958
+ * type: 'beverage',
959
+ * nutrients: {
960
+ * calories: 300,
961
+ * protein: 40,
962
+ * carbohydrates: 20,
963
+ * fat: 5
964
+ * },
965
+ * servingSizes: [{
966
+ * name: '1 serving',
967
+ * grams: 300,
968
+ * isDefault: true
969
+ * }]
970
+ * });
971
+ * ```
972
+ */
973
+ async create(request) {
974
+ const response = await this.http.post("/v1/foods", request);
975
+ return response.data;
976
+ }
977
+ /**
978
+ * Update an existing food item
979
+ *
980
+ * @example
981
+ * ```typescript
982
+ * const food = await client.foods.update('food-id', {
983
+ * description: 'Updated description'
984
+ * });
985
+ * ```
986
+ */
987
+ async update(foodId, request) {
988
+ const response = await this.http.put(`/v1/foods/${foodId}`, request);
989
+ return response.data;
990
+ }
991
+ /**
992
+ * Delete a food item
993
+ *
994
+ * @example
995
+ * ```typescript
996
+ * await client.foods.delete('food-id');
997
+ * ```
998
+ */
999
+ async delete(foodId) {
1000
+ await this.http.delete(`/v1/foods/${foodId}`);
1001
+ }
1002
+ /**
1003
+ * Get favorite foods
1004
+ *
1005
+ * @example
1006
+ * ```typescript
1007
+ * const { data } = await client.foods.getFavorites();
1008
+ * ```
1009
+ */
1010
+ async getFavorites(params) {
1011
+ const response = await this.http.get("/v1/foods/favorites", params);
1012
+ return response.data;
1013
+ }
1014
+ /**
1015
+ * Add food to favorites
1016
+ *
1017
+ * @example
1018
+ * ```typescript
1019
+ * await client.foods.addToFavorites('food-id');
1020
+ * ```
1021
+ */
1022
+ async addToFavorites(foodId) {
1023
+ await this.http.post(`/v1/foods/${foodId}/favorite`);
1024
+ }
1025
+ /**
1026
+ * Remove food from favorites
1027
+ *
1028
+ * @example
1029
+ * ```typescript
1030
+ * await client.foods.removeFromFavorites('food-id');
1031
+ * ```
1032
+ */
1033
+ async removeFromFavorites(foodId) {
1034
+ await this.http.delete(`/v1/foods/${foodId}/favorite`);
1035
+ }
1036
+ };
1037
+
1038
+ // resources/food-logs.ts
1039
+ var FoodLogsResource = class {
1040
+ constructor(http) {
1041
+ this.http = http;
1042
+ }
1043
+ /**
1044
+ * List food log entries with filtering
1045
+ *
1046
+ * @example
1047
+ * ```typescript
1048
+ * const logs = await client.foodLogs.list({
1049
+ * date: '2024-01-15',
1050
+ * mealType: 'lunch'
1051
+ * });
1052
+ * ```
1053
+ */
1054
+ async list(params) {
1055
+ const response = await this.http.get("/v1/food-logs", params);
1056
+ return response.data;
1057
+ }
1058
+ /**
1059
+ * Get daily nutrition summary
1060
+ *
1061
+ * @example
1062
+ * ```typescript
1063
+ * const summary = await client.foodLogs.getDailySummary({
1064
+ * date: '2024-01-15'
1065
+ * });
1066
+ * console.log(`Total calories: ${summary.totalCalories}`);
1067
+ * ```
1068
+ */
1069
+ async getDailySummary(params) {
1070
+ const response = await this.http.get("/v1/food-logs/summary", params);
1071
+ return response.data;
1072
+ }
1073
+ /**
1074
+ * Get specific food log entry
1075
+ *
1076
+ * @example
1077
+ * ```typescript
1078
+ * const log = await client.foodLogs.get('log-id');
1079
+ * ```
1080
+ */
1081
+ async get(logId) {
1082
+ const response = await this.http.get(`/v1/food-logs/${logId}`);
1083
+ return response.data;
1084
+ }
1085
+ /**
1086
+ * Create a food log entry
1087
+ *
1088
+ * @example
1089
+ * ```typescript
1090
+ * const log = await client.foodLogs.create({
1091
+ * foodId: 'food-uuid',
1092
+ * name: 'Chicken Breast',
1093
+ * servingSizeName: 'breast (200g)',
1094
+ * quantity: 1.5,
1095
+ * unitGrams: 200,
1096
+ * mealType: 'lunch',
1097
+ * notes: 'Grilled with olive oil'
1098
+ * });
1099
+ * ```
1100
+ */
1101
+ async create(request) {
1102
+ const response = await this.http.post("/v1/food-logs", request);
1103
+ return response.data;
1104
+ }
1105
+ /**
1106
+ * Quick entry food log with just name and nutrients
1107
+ * Creates a food log entry without creating a food (one-off entry)
1108
+ *
1109
+ * @example
1110
+ * ```typescript
1111
+ * const log = await client.foodLogs.quickEntry({
1112
+ * name: 'Homemade Salad',
1113
+ * protein: 15,
1114
+ * carbohydrates: 20,
1115
+ * fat: 10,
1116
+ * mealType: 'lunch'
1117
+ * });
1118
+ * ```
1119
+ */
1120
+ async quickEntry(request) {
1121
+ const response = await this.http.post("/v1/food-logs-quick-entry", request);
1122
+ return response.data;
1123
+ }
1124
+ /**
1125
+ * Update a food log entry
1126
+ *
1127
+ * @example
1128
+ * ```typescript
1129
+ * const log = await client.foodLogs.update('log-id', {
1130
+ * quantity: 2,
1131
+ * notes: 'Updated portion size'
1132
+ * });
1133
+ * ```
1134
+ */
1135
+ async update(logId, request) {
1136
+ const response = await this.http.put(`/v1/food-logs/${logId}`, request);
1137
+ return response.data;
1138
+ }
1139
+ /**
1140
+ * Delete a food log entry
1141
+ *
1142
+ * @example
1143
+ * ```typescript
1144
+ * await client.foodLogs.delete('log-id');
1145
+ * ```
1146
+ */
1147
+ async delete(logId) {
1148
+ await this.http.delete(`/v1/food-logs/${logId}`);
1149
+ }
1150
+ };
1151
+
1152
+ // resources/exercises.ts
1153
+ var ExercisesResource = class {
1154
+ constructor(http) {
1155
+ this.http = http;
1156
+ }
1157
+ /**
1158
+ * List exercises with filtering
1159
+ *
1160
+ * @example
1161
+ * ```typescript
1162
+ * const { data } = await client.exercises.list({
1163
+ * category: 'strength',
1164
+ * muscleGroup: 'chest'
1165
+ * });
1166
+ * ```
1167
+ */
1168
+ async list(params) {
1169
+ const response = await this.http.get("/v1/exercises", params);
1170
+ return response.data;
1171
+ }
1172
+ /**
1173
+ * List exercises with automatic pagination
1174
+ */
1175
+ listAutoPaginate(params) {
1176
+ return createPaginatedIterator(
1177
+ (cursor) => this.list({ ...params, cursor })
1178
+ );
1179
+ }
1180
+ /**
1181
+ * Get total count of exercises
1182
+ */
1183
+ async count() {
1184
+ const response = await this.http.get("/v1/exercises/count");
1185
+ return response.data;
1186
+ }
1187
+ /**
1188
+ * Search exercises by name
1189
+ */
1190
+ async search(params) {
1191
+ const response = await this.http.get("/v1/exercises/search", params);
1192
+ return response.data;
1193
+ }
1194
+ /**
1195
+ * Get specific exercise by ID
1196
+ */
1197
+ async get(exerciseId) {
1198
+ const response = await this.http.get(`/v1/exercises/${exerciseId}`);
1199
+ return response.data;
1200
+ }
1201
+ /**
1202
+ * Create a new exercise
1203
+ */
1204
+ async create(request) {
1205
+ const response = await this.http.post("/v1/exercises", request);
1206
+ return response.data;
1207
+ }
1208
+ /**
1209
+ * Update an existing exercise
1210
+ */
1211
+ async update(exerciseId, request) {
1212
+ const response = await this.http.put(`/v1/exercises/${exerciseId}`, request);
1213
+ return response.data;
1214
+ }
1215
+ /**
1216
+ * Delete an exercise
1217
+ */
1218
+ async delete(exerciseId) {
1219
+ await this.http.delete(`/v1/exercises/${exerciseId}`);
1220
+ }
1221
+ /**
1222
+ * Get favorite exercises
1223
+ */
1224
+ async getFavorites(params) {
1225
+ const response = await this.http.get("/v1/exercises/favorites", params);
1226
+ return response.data;
1227
+ }
1228
+ /**
1229
+ * Add exercise to favorites
1230
+ */
1231
+ async addToFavorites(exerciseId) {
1232
+ await this.http.post(`/v1/exercises/${exerciseId}/favorite`);
1233
+ }
1234
+ /**
1235
+ * Remove exercise from favorites
1236
+ */
1237
+ async removeFromFavorites(exerciseId) {
1238
+ await this.http.delete(`/v1/exercises/${exerciseId}/favorite`);
1239
+ }
1240
+ };
1241
+
1242
+ // resources/workouts.ts
1243
+ var WorkoutsResource = class {
1244
+ constructor(http) {
1245
+ this.http = http;
1246
+ }
1247
+ /**
1248
+ * List workout templates
1249
+ */
1250
+ async list(params) {
1251
+ const response = await this.http.get("/v1/workouts", params);
1252
+ return response.data;
1253
+ }
1254
+ /**
1255
+ * List workouts with automatic pagination
1256
+ */
1257
+ listAutoPaginate(params) {
1258
+ return createPaginatedIterator(
1259
+ (cursor) => this.list({ ...params, cursor })
1260
+ );
1261
+ }
1262
+ /**
1263
+ * Get total count of workouts
1264
+ */
1265
+ async count() {
1266
+ const response = await this.http.get("/v1/workouts/count");
1267
+ return response.data;
1268
+ }
1269
+ /**
1270
+ * Search workouts by name
1271
+ */
1272
+ async search(params) {
1273
+ const response = await this.http.get("/v1/workouts/search", params);
1274
+ return response.data;
1275
+ }
1276
+ /**
1277
+ * Get specific workout with all exercises
1278
+ */
1279
+ async get(workoutId) {
1280
+ const response = await this.http.get(`/v1/workouts/${workoutId}`);
1281
+ return response.data;
1282
+ }
1283
+ /**
1284
+ * Create a new workout template
1285
+ */
1286
+ async create(request) {
1287
+ const response = await this.http.post("/v1/workouts", request);
1288
+ return response.data;
1289
+ }
1290
+ /**
1291
+ * Update a workout template
1292
+ */
1293
+ async update(workoutId, request) {
1294
+ const response = await this.http.put(`/v1/workouts/${workoutId}`, request);
1295
+ return response.data;
1296
+ }
1297
+ /**
1298
+ * Clone an existing workout
1299
+ */
1300
+ async clone(workoutId) {
1301
+ const response = await this.http.post(`/v1/workouts/${workoutId}/clone`);
1302
+ return response.data;
1303
+ }
1304
+ /**
1305
+ * Delete a workout template
1306
+ */
1307
+ async delete(workoutId) {
1308
+ await this.http.delete(`/v1/workouts/${workoutId}`);
1309
+ }
1310
+ /**
1311
+ * Add exercises to workout
1312
+ */
1313
+ async addExercises(workoutId, request) {
1314
+ await this.http.post(`/v1/workouts/${workoutId}/exercises`, request);
1315
+ }
1316
+ /**
1317
+ * Update exercise in workout
1318
+ */
1319
+ async updateExercise(workoutId, exerciseId, request) {
1320
+ await this.http.put(`/v1/workouts/${workoutId}/exercises/${exerciseId}`, request);
1321
+ }
1322
+ /**
1323
+ * Remove exercise from workout
1324
+ */
1325
+ async removeExercise(workoutId, exerciseId) {
1326
+ await this.http.delete(`/v1/workouts/${workoutId}/exercises/${exerciseId}`);
1327
+ }
1328
+ /**
1329
+ * Get all workouts containing a specific exercise
1330
+ */
1331
+ async getWorkoutsByExercise(exerciseId) {
1332
+ const response = await this.http.get(`/v1/exercises/${exerciseId}/workouts`);
1333
+ return response.data;
1334
+ }
1335
+ /**
1336
+ * Get favorite workouts
1337
+ */
1338
+ async getFavorites(params) {
1339
+ const response = await this.http.get("/v1/workouts/favorites", params);
1340
+ return response.data;
1341
+ }
1342
+ /**
1343
+ * Add workout to favorites
1344
+ */
1345
+ async addToFavorites(workoutId) {
1346
+ await this.http.post(`/v1/workouts/${workoutId}/favorite`);
1347
+ }
1348
+ /**
1349
+ * Remove workout from favorites
1350
+ */
1351
+ async removeFromFavorites(workoutId) {
1352
+ await this.http.delete(`/v1/workouts/${workoutId}/favorite`);
1353
+ }
1354
+ };
1355
+
1356
+ // resources/sessions.ts
1357
+ var SessionsResource = class {
1358
+ constructor(http) {
1359
+ this.http = http;
1360
+ }
1361
+ /**
1362
+ * List workout sessions with filtering
1363
+ */
1364
+ async list(params) {
1365
+ const response = await this.http.get("/v1/workout-sessions", params);
1366
+ return response.data;
1367
+ }
1368
+ /**
1369
+ * List sessions with automatic pagination
1370
+ */
1371
+ listAutoPaginate(params) {
1372
+ return createPaginatedIterator(
1373
+ (cursor) => this.list({ ...params, cursor })
1374
+ );
1375
+ }
1376
+ /**
1377
+ * Create a new workout session
1378
+ */
1379
+ async create(request) {
1380
+ const response = await this.http.post("/v1/workout-sessions", request);
1381
+ return response.data;
1382
+ }
1383
+ /**
1384
+ * Start a workout session (convenience method)
1385
+ */
1386
+ async start(request) {
1387
+ return this.create({ ...request, status: "in_progress" });
1388
+ }
1389
+ /**
1390
+ * Get specific session with all exercise data
1391
+ */
1392
+ async get(sessionId) {
1393
+ const response = await this.http.get(`/v1/workout-sessions/${sessionId}`);
1394
+ return response.data;
1395
+ }
1396
+ /**
1397
+ * Update a workout session
1398
+ */
1399
+ async update(sessionId, request) {
1400
+ const response = await this.http.patch(`/v1/workout-sessions/${sessionId}`, request);
1401
+ return response.data;
1402
+ }
1403
+ /**
1404
+ * Complete a workout session (convenience method)
1405
+ */
1406
+ async complete(sessionId, notes) {
1407
+ return this.update(sessionId, {
1408
+ status: "completed",
1409
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
1410
+ ...notes && { notes }
1411
+ });
1412
+ }
1413
+ /**
1414
+ * Add exercises to a session (convenience method)
1415
+ *
1416
+ * @example
1417
+ * ```typescript
1418
+ * await client.sessions.addExercises('session-123', [
1419
+ * { exerciseId: 'ex-1', targetSets: 3 },
1420
+ * { exerciseId: 'ex-2', targetSets: 4, notes: 'Focus on form' }
1421
+ * ]);
1422
+ * ```
1423
+ */
1424
+ async addExercises(sessionId, exercises) {
1425
+ return this.update(sessionId, { addExercises: exercises });
1426
+ }
1427
+ /**
1428
+ * Delete a workout session
1429
+ */
1430
+ async delete(sessionId) {
1431
+ await this.http.delete(`/v1/workout-sessions/${sessionId}`);
1432
+ }
1433
+ /**
1434
+ * Get all sessions for a specific workout
1435
+ */
1436
+ async getSessionsByWorkout(workoutId, params) {
1437
+ const response = await this.http.get(`/v1/workouts/${workoutId}/sessions`, params);
1438
+ return response.data;
1439
+ }
1440
+ /**
1441
+ * Get exercise performance history across sessions
1442
+ */
1443
+ async getExerciseHistory(exerciseId) {
1444
+ const response = await this.http.get(`/v1/exercises/${exerciseId}/history`);
1445
+ return response.data;
1446
+ }
1447
+ /**
1448
+ * Get user's personal records
1449
+ */
1450
+ async getPersonalRecords() {
1451
+ const response = await this.http.get("/v1/personal-records");
1452
+ return response.data;
1453
+ }
1454
+ /**
1455
+ * Get personal records for a specific exercise
1456
+ */
1457
+ async getExercisePersonalRecords(exerciseId) {
1458
+ const response = await this.http.get(`/v1/exercises/${exerciseId}/personal-records`);
1459
+ return response.data;
1460
+ }
1461
+ /**
1462
+ * Get personal record progression history for an exercise
1463
+ */
1464
+ async getPersonalRecordHistory(exerciseId) {
1465
+ const response = await this.http.get(`/v1/exercises/${exerciseId}/personal-records/history`);
1466
+ return response.data;
1467
+ }
1468
+ };
1469
+
1470
+ // resources/programs.ts
1471
+ var ProgramsResource = class {
1472
+ constructor(http) {
1473
+ this.http = http;
1474
+ }
1475
+ /**
1476
+ * List user's programs and enrollments
1477
+ */
1478
+ async list(params) {
1479
+ const response = await this.http.get("/v1/programs", params);
1480
+ return response.data;
1481
+ }
1482
+ /**
1483
+ * List available program templates
1484
+ */
1485
+ async listTemplates(params) {
1486
+ const response = await this.http.get("/v1/programs/templates", params);
1487
+ return response.data;
1488
+ }
1489
+ /**
1490
+ * Create a new program
1491
+ */
1492
+ async create(request) {
1493
+ const response = await this.http.post("/v1/programs", request);
1494
+ return response.data;
1495
+ }
1496
+ /**
1497
+ * Get specific program details
1498
+ */
1499
+ async get(programId) {
1500
+ const response = await this.http.get(`/v1/programs/${programId}`);
1501
+ return response.data;
1502
+ }
1503
+ /**
1504
+ * Update a program
1505
+ */
1506
+ async update(programId, request) {
1507
+ const response = await this.http.put(`/v1/programs/${programId}`, request);
1508
+ return response.data;
1509
+ }
1510
+ /**
1511
+ * Delete a program
1512
+ */
1513
+ async delete(programId) {
1514
+ await this.http.delete(`/v1/programs/${programId}`);
1515
+ }
1516
+ /**
1517
+ * Enroll in a program
1518
+ */
1519
+ async enroll(programId, request) {
1520
+ const response = await this.http.post(`/v1/programs/${programId}/enroll`, request);
1521
+ return response.data;
1522
+ }
1523
+ /**
1524
+ * List program enrollments
1525
+ */
1526
+ async listEnrollments(params) {
1527
+ const response = await this.http.get("/v1/enrollments", params);
1528
+ return response.data;
1529
+ }
1530
+ /**
1531
+ * Get enrollment details
1532
+ */
1533
+ async getEnrollment(enrollmentId) {
1534
+ const response = await this.http.get(`/v1/enrollments/${enrollmentId}`);
1535
+ return response.data;
1536
+ }
1537
+ /**
1538
+ * Update enrollment (pause, resume, etc.)
1539
+ */
1540
+ async updateEnrollment(enrollmentId, request) {
1541
+ const response = await this.http.put(`/v1/enrollments/${enrollmentId}`, request);
1542
+ return response.data;
1543
+ }
1544
+ /**
1545
+ * Unenroll from a program
1546
+ */
1547
+ async unenroll(enrollmentId) {
1548
+ await this.http.delete(`/v1/enrollments/${enrollmentId}`);
1549
+ }
1550
+ /**
1551
+ * Get enrollment progress
1552
+ */
1553
+ async getEnrollmentProgress(enrollmentId) {
1554
+ const response = await this.http.get(`/v1/enrollments/${enrollmentId}/progress`);
1555
+ return response.data;
1556
+ }
1557
+ /**
1558
+ * Get current week schedule for enrollment
1559
+ */
1560
+ async getCurrentWeek(enrollmentId) {
1561
+ const response = await this.http.get(`/v1/enrollments/${enrollmentId}/current-week`);
1562
+ return response.data;
1563
+ }
1564
+ };
1565
+
1566
+ // resources/metrics.ts
1567
+ var MetricsResource = class {
1568
+ constructor(http) {
1569
+ this.http = http;
1570
+ }
1571
+ /**
1572
+ * List available metrics
1573
+ */
1574
+ async list() {
1575
+ const response = await this.http.get("/v1/metrics");
1576
+ return response.data;
1577
+ }
1578
+ /**
1579
+ * Get specific metric details
1580
+ */
1581
+ async get(metricId) {
1582
+ const response = await this.http.get(`/v1/metrics/${metricId}`);
1583
+ return response.data;
1584
+ }
1585
+ /**
1586
+ * Get metrics by category
1587
+ */
1588
+ async getByCategory(category) {
1589
+ const response = await this.http.get(`/v1/metrics/category/${category}`);
1590
+ return response.data;
1591
+ }
1592
+ /**
1593
+ * Get daily aggregated metric value
1594
+ */
1595
+ async getDailyMetric(metricKey, params) {
1596
+ const response = await this.http.get(`/v1/metrics/daily/${metricKey}`, params);
1597
+ return response.data;
1598
+ }
1599
+ /**
1600
+ * List metric events (data points)
1601
+ */
1602
+ async listEvents(params) {
1603
+ const response = await this.http.get("/v1/metric-events", params);
1604
+ return response.data;
1605
+ }
1606
+ /**
1607
+ * List metric events with automatic pagination
1608
+ */
1609
+ listEventsAutoPaginate(params) {
1610
+ return createPaginatedIterator(
1611
+ (cursor) => this.listEvents({ ...params, cursor })
1612
+ );
1613
+ }
1614
+ /**
1615
+ * Get specific metric event
1616
+ */
1617
+ async getEvent(eventId) {
1618
+ const response = await this.http.get(`/v1/metric-events/${eventId}`);
1619
+ return response.data;
1620
+ }
1621
+ /**
1622
+ * Log a metric value (convenience method)
1623
+ */
1624
+ async log(request) {
1625
+ const response = await this.http.post("/v1/metric-events", request);
1626
+ return response.data;
1627
+ }
1628
+ /**
1629
+ * Create a metric event
1630
+ */
1631
+ async createEvent(request) {
1632
+ return this.log(request);
1633
+ }
1634
+ /**
1635
+ * Bulk create metric events
1636
+ */
1637
+ async bulkCreateEvents(request) {
1638
+ await this.http.post("/v1/metric-events/bulk", request);
1639
+ }
1640
+ /**
1641
+ * Update a metric event
1642
+ */
1643
+ async updateEvent(eventId, request) {
1644
+ const response = await this.http.put(`/v1/metric-events/${eventId}`, request);
1645
+ return response.data;
1646
+ }
1647
+ /**
1648
+ * Delete a metric event
1649
+ */
1650
+ async deleteEvent(eventId) {
1651
+ await this.http.delete(`/v1/metric-events/${eventId}`);
1652
+ }
1653
+ };
1654
+
1655
+ // resources/goals.ts
1656
+ var GoalsResource = class {
1657
+ constructor(http) {
1658
+ this.http = http;
1659
+ }
1660
+ /**
1661
+ * Get active user goals
1662
+ */
1663
+ async list() {
1664
+ const response = await this.http.get("/v1/goals");
1665
+ return response.data;
1666
+ }
1667
+ /**
1668
+ * Get goals effective on a specific date
1669
+ */
1670
+ async getByDate(date) {
1671
+ const response = await this.http.get(`/v1/goals/date/${date}`);
1672
+ return response.data;
1673
+ }
1674
+ /**
1675
+ * Create a new goal
1676
+ */
1677
+ async create(request) {
1678
+ const response = await this.http.post("/v1/goals", request);
1679
+ return response.data;
1680
+ }
1681
+ /**
1682
+ * Update a goal
1683
+ */
1684
+ async update(goalId, request) {
1685
+ const response = await this.http.put(`/v1/goals/${goalId}`, request);
1686
+ return response.data;
1687
+ }
1688
+ /**
1689
+ * Delete a goal
1690
+ */
1691
+ async delete(goalId) {
1692
+ await this.http.delete(`/v1/goals/${goalId}`);
1693
+ }
1694
+ /**
1695
+ * Get today's goal progress
1696
+ */
1697
+ async getProgress() {
1698
+ const response = await this.http.get("/v1/goals/progress");
1699
+ return response.data;
1700
+ }
1701
+ /**
1702
+ * Get goal progress for a specific date
1703
+ */
1704
+ async getProgressByDate(date) {
1705
+ const response = await this.http.get(`/v1/goals/progress/${date}`);
1706
+ return response.data;
1707
+ }
1708
+ /**
1709
+ * Get current nutrition goals
1710
+ */
1711
+ async getNutritionGoals() {
1712
+ const response = await this.http.get("/v1/nutrition/goals");
1713
+ return response.data;
1714
+ }
1715
+ /**
1716
+ * Get nutrition goals for a specific date
1717
+ */
1718
+ async getNutritionGoalsByDate(date) {
1719
+ const response = await this.http.get(`/v1/nutrition/goals/date/${date}`);
1720
+ return response.data;
1721
+ }
1722
+ /**
1723
+ * Create nutrition goals
1724
+ */
1725
+ async createNutritionGoals(request) {
1726
+ const response = await this.http.post("/v1/nutrition/goals", request);
1727
+ return response.data;
1728
+ }
1729
+ /**
1730
+ * Update nutrition goals for a specific date
1731
+ */
1732
+ async updateNutritionGoals(date, request) {
1733
+ const response = await this.http.put(`/v1/nutrition/goals/date/${date}`, request);
1734
+ return response.data;
1735
+ }
1736
+ /**
1737
+ * Delete nutrition goals for a specific date
1738
+ */
1739
+ async deleteNutritionGoals(date) {
1740
+ await this.http.delete(`/v1/nutrition/goals/date/${date}`);
1741
+ }
1742
+ /**
1743
+ * Bulk create nutrition goals for multiple dates
1744
+ */
1745
+ async bulkCreateNutritionGoals(request) {
1746
+ await this.http.post("/v1/nutrition/goals/bulk", request);
1747
+ }
1748
+ /**
1749
+ * Copy nutrition goals from one date to another
1750
+ */
1751
+ async copyNutritionGoals(request) {
1752
+ await this.http.post("/v1/nutrition/goals/copy", request);
1753
+ }
1754
+ /**
1755
+ * Get nutrition goals history
1756
+ */
1757
+ async getNutritionGoalsHistory(params) {
1758
+ const response = await this.http.get("/v1/nutrition/goals/history", params);
1759
+ return response.data;
1760
+ }
1761
+ /**
1762
+ * Get today's nutrition progress toward goals
1763
+ */
1764
+ async getNutritionProgress() {
1765
+ const response = await this.http.get("/v1/nutrition/progress/today");
1766
+ return response.data;
1767
+ }
1768
+ /**
1769
+ * Get nutrition progress for a specific date
1770
+ */
1771
+ async getNutritionProgressByDate(date) {
1772
+ const response = await this.http.get(`/v1/nutrition/progress/date/${date}`);
1773
+ return response.data;
1774
+ }
1775
+ };
1776
+
1777
+ // resources/ai.ts
1778
+ var AIResource = class {
1779
+ constructor(http) {
1780
+ this.http = http;
1781
+ }
1782
+ /**
1783
+ * Get AI-generated nutrition insights
1784
+ *
1785
+ * @example
1786
+ * ```typescript
1787
+ * const insights = await client.ai.getFoodInsights({
1788
+ * startDate: '2024-01-01',
1789
+ * endDate: '2024-01-15'
1790
+ * });
1791
+ * ```
1792
+ */
1793
+ async getFoodInsights(params) {
1794
+ const response = await this.http.get("/v1/ai/food-insights", params);
1795
+ return response.data;
1796
+ }
1797
+ };
1798
+
1799
+ // client.ts
1800
+ var OpenLifeLog = class {
1801
+ constructor(config = {}) {
1802
+ this.config = mergeConfig(config);
1803
+ this.httpClient = new HttpClient(this.config);
1804
+ this.unitConverter = createUnitConverter(this.config.measurementSystem);
1805
+ this.auth = new AuthResource(this.httpClient);
1806
+ this.users = new UsersResource(this.httpClient);
1807
+ this.foods = new FoodsResource(this.httpClient);
1808
+ this.foodLogs = new FoodLogsResource(this.httpClient);
1809
+ this.exercises = new ExercisesResource(this.httpClient);
1810
+ this.workouts = new WorkoutsResource(this.httpClient);
1811
+ this.sessions = new SessionsResource(this.httpClient);
1812
+ this.programs = new ProgramsResource(this.httpClient);
1813
+ this.metrics = new MetricsResource(this.httpClient);
1814
+ this.goals = new GoalsResource(this.httpClient);
1815
+ this.ai = new AIResource(this.httpClient);
1816
+ }
1817
+ /**
1818
+ * Update the API key (JWT token)
1819
+ *
1820
+ * @example
1821
+ * ```typescript
1822
+ * client.setApiKey('new-jwt-token');
1823
+ * ```
1824
+ */
1825
+ setApiKey(apiKey) {
1826
+ this.httpClient.setApiKey(apiKey);
1827
+ }
1828
+ /**
1829
+ * Get the current API key
1830
+ */
1831
+ getApiKey() {
1832
+ return this.httpClient.getApiKey();
1833
+ }
1834
+ /**
1835
+ * Get the unit converter instance
1836
+ */
1837
+ getUnitConverter() {
1838
+ return this.unitConverter;
1839
+ }
1840
+ /**
1841
+ * Update the measurement system preference
1842
+ *
1843
+ * @example
1844
+ * ```typescript
1845
+ * client.setMeasurementSystem('imperial');
1846
+ * ```
1847
+ */
1848
+ setMeasurementSystem(system) {
1849
+ this.config.measurementSystem = system;
1850
+ this.unitConverter.setMeasurementSystem(system);
1851
+ }
1852
+ /**
1853
+ * Get the current measurement system
1854
+ */
1855
+ getMeasurementSystem() {
1856
+ return this.config.measurementSystem;
1857
+ }
1858
+ /**
1859
+ * Convenience method: Log food (combines food lookup and logging)
1860
+ *
1861
+ * This is a high-level method that developers love - simple and intuitive.
1862
+ *
1863
+ * @example
1864
+ * ```typescript
1865
+ * const log = await client.logFood({
1866
+ * foodId: 'food-uuid',
1867
+ * name: 'Chicken Breast',
1868
+ * servingSizeName: 'breast (200g)',
1869
+ * quantity: 1.5,
1870
+ * mealType: 'lunch',
1871
+ * notes: 'Grilled with olive oil'
1872
+ * });
1873
+ * ```
1874
+ */
1875
+ async logFood(request) {
1876
+ return this.foodLogs.create(request);
1877
+ }
1878
+ /**
1879
+ * Convenience method: Get today's nutrition summary
1880
+ *
1881
+ * @example
1882
+ * ```typescript
1883
+ * const summary = await client.getTodayNutrition();
1884
+ * console.log(`Calories: ${summary.totalCalories}`);
1885
+ * ```
1886
+ */
1887
+ async getTodayNutrition() {
1888
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1889
+ return this.foodLogs.getDailySummary({ date: today });
1890
+ }
1891
+ /**
1892
+ * Convenience method: Get today's goal progress
1893
+ *
1894
+ * @example
1895
+ * ```typescript
1896
+ * const progress = await client.getTodayProgress();
1897
+ * ```
1898
+ */
1899
+ async getTodayProgress() {
1900
+ return this.goals.getProgress();
1901
+ }
1902
+ /**
1903
+ * Convenience method: Get today's nutrition progress
1904
+ *
1905
+ * @example
1906
+ * ```typescript
1907
+ * const progress = await client.getTodayNutritionProgress();
1908
+ * ```
1909
+ */
1910
+ async getTodayNutritionProgress() {
1911
+ return this.goals.getNutritionProgress();
1912
+ }
1913
+ /**
1914
+ * Check if user is authenticated
1915
+ */
1916
+ isAuthenticated() {
1917
+ return !!this.httpClient.getApiKey();
1918
+ }
1919
+ };
1920
+
1921
+ // constants/metrics.ts
1922
+ var BODY_METRICS = [
1923
+ { key: "height", displayName: "Height", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1924
+ { key: "weight", displayName: "Body Weight", category: "body", unit: "kg", aggregation: "last", imperialUnit: "lbs", imperialConversion: 2.20462 },
1925
+ { key: "body_fat", displayName: "Body Fat %", category: "body", unit: "%", aggregation: "last" },
1926
+ { key: "muscle_mass", displayName: "Muscle Mass", category: "body", unit: "kg", aggregation: "last", imperialUnit: "lbs", imperialConversion: 2.20462 },
1927
+ { key: "bone_mass", displayName: "Bone Mass", category: "body", unit: "kg", aggregation: "last", imperialUnit: "lbs", imperialConversion: 2.20462 },
1928
+ { key: "body_water", displayName: "Body Water %", category: "body", unit: "%", aggregation: "last" },
1929
+ { key: "bmi", displayName: "BMI", category: "body", unit: "kg/m\xB2", aggregation: "last" },
1930
+ { key: "waist", displayName: "Waist Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1931
+ { key: "hip", displayName: "Hip Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1932
+ { key: "chest", displayName: "Chest Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1933
+ { key: "neck", displayName: "Neck Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1934
+ { key: "left_bicep", displayName: "Left Bicep", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1935
+ { key: "right_bicep", displayName: "Right Bicep", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1936
+ { key: "left_forearm", displayName: "Left Forearm", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1937
+ { key: "right_forearm", displayName: "Right Forearm", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1938
+ { key: "left_thigh", displayName: "Left Thigh", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1939
+ { key: "right_thigh", displayName: "Right Thigh", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1940
+ { key: "left_calf", displayName: "Left Calf", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
1941
+ { key: "right_calf", displayName: "Right Calf", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 }
1942
+ ];
1943
+ var ACTIVITY_METRICS = [
1944
+ { key: "steps", displayName: "Steps", category: "activity", unit: "steps", aggregation: "sum" },
1945
+ { key: "distance", displayName: "Distance", category: "activity", unit: "km", aggregation: "sum", imperialUnit: "mi", imperialConversion: 0.621371 },
1946
+ { key: "active_minutes", displayName: "Active Minutes", category: "activity", unit: "min", aggregation: "sum" },
1947
+ { key: "exercise_minutes", displayName: "Exercise Minutes", category: "activity", unit: "min", aggregation: "sum" },
1948
+ { key: "exercise_calories", displayName: "Exercise Calories", category: "activity", unit: "kcal", aggregation: "sum" },
1949
+ { key: "floors_climbed", displayName: "Floors Climbed", category: "activity", unit: "floors", aggregation: "sum" },
1950
+ { key: "standing_hours", displayName: "Standing Hours", category: "activity", unit: "hours", aggregation: "sum" },
1951
+ { key: "vo2_max", displayName: "VO2 Max", category: "activity", unit: "ml/kg/min", aggregation: "last" }
1952
+ ];
1953
+ var SLEEP_METRICS = [
1954
+ { key: "sleep_duration", displayName: "Sleep Duration", category: "sleep", unit: "hours", aggregation: "last" },
1955
+ { key: "deep_sleep", displayName: "Deep Sleep", category: "sleep", unit: "hours", aggregation: "last" },
1956
+ { key: "rem_sleep", displayName: "REM Sleep", category: "sleep", unit: "hours", aggregation: "last" },
1957
+ { key: "light_sleep", displayName: "Light Sleep", category: "sleep", unit: "hours", aggregation: "last" },
1958
+ { key: "sleep_quality", displayName: "Sleep Quality", category: "sleep", unit: "score", aggregation: "avg" },
1959
+ { key: "sleep_efficiency", displayName: "Sleep Efficiency", category: "sleep", unit: "%", aggregation: "avg" },
1960
+ { key: "time_to_fall_asleep", displayName: "Time to Fall Asleep", category: "sleep", unit: "min", aggregation: "avg" },
1961
+ { key: "times_awakened", displayName: "Times Awakened", category: "sleep", unit: "count", aggregation: "sum" }
1962
+ ];
1963
+ var VITAL_METRICS = [
1964
+ { key: "heart_rate", displayName: "Heart Rate", category: "vital", unit: "bpm", aggregation: "avg" },
1965
+ { key: "resting_heart_rate", displayName: "Resting Heart Rate", category: "vital", unit: "bpm", aggregation: "min" },
1966
+ { key: "heart_rate_variability", displayName: "Heart Rate Variability", category: "vital", unit: "ms", aggregation: "avg" },
1967
+ { key: "blood_pressure_systolic", displayName: "Blood Pressure (Systolic)", category: "vital", unit: "mmHg", aggregation: "last" },
1968
+ { key: "blood_pressure_diastolic", displayName: "Blood Pressure (Diastolic)", category: "vital", unit: "mmHg", aggregation: "last" },
1969
+ { key: "blood_glucose", displayName: "Blood Glucose", category: "vital", unit: "mg/dL", aggregation: "avg" },
1970
+ { key: "blood_oxygen", displayName: "Blood Oxygen", category: "vital", unit: "%", aggregation: "avg" },
1971
+ { key: "respiratory_rate", displayName: "Respiratory Rate", category: "vital", unit: "breaths/min", aggregation: "avg" },
1972
+ { key: "body_temperature", displayName: "Body Temperature", category: "vital", unit: "\xB0C", aggregation: "avg", imperialUnit: "\xB0F", imperialConversion: 1.8 }
1973
+ // Note: Fahrenheit conversion requires adding 32, handle separately
1974
+ ];
1975
+ var WELLNESS_METRICS = [
1976
+ { key: "mood", displayName: "Mood", category: "wellness", unit: "score", aggregation: "avg" },
1977
+ { key: "energy_level", displayName: "Energy Level", category: "wellness", unit: "score", aggregation: "avg" },
1978
+ { key: "stress_level", displayName: "Stress Level", category: "wellness", unit: "score", aggregation: "avg" }
1979
+ ];
1980
+ var ALL_METRICS = [
1981
+ ...BODY_METRICS,
1982
+ ...ACTIVITY_METRICS,
1983
+ ...SLEEP_METRICS,
1984
+ ...VITAL_METRICS,
1985
+ ...WELLNESS_METRICS
1986
+ ];
1987
+ function getMetricDefinition(key) {
1988
+ return ALL_METRICS.find((m) => m.key === key);
1989
+ }
1990
+ function getMetricsByCategory(category) {
1991
+ return ALL_METRICS.filter((m) => m.category === category);
1992
+ }
1993
+ // Annotate the CommonJS export names for ESM import in node:
1994
+ 0 && (module.exports = {
1995
+ ACTIVITY_METRICS,
1996
+ ALL_METRICS,
1997
+ AuthenticationError,
1998
+ AuthorizationError,
1999
+ BODY_METRICS,
2000
+ DistanceConverter,
2001
+ HeightConverter,
2002
+ NetworkError,
2003
+ NotFoundError,
2004
+ OpenLifeLog,
2005
+ OpenLifeLogError,
2006
+ PaginatedIterator,
2007
+ RateLimitError,
2008
+ SLEEP_METRICS,
2009
+ ServerError,
2010
+ TimeoutError,
2011
+ UnitConversionError,
2012
+ UnitConverter,
2013
+ VITAL_METRICS,
2014
+ ValidationError,
2015
+ WELLNESS_METRICS,
2016
+ WeightConverter,
2017
+ createPaginatedIterator,
2018
+ createUnitConverter,
2019
+ fetchAllPages,
2020
+ getMetricDefinition,
2021
+ getMetricsByCategory,
2022
+ hasMorePages
2023
+ });