@nativesquare/soma 0.8.0 → 0.9.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/client/index.d.ts +7 -128
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +31 -112
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +80 -4
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +135 -261
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/garmin/private.d.ts +475 -0
- package/dist/component/garmin/private.d.ts.map +1 -0
- package/dist/component/garmin/private.js +1614 -0
- package/dist/component/garmin/private.js.map +1 -0
- package/dist/component/garmin/public.d.ts +155 -0
- package/dist/component/garmin/public.d.ts.map +1 -0
- package/dist/component/garmin/public.js +787 -0
- package/dist/component/garmin/public.js.map +1 -0
- package/dist/component/garmin/schemas/activity.d.ts +94 -0
- package/dist/component/garmin/schemas/activity.d.ts.map +1 -0
- package/dist/component/garmin/schemas/activity.js +27 -0
- package/dist/component/garmin/schemas/activity.js.map +1 -0
- package/dist/component/garmin/schemas/activityDetails.d.ts +146 -0
- package/dist/component/garmin/schemas/activityDetails.d.ts.map +1 -0
- package/dist/component/garmin/schemas/activityDetails.js +27 -0
- package/dist/component/garmin/schemas/activityDetails.js.map +1 -0
- package/dist/component/garmin/schemas/bloodPressure.d.ts +38 -0
- package/dist/component/garmin/schemas/bloodPressure.d.ts.map +1 -0
- package/dist/component/garmin/schemas/bloodPressure.js +27 -0
- package/dist/component/garmin/schemas/bloodPressure.js.map +1 -0
- package/dist/component/garmin/schemas/bodyCompositions.d.ts +42 -0
- package/dist/component/garmin/schemas/bodyCompositions.d.ts.map +1 -0
- package/dist/component/garmin/schemas/bodyCompositions.js +27 -0
- package/dist/component/garmin/schemas/bodyCompositions.js.map +1 -0
- package/dist/component/garmin/schemas/dailies.d.ts +98 -0
- package/dist/component/garmin/schemas/dailies.d.ts.map +1 -0
- package/dist/component/garmin/schemas/dailies.js +27 -0
- package/dist/component/garmin/schemas/dailies.js.map +1 -0
- package/dist/component/garmin/schemas/epochs.d.ts +54 -0
- package/dist/component/garmin/schemas/epochs.d.ts.map +1 -0
- package/dist/component/garmin/schemas/epochs.js +27 -0
- package/dist/component/garmin/schemas/epochs.js.map +1 -0
- package/dist/component/garmin/schemas/healthSnapshot.d.ts +48 -0
- package/dist/component/garmin/schemas/healthSnapshot.d.ts.map +1 -0
- package/dist/component/garmin/schemas/healthSnapshot.js +27 -0
- package/dist/component/garmin/schemas/healthSnapshot.js.map +1 -0
- package/dist/component/garmin/schemas/hrvSummary.d.ts +40 -0
- package/dist/component/garmin/schemas/hrvSummary.d.ts.map +1 -0
- package/dist/component/garmin/schemas/hrvSummary.js +27 -0
- package/dist/component/garmin/schemas/hrvSummary.js.map +1 -0
- package/dist/component/garmin/schemas/manuallyUpdatedActivities.d.ts +94 -0
- package/dist/component/garmin/schemas/manuallyUpdatedActivities.d.ts.map +1 -0
- package/dist/component/garmin/schemas/manuallyUpdatedActivities.js +27 -0
- package/dist/component/garmin/schemas/manuallyUpdatedActivities.js.map +1 -0
- package/dist/component/garmin/schemas/menstrualCycleTracking.d.ts +100 -0
- package/dist/component/garmin/schemas/menstrualCycleTracking.d.ts.map +1 -0
- package/dist/component/garmin/schemas/menstrualCycleTracking.js +28 -0
- package/dist/component/garmin/schemas/menstrualCycleTracking.js.map +1 -0
- package/dist/component/garmin/schemas/moveIQ.d.ts +40 -0
- package/dist/component/garmin/schemas/moveIQ.d.ts.map +1 -0
- package/dist/component/garmin/schemas/moveIQ.js +27 -0
- package/dist/component/garmin/schemas/moveIQ.js.map +1 -0
- package/dist/component/garmin/schemas/pulseOx.d.ts +38 -0
- package/dist/component/garmin/schemas/pulseOx.d.ts.map +1 -0
- package/dist/component/garmin/schemas/pulseOx.js +28 -0
- package/dist/component/garmin/schemas/pulseOx.js.map +1 -0
- package/dist/component/garmin/schemas/respiration.d.ts +34 -0
- package/dist/component/garmin/schemas/respiration.d.ts.map +1 -0
- package/dist/component/garmin/schemas/respiration.js +28 -0
- package/dist/component/garmin/schemas/respiration.js.map +1 -0
- package/dist/component/garmin/schemas/skinTemperature.d.ts +36 -0
- package/dist/component/garmin/schemas/skinTemperature.d.ts.map +1 -0
- package/dist/component/garmin/schemas/skinTemperature.js +28 -0
- package/dist/component/garmin/schemas/skinTemperature.js.map +1 -0
- package/dist/component/garmin/schemas/sleeps.d.ts +88 -0
- package/dist/component/garmin/schemas/sleeps.d.ts.map +1 -0
- package/dist/component/garmin/schemas/sleeps.js +27 -0
- package/dist/component/garmin/schemas/sleeps.js.map +1 -0
- package/dist/component/garmin/schemas/stress.d.ts +70 -0
- package/dist/component/garmin/schemas/stress.d.ts.map +1 -0
- package/dist/component/garmin/schemas/stress.js +28 -0
- package/dist/component/garmin/schemas/stress.js.map +1 -0
- package/dist/component/garmin/schemas/userMetrics.d.ts +36 -0
- package/dist/component/garmin/schemas/userMetrics.d.ts.map +1 -0
- package/dist/component/garmin/schemas/userMetrics.js +28 -0
- package/dist/component/garmin/schemas/userMetrics.js.map +1 -0
- package/dist/component/garmin/transform/activity.d.ts +13 -0
- package/dist/component/garmin/transform/activity.d.ts.map +1 -0
- package/dist/component/garmin/transform/activity.js +111 -0
- package/dist/component/garmin/transform/activity.js.map +1 -0
- package/dist/component/garmin/transform/activityDetails.d.ts +13 -0
- package/dist/component/garmin/transform/activityDetails.d.ts.map +1 -0
- package/dist/component/garmin/transform/activityDetails.js +173 -0
- package/dist/component/garmin/transform/activityDetails.js.map +1 -0
- package/dist/component/garmin/transform/bloodPressure.d.ts +12 -0
- package/dist/component/garmin/transform/bloodPressure.d.ts.map +1 -0
- package/dist/component/garmin/transform/bloodPressure.js +33 -0
- package/dist/component/garmin/transform/bloodPressure.js.map +1 -0
- package/dist/component/garmin/transform/bodyCompositions.d.ts +12 -0
- package/dist/component/garmin/transform/bodyCompositions.d.ts.map +1 -0
- package/dist/component/garmin/transform/bodyCompositions.js +42 -0
- package/dist/component/garmin/transform/bodyCompositions.js.map +1 -0
- package/dist/component/garmin/transform/dailies.d.ts +12 -0
- package/dist/component/garmin/transform/dailies.d.ts.map +1 -0
- package/dist/component/garmin/transform/dailies.js +132 -0
- package/dist/component/garmin/transform/dailies.js.map +1 -0
- package/dist/component/garmin/transform/epochs.d.ts +13 -0
- package/dist/component/garmin/transform/epochs.d.ts.map +1 -0
- package/dist/component/garmin/transform/epochs.js +76 -0
- package/dist/component/garmin/transform/epochs.js.map +1 -0
- package/dist/component/garmin/transform/healthSnapshot.d.ts +12 -0
- package/dist/component/garmin/transform/healthSnapshot.d.ts.map +1 -0
- package/dist/component/garmin/transform/healthSnapshot.js +111 -0
- package/dist/component/garmin/transform/healthSnapshot.js.map +1 -0
- package/dist/component/garmin/transform/hrvSummary.d.ts +12 -0
- package/dist/component/garmin/transform/hrvSummary.d.ts.map +1 -0
- package/dist/component/garmin/transform/hrvSummary.js +45 -0
- package/dist/component/garmin/transform/hrvSummary.js.map +1 -0
- package/dist/component/garmin/transform/manuallyUpdatedActivities.d.ts +11 -0
- package/dist/component/garmin/transform/manuallyUpdatedActivities.d.ts.map +1 -0
- package/dist/component/garmin/transform/manuallyUpdatedActivities.js +20 -0
- package/dist/component/garmin/transform/manuallyUpdatedActivities.js.map +1 -0
- package/dist/component/garmin/transform/menstrualCycleTracking.d.ts +10 -0
- package/dist/component/garmin/transform/menstrualCycleTracking.d.ts.map +1 -0
- package/dist/component/garmin/transform/menstrualCycleTracking.js +43 -0
- package/dist/component/garmin/transform/menstrualCycleTracking.js.map +1 -0
- package/dist/component/garmin/transform/moveIQ.d.ts +17 -0
- package/dist/component/garmin/transform/moveIQ.d.ts.map +1 -0
- package/dist/component/garmin/transform/moveIQ.js +41 -0
- package/dist/component/garmin/transform/moveIQ.js.map +1 -0
- package/dist/component/garmin/transform/pulseOx.d.ts +12 -0
- package/dist/component/garmin/transform/pulseOx.d.ts.map +1 -0
- package/dist/component/garmin/transform/pulseOx.js +46 -0
- package/dist/component/garmin/transform/pulseOx.js.map +1 -0
- package/dist/component/garmin/transform/respiration.d.ts +12 -0
- package/dist/component/garmin/transform/respiration.d.ts.map +1 -0
- package/dist/component/garmin/transform/respiration.js +54 -0
- package/dist/component/garmin/transform/respiration.js.map +1 -0
- package/dist/component/garmin/transform/skinTemperature.d.ts +12 -0
- package/dist/component/garmin/transform/skinTemperature.d.ts.map +1 -0
- package/dist/component/garmin/transform/skinTemperature.js +38 -0
- package/dist/component/garmin/transform/skinTemperature.js.map +1 -0
- package/dist/component/garmin/transform/sleeps.d.ts +55 -0
- package/dist/component/garmin/transform/sleeps.d.ts.map +1 -0
- package/dist/component/garmin/transform/sleeps.js +120 -0
- package/dist/component/garmin/transform/sleeps.js.map +1 -0
- package/dist/component/garmin/transform/stress.d.ts +12 -0
- package/dist/component/garmin/transform/stress.d.ts.map +1 -0
- package/dist/component/garmin/transform/stress.js +56 -0
- package/dist/component/garmin/transform/stress.js.map +1 -0
- package/dist/component/garmin/transform/userMetrics.d.ts +12 -0
- package/dist/component/garmin/transform/userMetrics.d.ts.map +1 -0
- package/dist/component/garmin/transform/userMetrics.js +48 -0
- package/dist/component/garmin/transform/userMetrics.js.map +1 -0
- package/dist/component/garmin/types/garmin.d.ts +21 -0
- package/dist/component/garmin/types/garmin.d.ts.map +1 -0
- package/dist/component/garmin/types/garmin.js +6 -0
- package/dist/component/garmin/types/garmin.js.map +1 -0
- package/dist/component/garmin/types/zod/zod.gen.d.ts +1319 -0
- package/dist/component/garmin/types/zod/zod.gen.d.ts.map +1 -0
- package/dist/component/garmin/types/zod/zod.gen.js +784 -0
- package/dist/component/garmin/types/zod/zod.gen.js.map +1 -0
- package/dist/component/garmin/webhooks.d.ts +141 -0
- package/dist/component/garmin/webhooks.d.ts.map +1 -0
- package/dist/component/garmin/webhooks.js +766 -0
- package/dist/component/garmin/webhooks.js.map +1 -0
- package/dist/component/private.d.ts +4 -4
- package/dist/component/public.d.ts +333 -333
- package/dist/component/schema.d.ts +133 -133
- package/dist/component/strava/private.d.ts +30 -0
- package/dist/component/strava/private.d.ts.map +1 -0
- package/dist/component/strava/private.js +71 -0
- package/dist/component/strava/private.js.map +1 -0
- package/dist/component/{strava.d.ts → strava/public.d.ts} +3 -31
- package/dist/component/strava/public.d.ts.map +1 -0
- package/dist/component/{strava.js → strava/public.js} +22 -101
- package/dist/component/strava/public.js.map +1 -0
- package/dist/component/validators/activity.d.ts +6 -0
- package/dist/component/validators/activity.d.ts.map +1 -1
- package/dist/component/validators/activity.js.map +1 -1
- package/dist/component/validators/body.d.ts +20 -14
- package/dist/component/validators/body.d.ts.map +1 -1
- package/dist/component/validators/body.js.map +1 -1
- package/dist/component/validators/daily.d.ts +6 -0
- package/dist/component/validators/daily.d.ts.map +1 -1
- package/dist/component/validators/daily.js.map +1 -1
- package/dist/component/validators/enums.d.ts +1 -1
- package/dist/component/validators/menstruation.d.ts +5 -0
- package/dist/component/validators/menstruation.d.ts.map +1 -1
- package/dist/component/validators/menstruation.js.map +1 -1
- package/dist/garmin/client.js.map +1 -1
- package/dist/garmin/index.d.ts +0 -2
- package/dist/garmin/index.d.ts.map +1 -1
- package/dist/garmin/index.js +0 -1
- package/dist/garmin/index.js.map +1 -1
- package/dist/garmin/sync.d.ts.map +1 -1
- package/dist/garmin/sync.js +3 -2
- package/dist/garmin/sync.js.map +1 -1
- package/dist/garmin/types.d.ts +1 -1
- package/dist/garmin/types.d.ts.map +1 -1
- package/dist/validators.d.ts +31 -28
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +2 -2
- package/dist/validators.js.map +1 -1
- package/package.json +4 -7
- package/src/client/index.ts +41 -172
- package/src/component/_generated/api.ts +96 -4
- package/src/component/_generated/component.ts +252 -284
- package/src/{garmin → component/garmin}/auth.ts +8 -1
- package/src/component/garmin/client.ts +39 -0
- package/src/component/garmin/private.ts +1798 -0
- package/src/component/garmin/public.ts +938 -0
- package/src/component/garmin/schemas/activity.ts +40 -0
- package/src/component/garmin/schemas/activityDetails.ts +45 -0
- package/src/component/garmin/schemas/bloodPressure.ts +38 -0
- package/src/component/garmin/schemas/bodyCompositions.ts +38 -0
- package/src/component/garmin/schemas/dailies.ts +38 -0
- package/src/component/garmin/schemas/epochs.ts +38 -0
- package/src/component/garmin/schemas/healthSnapshot.ts +38 -0
- package/src/component/garmin/schemas/hrvSummary.ts +38 -0
- package/src/component/garmin/schemas/manuallyUpdatedActivities.ts +49 -0
- package/src/component/garmin/schemas/menstrualCycleTracking.ts +39 -0
- package/src/component/garmin/schemas/moveIQ.ts +38 -0
- package/src/component/garmin/schemas/pulseOx.ts +39 -0
- package/src/component/garmin/schemas/respiration.ts +39 -0
- package/src/component/garmin/schemas/skinTemperature.ts +39 -0
- package/src/component/garmin/schemas/sleeps.ts +38 -0
- package/src/component/garmin/schemas/stress.ts +43 -0
- package/src/component/garmin/schemas/userMetrics.ts +39 -0
- package/src/component/garmin/transform/activity.ts +143 -0
- package/src/component/garmin/transform/activityDetails.ts +236 -0
- package/src/{garmin → component/garmin/transform}/bloodPressure.ts +39 -41
- package/src/component/garmin/transform/bodyCompositions.ts +51 -0
- package/src/component/garmin/transform/dailies.ts +179 -0
- package/src/component/garmin/transform/epochs.ts +94 -0
- package/src/component/garmin/transform/healthSnapshot.ts +152 -0
- package/src/component/garmin/transform/hrvSummary.ts +56 -0
- package/src/component/garmin/transform/manuallyUpdatedActivities.ts +27 -0
- package/src/{garmin/maps/activity-type.ts → component/garmin/transform/maps/activityType.ts} +116 -116
- package/src/{garmin/maps/sleep-level.ts → component/garmin/transform/maps/sleepLevel.ts} +22 -22
- package/src/component/garmin/transform/menstrualCycleTracking.ts +48 -0
- package/src/component/garmin/transform/moveIQ.ts +48 -0
- package/src/{garmin → component/garmin/transform}/plannedWorkout.ts +328 -333
- package/src/component/garmin/transform/pulseOx.ts +64 -0
- package/src/component/garmin/transform/respiration.ts +73 -0
- package/src/component/garmin/transform/skinTemperature.ts +44 -0
- package/src/component/garmin/transform/sleeps.ts +159 -0
- package/src/component/garmin/transform/stress.ts +78 -0
- package/src/component/garmin/transform/userMetrics.ts +56 -0
- package/src/component/garmin/types/specs/training-api-workouts.json +699 -0
- package/src/component/garmin/types/trainingApiWorkouts/client/client.gen.ts +290 -0
- package/src/component/garmin/types/trainingApiWorkouts/client/index.ts +25 -0
- package/src/component/garmin/types/trainingApiWorkouts/client/types.gen.ts +214 -0
- package/src/component/garmin/types/trainingApiWorkouts/client/utils.gen.ts +316 -0
- package/src/component/garmin/types/trainingApiWorkouts/client.gen.ts +16 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/auth.gen.ts +41 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/bodySerializer.gen.ts +82 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/params.gen.ts +169 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/pathSerializer.gen.ts +171 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/queryKeySerializer.gen.ts +117 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/serverSentEvents.gen.ts +243 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/types.gen.ts +104 -0
- package/src/component/garmin/types/trainingApiWorkouts/core/utils.gen.ts +140 -0
- package/src/component/garmin/types/trainingApiWorkouts/index.ts +4 -0
- package/src/component/garmin/types/trainingApiWorkouts/sdk.gen.ts +126 -0
- package/src/component/garmin/types/trainingApiWorkouts/types.gen.ts +387 -0
- package/src/component/garmin/types/trainingApiWorkouts/zod.gen.ts +423 -0
- package/src/component/garmin/types/wellnessApi/client/client.gen.ts +290 -0
- package/src/component/garmin/types/wellnessApi/client/index.ts +25 -0
- package/src/component/garmin/types/wellnessApi/client/types.gen.ts +214 -0
- package/src/component/garmin/types/wellnessApi/client/utils.gen.ts +316 -0
- package/src/component/garmin/types/wellnessApi/client.gen.ts +16 -0
- package/src/component/garmin/types/wellnessApi/core/auth.gen.ts +41 -0
- package/src/component/garmin/types/wellnessApi/core/bodySerializer.gen.ts +82 -0
- package/src/component/garmin/types/wellnessApi/core/params.gen.ts +169 -0
- package/src/component/garmin/types/wellnessApi/core/pathSerializer.gen.ts +171 -0
- package/src/component/garmin/types/wellnessApi/core/queryKeySerializer.gen.ts +117 -0
- package/src/component/garmin/types/wellnessApi/core/serverSentEvents.gen.ts +243 -0
- package/src/component/garmin/types/wellnessApi/core/types.gen.ts +104 -0
- package/src/component/garmin/types/wellnessApi/core/utils.gen.ts +140 -0
- package/src/component/garmin/types/wellnessApi/index.ts +4 -0
- package/src/component/garmin/types/wellnessApi/sdk.gen.ts +207 -0
- package/src/component/garmin/types/wellnessApi/types.gen.ts +2942 -0
- package/src/component/garmin/types/wellnessApi/zod.gen.ts +878 -0
- package/src/component/garmin/utils.ts +25 -0
- package/src/component/garmin/webhooks.ts +852 -0
- package/src/component/strava/private.ts +89 -0
- package/src/component/{strava.ts → strava/public.ts} +341 -404
- package/src/component/validators/activity.ts +5 -0
- package/src/component/validators/body.ts +5 -0
- package/src/component/validators/daily.ts +5 -0
- package/src/component/validators/menstruation.ts +5 -1
- package/src/component/validators/plannedWorkout.ts +5 -0
- package/src/validators.ts +12 -2
- package/dist/component/garmin.d.ts +0 -366
- package/dist/component/garmin.d.ts.map +0 -1
- package/dist/component/garmin.js +0 -1481
- package/dist/component/garmin.js.map +0 -1
- package/dist/component/strava.d.ts.map +0 -1
- package/dist/component/strava.js.map +0 -1
- package/dist/garmin/activity.d.ts +0 -92
- package/dist/garmin/activity.d.ts.map +0 -1
- package/dist/garmin/activity.js +0 -201
- package/dist/garmin/activity.js.map +0 -1
- package/src/component/garmin.ts +0 -1722
- package/src/garmin/activity.test.ts +0 -170
- package/src/garmin/activity.ts +0 -265
- package/src/garmin/auth.test.ts +0 -103
- package/src/garmin/body.ts +0 -59
- package/src/garmin/client.ts +0 -886
- package/src/garmin/daily.ts +0 -215
- package/src/garmin/hrv.ts +0 -57
- package/src/garmin/index.ts +0 -145
- package/src/garmin/maps/activity-type.test.ts +0 -78
- package/src/garmin/menstruation.ts +0 -44
- package/src/garmin/pulseOx.ts +0 -45
- package/src/garmin/respiration.ts +0 -55
- package/src/garmin/skinTemp.ts +0 -42
- package/src/garmin/sleep.test.ts +0 -109
- package/src/garmin/sleep.ts +0 -176
- package/src/garmin/stressDetails.ts +0 -71
- package/src/garmin/sync.ts +0 -566
- package/src/garmin/types.ts +0 -268
- package/src/garmin/userMetrics.ts +0 -50
- package/src/garmin/wellness-api.d.ts +0 -5637
- /package/src/{garmin/spec → component/garmin/types/specs}/wellness-api.json +0 -0
package/src/garmin/daily.ts
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
// ─── Daily Transformer ───────────────────────────────────────────────────────
|
|
2
|
-
// Transforms a Garmin daily wellness summary into the Soma Daily schema shape.
|
|
3
|
-
|
|
4
|
-
import type { GarminDailySummary } from "./types.js";
|
|
5
|
-
|
|
6
|
-
// GarminDailySummary is an alias for GarminDailyExtended which includes
|
|
7
|
-
// both spec fields and additional fields the API returns (stress time-series,
|
|
8
|
-
// SpO2, body battery, respiration).
|
|
9
|
-
|
|
10
|
-
export type DailyData = ReturnType<typeof transformDaily>;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Transform a Garmin daily summary into a Soma Daily document shape.
|
|
14
|
-
*
|
|
15
|
-
* @param daily - The Garmin daily summary from the Health API
|
|
16
|
-
* @returns Soma Daily fields (without connectionId/userId)
|
|
17
|
-
*/
|
|
18
|
-
export function transformDaily(daily: GarminDailySummary) {
|
|
19
|
-
const startMs = (daily.startTimeInSeconds ?? 0) * 1000;
|
|
20
|
-
const endMs = startMs + (daily.durationInSeconds ?? 0) * 1000;
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
metadata: {
|
|
24
|
-
start_time: new Date(startMs).toISOString(),
|
|
25
|
-
end_time: new Date(endMs).toISOString(),
|
|
26
|
-
upload_type: 1, // Automatic
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
active_durations_data: buildActiveDurationsData(daily),
|
|
30
|
-
|
|
31
|
-
calories_data: buildCaloriesData(daily),
|
|
32
|
-
|
|
33
|
-
distance_data: buildDistanceData(daily),
|
|
34
|
-
|
|
35
|
-
heart_rate_data: buildHeartRateData(daily),
|
|
36
|
-
|
|
37
|
-
oxygen_data: buildOxygenData(daily),
|
|
38
|
-
|
|
39
|
-
stress_data: buildStressData(daily),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
function buildActiveDurationsData(daily: GarminDailySummary) {
|
|
46
|
-
if (
|
|
47
|
-
daily.activeTimeInSeconds == null &&
|
|
48
|
-
daily.moderateIntensityDurationInSeconds == null &&
|
|
49
|
-
daily.vigorousIntensityDurationInSeconds == null
|
|
50
|
-
) {
|
|
51
|
-
return undefined;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
activity_seconds: daily.activeTimeInSeconds,
|
|
56
|
-
moderate_intensity_seconds: daily.moderateIntensityDurationInSeconds,
|
|
57
|
-
vigorous_intensity_seconds: daily.vigorousIntensityDurationInSeconds,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function buildCaloriesData(daily: GarminDailySummary) {
|
|
62
|
-
if (daily.activeKilocalories == null && daily.bmrKilocalories == null) {
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const total =
|
|
67
|
-
(daily.activeKilocalories ?? 0) + (daily.bmrKilocalories ?? 0);
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
net_activity_calories: daily.activeKilocalories,
|
|
71
|
-
BMR_calories: daily.bmrKilocalories,
|
|
72
|
-
total_burned_calories: total || undefined,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function buildDistanceData(daily: GarminDailySummary) {
|
|
77
|
-
if (
|
|
78
|
-
daily.distanceInMeters == null &&
|
|
79
|
-
daily.steps == null &&
|
|
80
|
-
daily.floorsClimbed == null
|
|
81
|
-
) {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
distance_meters: daily.distanceInMeters,
|
|
87
|
-
steps: daily.steps,
|
|
88
|
-
floors_climbed: daily.floorsClimbed,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function buildHeartRateData(daily: GarminDailySummary) {
|
|
93
|
-
const hasSummary =
|
|
94
|
-
daily.averageHeartRateInBeatsPerMinute != null ||
|
|
95
|
-
daily.maxHeartRateInBeatsPerMinute != null ||
|
|
96
|
-
daily.restingHeartRateInBeatsPerMinute != null;
|
|
97
|
-
const hasSamples =
|
|
98
|
-
daily.timeOffsetHeartRateSamples != null &&
|
|
99
|
-
Object.keys(daily.timeOffsetHeartRateSamples).length > 0;
|
|
100
|
-
|
|
101
|
-
if (!hasSummary && !hasSamples) return undefined;
|
|
102
|
-
|
|
103
|
-
const hrSamples = hasSamples
|
|
104
|
-
? buildTimeOffsetSamples(
|
|
105
|
-
daily.startTimeInSeconds,
|
|
106
|
-
daily.timeOffsetHeartRateSamples!,
|
|
107
|
-
(bpm) => ({ bpm }),
|
|
108
|
-
)
|
|
109
|
-
: undefined;
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
summary: hasSummary
|
|
113
|
-
? {
|
|
114
|
-
avg_hr_bpm: daily.averageHeartRateInBeatsPerMinute,
|
|
115
|
-
max_hr_bpm: daily.maxHeartRateInBeatsPerMinute,
|
|
116
|
-
min_hr_bpm: daily.minHeartRateInBeatsPerMinute,
|
|
117
|
-
resting_hr_bpm: daily.restingHeartRateInBeatsPerMinute,
|
|
118
|
-
}
|
|
119
|
-
: undefined,
|
|
120
|
-
detailed:
|
|
121
|
-
hrSamples && hrSamples.length > 0
|
|
122
|
-
? { hr_samples: hrSamples }
|
|
123
|
-
: undefined,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function buildOxygenData(daily: GarminDailySummary) {
|
|
128
|
-
if (daily.averageSpo2Value == null && daily.timeOffsetSpo2Values == null) {
|
|
129
|
-
return undefined;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const samples =
|
|
133
|
-
daily.timeOffsetSpo2Values != null
|
|
134
|
-
? buildTimeOffsetSamples(
|
|
135
|
-
daily.startTimeInSeconds,
|
|
136
|
-
daily.timeOffsetSpo2Values,
|
|
137
|
-
(pct) => ({ percentage: pct }),
|
|
138
|
-
)
|
|
139
|
-
: undefined;
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
avg_saturation_percentage: daily.averageSpo2Value,
|
|
143
|
-
saturation_samples:
|
|
144
|
-
samples && samples.length > 0 ? samples : undefined,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function buildStressData(daily: GarminDailySummary) {
|
|
149
|
-
const hasStress =
|
|
150
|
-
daily.averageStressLevel != null ||
|
|
151
|
-
daily.maxStressLevel != null ||
|
|
152
|
-
daily.stressDurationInSeconds != null;
|
|
153
|
-
const hasStressSamples =
|
|
154
|
-
daily.timeOffsetStressLevelValues != null &&
|
|
155
|
-
Object.keys(daily.timeOffsetStressLevelValues).length > 0;
|
|
156
|
-
const hasBodyBatterySamples =
|
|
157
|
-
daily.timeOffsetBodyBatteryValues != null &&
|
|
158
|
-
Object.keys(daily.timeOffsetBodyBatteryValues).length > 0;
|
|
159
|
-
|
|
160
|
-
if (!hasStress && !hasStressSamples && !hasBodyBatterySamples) {
|
|
161
|
-
return undefined;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const stressSamples = hasStressSamples
|
|
165
|
-
? buildTimeOffsetSamples(
|
|
166
|
-
daily.startTimeInSeconds,
|
|
167
|
-
daily.timeOffsetStressLevelValues!,
|
|
168
|
-
(level) => ({ level }),
|
|
169
|
-
)
|
|
170
|
-
: undefined;
|
|
171
|
-
|
|
172
|
-
const bodyBatterySamples = hasBodyBatterySamples
|
|
173
|
-
? buildTimeOffsetSamples(
|
|
174
|
-
daily.startTimeInSeconds,
|
|
175
|
-
daily.timeOffsetBodyBatteryValues!,
|
|
176
|
-
(level) => ({ level }),
|
|
177
|
-
)
|
|
178
|
-
: undefined;
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
avg_stress_level: daily.averageStressLevel,
|
|
182
|
-
max_stress_level: daily.maxStressLevel,
|
|
183
|
-
stress_duration_seconds: daily.stressDurationInSeconds,
|
|
184
|
-
rest_stress_duration_seconds: daily.restStressDurationInSeconds,
|
|
185
|
-
activity_stress_duration_seconds: daily.activityStressDurationInSeconds,
|
|
186
|
-
low_stress_duration_seconds: daily.lowStressDurationInSeconds,
|
|
187
|
-
medium_stress_duration_seconds: daily.mediumStressDurationInSeconds,
|
|
188
|
-
high_stress_duration_seconds: daily.highStressDurationInSeconds,
|
|
189
|
-
samples:
|
|
190
|
-
stressSamples && stressSamples.length > 0 ? stressSamples : undefined,
|
|
191
|
-
body_battery_samples:
|
|
192
|
-
bodyBatterySamples && bodyBatterySamples.length > 0
|
|
193
|
-
? bodyBatterySamples
|
|
194
|
-
: undefined,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Convert Garmin offset-keyed time-series data into timestamped samples.
|
|
200
|
-
*
|
|
201
|
-
* Garmin sends time-series as `{ [offsetSeconds]: value }` maps.
|
|
202
|
-
* This converts to `{ timestamp: ISO-8601, ...fields }[]`.
|
|
203
|
-
*/
|
|
204
|
-
function buildTimeOffsetSamples<T extends Record<string, unknown>>(
|
|
205
|
-
startTimeInSeconds: number | undefined,
|
|
206
|
-
offsets: Record<string, number>,
|
|
207
|
-
mapValue: (value: number) => T,
|
|
208
|
-
): Array<{ timestamp: string } & T> {
|
|
209
|
-
return Object.entries(offsets).map(([offset, value]) => ({
|
|
210
|
-
timestamp: new Date(
|
|
211
|
-
((startTimeInSeconds ?? 0) + parseInt(offset, 10)) * 1000,
|
|
212
|
-
).toISOString(),
|
|
213
|
-
...mapValue(value),
|
|
214
|
-
}));
|
|
215
|
-
}
|
package/src/garmin/hrv.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// ─── HRV Transformer ─────────────────────────────────────────────────────────
|
|
2
|
-
// Transforms Garmin HRV summary data into fields that enrich a Soma Daily record.
|
|
3
|
-
|
|
4
|
-
import type { GarminHRVSummary } from "./types.js";
|
|
5
|
-
|
|
6
|
-
export type HRVData = ReturnType<typeof transformHRV>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Transform a Garmin HRV summary into heart rate data fields for a Soma Daily.
|
|
10
|
-
*
|
|
11
|
-
* This produces a partial daily shape that can be merged into a matching
|
|
12
|
-
* daily record by date.
|
|
13
|
-
*
|
|
14
|
-
* @param hrv - The Garmin HRV summary from the Health API
|
|
15
|
-
* @returns Partial Soma Daily heart_rate_data fields
|
|
16
|
-
*/
|
|
17
|
-
export function transformHRV(hrv: GarminHRVSummary) {
|
|
18
|
-
const startMs = (hrv.startTimeInSeconds ?? 0) * 1000;
|
|
19
|
-
const endMs = startMs + (hrv.durationInSeconds ?? 0) * 1000;
|
|
20
|
-
|
|
21
|
-
const hasSummary = hrv.lastNightAvg != null || hrv.lastNight5MinHigh != null;
|
|
22
|
-
const hasSamples =
|
|
23
|
-
hrv.hrvValues != null && Object.keys(hrv.hrvValues).length > 0;
|
|
24
|
-
|
|
25
|
-
if (!hasSummary && !hasSamples) {
|
|
26
|
-
return {
|
|
27
|
-
calendar_date: hrv.calendarDate,
|
|
28
|
-
heart_rate_data: undefined,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const startTime = hrv.startTimeInSeconds ?? 0;
|
|
33
|
-
const hrvSamples = hasSamples
|
|
34
|
-
? Object.entries(hrv.hrvValues!).map(([offset, rmssd]) => ({
|
|
35
|
-
timestamp: new Date(
|
|
36
|
-
(startTime + parseInt(offset, 10)) * 1000,
|
|
37
|
-
).toISOString(),
|
|
38
|
-
hrv_rmssd: rmssd,
|
|
39
|
-
}))
|
|
40
|
-
: undefined;
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
calendar_date: hrv.calendarDate,
|
|
44
|
-
heart_rate_data: {
|
|
45
|
-
summary: hasSummary
|
|
46
|
-
? {
|
|
47
|
-
avg_hrv_rmssd: hrv.lastNightAvg,
|
|
48
|
-
max_hrv_rmssd: hrv.lastNight5MinHigh,
|
|
49
|
-
}
|
|
50
|
-
: undefined,
|
|
51
|
-
detailed:
|
|
52
|
-
hrvSamples && hrvSamples.length > 0
|
|
53
|
-
? { hrv_samples_rmssd: hrvSamples }
|
|
54
|
-
: undefined,
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
}
|
package/src/garmin/index.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// ─── @nativesquare/soma/garmin ───────────────────────────────────────────────
|
|
2
|
-
// Garmin Health API → Soma schema transformers, API client, OAuth 2.0 PKCE helpers, and sync.
|
|
3
|
-
//
|
|
4
|
-
// Uses the Web Crypto API for PKCE code challenge generation.
|
|
5
|
-
// Compatible with both the Convex V8 runtime and Node.js environments.
|
|
6
|
-
|
|
7
|
-
// ── Transformers ─────────────────────────────────────────────────────────────
|
|
8
|
-
export { transformActivity } from "./activity.js";
|
|
9
|
-
export type { ActivityData } from "./activity.js";
|
|
10
|
-
|
|
11
|
-
export { transformDaily } from "./daily.js";
|
|
12
|
-
export type { DailyData } from "./daily.js";
|
|
13
|
-
|
|
14
|
-
export { transformSleep } from "./sleep.js";
|
|
15
|
-
export type { SleepData } from "./sleep.js";
|
|
16
|
-
|
|
17
|
-
export { transformBody } from "./body.js";
|
|
18
|
-
export type { BodyData } from "./body.js";
|
|
19
|
-
|
|
20
|
-
export { transformMenstruation } from "./menstruation.js";
|
|
21
|
-
export type { MenstruationData } from "./menstruation.js";
|
|
22
|
-
|
|
23
|
-
export { transformBloodPressure } from "./bloodPressure.js";
|
|
24
|
-
export type { BloodPressureData } from "./bloodPressure.js";
|
|
25
|
-
|
|
26
|
-
export { transformSkinTemp } from "./skinTemp.js";
|
|
27
|
-
export type { SkinTempData } from "./skinTemp.js";
|
|
28
|
-
|
|
29
|
-
export { transformUserMetrics } from "./userMetrics.js";
|
|
30
|
-
export type { UserMetricsData } from "./userMetrics.js";
|
|
31
|
-
|
|
32
|
-
export { transformHRV } from "./hrv.js";
|
|
33
|
-
export type { HRVData } from "./hrv.js";
|
|
34
|
-
|
|
35
|
-
export { transformStressDetails } from "./stressDetails.js";
|
|
36
|
-
export type { StressDetailsData } from "./stressDetails.js";
|
|
37
|
-
|
|
38
|
-
export { transformPulseOx } from "./pulseOx.js";
|
|
39
|
-
export type { PulseOxData } from "./pulseOx.js";
|
|
40
|
-
|
|
41
|
-
export { transformRespiration } from "./respiration.js";
|
|
42
|
-
export type { RespirationData } from "./respiration.js";
|
|
43
|
-
|
|
44
|
-
// ── Enum Maps ────────────────────────────────────────────────────────────────
|
|
45
|
-
export { mapActivityType } from "./maps/activity-type.js";
|
|
46
|
-
export { mapSleepLevel } from "./maps/sleep-level.js";
|
|
47
|
-
|
|
48
|
-
// ── API Client ───────────────────────────────────────────────────────────────
|
|
49
|
-
export { GarminClient, GarminApiError } from "./client.js";
|
|
50
|
-
export type { GarminClientOptions, TimeRangeParams } from "./client.js";
|
|
51
|
-
|
|
52
|
-
// ── OAuth 2.0 PKCE Helpers ───────────────────────────────────────────────────
|
|
53
|
-
export {
|
|
54
|
-
generateCodeVerifier,
|
|
55
|
-
generateCodeChallenge,
|
|
56
|
-
generateState,
|
|
57
|
-
buildAuthUrl,
|
|
58
|
-
exchangeCode,
|
|
59
|
-
refreshToken,
|
|
60
|
-
} from "./auth.js";
|
|
61
|
-
export type {
|
|
62
|
-
BuildAuthUrlOptions,
|
|
63
|
-
ExchangeCodeOptions,
|
|
64
|
-
RefreshTokenOptions,
|
|
65
|
-
} from "./auth.js";
|
|
66
|
-
|
|
67
|
-
// ── Sync Helpers ─────────────────────────────────────────────────────────────
|
|
68
|
-
export {
|
|
69
|
-
syncAll,
|
|
70
|
-
syncActivities,
|
|
71
|
-
syncDailies,
|
|
72
|
-
syncSleep,
|
|
73
|
-
syncBody,
|
|
74
|
-
syncMenstruation,
|
|
75
|
-
syncBloodPressures,
|
|
76
|
-
syncSkinTemp,
|
|
77
|
-
syncUserMetrics,
|
|
78
|
-
syncHRV,
|
|
79
|
-
syncStressDetails,
|
|
80
|
-
syncPulseOx,
|
|
81
|
-
syncRespiration,
|
|
82
|
-
} from "./sync.js";
|
|
83
|
-
export type {
|
|
84
|
-
SyncOptions,
|
|
85
|
-
SyncResult,
|
|
86
|
-
SyncAllResult,
|
|
87
|
-
} from "./sync.js";
|
|
88
|
-
|
|
89
|
-
// ── Types ────────────────────────────────────────────────────────────────────
|
|
90
|
-
export type {
|
|
91
|
-
// Wellness API types (aliases for generated spec types)
|
|
92
|
-
GarminActivity,
|
|
93
|
-
GarminActivityDetail,
|
|
94
|
-
GarminDaily,
|
|
95
|
-
GarminSleep,
|
|
96
|
-
GarminBodyComposition,
|
|
97
|
-
GarminMenstrualCycle,
|
|
98
|
-
GarminUserMetrics,
|
|
99
|
-
GarminStressDetail,
|
|
100
|
-
GarminSkinTemperature,
|
|
101
|
-
GarminRespiration,
|
|
102
|
-
GarminPulseOx,
|
|
103
|
-
GarminHRVSummary,
|
|
104
|
-
GarminHealthSnapshot,
|
|
105
|
-
GarminEpoch,
|
|
106
|
-
GarminBloodPressure,
|
|
107
|
-
GarminMoveIQEvent,
|
|
108
|
-
GarminSolar,
|
|
109
|
-
GarminSample,
|
|
110
|
-
GarminLap,
|
|
111
|
-
GarminTimeRange,
|
|
112
|
-
GarminSleepScoreItem,
|
|
113
|
-
GarminNap,
|
|
114
|
-
// Extended types (spec + undocumented fields)
|
|
115
|
-
GarminDailyExtended,
|
|
116
|
-
GarminSleepExtended,
|
|
117
|
-
GarminActivityExtended,
|
|
118
|
-
// Backward compatibility aliases
|
|
119
|
-
GarminDailySummary,
|
|
120
|
-
GarminMenstrualCycleData,
|
|
121
|
-
GarminSleepLevel,
|
|
122
|
-
GarminActivityLap,
|
|
123
|
-
GarminActivitySample,
|
|
124
|
-
// Training API types
|
|
125
|
-
GarminWorkout,
|
|
126
|
-
GarminWorkoutStep,
|
|
127
|
-
GarminWorkoutRepeatStep,
|
|
128
|
-
GarminWorkoutSegment,
|
|
129
|
-
GarminWorkoutSchedule,
|
|
130
|
-
GarminWorkoutSport,
|
|
131
|
-
// OAuth
|
|
132
|
-
GarminOAuth2TokenResponse,
|
|
133
|
-
// Webhook payloads
|
|
134
|
-
GarminWebhookActivityPayload,
|
|
135
|
-
GarminWebhookDailyPayload,
|
|
136
|
-
GarminWebhookSleepPayload,
|
|
137
|
-
GarminWebhookBodyPayload,
|
|
138
|
-
GarminWebhookBloodPressurePayload,
|
|
139
|
-
GarminWebhookSkinTempPayload,
|
|
140
|
-
GarminWebhookUserMetricsPayload,
|
|
141
|
-
GarminWebhookHRVPayload,
|
|
142
|
-
GarminWebhookStressDetailPayload,
|
|
143
|
-
GarminWebhookPulseOxPayload,
|
|
144
|
-
GarminWebhookRespirationPayload,
|
|
145
|
-
} from "./types.js";
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { mapActivityType } from "./activity-type.js";
|
|
3
|
-
|
|
4
|
-
describe("mapActivityType", () => {
|
|
5
|
-
it("maps running types to Terra Running (8)", () => {
|
|
6
|
-
expect(mapActivityType("RUNNING")).toBe(8);
|
|
7
|
-
expect(mapActivityType("INDOOR_RUNNING")).toBe(8);
|
|
8
|
-
expect(mapActivityType("TRAIL_RUNNING")).toBe(8);
|
|
9
|
-
expect(mapActivityType("TREADMILL_RUNNING")).toBe(8);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it("maps cycling types to Terra Biking (1)", () => {
|
|
13
|
-
expect(mapActivityType("CYCLING")).toBe(1);
|
|
14
|
-
expect(mapActivityType("INDOOR_CYCLING")).toBe(1);
|
|
15
|
-
expect(mapActivityType("MOUNTAIN_BIKING")).toBe(1);
|
|
16
|
-
expect(mapActivityType("GRAVEL_CYCLING")).toBe(1);
|
|
17
|
-
expect(mapActivityType("VIRTUAL_RIDE")).toBe(1);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("maps WALKING to Terra Walking (7)", () => {
|
|
21
|
-
expect(mapActivityType("WALKING")).toBe(7);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("maps HIKING to Terra Hiking (35)", () => {
|
|
25
|
-
expect(mapActivityType("HIKING")).toBe(35);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("maps swimming types to Terra Swimming (82)", () => {
|
|
29
|
-
expect(mapActivityType("SWIMMING")).toBe(82);
|
|
30
|
-
expect(mapActivityType("OPEN_WATER_SWIMMING")).toBe(82);
|
|
31
|
-
expect(mapActivityType("LAP_SWIMMING")).toBe(82);
|
|
32
|
-
expect(mapActivityType("POOL_SWIMMING")).toBe(82);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("maps snow sports correctly", () => {
|
|
36
|
-
expect(mapActivityType("ALPINE_SKIING")).toBe(66);
|
|
37
|
-
expect(mapActivityType("CROSS_COUNTRY_SKIING")).toBe(67);
|
|
38
|
-
expect(mapActivityType("SNOWBOARDING")).toBe(73);
|
|
39
|
-
expect(mapActivityType("SNOWSHOEING")).toBe(74);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("maps water sports correctly", () => {
|
|
43
|
-
expect(mapActivityType("ROWING")).toBe(53);
|
|
44
|
-
expect(mapActivityType("INDOOR_ROWING")).toBe(53);
|
|
45
|
-
expect(mapActivityType("KAYAKING")).toBe(40);
|
|
46
|
-
expect(mapActivityType("SAILING")).toBe(59);
|
|
47
|
-
expect(mapActivityType("SURFING")).toBe(81);
|
|
48
|
-
expect(mapActivityType("KITESURFING")).toBe(41);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("maps racket sports correctly", () => {
|
|
52
|
-
expect(mapActivityType("TENNIS")).toBe(87);
|
|
53
|
-
expect(mapActivityType("TABLE_TENNIS")).toBe(85);
|
|
54
|
-
expect(mapActivityType("BADMINTON")).toBe(10);
|
|
55
|
-
expect(mapActivityType("SQUASH")).toBe(76);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("maps gym/fitness activities correctly", () => {
|
|
59
|
-
expect(mapActivityType("STRENGTH_TRAINING")).toBe(80);
|
|
60
|
-
expect(mapActivityType("CROSSFIT")).toBe(113);
|
|
61
|
-
expect(mapActivityType("YOGA")).toBe(100);
|
|
62
|
-
expect(mapActivityType("PILATES")).toBe(49);
|
|
63
|
-
expect(mapActivityType("HIIT")).toBe(114);
|
|
64
|
-
expect(mapActivityType("ELLIPTICAL")).toBe(25);
|
|
65
|
-
expect(mapActivityType("STAIR_CLIMBING")).toBe(78);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("maps team sports correctly", () => {
|
|
69
|
-
expect(mapActivityType("SOCCER")).toBe(29);
|
|
70
|
-
expect(mapActivityType("BASKETBALL")).toBe(11);
|
|
71
|
-
expect(mapActivityType("VOLLEYBALL")).toBe(94);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("returns Terra Other (108) for unknown types", () => {
|
|
75
|
-
expect(mapActivityType("UNKNOWN_SPORT" as never)).toBe(108);
|
|
76
|
-
expect(mapActivityType("" as never)).toBe(108);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
// ─── Menstruation Transformer ────────────────────────────────────────────────
|
|
2
|
-
// Transforms Garmin menstrual cycle data into the Soma Menstruation schema shape.
|
|
3
|
-
|
|
4
|
-
import type { GarminMenstrualCycle } from "./types.js";
|
|
5
|
-
|
|
6
|
-
export type MenstruationData = ReturnType<typeof transformMenstruation>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Transform a Garmin menstrual cycle record into a Soma Menstruation document shape.
|
|
10
|
-
*
|
|
11
|
-
* @param data - The Garmin menstrual cycle data from the Health API
|
|
12
|
-
* @returns Soma Menstruation fields (without connectionId/userId)
|
|
13
|
-
*/
|
|
14
|
-
export function transformMenstruation(data: GarminMenstrualCycle) {
|
|
15
|
-
// Spec uses periodStartDate (date string like "2021-01-04")
|
|
16
|
-
const dateStr = data.periodStartDate;
|
|
17
|
-
const startTime = dateStr
|
|
18
|
-
? `${dateStr}T00:00:00.000Z`
|
|
19
|
-
: undefined;
|
|
20
|
-
const endTime = dateStr
|
|
21
|
-
? `${dateStr}T23:59:59.999Z`
|
|
22
|
-
: undefined;
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
metadata: {
|
|
26
|
-
start_time: startTime,
|
|
27
|
-
end_time: endTime,
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
menstruation_data: {
|
|
31
|
-
day_in_cycle: data.dayInCycle,
|
|
32
|
-
// Spec has currentPhaseType (string) replacing deprecated currentPhase (int)
|
|
33
|
-
current_phase: data.currentPhaseType?.toLowerCase(),
|
|
34
|
-
length_of_current_phase_days: data.lengthOfCurrentPhase,
|
|
35
|
-
days_until_next_phase: data.daysUntilNextPhase,
|
|
36
|
-
period_length_days: data.periodLength,
|
|
37
|
-
predicted_cycle_length_days: data.predictedCycleLength,
|
|
38
|
-
cycle_length_days: data.cycleLength,
|
|
39
|
-
is_predicted_cycle: data.isPredictedCycle != null
|
|
40
|
-
? String(data.isPredictedCycle)
|
|
41
|
-
: undefined,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
}
|
package/src/garmin/pulseOx.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
// ─── Pulse Ox Transformer ────────────────────────────────────────────────────
|
|
2
|
-
// Transforms Garmin pulse ox data into fields that enrich a Soma Daily record.
|
|
3
|
-
|
|
4
|
-
import type { GarminPulseOx } from "./types.js";
|
|
5
|
-
|
|
6
|
-
export type PulseOxData = ReturnType<typeof transformPulseOx>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Transform a Garmin pulse ox record into oxygen data fields for a Soma Daily.
|
|
10
|
-
*
|
|
11
|
-
* This produces a partial daily shape that can be merged into a matching
|
|
12
|
-
* daily record by date.
|
|
13
|
-
*
|
|
14
|
-
* @param pulseOx - The Garmin pulse ox data from the Health API
|
|
15
|
-
* @returns Partial Soma Daily oxygen_data fields
|
|
16
|
-
*/
|
|
17
|
-
export function transformPulseOx(pulseOx: GarminPulseOx) {
|
|
18
|
-
const hasSamples =
|
|
19
|
-
pulseOx.timeOffsetSpo2Values != null &&
|
|
20
|
-
Object.keys(pulseOx.timeOffsetSpo2Values).length > 0;
|
|
21
|
-
|
|
22
|
-
if (!hasSamples) {
|
|
23
|
-
return {
|
|
24
|
-
calendar_date: pulseOx.calendarDate,
|
|
25
|
-
oxygen_data: undefined,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const startTime = pulseOx.startTimeInSeconds ?? 0;
|
|
30
|
-
const samples = Object.entries(pulseOx.timeOffsetSpo2Values!).map(
|
|
31
|
-
([offset, percentage]) => ({
|
|
32
|
-
timestamp: new Date(
|
|
33
|
-
(startTime + parseInt(offset, 10)) * 1000,
|
|
34
|
-
).toISOString(),
|
|
35
|
-
percentage,
|
|
36
|
-
}),
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
calendar_date: pulseOx.calendarDate,
|
|
41
|
-
oxygen_data: {
|
|
42
|
-
saturation_samples: samples.length > 0 ? samples : undefined,
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// ─── Respiration Transformer ─────────────────────────────────────────────────
|
|
2
|
-
// Transforms Garmin respiration data into fields that enrich a Soma Daily record.
|
|
3
|
-
|
|
4
|
-
import type { GarminRespiration } from "./types.js";
|
|
5
|
-
|
|
6
|
-
export type RespirationData = ReturnType<typeof transformRespiration>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Transform a Garmin respiration record into respiration data fields for a Soma Daily.
|
|
10
|
-
*
|
|
11
|
-
* This produces a partial daily shape that can be merged into a matching
|
|
12
|
-
* daily record by date.
|
|
13
|
-
*
|
|
14
|
-
* @param resp - The Garmin respiration data from the Health API
|
|
15
|
-
* @returns Partial Soma Daily respiration_data fields
|
|
16
|
-
*/
|
|
17
|
-
export function transformRespiration(resp: GarminRespiration) {
|
|
18
|
-
const hasSamples =
|
|
19
|
-
resp.timeOffsetEpochToBreaths != null &&
|
|
20
|
-
Object.keys(resp.timeOffsetEpochToBreaths).length > 0;
|
|
21
|
-
|
|
22
|
-
if (!hasSamples) {
|
|
23
|
-
return {
|
|
24
|
-
calendar_date: undefined,
|
|
25
|
-
respiration_data: undefined,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const startTime = resp.startTimeInSeconds ?? 0;
|
|
30
|
-
const samples = Object.entries(resp.timeOffsetEpochToBreaths!).map(
|
|
31
|
-
([offset, breaths_per_min]) => ({
|
|
32
|
-
timestamp: new Date(
|
|
33
|
-
(startTime + parseInt(offset, 10)) * 1000,
|
|
34
|
-
).toISOString(),
|
|
35
|
-
breaths_per_min,
|
|
36
|
-
}),
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
// Compute summary stats from samples
|
|
40
|
-
const values = samples.map((s) => s.breaths_per_min);
|
|
41
|
-
const avg = values.reduce((sum, v) => sum + v, 0) / values.length;
|
|
42
|
-
|
|
43
|
-
return {
|
|
44
|
-
// Respiration endpoint doesn't have calendarDate, derive from startTime
|
|
45
|
-
calendar_date: new Date(startTime * 1000).toISOString().split("T")[0],
|
|
46
|
-
respiration_data: {
|
|
47
|
-
breaths_data: {
|
|
48
|
-
avg_breaths_per_min: Math.round(avg * 10) / 10,
|
|
49
|
-
min_breaths_per_min: Math.min(...values),
|
|
50
|
-
max_breaths_per_min: Math.max(...values),
|
|
51
|
-
samples: samples.length > 0 ? samples : undefined,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
}
|
package/src/garmin/skinTemp.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// ─── Skin Temperature Transformer ────────────────────────────────────────────
|
|
2
|
-
// Transforms Garmin skin temperature data into the Soma Body schema shape.
|
|
3
|
-
|
|
4
|
-
import type { GarminSkinTemperature } from "./types.js";
|
|
5
|
-
|
|
6
|
-
export type SkinTempData = ReturnType<typeof transformSkinTemp>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Transform a Garmin skin temperature record into a Soma Body document shape.
|
|
10
|
-
*
|
|
11
|
-
* @param skinTemp - The Garmin skin temperature data from the Health API
|
|
12
|
-
* @returns Soma Body fields (without connectionId/userId)
|
|
13
|
-
*/
|
|
14
|
-
export function transformSkinTemp(skinTemp: GarminSkinTemperature) {
|
|
15
|
-
const startMs = (skinTemp.startTimeInSeconds ?? 0) * 1000;
|
|
16
|
-
const endMs = startMs + (skinTemp.durationInSeconds ?? 0) * 1000;
|
|
17
|
-
const startTime = new Date(startMs).toISOString();
|
|
18
|
-
const endTime = new Date(endMs).toISOString();
|
|
19
|
-
|
|
20
|
-
if (skinTemp.avgDeviationCelsius == null) {
|
|
21
|
-
return {
|
|
22
|
-
metadata: { start_time: startTime, end_time: endTime },
|
|
23
|
-
temperature_data: undefined,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return {
|
|
28
|
-
metadata: {
|
|
29
|
-
start_time: startTime,
|
|
30
|
-
end_time: endTime,
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
temperature_data: {
|
|
34
|
-
skin_temperature_samples: [
|
|
35
|
-
{
|
|
36
|
-
timestamp: startTime,
|
|
37
|
-
temperature_celsius: skinTemp.avgDeviationCelsius,
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
}
|