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