@nativesquare/soma 0.7.3 → 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 +17 -55
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +63 -13
- 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 +153 -120
- 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.d.ts → garmin/public.d.ts} +25 -52
- package/dist/component/garmin/public.d.ts.map +1 -0
- package/dist/component/{garmin.js → garmin/public.js} +301 -215
- 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 +20 -2
- package/dist/component/private.d.ts.map +1 -1
- package/dist/component/private.js +18 -0
- package/dist/component/private.js.map +1 -1
- package/dist/component/public.d.ts +433 -387
- package/dist/component/public.d.ts.map +1 -1
- package/dist/component/public.js +12 -2
- package/dist/component/public.js.map +1 -1
- package/dist/component/schema.d.ts +217 -162
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +2 -1
- package/dist/component/schema.js.map +1 -1
- 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/connection.d.ts +1 -0
- package/dist/component/validators/connection.d.ts.map +1 -1
- package/dist/component/validators/connection.js +2 -0
- package/dist/component/validators/connection.js.map +1 -1
- package/dist/component/validators/daily.d.ts +46 -5
- package/dist/component/validators/daily.d.ts.map +1 -1
- package/dist/component/validators/daily.js +10 -1
- package/dist/component/validators/daily.js.map +1 -1
- package/dist/component/validators/enums.d.ts +2 -2
- 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/component/validators/plannedWorkout.d.ts +5 -1
- package/dist/component/validators/plannedWorkout.d.ts.map +1 -1
- package/dist/component/validators/plannedWorkout.js +4 -0
- package/dist/component/validators/plannedWorkout.js.map +1 -1
- package/dist/component/validators/sleep.d.ts +8 -8
- package/dist/garmin/bloodPressure.d.ts +28 -0
- package/dist/garmin/bloodPressure.d.ts.map +1 -0
- package/dist/garmin/bloodPressure.js +34 -0
- package/dist/garmin/bloodPressure.js.map +1 -0
- package/dist/garmin/body.js +1 -1
- package/dist/garmin/body.js.map +1 -1
- package/dist/garmin/client.d.ts +117 -17
- package/dist/garmin/client.d.ts.map +1 -1
- package/dist/garmin/client.js +337 -43
- package/dist/garmin/client.js.map +1 -1
- package/dist/garmin/daily.d.ts.map +1 -1
- package/dist/garmin/daily.js +3 -3
- package/dist/garmin/daily.js.map +1 -1
- package/dist/garmin/hrv.d.ts +30 -0
- package/dist/garmin/hrv.d.ts.map +1 -0
- package/dist/garmin/hrv.js +45 -0
- package/dist/garmin/hrv.js.map +1 -0
- package/dist/garmin/index.d.ts +16 -4
- package/dist/garmin/index.d.ts.map +1 -1
- package/dist/garmin/index.js +8 -2
- package/dist/garmin/index.js.map +1 -1
- package/dist/garmin/maps/activity-type.d.ts +1 -2
- package/dist/garmin/maps/activity-type.d.ts.map +1 -1
- package/dist/garmin/maps/activity-type.js +1 -0
- package/dist/garmin/maps/activity-type.js.map +1 -1
- package/dist/garmin/menstruation.d.ts +6 -4
- package/dist/garmin/menstruation.d.ts.map +1 -1
- package/dist/garmin/menstruation.js +12 -8
- package/dist/garmin/menstruation.js.map +1 -1
- package/dist/garmin/pulseOx.d.ts +24 -0
- package/dist/garmin/pulseOx.d.ts.map +1 -0
- package/dist/garmin/pulseOx.js +33 -0
- package/dist/garmin/pulseOx.js.map +1 -0
- package/dist/garmin/respiration.d.ts +29 -0
- package/dist/garmin/respiration.d.ts.map +1 -0
- package/dist/garmin/respiration.js +42 -0
- package/dist/garmin/respiration.js.map +1 -0
- package/dist/garmin/skinTemp.d.ts +27 -0
- package/dist/garmin/skinTemp.d.ts.map +1 -0
- package/dist/garmin/skinTemp.js +35 -0
- package/dist/garmin/skinTemp.js.map +1 -0
- package/dist/garmin/sleep.d.ts +4 -4
- package/dist/garmin/sleep.d.ts.map +1 -1
- package/dist/garmin/sleep.js +15 -9
- package/dist/garmin/sleep.js.map +1 -1
- package/dist/garmin/stressDetails.d.ts +30 -0
- package/dist/garmin/stressDetails.d.ts.map +1 -0
- package/dist/garmin/stressDetails.js +49 -0
- package/dist/garmin/stressDetails.js.map +1 -0
- package/dist/garmin/sync.d.ts +14 -0
- package/dist/garmin/sync.d.ts.map +1 -1
- package/dist/garmin/sync.js +290 -7
- package/dist/garmin/sync.js.map +1 -1
- package/dist/garmin/types.d.ts +77 -186
- package/dist/garmin/types.d.ts.map +1 -1
- package/dist/garmin/types.js +4 -2
- package/dist/garmin/types.js.map +1 -1
- package/dist/garmin/userMetrics.d.ts +23 -0
- package/dist/garmin/userMetrics.d.ts.map +1 -0
- package/dist/garmin/userMetrics.js +41 -0
- package/dist/garmin/userMetrics.js.map +1 -0
- package/dist/validators.d.ts +138 -56
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +2 -2
- package/dist/validators.js.map +1 -1
- package/package.json +130 -124
- package/src/client/index.ts +86 -18
- package/src/component/_generated/api.ts +96 -4
- package/src/component/_generated/component.ts +271 -144
- 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/component/garmin/transform/bloodPressure.ts +39 -0
- 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/specs/wellness-api.json +1 -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/private.ts +21 -0
- package/src/component/public.ts +11 -2
- package/src/component/schema.ts +2 -1
- 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/connection.ts +2 -0
- package/src/component/validators/daily.ts +20 -0
- package/src/component/validators/menstruation.ts +5 -1
- package/src/component/validators/plannedWorkout.ts +9 -0
- package/src/validators.ts +12 -2
- package/dist/component/garmin.d.ts.map +0 -1
- 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 -101
- package/dist/garmin/activity.d.ts.map +0 -1
- package/dist/garmin/activity.js +0 -207
- package/dist/garmin/activity.js.map +0 -1
- package/src/component/garmin.ts +0 -850
- package/src/garmin/activity.test.ts +0 -178
- package/src/garmin/activity.ts +0 -272
- package/src/garmin/auth.test.ts +0 -103
- package/src/garmin/body.ts +0 -59
- package/src/garmin/client.ts +0 -407
- package/src/garmin/daily.ts +0 -211
- package/src/garmin/index.ts +0 -75
- package/src/garmin/maps/activity-type.test.ts +0 -78
- package/src/garmin/menstruation.ts +0 -42
- package/src/garmin/sleep.test.ts +0 -110
- package/src/garmin/sleep.ts +0 -170
- package/src/garmin/sync.ts +0 -223
- package/src/garmin/types.ts +0 -480
|
@@ -1,152 +1,45 @@
|
|
|
1
|
-
// ─── Garmin
|
|
1
|
+
// ─── Garmin Public Actions ───────────────────────────────────────────────────
|
|
2
2
|
// Public actions that handle the full Garmin OAuth 2.0 PKCE + sync lifecycle.
|
|
3
3
|
// The host app calls these through the Soma class, which threads the
|
|
4
4
|
// credentials automatically from env vars or constructor config.
|
|
5
|
-
//
|
|
6
|
-
// Internal mutations manage the providerTokens table (token CRUD).
|
|
7
5
|
import { v } from "convex/values";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
6
|
+
import { action } from "../_generated/server";
|
|
7
|
+
import { generateCodeVerifier, generateCodeChallenge, generateState, buildAuthUrl, exchangeCode, refreshToken, } from "../../garmin/auth.js";
|
|
8
|
+
import { GarminClient } from "../../garmin/client.js";
|
|
9
|
+
import { transformActivity } from "./transform/activity.js";
|
|
10
|
+
import { transformDaily } from "../../garmin/daily.js";
|
|
11
|
+
import { transformSleep } from "../../garmin/sleep.js";
|
|
12
|
+
import { transformBody } from "../../garmin/body.js";
|
|
13
|
+
import { transformMenstruation } from "../../garmin/menstruation.js";
|
|
14
|
+
import { transformBloodPressure } from "../../garmin/bloodPressure.js";
|
|
15
|
+
import { transformSkinTemp } from "../../garmin/skinTemp.js";
|
|
16
|
+
import { transformUserMetrics } from "../../garmin/userMetrics.js";
|
|
17
|
+
import { transformHRV } from "../../garmin/hrv.js";
|
|
18
|
+
import { transformStressDetails } from "../../garmin/stressDetails.js";
|
|
19
|
+
import { transformPulseOx } from "../../garmin/pulseOx.js";
|
|
20
|
+
import { transformRespiration } from "../../garmin/respiration.js";
|
|
21
|
+
import { transformPlannedWorkoutToGarmin } from "../../garmin/plannedWorkout.js";
|
|
22
|
+
import { api, internal } from "../_generated/api";
|
|
23
|
+
import { zClientActivity } from "./types/zod/zod.gen";
|
|
23
24
|
// Default sync window: last 30 days
|
|
24
25
|
const DEFAULT_SYNC_DAYS = 30;
|
|
26
|
+
// Shared synced counter validator for all sync actions
|
|
27
|
+
const syncedValidator = v.object({
|
|
28
|
+
activities: v.number(),
|
|
29
|
+
dailies: v.number(),
|
|
30
|
+
sleep: v.number(),
|
|
31
|
+
body: v.number(),
|
|
32
|
+
menstruation: v.number(),
|
|
33
|
+
bloodPressures: v.number(),
|
|
34
|
+
skinTemp: v.number(),
|
|
35
|
+
userMetrics: v.number(),
|
|
36
|
+
hrv: v.number(),
|
|
37
|
+
stressDetails: v.number(),
|
|
38
|
+
pulseOx: v.number(),
|
|
39
|
+
respiration: v.number(),
|
|
40
|
+
});
|
|
25
41
|
// Refresh buffer: refresh tokens 10 minutes before expiry
|
|
26
42
|
const REFRESH_BUFFER_SECONDS = 600;
|
|
27
|
-
// ─── Internal Pending OAuth CRUD ─────────────────────────────────────────────
|
|
28
|
-
// Temporary storage for in-progress Garmin OAuth 2.0 PKCE flows.
|
|
29
|
-
// Bridges getGarminAuthUrl and completeGarminOAuth.
|
|
30
|
-
export const storePendingOAuth = internalMutation({
|
|
31
|
-
args: {
|
|
32
|
-
provider: v.string(),
|
|
33
|
-
state: v.string(),
|
|
34
|
-
codeVerifier: v.string(),
|
|
35
|
-
userId: v.string(),
|
|
36
|
-
},
|
|
37
|
-
returns: v.null(),
|
|
38
|
-
handler: async (ctx, args) => {
|
|
39
|
-
await ctx.db.insert("pendingOAuth", {
|
|
40
|
-
...args,
|
|
41
|
-
createdAt: Date.now(),
|
|
42
|
-
});
|
|
43
|
-
return null;
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
export const getPendingOAuth = internalQuery({
|
|
47
|
-
args: { state: v.string() },
|
|
48
|
-
returns: v.union(v.object({
|
|
49
|
-
_id: v.id("pendingOAuth"),
|
|
50
|
-
_creationTime: v.number(),
|
|
51
|
-
provider: v.string(),
|
|
52
|
-
state: v.string(),
|
|
53
|
-
codeVerifier: v.string(),
|
|
54
|
-
userId: v.string(),
|
|
55
|
-
createdAt: v.number(),
|
|
56
|
-
}), v.null()),
|
|
57
|
-
handler: async (ctx, args) => {
|
|
58
|
-
return await ctx.db
|
|
59
|
-
.query("pendingOAuth")
|
|
60
|
-
.withIndex("by_state", (q) => q.eq("state", args.state))
|
|
61
|
-
.first();
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
export const deletePendingOAuth = internalMutation({
|
|
65
|
-
args: { state: v.string() },
|
|
66
|
-
returns: v.null(),
|
|
67
|
-
handler: async (ctx, args) => {
|
|
68
|
-
const pending = await ctx.db
|
|
69
|
-
.query("pendingOAuth")
|
|
70
|
-
.withIndex("by_state", (q) => q.eq("state", args.state))
|
|
71
|
-
.first();
|
|
72
|
-
if (pending) {
|
|
73
|
-
await ctx.db.delete(pending._id);
|
|
74
|
-
}
|
|
75
|
-
return null;
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
// ─── Internal Token CRUD ─────────────────────────────────────────────────────
|
|
79
|
-
/**
|
|
80
|
-
* Store OAuth 2.0 tokens for a Garmin connection.
|
|
81
|
-
* Upserts by connectionId — one token record per connection.
|
|
82
|
-
*/
|
|
83
|
-
export const storeTokens = internalMutation({
|
|
84
|
-
args: {
|
|
85
|
-
connectionId: v.id("connections"),
|
|
86
|
-
accessToken: v.string(),
|
|
87
|
-
refreshToken: v.string(),
|
|
88
|
-
expiresAt: v.number(),
|
|
89
|
-
},
|
|
90
|
-
returns: v.null(),
|
|
91
|
-
handler: async (ctx, args) => {
|
|
92
|
-
const existing = await ctx.db
|
|
93
|
-
.query("providerTokens")
|
|
94
|
-
.withIndex("by_connectionId", (q) => q.eq("connectionId", args.connectionId))
|
|
95
|
-
.first();
|
|
96
|
-
if (existing) {
|
|
97
|
-
await ctx.db.patch(existing._id, {
|
|
98
|
-
accessToken: args.accessToken,
|
|
99
|
-
refreshToken: args.refreshToken,
|
|
100
|
-
expiresAt: args.expiresAt,
|
|
101
|
-
});
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
await ctx.db.insert("providerTokens", {
|
|
105
|
-
connectionId: args.connectionId,
|
|
106
|
-
accessToken: args.accessToken,
|
|
107
|
-
refreshToken: args.refreshToken,
|
|
108
|
-
expiresAt: args.expiresAt,
|
|
109
|
-
});
|
|
110
|
-
return null;
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
/**
|
|
114
|
-
* Get stored tokens for a connection.
|
|
115
|
-
*/
|
|
116
|
-
export const getTokens = internalQuery({
|
|
117
|
-
args: { connectionId: v.id("connections") },
|
|
118
|
-
returns: v.union(v.object({
|
|
119
|
-
_id: v.id("providerTokens"),
|
|
120
|
-
_creationTime: v.number(),
|
|
121
|
-
connectionId: v.id("connections"),
|
|
122
|
-
accessToken: v.string(),
|
|
123
|
-
refreshToken: v.optional(v.string()),
|
|
124
|
-
expiresAt: v.optional(v.number()),
|
|
125
|
-
}), v.null()),
|
|
126
|
-
handler: async (ctx, args) => {
|
|
127
|
-
return await ctx.db
|
|
128
|
-
.query("providerTokens")
|
|
129
|
-
.withIndex("by_connectionId", (q) => q.eq("connectionId", args.connectionId))
|
|
130
|
-
.first();
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
/**
|
|
134
|
-
* Delete stored tokens for a connection.
|
|
135
|
-
*/
|
|
136
|
-
export const deleteTokens = internalMutation({
|
|
137
|
-
args: { connectionId: v.id("connections") },
|
|
138
|
-
returns: v.null(),
|
|
139
|
-
handler: async (ctx, args) => {
|
|
140
|
-
const existing = await ctx.db
|
|
141
|
-
.query("providerTokens")
|
|
142
|
-
.withIndex("by_connectionId", (q) => q.eq("connectionId", args.connectionId))
|
|
143
|
-
.first();
|
|
144
|
-
if (existing) {
|
|
145
|
-
await ctx.db.delete(existing._id);
|
|
146
|
-
}
|
|
147
|
-
return null;
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
43
|
// ─── Public Actions ──────────────────────────────────────────────────────────
|
|
151
44
|
/**
|
|
152
45
|
* Generate a Garmin OAuth 2.0 authorization URL with PKCE.
|
|
@@ -165,11 +58,6 @@ export const getGarminAuthUrl = action({
|
|
|
165
58
|
redirectUri: v.optional(v.string()),
|
|
166
59
|
userId: v.optional(v.string()),
|
|
167
60
|
},
|
|
168
|
-
returns: v.object({
|
|
169
|
-
authUrl: v.string(),
|
|
170
|
-
state: v.string(),
|
|
171
|
-
codeVerifier: v.string(),
|
|
172
|
-
}),
|
|
173
61
|
handler: async (ctx, args) => {
|
|
174
62
|
const codeVerifier = generateCodeVerifier();
|
|
175
63
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
@@ -181,7 +69,7 @@ export const getGarminAuthUrl = action({
|
|
|
181
69
|
state,
|
|
182
70
|
});
|
|
183
71
|
if (args.userId) {
|
|
184
|
-
await ctx.runMutation(
|
|
72
|
+
await ctx.runMutation(internal.garmin.private.storePendingOAuth, {
|
|
185
73
|
provider: "GARMIN",
|
|
186
74
|
state,
|
|
187
75
|
codeVerifier,
|
|
@@ -206,17 +94,6 @@ export const connectGarmin = action({
|
|
|
206
94
|
codeVerifier: v.string(),
|
|
207
95
|
redirectUri: v.optional(v.string()),
|
|
208
96
|
},
|
|
209
|
-
returns: v.object({
|
|
210
|
-
connectionId: v.string(),
|
|
211
|
-
synced: v.object({
|
|
212
|
-
activities: v.number(),
|
|
213
|
-
dailies: v.number(),
|
|
214
|
-
sleep: v.number(),
|
|
215
|
-
body: v.number(),
|
|
216
|
-
menstruation: v.number(),
|
|
217
|
-
}),
|
|
218
|
-
errors: v.array(v.object({ type: v.string(), id: v.string(), error: v.string() })),
|
|
219
|
-
}),
|
|
220
97
|
handler: async (ctx, args) => {
|
|
221
98
|
const tokenResult = await exchangeCode({
|
|
222
99
|
clientId: args.clientId,
|
|
@@ -225,12 +102,12 @@ export const connectGarmin = action({
|
|
|
225
102
|
codeVerifier: args.codeVerifier,
|
|
226
103
|
redirectUri: args.redirectUri,
|
|
227
104
|
});
|
|
228
|
-
const connectionId = await ctx.runMutation(
|
|
105
|
+
const connectionId = await ctx.runMutation(api.public.connect, {
|
|
229
106
|
userId: args.userId,
|
|
230
107
|
provider: "GARMIN",
|
|
231
108
|
});
|
|
232
109
|
const expiresAt = Math.floor(Date.now() / 1000) + tokenResult.expires_in;
|
|
233
|
-
await ctx.runMutation(
|
|
110
|
+
const _stored = await ctx.runMutation(internal.garmin.private.storeTokens, {
|
|
234
111
|
connectionId,
|
|
235
112
|
accessToken: tokenResult.access_token,
|
|
236
113
|
refreshToken: tokenResult.refresh_token,
|
|
@@ -239,6 +116,14 @@ export const connectGarmin = action({
|
|
|
239
116
|
const client = new GarminClient({
|
|
240
117
|
accessToken: tokenResult.access_token,
|
|
241
118
|
});
|
|
119
|
+
// Best-effort: resolve Garmin user ID for webhook mapping
|
|
120
|
+
const garminUserId = await client.getUserId();
|
|
121
|
+
if (garminUserId) {
|
|
122
|
+
const _updated = await ctx.runMutation(api.public.updateConnection, {
|
|
123
|
+
connectionId,
|
|
124
|
+
providerUserId: garminUserId,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
242
127
|
const now = Math.floor(Date.now() / 1000);
|
|
243
128
|
const thirtyDaysAgo = now - DEFAULT_SYNC_DAYS * 86400;
|
|
244
129
|
const timeRange = {
|
|
@@ -250,7 +135,7 @@ export const connectGarmin = action({
|
|
|
250
135
|
userId: args.userId,
|
|
251
136
|
timeRange,
|
|
252
137
|
});
|
|
253
|
-
await ctx.runMutation(
|
|
138
|
+
const _updated = await ctx.runMutation(api.public.updateConnection, {
|
|
254
139
|
connectionId,
|
|
255
140
|
lastDataUpdate: new Date().toISOString(),
|
|
256
141
|
});
|
|
@@ -278,19 +163,8 @@ export const completeGarminOAuth = action({
|
|
|
278
163
|
clientSecret: v.string(),
|
|
279
164
|
redirectUri: v.optional(v.string()),
|
|
280
165
|
},
|
|
281
|
-
returns: v.object({
|
|
282
|
-
connectionId: v.string(),
|
|
283
|
-
synced: v.object({
|
|
284
|
-
activities: v.number(),
|
|
285
|
-
dailies: v.number(),
|
|
286
|
-
sleep: v.number(),
|
|
287
|
-
body: v.number(),
|
|
288
|
-
menstruation: v.number(),
|
|
289
|
-
}),
|
|
290
|
-
errors: v.array(v.object({ type: v.string(), id: v.string(), error: v.string() })),
|
|
291
|
-
}),
|
|
292
166
|
handler: async (ctx, args) => {
|
|
293
|
-
const pending = await ctx.runQuery(
|
|
167
|
+
const pending = await ctx.runQuery(internal.garmin.private.getPendingOAuth, {
|
|
294
168
|
state: args.state,
|
|
295
169
|
});
|
|
296
170
|
if (!pending) {
|
|
@@ -304,15 +178,15 @@ export const completeGarminOAuth = action({
|
|
|
304
178
|
codeVerifier: pending.codeVerifier,
|
|
305
179
|
redirectUri: args.redirectUri,
|
|
306
180
|
});
|
|
307
|
-
await ctx.runMutation(
|
|
181
|
+
const _deleted = await ctx.runMutation(internal.garmin.private.deletePendingOAuth, {
|
|
308
182
|
state: args.state,
|
|
309
183
|
});
|
|
310
|
-
const connectionId = await ctx.runMutation(
|
|
184
|
+
const connectionId = await ctx.runMutation(api.public.connect, {
|
|
311
185
|
userId: pending.userId,
|
|
312
186
|
provider: "GARMIN",
|
|
313
187
|
});
|
|
314
188
|
const expiresAt = Math.floor(Date.now() / 1000) + tokenResult.expires_in;
|
|
315
|
-
await ctx.runMutation(
|
|
189
|
+
const _stored = await ctx.runMutation(internal.garmin.private.storeTokens, {
|
|
316
190
|
connectionId,
|
|
317
191
|
accessToken: tokenResult.access_token,
|
|
318
192
|
refreshToken: tokenResult.refresh_token,
|
|
@@ -321,6 +195,14 @@ export const completeGarminOAuth = action({
|
|
|
321
195
|
const client = new GarminClient({
|
|
322
196
|
accessToken: tokenResult.access_token,
|
|
323
197
|
});
|
|
198
|
+
// Best-effort: resolve Garmin user ID for webhook mapping
|
|
199
|
+
const garminUserId = await client.getUserId();
|
|
200
|
+
if (garminUserId) {
|
|
201
|
+
const _updated = await ctx.runMutation(api.public.updateConnection, {
|
|
202
|
+
connectionId,
|
|
203
|
+
providerUserId: garminUserId,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
324
206
|
const now = Math.floor(Date.now() / 1000);
|
|
325
207
|
const thirtyDaysAgo = now - DEFAULT_SYNC_DAYS * 86400;
|
|
326
208
|
const timeRange = {
|
|
@@ -332,7 +214,7 @@ export const completeGarminOAuth = action({
|
|
|
332
214
|
userId: pending.userId,
|
|
333
215
|
timeRange,
|
|
334
216
|
});
|
|
335
|
-
await ctx.runMutation(
|
|
217
|
+
const _updated = await ctx.runMutation(api.public.updateConnection, {
|
|
336
218
|
connectionId,
|
|
337
219
|
lastDataUpdate: new Date().toISOString(),
|
|
338
220
|
});
|
|
@@ -357,18 +239,8 @@ export const syncGarmin = action({
|
|
|
357
239
|
startTimeInSeconds: v.optional(v.number()),
|
|
358
240
|
endTimeInSeconds: v.optional(v.number()),
|
|
359
241
|
},
|
|
360
|
-
returns: v.object({
|
|
361
|
-
synced: v.object({
|
|
362
|
-
activities: v.number(),
|
|
363
|
-
dailies: v.number(),
|
|
364
|
-
sleep: v.number(),
|
|
365
|
-
body: v.number(),
|
|
366
|
-
menstruation: v.number(),
|
|
367
|
-
}),
|
|
368
|
-
errors: v.array(v.object({ type: v.string(), id: v.string(), error: v.string() })),
|
|
369
|
-
}),
|
|
370
242
|
handler: async (ctx, args) => {
|
|
371
|
-
const connection = await ctx.runQuery(
|
|
243
|
+
const connection = await ctx.runQuery(internal.private.getConnectionByProvider, { userId: args.userId, provider: "GARMIN" });
|
|
372
244
|
if (!connection) {
|
|
373
245
|
throw new Error(`No Garmin connection found for user "${args.userId}". ` +
|
|
374
246
|
"Call connectGarmin first.");
|
|
@@ -377,7 +249,7 @@ export const syncGarmin = action({
|
|
|
377
249
|
throw new Error(`Garmin connection for user "${args.userId}" is inactive. Reconnect first.`);
|
|
378
250
|
}
|
|
379
251
|
const connectionId = connection._id;
|
|
380
|
-
const tokenDoc = await ctx.runQuery(
|
|
252
|
+
const tokenDoc = await ctx.runQuery(internal.garmin.private.getTokens, {
|
|
381
253
|
connectionId,
|
|
382
254
|
});
|
|
383
255
|
if (!tokenDoc) {
|
|
@@ -397,7 +269,7 @@ export const syncGarmin = action({
|
|
|
397
269
|
});
|
|
398
270
|
accessToken = refreshed.access_token;
|
|
399
271
|
const newExpiresAt = nowSeconds + refreshed.expires_in;
|
|
400
|
-
await ctx.runMutation(
|
|
272
|
+
const _refreshed = await ctx.runMutation(internal.garmin.private.storeTokens, {
|
|
401
273
|
connectionId,
|
|
402
274
|
accessToken: refreshed.access_token,
|
|
403
275
|
refreshToken: refreshed.refresh_token,
|
|
@@ -405,6 +277,16 @@ export const syncGarmin = action({
|
|
|
405
277
|
});
|
|
406
278
|
}
|
|
407
279
|
const client = new GarminClient({ accessToken });
|
|
280
|
+
// Lazy backfill: resolve Garmin user ID if missing (for webhook mapping)
|
|
281
|
+
if (!connection.providerUserId) {
|
|
282
|
+
const garminUserId = await client.getUserId();
|
|
283
|
+
if (garminUserId) {
|
|
284
|
+
const _updated = await ctx.runMutation(api.public.updateConnection, {
|
|
285
|
+
connectionId,
|
|
286
|
+
providerUserId: garminUserId,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
408
290
|
const now = Math.floor(Date.now() / 1000);
|
|
409
291
|
const timeRange = {
|
|
410
292
|
uploadStartTimeInSeconds: args.startTimeInSeconds ?? now - DEFAULT_SYNC_DAYS * 86400,
|
|
@@ -415,7 +297,7 @@ export const syncGarmin = action({
|
|
|
415
297
|
userId: args.userId,
|
|
416
298
|
timeRange,
|
|
417
299
|
});
|
|
418
|
-
await ctx.runMutation(
|
|
300
|
+
const _updated = await ctx.runMutation(api.public.updateConnection, {
|
|
419
301
|
connectionId,
|
|
420
302
|
lastDataUpdate: new Date().toISOString(),
|
|
421
303
|
});
|
|
@@ -432,15 +314,14 @@ export const disconnectGarmin = action({
|
|
|
432
314
|
args: {
|
|
433
315
|
userId: v.string(),
|
|
434
316
|
},
|
|
435
|
-
returns: v.null(),
|
|
436
317
|
handler: async (ctx, args) => {
|
|
437
|
-
const connection = await ctx.runQuery(
|
|
318
|
+
const connection = await ctx.runQuery(internal.private.getConnectionByProvider, { userId: args.userId, provider: "GARMIN" });
|
|
438
319
|
if (!connection) {
|
|
439
320
|
throw new Error(`No Garmin connection found for user "${args.userId}".`);
|
|
440
321
|
}
|
|
441
322
|
const connectionId = connection._id;
|
|
442
323
|
// Best-effort: deregister user at Garmin
|
|
443
|
-
const tokenDoc = await ctx.runQuery(
|
|
324
|
+
const tokenDoc = await ctx.runQuery(internal.garmin.private.getTokens, {
|
|
444
325
|
connectionId,
|
|
445
326
|
});
|
|
446
327
|
if (tokenDoc) {
|
|
@@ -452,8 +333,8 @@ export const disconnectGarmin = action({
|
|
|
452
333
|
// Deregistration is best-effort; proceed with local cleanup
|
|
453
334
|
}
|
|
454
335
|
}
|
|
455
|
-
await ctx.runMutation(
|
|
456
|
-
await ctx.runMutation(
|
|
336
|
+
const _deleted = await ctx.runMutation(internal.garmin.private.deleteTokens, { connectionId });
|
|
337
|
+
const _disconnected = await ctx.runMutation(api.public.disconnect, {
|
|
457
338
|
userId: args.userId,
|
|
458
339
|
provider: "GARMIN",
|
|
459
340
|
});
|
|
@@ -478,12 +359,8 @@ export const pushPlannedWorkout = action({
|
|
|
478
359
|
plannedWorkoutId: v.string(),
|
|
479
360
|
workoutProvider: v.optional(v.string()),
|
|
480
361
|
},
|
|
481
|
-
returns: v.object({
|
|
482
|
-
garminWorkoutId: v.number(),
|
|
483
|
-
garminScheduleId: v.union(v.number(), v.null()),
|
|
484
|
-
}),
|
|
485
362
|
handler: async (ctx, args) => {
|
|
486
|
-
const connection = await ctx.runQuery(
|
|
363
|
+
const connection = await ctx.runQuery(internal.private.getConnectionByProvider, { userId: args.userId, provider: "GARMIN" });
|
|
487
364
|
if (!connection) {
|
|
488
365
|
throw new Error(`No Garmin connection found for user "${args.userId}". ` +
|
|
489
366
|
"Call connectGarmin first.");
|
|
@@ -492,7 +369,7 @@ export const pushPlannedWorkout = action({
|
|
|
492
369
|
throw new Error(`Garmin connection for user "${args.userId}" is inactive. Reconnect first.`);
|
|
493
370
|
}
|
|
494
371
|
const connectionId = connection._id;
|
|
495
|
-
const tokenDoc = await ctx.runQuery(
|
|
372
|
+
const tokenDoc = await ctx.runQuery(internal.garmin.private.getTokens, {
|
|
496
373
|
connectionId,
|
|
497
374
|
});
|
|
498
375
|
if (!tokenDoc) {
|
|
@@ -512,7 +389,7 @@ export const pushPlannedWorkout = action({
|
|
|
512
389
|
accessToken = refreshed.access_token;
|
|
513
390
|
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
514
391
|
const newExpiresAt = nowSeconds + refreshed.expires_in;
|
|
515
|
-
await ctx.runMutation(
|
|
392
|
+
const _refreshed = await ctx.runMutation(internal.garmin.private.storeTokens, {
|
|
516
393
|
connectionId,
|
|
517
394
|
accessToken: refreshed.access_token,
|
|
518
395
|
refreshToken: refreshed.refresh_token,
|
|
@@ -524,7 +401,7 @@ export const pushPlannedWorkout = action({
|
|
|
524
401
|
"The user may need to reconnect their Garmin account.");
|
|
525
402
|
}
|
|
526
403
|
}
|
|
527
|
-
const plannedWorkout = await ctx.runQuery(
|
|
404
|
+
const plannedWorkout = await ctx.runQuery(api.public.getPlannedWorkout, { plannedWorkoutId: args.plannedWorkoutId });
|
|
528
405
|
if (!plannedWorkout) {
|
|
529
406
|
throw new Error(`Planned workout "${args.plannedWorkoutId}" not found.`);
|
|
530
407
|
}
|
|
@@ -541,6 +418,18 @@ export const pushPlannedWorkout = action({
|
|
|
541
418
|
const schedule = await client.createSchedule(created.workoutId, plannedDate);
|
|
542
419
|
garminScheduleId = schedule.scheduleId ?? null;
|
|
543
420
|
}
|
|
421
|
+
// Store the Garmin workout/schedule IDs back on the planned workout
|
|
422
|
+
// so the host app can match completed activities to planned sessions.
|
|
423
|
+
const _ingested = await ctx.runMutation(api.public.ingestPlannedWorkout, {
|
|
424
|
+
...plannedWorkout,
|
|
425
|
+
_id: undefined,
|
|
426
|
+
_creationTime: undefined,
|
|
427
|
+
metadata: {
|
|
428
|
+
...plannedWorkout.metadata,
|
|
429
|
+
provider_workout_id: String(created.workoutId),
|
|
430
|
+
provider_schedule_id: garminScheduleId != null ? String(garminScheduleId) : undefined,
|
|
431
|
+
},
|
|
432
|
+
});
|
|
544
433
|
return {
|
|
545
434
|
garminWorkoutId: created.workoutId,
|
|
546
435
|
garminScheduleId,
|
|
@@ -549,15 +438,19 @@ export const pushPlannedWorkout = action({
|
|
|
549
438
|
});
|
|
550
439
|
async function syncAllTypes(ctx, client, config) {
|
|
551
440
|
const { connectionId, userId, timeRange } = config;
|
|
552
|
-
const synced = {
|
|
441
|
+
const synced = {
|
|
442
|
+
activities: 0, dailies: 0, sleep: 0, body: 0, menstruation: 0,
|
|
443
|
+
bloodPressures: 0, skinTemp: 0, userMetrics: 0,
|
|
444
|
+
hrv: 0, stressDetails: 0, pulseOx: 0, respiration: 0,
|
|
445
|
+
};
|
|
553
446
|
const errors = [];
|
|
554
447
|
// ── Activities ──────────────────────────────────────────────────────────
|
|
555
448
|
try {
|
|
556
449
|
const activities = await client.getActivities(timeRange);
|
|
557
450
|
for (const activity of activities) {
|
|
558
451
|
try {
|
|
559
|
-
const data = transformActivity(activity);
|
|
560
|
-
await ctx.runMutation(
|
|
452
|
+
const data = transformActivity(zClientActivity.parse(activity));
|
|
453
|
+
await ctx.runMutation(api.public.ingestActivity, {
|
|
561
454
|
connectionId,
|
|
562
455
|
userId,
|
|
563
456
|
...data,
|
|
@@ -586,7 +479,7 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
586
479
|
for (const daily of dailies) {
|
|
587
480
|
try {
|
|
588
481
|
const data = transformDaily(daily);
|
|
589
|
-
await ctx.runMutation(
|
|
482
|
+
await ctx.runMutation(api.public.ingestDaily, {
|
|
590
483
|
connectionId,
|
|
591
484
|
userId,
|
|
592
485
|
...data,
|
|
@@ -596,7 +489,7 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
596
489
|
catch (err) {
|
|
597
490
|
errors.push({
|
|
598
491
|
type: "daily",
|
|
599
|
-
id: daily.summaryId ?? daily.calendarDate,
|
|
492
|
+
id: daily.summaryId ?? daily.calendarDate ?? "unknown",
|
|
600
493
|
error: err instanceof Error ? err.message : String(err),
|
|
601
494
|
});
|
|
602
495
|
}
|
|
@@ -615,7 +508,7 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
615
508
|
for (const sleep of sleeps) {
|
|
616
509
|
try {
|
|
617
510
|
const data = transformSleep(sleep);
|
|
618
|
-
await ctx.runMutation(
|
|
511
|
+
await ctx.runMutation(api.public.ingestSleep, {
|
|
619
512
|
connectionId,
|
|
620
513
|
userId,
|
|
621
514
|
...data,
|
|
@@ -625,7 +518,7 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
625
518
|
catch (err) {
|
|
626
519
|
errors.push({
|
|
627
520
|
type: "sleep",
|
|
628
|
-
id: sleep.summaryId ?? sleep.calendarDate,
|
|
521
|
+
id: sleep.summaryId ?? sleep.calendarDate ?? "unknown",
|
|
629
522
|
error: err instanceof Error ? err.message : String(err),
|
|
630
523
|
});
|
|
631
524
|
}
|
|
@@ -644,7 +537,7 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
644
537
|
for (const body of bodyComps) {
|
|
645
538
|
try {
|
|
646
539
|
const data = transformBody(body);
|
|
647
|
-
await ctx.runMutation(
|
|
540
|
+
await ctx.runMutation(api.public.ingestBody, {
|
|
648
541
|
connectionId,
|
|
649
542
|
userId,
|
|
650
543
|
...data,
|
|
@@ -673,7 +566,7 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
673
566
|
for (const record of records) {
|
|
674
567
|
try {
|
|
675
568
|
const data = transformMenstruation(record);
|
|
676
|
-
await ctx.runMutation(
|
|
569
|
+
await ctx.runMutation(api.public.ingestMenstruation, {
|
|
677
570
|
connectionId,
|
|
678
571
|
userId,
|
|
679
572
|
...data,
|
|
@@ -683,7 +576,7 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
683
576
|
catch (err) {
|
|
684
577
|
errors.push({
|
|
685
578
|
type: "menstruation",
|
|
686
|
-
id: record.summaryId ?? record.
|
|
579
|
+
id: record.summaryId ?? record.periodStartDate ?? "unknown",
|
|
687
580
|
error: err instanceof Error ? err.message : String(err),
|
|
688
581
|
});
|
|
689
582
|
}
|
|
@@ -696,6 +589,199 @@ async function syncAllTypes(ctx, client, config) {
|
|
|
696
589
|
error: err instanceof Error ? err.message : String(err),
|
|
697
590
|
});
|
|
698
591
|
}
|
|
592
|
+
// ── Blood Pressures (→ body) ───────────────────────────────────────────
|
|
593
|
+
try {
|
|
594
|
+
const bpRecords = await client.getBloodPressures(timeRange);
|
|
595
|
+
for (const bp of bpRecords) {
|
|
596
|
+
try {
|
|
597
|
+
const data = transformBloodPressure(bp);
|
|
598
|
+
await ctx.runMutation(api.public.ingestBody, {
|
|
599
|
+
connectionId, userId, ...data,
|
|
600
|
+
});
|
|
601
|
+
synced.bloodPressures++;
|
|
602
|
+
}
|
|
603
|
+
catch (err) {
|
|
604
|
+
errors.push({
|
|
605
|
+
type: "bloodPressure",
|
|
606
|
+
id: bp.summaryId ?? String(bp.measurementTimeInSeconds),
|
|
607
|
+
error: err instanceof Error ? err.message : String(err),
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
catch (err) {
|
|
613
|
+
errors.push({ type: "bloodPressure", id: "fetch", error: err instanceof Error ? err.message : String(err) });
|
|
614
|
+
}
|
|
615
|
+
// ── Skin Temperature (→ body) ──────────────────────────────────────────
|
|
616
|
+
try {
|
|
617
|
+
const skinRecords = await client.getSkinTemperature(timeRange);
|
|
618
|
+
for (const skin of skinRecords) {
|
|
619
|
+
try {
|
|
620
|
+
const data = transformSkinTemp(skin);
|
|
621
|
+
await ctx.runMutation(api.public.ingestBody, {
|
|
622
|
+
connectionId, userId, ...data,
|
|
623
|
+
});
|
|
624
|
+
synced.skinTemp++;
|
|
625
|
+
}
|
|
626
|
+
catch (err) {
|
|
627
|
+
errors.push({
|
|
628
|
+
type: "skinTemp",
|
|
629
|
+
id: skin.summaryId ?? skin.calendarDate ?? "unknown",
|
|
630
|
+
error: err instanceof Error ? err.message : String(err),
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
catch (err) {
|
|
636
|
+
errors.push({ type: "skinTemp", id: "fetch", error: err instanceof Error ? err.message : String(err) });
|
|
637
|
+
}
|
|
638
|
+
// ── User Metrics (→ body) ──────────────────────────────────────────────
|
|
639
|
+
try {
|
|
640
|
+
const metricsRecords = await client.getUserMetrics(timeRange);
|
|
641
|
+
for (const metrics of metricsRecords) {
|
|
642
|
+
try {
|
|
643
|
+
const data = transformUserMetrics(metrics);
|
|
644
|
+
await ctx.runMutation(api.public.ingestBody, {
|
|
645
|
+
connectionId, userId, ...data,
|
|
646
|
+
});
|
|
647
|
+
synced.userMetrics++;
|
|
648
|
+
}
|
|
649
|
+
catch (err) {
|
|
650
|
+
errors.push({
|
|
651
|
+
type: "userMetrics",
|
|
652
|
+
id: metrics.summaryId ?? metrics.calendarDate ?? "unknown",
|
|
653
|
+
error: err instanceof Error ? err.message : String(err),
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
catch (err) {
|
|
659
|
+
errors.push({ type: "userMetrics", id: "fetch", error: err instanceof Error ? err.message : String(err) });
|
|
660
|
+
}
|
|
661
|
+
// ── HRV (enriches daily) ──────────────────────────────────────────────
|
|
662
|
+
try {
|
|
663
|
+
const hrvRecords = await client.getHRV(timeRange);
|
|
664
|
+
for (const hrv of hrvRecords) {
|
|
665
|
+
try {
|
|
666
|
+
const data = transformHRV(hrv);
|
|
667
|
+
if (data.heart_rate_data) {
|
|
668
|
+
await ctx.runMutation(api.public.ingestDaily, {
|
|
669
|
+
connectionId, userId,
|
|
670
|
+
metadata: {
|
|
671
|
+
start_time: new Date((hrv.startTimeInSeconds ?? 0) * 1000).toISOString(),
|
|
672
|
+
end_time: new Date(((hrv.startTimeInSeconds ?? 0) + (hrv.durationInSeconds ?? 86400)) * 1000).toISOString(),
|
|
673
|
+
upload_type: 1,
|
|
674
|
+
},
|
|
675
|
+
heart_rate_data: data.heart_rate_data,
|
|
676
|
+
});
|
|
677
|
+
synced.hrv++;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
catch (err) {
|
|
681
|
+
errors.push({
|
|
682
|
+
type: "hrv",
|
|
683
|
+
id: hrv.summaryId ?? hrv.calendarDate ?? "unknown",
|
|
684
|
+
error: err instanceof Error ? err.message : String(err),
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
catch (err) {
|
|
690
|
+
errors.push({ type: "hrv", id: "fetch", error: err instanceof Error ? err.message : String(err) });
|
|
691
|
+
}
|
|
692
|
+
// ── Stress Details (enriches daily) ────────────────────────────────────
|
|
693
|
+
try {
|
|
694
|
+
const stressRecords = await client.getStressDetails(timeRange);
|
|
695
|
+
for (const stress of stressRecords) {
|
|
696
|
+
try {
|
|
697
|
+
const data = transformStressDetails(stress);
|
|
698
|
+
if (data.stress_data) {
|
|
699
|
+
await ctx.runMutation(api.public.ingestDaily, {
|
|
700
|
+
connectionId, userId,
|
|
701
|
+
metadata: {
|
|
702
|
+
start_time: new Date((stress.startTimeInSeconds ?? 0) * 1000).toISOString(),
|
|
703
|
+
end_time: new Date(((stress.startTimeInSeconds ?? 0) + (stress.durationInSeconds ?? 86400)) * 1000).toISOString(),
|
|
704
|
+
upload_type: 1,
|
|
705
|
+
},
|
|
706
|
+
stress_data: data.stress_data,
|
|
707
|
+
});
|
|
708
|
+
synced.stressDetails++;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
catch (err) {
|
|
712
|
+
errors.push({
|
|
713
|
+
type: "stressDetails",
|
|
714
|
+
id: stress.summaryId ?? stress.calendarDate ?? "unknown",
|
|
715
|
+
error: err instanceof Error ? err.message : String(err),
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
catch (err) {
|
|
721
|
+
errors.push({ type: "stressDetails", id: "fetch", error: err instanceof Error ? err.message : String(err) });
|
|
722
|
+
}
|
|
723
|
+
// ── Pulse Ox (enriches daily) ──────────────────────────────────────────
|
|
724
|
+
try {
|
|
725
|
+
const pulseOxRecords = await client.getPulseOx(timeRange);
|
|
726
|
+
for (const po of pulseOxRecords) {
|
|
727
|
+
try {
|
|
728
|
+
const data = transformPulseOx(po);
|
|
729
|
+
if (data.oxygen_data) {
|
|
730
|
+
await ctx.runMutation(api.public.ingestDaily, {
|
|
731
|
+
connectionId, userId,
|
|
732
|
+
metadata: {
|
|
733
|
+
start_time: new Date((po.startTimeInSeconds ?? 0) * 1000).toISOString(),
|
|
734
|
+
end_time: new Date(((po.startTimeInSeconds ?? 0) + (po.durationInSeconds ?? 86400)) * 1000).toISOString(),
|
|
735
|
+
upload_type: 1,
|
|
736
|
+
},
|
|
737
|
+
oxygen_data: data.oxygen_data,
|
|
738
|
+
});
|
|
739
|
+
synced.pulseOx++;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
catch (err) {
|
|
743
|
+
errors.push({
|
|
744
|
+
type: "pulseOx",
|
|
745
|
+
id: po.summaryId ?? po.calendarDate ?? "unknown",
|
|
746
|
+
error: err instanceof Error ? err.message : String(err),
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
catch (err) {
|
|
752
|
+
errors.push({ type: "pulseOx", id: "fetch", error: err instanceof Error ? err.message : String(err) });
|
|
753
|
+
}
|
|
754
|
+
// ── Respiration (enriches daily) ───────────────────────────────────────
|
|
755
|
+
try {
|
|
756
|
+
const respRecords = await client.getRespiration(timeRange);
|
|
757
|
+
for (const resp of respRecords) {
|
|
758
|
+
try {
|
|
759
|
+
const data = transformRespiration(resp);
|
|
760
|
+
if (data.respiration_data) {
|
|
761
|
+
await ctx.runMutation(api.public.ingestDaily, {
|
|
762
|
+
connectionId, userId,
|
|
763
|
+
metadata: {
|
|
764
|
+
start_time: new Date((resp.startTimeInSeconds ?? 0) * 1000).toISOString(),
|
|
765
|
+
end_time: new Date(((resp.startTimeInSeconds ?? 0) + (resp.durationInSeconds ?? 86400)) * 1000).toISOString(),
|
|
766
|
+
upload_type: 1,
|
|
767
|
+
},
|
|
768
|
+
respiration_data: data.respiration_data,
|
|
769
|
+
});
|
|
770
|
+
synced.respiration++;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
catch (err) {
|
|
774
|
+
errors.push({
|
|
775
|
+
type: "respiration",
|
|
776
|
+
id: resp.summaryId ?? "unknown",
|
|
777
|
+
error: err instanceof Error ? err.message : String(err),
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
catch (err) {
|
|
783
|
+
errors.push({ type: "respiration", id: "fetch", error: err instanceof Error ? err.message : String(err) });
|
|
784
|
+
}
|
|
699
785
|
return { synced, errors };
|
|
700
786
|
}
|
|
701
|
-
//# sourceMappingURL=
|
|
787
|
+
//# sourceMappingURL=public.js.map
|