@openlifelog/sdk 1.0.1 → 1.0.3
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/client.ts +6 -6
- package/dist/index.d.mts +13 -6
- package/dist/index.d.ts +13 -6
- package/dist/index.js +390 -20
- package/dist/index.mjs +390 -20
- package/package.json +1 -1
- package/resources/goals.ts +39 -4
- package/resources/metrics.ts +87 -4
- package/resources/programs.ts +44 -4
- package/resources/sessions.ts +59 -4
- package/resources/workouts.ts +54 -4
- package/types/exercise.ts +1 -1
- package/types/food.ts +2 -0
- package/utils/units.ts +357 -0
package/utils/units.ts
CHANGED
|
@@ -13,6 +13,8 @@ const METERS_TO_FEET = 3.28084;
|
|
|
13
13
|
const FEET_TO_METERS = 1 / METERS_TO_FEET;
|
|
14
14
|
const CM_TO_INCHES = 0.393701;
|
|
15
15
|
const INCHES_TO_CM = 1 / CM_TO_INCHES;
|
|
16
|
+
const ML_TO_FL_OZ = 0.033814;
|
|
17
|
+
const FL_OZ_TO_ML = 1 / ML_TO_FL_OZ;
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* Weight conversion
|
|
@@ -167,6 +169,45 @@ export class HeightConverter {
|
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Volume conversion
|
|
174
|
+
*/
|
|
175
|
+
export class VolumeConverter {
|
|
176
|
+
/**
|
|
177
|
+
* Convert milliliters to fluid ounces
|
|
178
|
+
*/
|
|
179
|
+
static mlToFlOz(ml: number): number {
|
|
180
|
+
return ml * ML_TO_FL_OZ;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Convert fluid ounces to milliliters
|
|
185
|
+
*/
|
|
186
|
+
static flOzToMl(flOz: number): number {
|
|
187
|
+
return flOz * FL_OZ_TO_ML;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Convert volume from metric to the target measurement system
|
|
192
|
+
*/
|
|
193
|
+
static fromMetric(ml: number, targetSystem: MeasurementSystem): number {
|
|
194
|
+
if (targetSystem === 'imperial') {
|
|
195
|
+
return this.mlToFlOz(ml);
|
|
196
|
+
}
|
|
197
|
+
return ml;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Convert volume to metric from the source measurement system
|
|
202
|
+
*/
|
|
203
|
+
static toMetric(value: number, sourceSystem: MeasurementSystem): number {
|
|
204
|
+
if (sourceSystem === 'imperial') {
|
|
205
|
+
return this.flOzToMl(value);
|
|
206
|
+
}
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
170
211
|
/**
|
|
171
212
|
* Generic unit converter that handles all conversions
|
|
172
213
|
*/
|
|
@@ -277,3 +318,319 @@ export class UnitConverter {
|
|
|
277
318
|
export function createUnitConverter(measurementSystem: MeasurementSystem = 'metric'): UnitConverter {
|
|
278
319
|
return new UnitConverter(measurementSystem);
|
|
279
320
|
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Deep conversion utilities for nested workout data structures
|
|
324
|
+
*/
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Convert a single SetData object from user units to metric (for API requests)
|
|
328
|
+
*/
|
|
329
|
+
export function convertSetDataToMetric(
|
|
330
|
+
setData: any,
|
|
331
|
+
measurementSystem: MeasurementSystem
|
|
332
|
+
): any {
|
|
333
|
+
if (!setData || typeof setData !== 'object') {
|
|
334
|
+
return setData;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const converted = { ...setData };
|
|
338
|
+
|
|
339
|
+
// Convert weight (lbs → kg)
|
|
340
|
+
if (converted.weight !== null && converted.weight !== undefined) {
|
|
341
|
+
converted.weight = WeightConverter.toMetric(converted.weight, measurementSystem);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Convert distance (feet/miles → meters)
|
|
345
|
+
if (converted.distance !== null && converted.distance !== undefined) {
|
|
346
|
+
// Determine if this is miles (cardio, longer distances) or feet based on value
|
|
347
|
+
// This is a heuristic: distances > 200 are likely in feet (for imperial), so treat as feet
|
|
348
|
+
// Distances <= 200 could be miles for cardio workouts
|
|
349
|
+
const isMiles = measurementSystem === 'imperial' && converted.distance <= 200;
|
|
350
|
+
converted.distance = DistanceConverter.toMetric(converted.distance, measurementSystem, isMiles);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return converted;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Convert a single SetData object from metric to user units (for API responses)
|
|
358
|
+
*/
|
|
359
|
+
export function convertSetDataFromMetric(
|
|
360
|
+
setData: any,
|
|
361
|
+
measurementSystem: MeasurementSystem
|
|
362
|
+
): any {
|
|
363
|
+
if (!setData || typeof setData !== 'object') {
|
|
364
|
+
return setData;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const converted = { ...setData };
|
|
368
|
+
|
|
369
|
+
// Convert weight (kg → lbs)
|
|
370
|
+
if (converted.weight !== null && converted.weight !== undefined) {
|
|
371
|
+
converted.weight = WeightConverter.fromMetric(converted.weight, measurementSystem);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Convert distance (meters → feet/miles)
|
|
375
|
+
if (converted.distance !== null && converted.distance !== undefined) {
|
|
376
|
+
// For imperial: convert to miles if > 1609 meters (1 mile), otherwise feet
|
|
377
|
+
const preferMiles = measurementSystem === 'imperial' && converted.distance > 1609;
|
|
378
|
+
converted.distance = DistanceConverter.fromMetric(converted.distance, measurementSystem, preferMiles);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return converted;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Convert an array of SetData objects to metric (for API requests)
|
|
386
|
+
*/
|
|
387
|
+
export function convertSetsDataToMetric(
|
|
388
|
+
setsData: any[] | null | undefined,
|
|
389
|
+
measurementSystem: MeasurementSystem
|
|
390
|
+
): any[] {
|
|
391
|
+
if (!setsData || !Array.isArray(setsData)) {
|
|
392
|
+
return setsData || [];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return setsData.map(setData => convertSetDataToMetric(setData, measurementSystem));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Convert an array of SetData objects from metric (for API responses)
|
|
400
|
+
*/
|
|
401
|
+
export function convertSetsDataFromMetric(
|
|
402
|
+
setsData: any[] | null | undefined,
|
|
403
|
+
measurementSystem: MeasurementSystem
|
|
404
|
+
): any[] {
|
|
405
|
+
if (!setsData || !Array.isArray(setsData)) {
|
|
406
|
+
return setsData || [];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return setsData.map(setData => convertSetDataFromMetric(setData, measurementSystem));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Deep convert workout data structure to metric (for API requests)
|
|
414
|
+
* Handles nested setsData arrays in various structures
|
|
415
|
+
*/
|
|
416
|
+
export function convertWorkoutDataToMetric(
|
|
417
|
+
data: any,
|
|
418
|
+
measurementSystem: MeasurementSystem
|
|
419
|
+
): any {
|
|
420
|
+
if (!data || typeof data !== 'object') {
|
|
421
|
+
return data;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Handle arrays
|
|
425
|
+
if (Array.isArray(data)) {
|
|
426
|
+
return data.map(item => convertWorkoutDataToMetric(item, measurementSystem));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
const converted = { ...data };
|
|
430
|
+
|
|
431
|
+
// Convert setsData arrays
|
|
432
|
+
if (converted.setsData && Array.isArray(converted.setsData)) {
|
|
433
|
+
converted.setsData = convertSetsDataToMetric(converted.setsData, measurementSystem);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Convert sets arrays (used in program schedules)
|
|
437
|
+
if (converted.sets && Array.isArray(converted.sets)) {
|
|
438
|
+
converted.sets = convertSetsDataToMetric(converted.sets, measurementSystem);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Convert exercises arrays (nested structures)
|
|
442
|
+
if (converted.exercises && Array.isArray(converted.exercises)) {
|
|
443
|
+
converted.exercises = converted.exercises.map((exercise: any) =>
|
|
444
|
+
convertWorkoutDataToMetric(exercise, measurementSystem)
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Convert schedule arrays (for programs)
|
|
449
|
+
if (converted.schedule && Array.isArray(converted.schedule)) {
|
|
450
|
+
converted.schedule = converted.schedule.map((day: any) =>
|
|
451
|
+
convertWorkoutDataToMetric(day, measurementSystem)
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Convert individual numeric fields at top level
|
|
456
|
+
if (converted.userBodyweight !== null && converted.userBodyweight !== undefined) {
|
|
457
|
+
converted.userBodyweight = WeightConverter.toMetric(converted.userBodyweight, measurementSystem);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (converted.totalVolume !== null && converted.totalVolume !== undefined) {
|
|
461
|
+
converted.totalVolume = WeightConverter.toMetric(converted.totalVolume, measurementSystem);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (converted.totalDistance !== null && converted.totalDistance !== undefined) {
|
|
465
|
+
const preferMiles = measurementSystem === 'imperial' && converted.totalDistance <= 200;
|
|
466
|
+
converted.totalDistance = DistanceConverter.toMetric(converted.totalDistance, measurementSystem, preferMiles);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return converted;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Deep convert workout data structure from metric (for API responses)
|
|
474
|
+
* Handles nested setsData arrays in various structures
|
|
475
|
+
*/
|
|
476
|
+
export function convertWorkoutDataFromMetric(
|
|
477
|
+
data: any,
|
|
478
|
+
measurementSystem: MeasurementSystem
|
|
479
|
+
): any {
|
|
480
|
+
if (!data || typeof data !== 'object') {
|
|
481
|
+
return data;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Handle arrays
|
|
485
|
+
if (Array.isArray(data)) {
|
|
486
|
+
return data.map(item => convertWorkoutDataFromMetric(item, measurementSystem));
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const converted = { ...data };
|
|
490
|
+
|
|
491
|
+
// Convert setsData arrays
|
|
492
|
+
if (converted.setsData && Array.isArray(converted.setsData)) {
|
|
493
|
+
converted.setsData = convertSetsDataFromMetric(converted.setsData, measurementSystem);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Convert sets arrays (used in program schedules)
|
|
497
|
+
if (converted.sets && Array.isArray(converted.sets)) {
|
|
498
|
+
converted.sets = convertSetsDataFromMetric(converted.sets, measurementSystem);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Convert exercises arrays (nested structures)
|
|
502
|
+
if (converted.exercises && Array.isArray(converted.exercises)) {
|
|
503
|
+
converted.exercises = converted.exercises.map((exercise: any) =>
|
|
504
|
+
convertWorkoutDataFromMetric(exercise, measurementSystem)
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Convert schedule arrays (for programs)
|
|
509
|
+
if (converted.schedule && Array.isArray(converted.schedule)) {
|
|
510
|
+
converted.schedule = converted.schedule.map((day: any) =>
|
|
511
|
+
convertWorkoutDataFromMetric(day, measurementSystem)
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Convert data arrays (for response lists)
|
|
516
|
+
if (converted.data && Array.isArray(converted.data)) {
|
|
517
|
+
converted.data = converted.data.map((item: any) =>
|
|
518
|
+
convertWorkoutDataFromMetric(item, measurementSystem)
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Convert individual numeric fields at top level
|
|
523
|
+
if (converted.userBodyweight !== null && converted.userBodyweight !== undefined) {
|
|
524
|
+
converted.userBodyweight = WeightConverter.fromMetric(converted.userBodyweight, measurementSystem);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (converted.totalVolume !== null && converted.totalVolume !== undefined) {
|
|
528
|
+
converted.totalVolume = WeightConverter.fromMetric(converted.totalVolume, measurementSystem);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (converted.totalDistance !== null && converted.totalDistance !== undefined) {
|
|
532
|
+
const preferMiles = measurementSystem === 'imperial' && converted.totalDistance > 1609;
|
|
533
|
+
converted.totalDistance = DistanceConverter.fromMetric(converted.totalDistance, measurementSystem, preferMiles);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Convert value field (for personal records)
|
|
537
|
+
if (converted.value !== null && converted.value !== undefined && converted.unit) {
|
|
538
|
+
// Detect unit type and convert accordingly
|
|
539
|
+
if (converted.unit === 'kg' || converted.unit === 'lbs') {
|
|
540
|
+
converted.value = WeightConverter.fromMetric(converted.value, measurementSystem);
|
|
541
|
+
converted.unit = measurementSystem === 'imperial' ? 'lbs' : 'kg';
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return converted;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Convert nutrition goals data structure to metric (for API requests)
|
|
550
|
+
* Handles water goals: ml ↔ fl oz
|
|
551
|
+
*/
|
|
552
|
+
export function convertNutritionGoalsToMetric(
|
|
553
|
+
data: any,
|
|
554
|
+
measurementSystem: MeasurementSystem
|
|
555
|
+
): any {
|
|
556
|
+
if (!data || typeof data !== 'object') {
|
|
557
|
+
return data;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const converted = { ...data };
|
|
561
|
+
|
|
562
|
+
// Convert goals object (contains water, protein, etc.)
|
|
563
|
+
if (converted.goals && typeof converted.goals === 'object') {
|
|
564
|
+
converted.goals = { ...converted.goals };
|
|
565
|
+
|
|
566
|
+
// Convert water goal values from fl oz → ml
|
|
567
|
+
if (converted.goals.water && typeof converted.goals.water === 'object') {
|
|
568
|
+
const waterGoal = { ...converted.goals.water };
|
|
569
|
+
|
|
570
|
+
if (waterGoal.value !== null && waterGoal.value !== undefined) {
|
|
571
|
+
waterGoal.value = VolumeConverter.toMetric(waterGoal.value, measurementSystem);
|
|
572
|
+
}
|
|
573
|
+
if (waterGoal.min !== null && waterGoal.min !== undefined) {
|
|
574
|
+
waterGoal.min = VolumeConverter.toMetric(waterGoal.min, measurementSystem);
|
|
575
|
+
}
|
|
576
|
+
if (waterGoal.max !== null && waterGoal.max !== undefined) {
|
|
577
|
+
waterGoal.max = VolumeConverter.toMetric(waterGoal.max, measurementSystem);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
converted.goals.water = waterGoal;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return converted;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Convert nutrition goals data structure from metric (for API responses)
|
|
589
|
+
* Handles water goals: ml ↔ fl oz
|
|
590
|
+
*/
|
|
591
|
+
export function convertNutritionGoalsFromMetric(
|
|
592
|
+
data: any,
|
|
593
|
+
measurementSystem: MeasurementSystem
|
|
594
|
+
): any {
|
|
595
|
+
if (!data || typeof data !== 'object') {
|
|
596
|
+
return data;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Handle arrays
|
|
600
|
+
if (Array.isArray(data)) {
|
|
601
|
+
return data.map(item => convertNutritionGoalsFromMetric(item, measurementSystem));
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const converted = { ...data };
|
|
605
|
+
|
|
606
|
+
// Convert data array (for list responses)
|
|
607
|
+
if (converted.data && Array.isArray(converted.data)) {
|
|
608
|
+
converted.data = converted.data.map((item: any) =>
|
|
609
|
+
convertNutritionGoalsFromMetric(item, measurementSystem)
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Convert goals object (contains water, protein, etc.)
|
|
614
|
+
if (converted.goals && typeof converted.goals === 'object') {
|
|
615
|
+
converted.goals = { ...converted.goals };
|
|
616
|
+
|
|
617
|
+
// Convert water goal values from ml → fl oz
|
|
618
|
+
if (converted.goals.water && typeof converted.goals.water === 'object') {
|
|
619
|
+
const waterGoal = { ...converted.goals.water };
|
|
620
|
+
|
|
621
|
+
if (waterGoal.value !== null && waterGoal.value !== undefined) {
|
|
622
|
+
waterGoal.value = VolumeConverter.fromMetric(waterGoal.value, measurementSystem);
|
|
623
|
+
}
|
|
624
|
+
if (waterGoal.min !== null && waterGoal.min !== undefined) {
|
|
625
|
+
waterGoal.min = VolumeConverter.fromMetric(waterGoal.min, measurementSystem);
|
|
626
|
+
}
|
|
627
|
+
if (waterGoal.max !== null && waterGoal.max !== undefined) {
|
|
628
|
+
waterGoal.max = VolumeConverter.fromMetric(waterGoal.max, measurementSystem);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
converted.goals.water = waterGoal;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return converted;
|
|
636
|
+
}
|